feat: init

master
Mu Yi 2025-10-09 10:34:52 +08:00
commit d2378f8782
84 changed files with 7278 additions and 0 deletions

28
.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.env
.env.local
.env.development.local

1
.npmrc Normal file
View File

@ -0,0 +1 @@
engine-strict = true

1
.nvmdrc Normal file
View File

@ -0,0 +1 @@
23.8.0

12
.prettierignore Normal file
View File

@ -0,0 +1,12 @@
/dist/*
.local
.output.js
.github
.vscode
/node_modules/**
*.html
**/*.svg
**/*.sh
/public/**

10
.prettierrc.json Normal file
View File

@ -0,0 +1,10 @@
{
"printWidth": 160,
"arrowParens": "always",
"bracketSameLine": true,
"bracketSpacing": true,
"semi": true,
"singleAttributePerLine": false,
"vueIndentScriptAndStyle": true,
"htmlWhitespaceSensitivity": "ignore"
}

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

27
ALIYUN.pem Normal file
View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA2SOM6Heb+BNGha/ucoV+GopddM7ckyGWALhGPJp/Z7P5jgw6
NSJ1G/E7CFEukaLC50eupji9mA4o8Emtrgn8y7uMIc5lafHe0IPy+WA90PZyien4
0u7dD0NrEbKH41SIEuZFbGev0CgQJsxmkS8CmOytmglyJ0JDBpJD9tQLwSuG9kad
DrYPArQdQu+ZALt4gyG7m14c4mZ2hAcIUwNYqFY9g/HIp0q9al8SW3WqzkB1U7GS
kh3i/MwtUvZWPI16aKW4/tdUX7y8PPguHQ1MWLd6DI0iGo9tqTQt35o9ax41O+0S
EY4MgU1Q3XJaMrmrYUpZ2/Y4xJbHOHgyi6afzQIDAQABAoIBAGms4ovUgkSmZOD1
MU/s5eVWx4rsje7RHqa1CAHAkxbOQTq/eqiXX3U83qT6lXZtRvu2KCpfXO4eng/r
W6pi0/P3D4j4YOTBwNWsEdkJ3KvQ9QdnpiBJ/a3K+tW/FGEvp5XDGbBbefYNOWcY
fSZVQadZMFfSFwtCNUqCbq82nY3hkoFVGiQ9EHUlvNCQM4y5VeJuCPzsl8rzAsyo
gpkHyKxU/CNg+f5UuPwostR5eTXgkp6nlpa65yDK0szsww78keE/J1tOB0d4r+Oe
12ZVzYLQrzQwt2CwIGT9KkAUv7eO7ZTMDsG8MYNnRPGXKgjSZqBSW0MCq7ksz1/P
dHTJmSECgYEA9Q8VbnLkdk5NlRCNTONfjLhNUGmAqt/qLPi7tnJa0wfSpr3tg1Aj
AxnV455fT81vbDP8V8tGDNx+/d5jBkIsdsCYOMa6dqZr1HOfSgbH8wETtU9mbKdB
Gt/frdM3rkJvyd5RjoqMex4U7x4f1OWfThHVzvi8TzqfRSXNpbXBMdUCgYEA4tVa
TBQhwgnjMHl9OYrW1urtf2fKEGOZA/uGJI55O7IL2SoYnVjFUHjlE4D94K/hdijp
l2oFydD0GrWVkWULPvTdUFzMTRPH+SUfXbVqXBMJfHJYrRuZHsJBH2jIwIzu4LaA
hliletIdJUtK8mUvwEb+4TlVUwfCYqkveu1EuhkCgYAHjK5pV6rIJkNnmznvK3YP
HMJs/sMTAJDzT7pgtYcsxynrLyC5EefyOYKIX6GqELclCzjz73Q6AzT6VzaPw8wg
4HAQF7c43oml4uX+XtUcHGViCY8rO7/atxjp/v7RJITTIEE89fG7/UJB15i9c1GE
EzKWDL2oZzLu62o5d676/QKBgQDgiCBhvmvMDs18ZkW2d+BBzTpaKvqxTmVgs9EM
zpripFNmG21SE1T9Wy4mKEEl7/NVaxoObzxbkSKQbb4ntcV0BB4uNi1k/ner/zsV
H0aw7YcuUGHGuNLQx6h+1tIhB2BNv1lposXq1aFUETuWxOKHib8yYfY7wiqATshY
/hRRwQKBgCkT2Wt/XjbXLCpX1viEJOLzYYQkrNyPvruXknCnQQ+0/cq4LoRqWZZR
4RjS0RkoOF4vM38u/hgICiUUCR4bYUy/4O7uhNu5tDle6lIeB+ZxVpRRedE0OfQT
tCpQd0yN9iONBlGyfAtpq7oNzuXgsl1OR4usZ8wCinfImChAl6wv
-----END RSA PRIVATE KEY-----

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# 支付统计项目
深泉支付统计项目

BIN
dist.zip Normal file

Binary file not shown.

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/icons/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
<title></title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

54
package.json Normal file
View File

@ -0,0 +1,54 @@
{
"name": "vue-app-template",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --host 0.0.0.0",
"build": "vue-tsc -b && vite build",
"upload": "bash ./upload.sh",
"build-and-upload": "pnpm run build && pnpm run upload",
"preview": "vite preview",
"check-env": "node ./scripts/checkVersions.cjs"
},
"dependencies": {
"@types/crypto-js": "^4.2.2",
"@types/node": "^22.10.1",
"@unocss/reset": "^66.1.1",
"axios": "^1.7.9",
"crypto-js": "^4.2.0",
"echarts": "^5.6.0",
"echarts-gl": "^2.0.9",
"gsap": "^3.13.0",
"pinia": "^2.3.0",
"pinia-plugin-persistedstate": "^4.1.3",
"semver": "^7.6.3",
"unocss-preset-px-to-vw-or-vh": "^1.0.6",
"unocss-preset-scrollbar-hide": "^1.0.1",
"vue": "^3.5.13",
"vue-router": "4",
"vue-virtual-draglist": "^3.3.8"
},
"devDependencies": {
"@iconify-json/carbon": "^1.2.8",
"@types/gsap": "^3.0.0",
"@types/qs": "^6.9.17",
"@unocss/preset-wind": "^0.65.2",
"@vitejs/plugin-basic-ssl": "^1.2.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vueuse/core": "^13.4.0",
"prettier": "3.4.2",
"sass-embedded": "^1.86.0",
"svg-sprite-loader": "^6.0.11",
"typescript": "~5.6.2",
"unocss": "^0.65.2",
"unplugin-auto-import": "^0.19.0",
"vite": "^6.0.1",
"vue-tsc": "^2.1.10"
},
"engines": {
"node": ">=22.11.0",
"pnpm": ">=9.13.2"
},
"preinstall": "npx only-allow pnpm"
}

70
plugins/svgBuilder.ts Normal file
View File

@ -0,0 +1,70 @@
// /plugins/svgBuilder.ts
import {readFileSync, readdirSync} from 'fs'
import {join as pathJoin} from 'path'
import {Plugin} from 'vite'
let idPrefix = ''
const svgTitle = /<svg([^>+].*?)>/
const clearHeightWidth = /(width|height)="([^>+].*?)"/g
const clearFill = /fill="[^>+].*?"/g;
const hasViewBox = /(viewBox="[^>+].*?")/g
const clearReturn = /(\r)|(\n)/g
const findSvgFile = (dir: string) => {
const svgRes: string[] = []
const directory = readdirSync(dir, {withFileTypes: true})
for (const dirent of directory) {
if (dirent?.isDirectory()) {
svgRes.push(...findSvgFile(pathJoin(dir, dirent.name, '/')))
} else {
const svg = readFileSync(pathJoin(dir, dirent.name))
.toString()
.replace(clearReturn, '')
.replace(clearFill,'')
.replace(svgTitle, (_$1: string, $2: string) => {
let width = '0'
let height = '0'
let content = $2.replace(
clearHeightWidth,
(_s1, s2:string, s3:string) => {
if (s2 === 'width') {
width = s3
} else if (s2 === 'height') {
height = s3
}
return ''
}
)
if (!hasViewBox.test($2)) {
content += `viewBox="0 0 ${width} ${height}"`
}
return `<symbol id="${idPrefix}-${dirent.name.replace(
'.svg',
''
)}" ${content}>`
})
.replace('</svg>', '</symbol>')
svgRes.push(svg)
}
}
return svgRes
}
const svgBuilder = (path: string, prefix = 'icon'): Plugin => {
idPrefix = prefix
const res = findSvgFile(path)
return {
name: 'svg-transform',
transformIndexHtml(html) {
return html.replace(
'<body>',
`<body><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">${res.join('')}</svg>`
)
}
}
}
export default svgBuilder

5363
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

BIN
public/images/home.webp Normal file

Binary file not shown.

BIN
public/images/logo.webp Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,39 @@
// timer.worker.js
let timer = null;
let interval = 1000;
self.addEventListener('message', (e) => {
switch (e.data.command) {
case 'start':
startTimer(e.data.interval);
break;
case 'stop':
stopTimer();
break;
case 'update':
interval = e.data.interval;
break;
}
});
// 关闭时的清理逻辑
self.addEventListener('close', () => {
stopTimer();
});
function startTimer(newInterval) {
interval = newInterval || interval;
stopTimer(); // 先停止已有定时器
self.postMessage({ type: 'tick', timestamp:performance.now() });
timer = setInterval(() => {
const timestamp = performance.now();
self.postMessage({ type: 'tick', timestamp });
}, interval);
}
function stopTimer() {
if (timer) {
clearInterval(timer);
timer = null;
}
}

18
scripts/checkVersions.cjs Normal file
View File

@ -0,0 +1,18 @@
const semver = require('semver')
const { engines } = require('../package')// 这里的package是你的package.json文件路径
const version = engines.node
if (!semver.satisfies(process.version, version)) {
console.log(
[
'node环境变量版本错误',
'你的node环境启动位置' + process.execPath + '.',
'要求环境版本' + version,
'你的环境版本' + process.version
].join('\n')
)
process.exit(1)
}else{
console.log(`echo check environment successfully`)
}

36
src/App.vue Normal file
View File

@ -0,0 +1,36 @@
<template>
<router-view v-slot="{ Component,route }">
<keep-alive :include="include" :exclude="excludes">
<component :is="Component" :key="route.path"/>
</keep-alive>
</router-view>
</template>
<script setup lang="ts">
import { excludes } from '@/router/keepAlive'
const include:string[] = []
</script>
<style scoped>
/* 过渡动画:左右滑动并且淡入淡出 */
.fade-slide-enter-active, .fade-slide-leave-active {
transition: transform 1s ease, opacity 1s ease;
}
/* 进入动画:从右侧进入 */
.fade-slide-enter {
transform: translateX(100%);
opacity: 0;
}
/* 离开动画:从左侧离开 */
.fade-slide-leave-to {
transform: translateX(-100%);
opacity: 0;
}
</style>

66
src/api/customFetch.ts Normal file
View File

@ -0,0 +1,66 @@
import { useUserStore } from "@/store/user";
/*
* @Author: HideInMatrix
* @Date: 2024-07-15
* @LastEditors: error: git config user.name & please set dead value or install git
* @LastEditTime: 2024-09-01
* @Description:
*/
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
interface FetchOptions extends RequestInit {
headers?: Record<string, string>;
}
interface ApiResponse {
result?: unknown;
error?: string;
code?: number;
success?: boolean;
message?:string;
}
const apiClient = (method: HttpMethod) => {
return async (
url: string,
data?: unknown,
options: FetchOptions = {}
): Promise<ApiResponse> => {
const userStore = useUserStore();
const accessToken = userStore.getAccessToken
const config: FetchOptions = {
method,
headers:{ Authorization: `Bearer ${accessToken}`},
...options,
};
if (method !== "GET" && data) {
config.body = JSON.stringify(data);
} else if (method === "GET" && data) {
const _params = [];
for (const [key, value] of Object.entries(data)) {
_params.push(`${key}=${value}`);
}
url += `?${_params.join("&")}`;
}
const response = await fetch(`${url}`, config);
const result = await response.json();
if (!response.ok) {
return {
error: result.message || "Request failed",
code: response.status,
};
}
return result;
};
};
export const getRequest = apiClient("GET");
export const postRequest = apiClient("POST");
export const putRequest = apiClient("PUT");
export const deleteRequest = apiClient("DELETE");

19
src/api/fetchUrl.ts Normal file
View File

@ -0,0 +1,19 @@
const baseUrl = "http://api.screen.jinze.ycymedu.com";
export const getPaymentUrl = () => `${baseUrl}/api/bigScreenData/bigScreenData`;
export const getGainUrl = () => `${baseUrl}/api/bigScreenData/bigScreenCustomerAcq`;
export const getAcqTrend = () => `${baseUrl}/api/bigScreenData/bigScreenAcqTrend`;
export const getSegmentStatic = () => `${baseUrl}/api/bigScreenData/bigScreenStages`;
export const getBigScreenRanking = () => `${baseUrl}/api/bigScreenData/bigScreenRanks`;
export const getSixStatisticsUrl = () => `${baseUrl}/api/bigScreenData/wechatData`
export const postLoginUrl=() => `${baseUrl}/api/sysAuth/BigScreenLogin`
export const getUserInfoUrl = ()=> `${baseUrl}/api/sysAuth/userInfo`
export const getLogoutUrl = () => `${baseUrl}/api/sysAuth/logout`

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="14.13671875" height="17.787841796875" viewBox="0 0 14.13671875 17.787841796875"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_110_5610"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="51.01040005683899%" stop-color="#97BBFF" stop-opacity="1"/><stop offset="52.34435796737671%" stop-color="#1168FF" stop-opacity="1"/><stop offset="100%" stop-color="#1185FF" stop-opacity="1"/></linearGradient><linearGradient x1="0.24648989737033844" y1="0" x2="0.3002182700303045" y2="0.8341024570154847" id="master_svg1_110_5613"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="100%" stop-color="#2D8CFF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg2_110_5623"><stop offset="0%" stop-color="#66E0FF" stop-opacity="0"/><stop offset="100%" stop-color="#1164FF" stop-opacity="0.5"/></linearGradient></defs><g><g style="opacity:0.30000001192092896;"><path d="M0.5,2.60546875L13.1633,10.46999875L0.5,17.78786875L0.5,15.87376875L5.18962,10.46999875L0.5,4.66468875L0.5,2.60546875Z" fill-rule="evenodd" fill="#044BB8" fill-opacity="1" style="mix-blend-mode:passthrough"/></g><g><path d="M0.5,0.8990478515625L13.1633,8.7635778515625L0.5,16.0814478515625L0.5,14.1673478515625L5.18962,8.7635778515625L0.5,2.9582678515625L0.5,0.8990478515625Z" fill-rule="evenodd" fill="url(#master_svg0_110_5610)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g><g><path d="M0,0L0,2.95833L0,3.13506L4.53757,8.75214L0,13.9807L0,16.948L14.1359,8.77909L0,0ZM1,2.78161L5.84168,8.77514L1,14.3541L1,15.2151L12.1907,8.74819L1,1.79821L1,2.78161Z" fill-rule="evenodd" fill="url(#master_svg1_110_5613)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g><g><path d="M0.5,0.89892578125L13.1633,8.76345578125L5.18962,8.76345578125L0.5,2.95814578125L0.5,0.89892578125Z" fill-rule="evenodd" fill="url(#master_svg2_110_5623)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 544.5 210.75"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_95_7905"><stop offset="0%" stop-color="#23518C" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#17439D" stop-opacity="0.10000000149011612"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_95_7906" gradientTransform="translate(272.25 210.5) rotate(90) scale(33.016276359558105 293.6848504078262)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.10000000149011612"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg2_95_7907" gradientTransform="translate(272.25 210.5) rotate(90) scale(7.3813605308532715 170.33950726831247)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg3_95_7908" gradientTransform="translate(272.25 210.5) rotate(90) scale(3.5998570919036865 121.80235547062695)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="0.5" y1="0.05106060206890106" x2="0.5" y2="1" id="master_svg4_81_5443"><stop offset="0%" stop-color="#525DFF" stop-opacity="0"/><stop offset="100%" stop-color="#525DFF" stop-opacity="0.47999998927116394"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg5_13_2169" gradientTransform="translate(250.49790859222412 0.5) rotate(0) scale(5.699835777282715 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg6_13_2170"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient></defs><g><g><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="#000000" fill-opacity="0.25"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="url(#master_svg0_95_7905)" fill-opacity="1"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="url(#master_svg1_95_7906)" fill-opacity="1"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="url(#master_svg2_95_7907)" fill-opacity="1"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="url(#master_svg3_95_7908)" fill-opacity="1"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" stroke="url(#master_svg4_81_5443)" fill-opacity="0" fill="none" stroke-width="0.5"/></g><g style="opacity:0.44999998807907104;"><path d="M480.25,1L289.725,1L245.498,1L64.25,1L64.25,0L245.498,0L289.725,0L480.25,0L480.25,1Z" fill-rule="evenodd" fill="url(#master_svg5_13_2169)" fill-opacity="1"/><path d="M480.25,1L289.725,1L245.498,1L64.25,1L64.25,0L245.498,0L289.725,0L480.25,0L480.25,1Z" fill-rule="evenodd" fill="url(#master_svg6_13_2170)" fill-opacity="1"/></g></g></svg>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 188 36"><defs><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg0_110_5669"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.4000000059604645"/><stop offset="23.317307233810425%" stop-color="#2773FF" stop-opacity="0.25"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.05999999865889549"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_110_4138" gradientTransform="translate(132.2986946851015 34.756103515625) rotate(76.51046439419082) scale(17.356884100084887 29.26667369717238)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg2_110_4139"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg3_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg4_110_5643"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/><stop offset="18.59523504972458%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg5_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient></defs><g><g><path d="M0,1L177.338,1L138.238,30.561L0,30.561L0,1Z" fill-rule="evenodd" fill="url(#master_svg0_110_5669)" fill-opacity="1"/></g><g><path d="M183.644,1.5L295.5,1.5L295.5,0.5L183.306,0.5L139.079,34.2561L0,34.2561L0,35.2561L139.417,35.2561L183.644,1.5Z" fill-rule="evenodd" fill="url(#master_svg1_110_4138)" fill-opacity="1"/><path d="M183.644,1.5L295.5,1.5L295.5,0.5L183.306,0.5L139.079,34.2561L0,34.2561L0,35.2561L139.417,35.2561L183.644,1.5Z" fill-rule="evenodd" fill="url(#master_svg2_110_4139)" fill-opacity="1"/></g><g><g><path d="M182.97852,1L294.145,1L288.074,6.2439L176,6.2439L182.97852,1Z" fill-rule="evenodd" fill="url(#master_svg3_110_5664)" fill-opacity="1"/></g><g><path d="M182.999984375,1L263.919784375,1L251.97318437500002,11.4878L169.146484375,11.4878L182.999984375,1Z" fill-rule="evenodd" fill="url(#master_svg4_110_5643)" fill-opacity="1"/></g><g style="opacity:0.5;"><g><path d="M184.1035,1L295.464,1L295.464,23.0244L155,23.0244L184.1035,1Z" fill-rule="evenodd" fill="url(#master_svg5_110_5664)" fill-opacity="1"/></g></g></g></g></svg>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 255 36"><defs><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg0_110_5669"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.4000000059604645"/><stop offset="23.317307233810425%" stop-color="#2773FF" stop-opacity="0.25"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.05999999865889549"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_110_4537" gradientTransform="translate(114.16638627648354 34.756103515625) rotate(78.3045141357308) scale(17.2358897800393 25.079449849220687)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1.578010082244873" y1="0.6616930961608887" x2="-0.00028524507193582627" y2="0.6588591327853952" id="master_svg2_110_4538"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg3_110_5566" gradientTransform="translate(538.6601538022733 1) rotate(0) scale(9.584570288854593 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg4_110_5567"><stop offset="0%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#27AEFF" stop-opacity="1"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg5_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg6_110_5643"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/><stop offset="18.59523504972458%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0.06541949510574341" y2="0.5" id="master_svg7_110_5455"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient></defs><g><g><g><path d="M0,1L217.337,1L178.239,30.561L0,30.561L0,1Z" fill-rule="evenodd" fill="url(#master_svg0_110_5669)" fill-opacity="1"/></g><g><path d="M225.643,1.5L255,1.5L255,0.5L225.305,0.5L181.079,34.2561L0,34.2561L0,35.2561L181.417,35.2561L225.643,1.5Z" fill-rule="evenodd" fill="url(#master_svg1_110_4537)" fill-opacity="1"/><path d="M225.643,1.5L255,1.5L255,0.5L225.305,0.5L181.079,34.2561L0,34.2561L0,35.2561L181.417,35.2561L225.643,1.5Z" fill-rule="evenodd" fill="url(#master_svg2_110_4538)" fill-opacity="1"/></g></g><g><g><path d="M925.000609375,1.5L225.474609375,1.5L225.474609375,0.5L925.000609375,0.5L925.000609375,1.5Z" fill-rule="evenodd" fill="url(#master_svg3_110_5566)" fill-opacity="1"/><path d="M925.000609375,1.5L225.474609375,1.5L225.474609375,0.5L925.000609375,0.5L925.000609375,1.5Z" fill-rule="evenodd" fill="url(#master_svg4_110_5567)" fill-opacity="1"/></g><g><path d="M225.97852,1L924.145,1L918.074,6.2439L219,6.2439L225.97852,1Z" fill-rule="evenodd" fill="url(#master_svg5_110_5664)" fill-opacity="1"/></g><g><path d="M225.3535,1L893.92,1L881.973,11.4878L211.5,11.4878L225.3535,1Z" fill-rule="evenodd" fill="url(#master_svg6_110_5643)" fill-opacity="1"/></g><g><path d="M225.1035,0L924.964,0L924.964,22.0244L197,22.0244L225.1035,0Z" fill-rule="evenodd" fill="url(#master_svg7_110_5455)" fill-opacity="1"/></g></g></g></svg>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="188 0 108 36"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_110_4138" gradientTransform="translate(132.2986946851015 34.756103515625) rotate(76.51046439419082) scale(17.356884100084887 29.26667369717238)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg1_110_4139"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg2_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg3_110_5643"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/><stop offset="18.59523504972458%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg4_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="0.9886833429336548" y1="0.5" x2="0" y2="0.5" id="master_svg5_110_5647"><stop offset="0%" stop-color="#02DBFF" stop-opacity="0"/><stop offset="100%" stop-color="#01B5FF" stop-opacity="1"/></linearGradient></defs><g><g><path d="M183.644,1.5L295.5,1.5L295.5,0.5L183.306,0.5L139.079,34.2561L0,34.2561L0,35.2561L139.417,35.2561L183.644,1.5Z" fill-rule="evenodd" fill="url(#master_svg0_110_4138)" fill-opacity="1"/><path d="M183.644,1.5L295.5,1.5L295.5,0.5L183.306,0.5L139.079,34.2561L0,34.2561L0,35.2561L139.417,35.2561L183.644,1.5Z" fill-rule="evenodd" fill="url(#master_svg1_110_4139)" fill-opacity="1"/></g><g><g><path d="M182.97852,1L294.145,1L288.074,6.2439L176,6.2439L182.97852,1Z" fill-rule="evenodd" fill="url(#master_svg2_110_5664)" fill-opacity="1"/></g><g><path d="M182.999984375,1L263.919784375,1L251.97318437500002,11.4878L169.146484375,11.4878L182.999984375,1Z" fill-rule="evenodd" fill="url(#master_svg3_110_5643)" fill-opacity="1"/></g><g style="opacity:0.5;"><g><path d="M184.1035,1L295.464,1L295.464,23.0244L155,23.0244L184.1035,1Z" fill-rule="evenodd" fill="url(#master_svg4_110_5664)" fill-opacity="1"/></g><g><g><path d="M268.89489541992185,5.195068359375L263.72240541992187,10.438968359375L260.8193054199219,10.438968359375L265.9917854199219,5.195068359375L268.89489541992185,5.195068359375ZM274.9515054199219,5.195068359375L269.78065541992186,10.438968359375L266.8759454199219,10.438968359375L272.0493054199219,5.195068359375L274.9515054199219,5.195068359375ZM281.00820541992186,5.195068359375L275.83480541992185,10.438968359375L272.93260541992186,10.438968359375L278.10600541992187,5.195068359375L281.00820541992186,5.195068359375ZM287.06480541992187,5.195068359375L281.89140541992185,10.438968359375L278.98920541992186,10.438968359375L284.1601054199219,5.195068359375L287.06480541992187,5.195068359375ZM286.9392054199219,10.438968359375L292.11170541992186,5.195068359375L289.20860541992187,5.195068359375L284.03610541992185,10.438968359375L286.9392054199219,10.438968359375Z" fill-rule="evenodd" fill="url(#master_svg5_110_5647)" fill-opacity="1"/></g></g></g></g></g></svg>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="256 0 669 36"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_110_5566" gradientTransform="translate(538.6601538022733 1) rotate(0) scale(9.584570288854593 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg1_110_5567"><stop offset="0%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#27AEFF" stop-opacity="1"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg2_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg3_110_5643"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/><stop offset="18.59523504972458%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0.06541949510574341" y2="0.5" id="master_svg4_110_5455"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="0.9886833429336548" y1="0.5" x2="0" y2="0.5" id="master_svg5_110_5647"><stop offset="0%" stop-color="#02DBFF" stop-opacity="0"/><stop offset="100%" stop-color="#01B5FF" stop-opacity="1"/></linearGradient></defs><g><g><g><path d="M925.000609375,1.5L225.474609375,1.5L225.474609375,0.5L925.000609375,0.5L925.000609375,1.5Z" fill-rule="evenodd" fill="url(#master_svg0_110_5566)" fill-opacity="1"/><path d="M925.000609375,1.5L225.474609375,1.5L225.474609375,0.5L925.000609375,0.5L925.000609375,1.5Z" fill-rule="evenodd" fill="url(#master_svg1_110_5567)" fill-opacity="1"/></g><g><path d="M225.97852,1L924.145,1L918.074,6.2439L219,6.2439L225.97852,1Z" fill-rule="evenodd" fill="url(#master_svg2_110_5664)" fill-opacity="1"/></g><g><path d="M225.3535,1L893.92,1L881.973,11.4878L211.5,11.4878L225.3535,1Z" fill-rule="evenodd" fill="url(#master_svg3_110_5643)" fill-opacity="1"/></g><g><path d="M225.1035,0L924.964,0L924.964,22.0244L197,22.0244L225.1035,0Z" fill-rule="evenodd" fill="url(#master_svg4_110_5455)" fill-opacity="1"/></g><g><path d="M898.3959025,4.195068359375L893.2234125,9.438968359375L890.3203125,9.438968359375L895.4927925,4.195068359375L898.3959025,4.195068359375ZM904.4525125,4.195068359375L899.2816625,9.438968359375L896.3769525,9.438968359375L901.5503125,4.195068359375L904.4525125,4.195068359375ZM910.5092125,4.195068359375L905.3358125,9.438968359375L902.4336125,9.438968359375L907.6070125,4.195068359375L910.5092125,4.195068359375ZM916.5658125,4.195068359375L911.3924125,9.438968359375L908.4902125,9.438968359375L913.6611125,4.195068359375L916.5658125,4.195068359375ZM916.4402125,9.438968359375L921.6127125,4.195068359375L918.7096125,4.195068359375L913.5371125,9.438968359375L916.4402125,9.438968359375Z" fill-rule="evenodd" fill="url(#master_svg5_110_5647)" fill-opacity="1"/></g></g></g></svg>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="480" height="48" viewBox="0 0 480 48"><g><path d="M0,48L480,48L480,0L10.1181,0L0,12.5L0,48L0,48Z" fill="#061E3A" fill-opacity="1"/><path d="M480,48L480,0L10.1181,0L0,12.5L0,48L480,48ZM1,47L479,47L479,1L10.5952,1L1,12.854L1,47Z" fill-rule="evenodd" fill="#2A8EFE" fill-opacity="1"/></g></svg>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 14 22"><defs><pattern x="1.9090908765792847" y="3" width="10.181818008422852" height="16" patternUnits="userSpaceOnUse" id="master_svg0_120_993"><image x="0" y="0" width="42" height="66" transform="scale(0.2424242382957822,0.24242424242424243)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAABCCAYAAAAhZERsAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAOFSURBVGiB7dk/bBN3FMDx77vYlH9qJFKwQQIkaLsUIXXoAgssDIEyVIz8ERJ0AaXAUrUm7YnYAfEnXZspVZmqDqUIZgSICYQU/qwUKSj2ORJDqColuPcYEreWdbbPd7/f7xbedu89nT96z3e+k+F9OI6JGV2VtQHA69Uw/wGDF6r6hQtMt+gJ9TdIzfP4tFLVvS5AqWOspr9lie050f8ahREVprLCxoaWChIgnFXhVhbY2FCA8wX5A+H3LLB9QQEaOUaAOdfYvqH+kMx7yjFgpUts31CA7zfKXVV+Ala7wiaCAgz+TQl4hiNsYujIJ7IQCoeBRRxgE0MBfijINPDj8qFVbCooQKPAZYUHy4fWsGLiJBcD3favMg2sXU79I8qB0ka5Y+L8YGCiAN8V5IXA2ZaU8ckamWgzyjW9CXzZkjI2WSMTbUYDTgBzLSljkzUK9YtSV+HrtrQRrFEowGhBbgBTbenUWONQgPwA3wAv29KpsFag366XN4QcA8K2UmKsFSjA+U1yT4VrEaVEWGtQgMF5RoGnEaW+sUbvo1FRCXSnKg+BFRHl2PdZqxMFKBXkCcpoh3LsyVqHAjSKXFXhfodyLKwTqC8SsvT68qZDS0+sEyjAaFH+EjjTpaUr1vrF1B6Vmv6pcLBLS+QF5myizXgLJ4F6l5bIyTqH+kWpK4z3aFutwk1/Rtc1E86hV2q6RuB0j7ZQhFP+ZnndTDiHLsI14OMuLaEIx0sF+bU16fRiGqvqsAi3u7REIsEhdPyVDoU5ngHFDi0dkeBw9ZrnZxIiwRG0HOgRVQ51KPdEgoPVX5rVLQ2PJ8BgRDkWEixPVFWl4fELKZFgGVoOOANE/Xb3hQSLq79Q1c884RGwsq3UNxIsTXRSNe/BdQwhwRJ0LsBH+LwtnRgJFlZfDnQXyj1goCWdCgmGoVdqumYBpoHtLenUSDC8+gWYwAISDE60UtX9KtxqSRlDgiGoP6sf5Tye8v9vuVEkGFp9XpjEIhIMQCuBHlXhq+VDK0hIufryrG5l6YHjQywiIcVEVVVYeuCwjoQU0PE654A9OEBCwtVXarpD4RGQd4GEJH+DP9cVuvTA4QwJCaADQ/jATpfIvmM80N3lmi5WAj3q+rNjf0f9uq7NhTwWoZzFJHNxG/MhV8kIGTvGqjpcDvRI1o6u4c/ourFA92Xt6BmXXmvUq+776BTvAA46hzw7ExF1AAAAAElFTkSuQmCC"/></pattern></defs><g><g><rect x="1.9090908765792847" y="3" width="10.181818008422852" height="16" rx="0" fill="url(#master_svg0_120_993)" fill-opacity="1"/></g></g></svg>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="127" height="104" viewBox="0 0 127 104"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_85_02406" gradientTransform="translate(62.63833460211754 261.1206922531128) rotate(90) scale(129.7585763875395 128.02340110725947)"><stop offset="0%" stop-color="#4EAAFF" stop-opacity="1"/><stop offset="36.93000078201294%" stop-color="#0066FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#000000" stop-opacity="0"/></radialGradient></defs><g><g transform="matrix(1,0,0,-1,0,262)" style="opacity:0.10000000149011612;"><path d="M63.5,131C28.4311,131,0,189.2103,0,261C0,261,127,261,127,261C127,189.1801,98.5743,131,63.5,131C63.5,131,63.5,131,63.5,131Z" fill="url(#master_svg0_85_02406)" fill-opacity="1"/></g><g style="opacity:0.20000000298023224;"><path d="M127,102.5L1,102.5L1,101.5L127,101.5L127,102.5Z" fill-rule="evenodd" fill="#0867A2" fill-opacity="1"/></g><g><path d="M126,1.5L0,1.5L0,0.5L126,0.5L126,1.5Z" fill-rule="evenodd" fill="#0867A2" fill-opacity="1"/></g><g><path d="M12,1.5L0,1.5L0,0.5L12,0.5L12,1.5Z" fill-rule="evenodd" fill="#00AAFF" fill-opacity="1"/></g></g></svg>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 55 121"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_85_7578"><stop offset="0%" stop-color="#0085FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#0047FF" stop-opacity="0"/></linearGradient><linearGradient x1="0.49977484345436096" y1="0.9948660731315613" x2="0.49977484345436096" y2="0.000026565079679130577" id="master_svg1_73_6481"><stop offset="0%" stop-color="#0058FF" stop-opacity="0"/><stop offset="100%" stop-color="#00AAFF" stop-opacity="0.5"/></linearGradient><linearGradient x1="0" y1="0.5" x2="1.0000001192092896" y2="0.5" id="master_svg2_73_6482"><stop offset="0%" stop-color="#0066FF" stop-opacity="1"/><stop offset="12.5%" stop-color="#0066FF" stop-opacity="1"/><stop offset="49.73750710487366%" stop-color="#87D4FF" stop-opacity="1"/><stop offset="91.14583134651184%" stop-color="#0075FF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5000787973403931" y1="0.9994168281555176" x2="0.5000787973403931" y2="0" id="master_svg3_85_5542"><stop offset="0%" stop-color="#00C9FF" stop-opacity="1"/><stop offset="100%" stop-color="#0072DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg4_13_2583"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="0"/><stop offset="100%" stop-color="#FFFFFF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5000787973403931" y1="0.9994168281555176" x2="0.5000787973403931" y2="0" id="master_svg5_85_5542"><stop offset="0%" stop-color="#00C9FF" stop-opacity="1"/><stop offset="100%" stop-color="#0072DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.5000787973403931" y1="0.9994168281555176" x2="0.5000787973403931" y2="0" id="master_svg6_85_5542"><stop offset="0%" stop-color="#00C9FF" stop-opacity="1"/><stop offset="100%" stop-color="#0072DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg7_13_2583"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="0"/><stop offset="100%" stop-color="#FFFFFF" stop-opacity="1"/></linearGradient></defs><g><g style="opacity:0.30000001192092896;"><path d="M1,111C1,113.761,3.23858,116,6,116L49,116C51.7614,116,54,113.761,54,111L54,4L1,4L1,111Z" fill="url(#master_svg0_85_7578)" fill-opacity="1"/></g><g><rect x="1" y="85" width="53" height="30" rx="0" fill="url(#master_svg1_73_6481)" fill-opacity="1" id="pw1" /><rect id="pw2" x="1" y="85" width="53" height="30" rx="0" fill="url(#master_svg2_73_6482)" fill-opacity="0.6000000238418579"/></g><g><ellipse cx="27.5" cy="5" rx="26.5" ry="5" fill="url(#master_svg3_85_5542)" fill-opacity="1"/></g><g><path d="M53.3333,5C53.3333,5.498801,52.8377,6.0743100000000005,51.576,6.68445C50.3307,7.28672,48.4753,7.85205,46.1077,8.33633C41.3823,9.30283,34.8033,9.909089999999999,27.5,9.909089999999999C27.5,9.909089999999999,27.5,11,27.5,11C34.924,11,41.6783,10.38521,46.6047,9.37758C49.063,8.87476,51.1127,8.26474,52.5663,7.56187C54.0033,6.86686,55,6.00743,55,5C55,5,53.3333,5,53.3333,5C53.3333,5,53.3333,5,53.3333,5ZM27.5,9.909089999999999C20.1965,9.909089999999999,13.6176,9.30283,8.89237,8.33633C6.52483,7.85205,4.6695,7.28672,3.42413,6.68445C2.16246,6.0743100000000005,1.66667,5.498801,1.66667,5C1.66667,5,0,5,0,5C0,6.00743,0.996595,6.86686,2.43374,7.56187C3.88718,8.26474,5.9371,8.87476,8.39527,9.37758C13.3215,10.38521,20.0759,11,27.5,11C27.5,11,27.5,9.909089999999999,27.5,9.909089999999999C27.5,9.909089999999999,27.5,9.909089999999999,27.5,9.909089999999999Z" fill="url(#master_svg4_13_2583)" fill-opacity="1"/></g><g><ellipse id="ellipse1" cx="27.5" cy="85" rx="26.5" ry="5" fill="url(#master_svg5_85_5542)" fill-opacity="1"/></g><g><ellipse cx="27.5" cy="115" rx="26.5" ry="5" fill="url(#master_svg6_85_5542)" fill-opacity="1"/></g><g><path d="M53.3333,115C53.3333,115.498801,52.8377,116.07431,51.576,116.68445C50.3307,117.28672,48.4753,117.85205,46.1077,118.33633C41.3823,119.30283,34.8033,119.90909,27.5,119.90909C27.5,119.90909,27.5,121,27.5,121C34.924,121,41.6783,120.38521,46.6047,119.37758C49.063,118.87476,51.1127,118.26474,52.5663,117.56187C54.0033,116.86686,55,116.00743,55,115C55,115,53.3333,115,53.3333,115C53.3333,115,53.3333,115,53.3333,115ZM27.5,119.90909C20.1965,119.90909,13.6176,119.30283,8.89237,118.33633C6.52483,117.85205,4.6695,117.28672,3.42413,116.68445C2.16246,116.07431,1.66667,115.498801,1.66667,115C1.66667,115,0,115,0,115C0,116.00743,0.996595,116.86686,2.43374,117.56187C3.88718,118.26474,5.9371,118.87476,8.39527,119.37758C13.3215,120.38521,20.0759,121,27.5,121C27.5,121,27.5,119.90909,27.5,119.90909C27.5,119.90909,27.5,119.90909,27.5,119.90909Z" fill="url(#master_svg7_13_2583)" fill-opacity="1"/></g></g></svg>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="312.5" height="210.75" viewBox="0 0 312.5 210.75"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_95_7905"><stop offset="0%" stop-color="#23518C" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#17439D" stop-opacity="0.10000000149011612"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_95_7906" gradientTransform="translate(156.25 210.5) rotate(90) scale(33.016276359558105 168.4368994986062)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.10000000149011612"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg2_95_7907" gradientTransform="translate(156.25 210.5) rotate(90) scale(7.3813605308532715 97.69471740388508)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg3_95_7908" gradientTransform="translate(156.25 210.5) rotate(90) scale(3.5998570919036865 69.85723328462429)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="0.5" y1="0.05106060206890106" x2="0.5" y2="1" id="master_svg4_81_5443"><stop offset="0%" stop-color="#525DFF" stop-opacity="0"/><stop offset="100%" stop-color="#525DFF" stop-opacity="0.47999998927116394"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg5_13_2169" gradientTransform="translate(139.9359314441681 0.5) rotate(0) scale(4.274876832962036 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg6_13_2170"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient></defs><g><g><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="#000000" fill-opacity="0.25"/><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="url(#master_svg0_95_7905)" fill-opacity="1"/><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="url(#master_svg1_95_7906)" fill-opacity="1"/><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="url(#master_svg2_95_7907)" fill-opacity="1"/><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="url(#master_svg3_95_7908)" fill-opacity="1"/><path d="M312.5,0.25L0,0.25L0,210.75L312.5,210.75L312.5,0.25ZM0.5,210.25L0.5,0.75L312,0.75L312,210.25L0.5,210.25Z" fill-rule="evenodd" fill="url(#master_svg4_81_5443)" fill-opacity="1"/></g><g style="opacity:0.4000000059604645;"><path d="M312.25,1L220.432,1L177.243,1L0.25,1L0.25,0L177.243,0L220.432,0L312.25,0L312.25,1Z" fill-rule="evenodd" fill="url(#master_svg5_13_2169)" fill-opacity="1"/><path d="M312.25,1L220.432,1L177.243,1L0.25,1L0.25,0L177.243,0L220.432,0L312.25,0L312.25,1Z" fill-rule="evenodd" fill="url(#master_svg6_13_2170)" fill-opacity="1"/></g></g></svg>

File diff suppressed because one or more lines are too long

88
src/auto-imports.d.ts vendored Normal file
View File

@ -0,0 +1,88 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const createPinia: typeof import('pinia')['createPinia']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineStore: typeof import('pinia')['defineStore']
const effectScope: typeof import('vue')['effectScope']
const getActivePinia: typeof import('pinia')['getActivePinia']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const mapActions: typeof import('pinia')['mapActions']
const mapGetters: typeof import('pinia')['mapGetters']
const mapState: typeof import('pinia')['mapState']
const mapStores: typeof import('pinia')['mapStores']
const mapWritableState: typeof import('pinia')['mapWritableState']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const setActivePinia: typeof import('pinia')['setActivePinia']
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const storeToRefs: typeof import('pinia')['storeToRefs']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

View File

@ -0,0 +1,29 @@
<template>
<div class="error-container flex flex-col items-center justify-center w-full h-full">
<SvgIcon name="error" class="w-[48px] h-[48px] text-red-500 mb-2"/>
<div class="text-red-500 text-sm">加载失败</div>
<button
class="mt-2 px-4 py-1 bg-[#45A2FF] text-white rounded hover:bg-[#3d8fe0] transition-colors"
@click="retry"
>
重试
</button>
</div>
</template>
<script lang="ts" setup>
import SvgIcon from "@/components/svg-icon/SvgIcon.vue";
const emit = defineEmits(['retry']);
const retry = () => {
emit('retry');
};
</script>
<style scoped lang="scss">
.error-container {
background: rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
</style>

View File

@ -0,0 +1,26 @@
<template>
<div class="loading-container flex items-center justify-center w-full h-full">
<div class="loading-spinner"></div>
</div>
</template>
<style scoped lang="scss">
.loading-container {
background: rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 3px solid #f3f3f3;
border-top: 3px solid #45A2FF;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>

View File

@ -0,0 +1,25 @@
<template>
<div v-html="content">
</div>
</template>
<script setup lang="ts">
defineProps({
content:{
type:String,
default: ""
}
})
</script>
<style scoped>
:deep(svg){
width:100%;
height:100%;
vertical-align: middle;
overflow: hidden;
object-fit: contain;
}
</style>

View File

@ -0,0 +1,40 @@
export const useDate = () => {
const hours = ref("00");
const minutes = ref("00");
const seconds = ref("00");
const year = ref("");
const month = ref("");
const day = ref("");
const weekday = ref(""); // 新增星期几变量
let timer: number | null = null;
const formateTime = () => {
const now = new Date();
hours.value = now.getHours().toString().padStart(2, "0");
minutes.value = now.getMinutes().toString().padStart(2, "0");
seconds.value = now.getSeconds().toString().padStart(2, "0");
year.value = now.getFullYear().toString();
month.value = (now.getMonth() + 1).toString().padStart(2, "0");
day.value = now.getDate().toString().padStart(2, "0");
// 获取星期几并转换为中文格式
const weekdayNumber = now.getDay(); // 0是星期日1-6是星期一至星期六
const weekdayNames = ["日", "一", "二", "三", "四", "五", "六"];
weekday.value = "星期" + weekdayNames[weekdayNumber];
};
return {
hours,
minutes,
seconds,
year,
month,
day,
weekday, // 返回星期几
timer,
formateTime,
};
};

View File

@ -0,0 +1,32 @@
// 自定义 Hook
export const useScreenAuto = (designWidth = 1920, designHeight = 1080) => {
const screenEl = useTemplateRef<HTMLDivElement>("screen")
const handleScreenAuto = () => {
const clientWidth = document.documentElement.clientWidth
const clientHeight = document.documentElement.clientHeight
const scale = clientWidth / clientHeight < designWidth / designHeight
? clientWidth / designWidth
: clientHeight / designHeight
if (screenEl.value) {
screenEl.value.style.transform = `scale(${scale}) translate(-50%, -50%)`
screenEl.value.classList.add('screen')
}
}
// 生命周期
onMounted(() => {
handleScreenAuto()
window.addEventListener('resize', handleScreenAuto)
})
onUnmounted(() => {
window.removeEventListener('resize', handleScreenAuto)
})
return {
handleScreenAuto
}
}

View File

@ -0,0 +1,214 @@
// 定义二进制数字类型
type BinaryDigits = Record<string, boolean[]>;
type CanvasRef = HTMLCanvasElement | null;
/**
* Hook
* @returns {Object} - canvas
*/
export const useDigitalWatch = () => {
const canvasRef = ref<CanvasRef>(null)
let animationTimer: number | null = null
// 二进制表示数字的配置
const binary: BinaryDigits = {
"0": [true, true, true, false, true, true, true],
"1": [false, false, true, false, false, true, false],
"2": [true, false, true, true, true, false, true],
"3": [true, false, true, true, false, true, true],
"4": [false, true, true, true, false, true, false],
"5": [true, true, false, true, false, true, true],
"6": [true, true, false, true, true, true, true],
"7": [true, true, true, false, false, true, false],
"8": [true, true, true, true, true, true, true],
"9": [true, true, true, true, false, true, false]
}
// 样式配置
let on = "#44F1FF" // 激活颜色
let off = "#031743" // 未激活颜色
// 缩放比例
let scale = 1
// 工具函数 - 格式化数字为两位(补零)
const formatZero = (n: number): string => {
return n >= 10 ? n.toString() : `0${n}`
}
// 渲染数字的一个区段
const renderDigit = (ctx: CanvasRenderingContext2D, x = 0, y = 0, binaryPattern: boolean[]) => {
const s = scale
// top
ctx.beginPath()
ctx.moveTo(x + 20 * s, y + 5 * s)
ctx.lineTo(x + 35 * s, y)
ctx.lineTo(x + 105 * s, y)
ctx.lineTo(x + 120 * s, y + 5 * s)
ctx.lineTo(x + 105 * s, y + 20 * s)
ctx.lineTo(x + 35 * s, y + 20 * s)
ctx.lineTo(x + 20 * s, y + 5 * s)
ctx.fillStyle = binaryPattern[0] ? on : off
ctx.fill()
// top-left
ctx.beginPath()
ctx.moveTo(x + 15 * s, y + 10 * s)
ctx.lineTo(x + 10 * s, y + 25 * s)
ctx.lineTo(x + 10 * s, y + 95 * s)
ctx.lineTo(x + 15 * s, y + 110 * s)
ctx.lineTo(x + 30 * s, y + 95 * s)
ctx.lineTo(x + 30 * s, y + 25 * s)
ctx.fillStyle = binaryPattern[1] ? on : off
ctx.fill()
// top-right
ctx.beginPath()
ctx.moveTo(x + 125 * s, y + 10 * s)
ctx.lineTo(x + 130 * s, y + 25 * s)
ctx.lineTo(x + 130 * s, y + 95 * s)
ctx.lineTo(x + 125 * s, y + 110 * s)
ctx.lineTo(x + 110 * s, y + 95 * s)
ctx.lineTo(x + 110 * s, y + 25 * s)
ctx.fillStyle = binaryPattern[2] ? on : off
ctx.fill()
// middle
ctx.beginPath()
ctx.moveTo(x + 20 * s, y + 115 * s)
ctx.lineTo(x + 35 * s, y + 100 * s)
ctx.lineTo(x + 105 * s, y + 100 * s)
ctx.lineTo(x + 120 * s, y + 115 * s)
ctx.lineTo(x + 105 * s, y + 130 * s)
ctx.lineTo(x + 35 * s, y + 130 * s)
ctx.fillStyle = binaryPattern[3] ? on : off
ctx.fill()
// bottom-left
ctx.beginPath()
ctx.moveTo(x + 15 * s, y + 120 * s)
ctx.lineTo(x + 10 * s, y + 135 * s)
ctx.lineTo(x + 10 * s, y + 205 * s)
ctx.lineTo(x + 15 * s, y + 220 * s)
ctx.lineTo(x + 30 * s, y + 205 * s)
ctx.lineTo(x + 30 * s, y + 135 * s)
ctx.fillStyle = binaryPattern[4] ? on : off
ctx.fill()
// bottom-right
ctx.beginPath()
ctx.moveTo(x + 125 * s, y + 120 * s)
ctx.lineTo(x + 130 * s, y + 135 * s)
ctx.lineTo(x + 130 * s, y + 205 * s)
ctx.lineTo(x + 125 * s, y + 220 * s)
ctx.lineTo(x + 110 * s, y + 205 * s)
ctx.lineTo(x + 110 * s, y + 135 * s)
ctx.fillStyle = binaryPattern[5] ? on : off
ctx.fill()
// bottom
ctx.beginPath()
ctx.moveTo(x + 20 * s, y + 225 * s)
ctx.lineTo(x + 35 * s, y + 210 * s)
ctx.lineTo(x + 105 * s, y + 210 * s)
ctx.lineTo(x + 120 * s, y + 225 * s)
ctx.lineTo(x + 105 * s, y + 235 * s)
ctx.lineTo(x + 35 * s, y + 235 * s)
ctx.lineTo(x + 20 * s, y + 225 * s)
ctx.fillStyle = binaryPattern[6] ? on : off
ctx.fill()
}
// 计算合适的缩放比例
const calculateScale = (width: number, height: number): number => {
// 原始设计下整个表宽约为940高约为240
const originalWidth = 940
const originalHeight = 240
const scaleX = width / originalWidth
const scaleY = height / originalHeight
// 取较小的缩放比例,确保完全显示
return Math.min(scaleX, scaleY) * 0.9 // 稍微缩小一点,留出边距
}
// 绘制时间
const drawTime = () => {
if (!canvasRef.value) return
const canvas = canvasRef.value
const ctx = canvas.getContext('2d')
if (!ctx) return
// 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 获取当前时间
const date = new Date()
// 格式化时间数字
const [hour_ten_digit, hour_one_digit] = formatZero(date.getHours()).split("")
const [minute_ten_digit, minute_one_digit] = formatZero(date.getMinutes()).split("")
const [second_ten_digit, second_one_digit] = formatZero(date.getSeconds()).split("")
// 计算中心位置,使表居中
const centerY = (canvas.height - 240 * scale) / 2 + 20 * scale
const startX = (canvas.width - 940 * scale) / 2 + 20 * scale
// 使用指定的间距渲染每个数字
const spacing = 140 * scale
// 渲染每个数字
renderDigit(ctx, startX, centerY, binary[hour_ten_digit])
renderDigit(ctx, startX + spacing, centerY, binary[hour_one_digit])
renderDigit(ctx, startX + spacing * 2.5, centerY, binary[minute_ten_digit])
renderDigit(ctx, startX + spacing * 3.5, centerY, binary[minute_one_digit])
renderDigit(ctx, startX + spacing * 5, centerY, binary[second_ten_digit])
renderDigit(ctx, startX + spacing * 6, centerY, binary[second_one_digit])
}
// 初始化函数
const initWatch = (width = 1000, height = 300, interval = 500) => {
if (!canvasRef.value) return
const canvas = canvasRef.value
canvas.width = width
canvas.height = height
// 计算适合的缩放比例
scale = calculateScale(width, height)
// 启动定时器更新时间显示
drawTime() // 立即首次绘制
animationTimer = window.setInterval(() => {
drawTime()
}, interval)
}
// 停止计时器
const stopWatch = () => {
if (animationTimer) {
clearInterval(animationTimer)
animationTimer = null
}
}
// 自动清理
onBeforeUnmount(() => {
stopWatch()
})
// 返回需要暴露的内容
return {
canvasRef,
initWatch,
stopWatch,
drawTime,
// 自定义选项
setColors: (onColor: string, offColor: string) => {
on = onColor
off = offColor
}
}
}

View File

@ -0,0 +1,365 @@
/**
* 3d
* @param pieData
* @param internalDiameterRatio:
* @param distance
* @param alpha
* @param pieHeight
* @param opacity
*/
// 定义饼图数据项接口
interface PieDataItem {
name: string;
value: number;
itemStyle?: {
color?: string;
opacity?: number;
};
startRatio?: number;
endRatio?: number;
}
// 定义图例数据项接口
interface LegendItem {
name: string;
value: number;
}
// 参数方程接口
interface ParametricEquation {
u: {
min: number;
max: number;
step: number;
};
v: {
min: number;
max: number;
step: number;
};
x: (u: number, v: number) => number;
y: (u: number, v: number) => number;
z: (u: number, v: number) => number;
}
// ECharts配置相关类型
interface EChartsOption {
series: SeriesItem[];
[key: string]: any;
}
// 定义图表系列项接口
interface SeriesItem {
name: string;
type: string;
parametric: boolean;
wireframe: {
show: boolean;
};
pieData: PieDataItem;
pieStatus: {
selected: boolean;
hovered: boolean;
k: number;
};
center: string[];
itemStyle?: {
color?: string | number;
opacity?: number;
};
parametricEquation?: ParametricEquation;
}
const getPie3D = (
pieData: PieDataItem[],
internalDiameterRatio: number,
distance: number,
alpha: number,
pieHeight: number,
opacity: number = 1
): EChartsOption => {
const series: SeriesItem[] = []
let sumValue: number = 0
let startValue: number = 0
let endValue: number = 0
let legendData: LegendItem[] = []
let legendBfb: LegendItem[] = []
const k: number = 1 - internalDiameterRatio
pieData.sort((a: PieDataItem, b: PieDataItem) => {
return b.value - a.value
})
// 为每一个饼图数据,生成一个 series-surface 配置
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value
const seriesItem: SeriesItem = {
name:
typeof pieData[i].name === 'undefined'
? `series${i}`
: pieData[i].name,
type: 'surface',
parametric: true,
wireframe: {
show: false
},
pieData: pieData[i],
pieStatus: {
selected: false,
hovered: false,
k: k
},
center: ['10%', '50%']
}
if (typeof pieData[i].itemStyle !== 'undefined') {
const itemStyle: { color?: string | number; opacity?: number } = {}
itemStyle.color =
typeof pieData[i].itemStyle?.color !== 'undefined'
? pieData[i].itemStyle?.color
: opacity
itemStyle.opacity =
typeof pieData[i].itemStyle?.opacity !== 'undefined'
? pieData[i].itemStyle?.opacity
: opacity
seriesItem.itemStyle = itemStyle
}
series.push(seriesItem)
}
// 使用上一次遍历时,计算出的数据和 sumValue调用 getParametricEquation 函数,
// 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation也就是实现每一个扇形。
legendData = []
legendBfb = []
for (let i = 0; i < series.length; i++) {
endValue = startValue + series[i].pieData.value
series[i].pieData.startRatio = startValue / sumValue
series[i].pieData.endRatio = endValue / sumValue
series[i].parametricEquation = getParametricEquation(
series[i].pieData.startRatio || 0,
series[i].pieData.endRatio || 0,
false,
false,
k,
series[i].pieData.value
)
startValue = endValue
const bfb = fomatFloat(series[i].pieData.value / sumValue, 4)
if (typeof bfb === 'string') {
legendData.push({
name: series[i].name,
value: parseFloat(bfb)
})
legendBfb.push({
name: series[i].name,
value: parseFloat(bfb)
})
}
}
const boxHeight = getHeight3D(series, pieHeight) // 通过pieHeight设定3d饼/环的高度单位是px
// 准备待返回的配置项,把准备好的 legendData、series 传入。
const option: EChartsOption = {
// legend: {
// show: false,
// data: legendData,
// orient: 'vertical',
// left: 10,
// top: 10,
// itemGap: 10,
// textStyle: {
// color: '#A1E2FF'
// },
// icon: 'circle',
// formatter: function (param: string) {
// const item = legendBfb.filter(item => item.name === param)[0]
// if (item) {
// const bfs = fomatFloat(item.value * 100, 2)
// if (typeof bfs === 'string') {
// return `${item.name} ${bfs}%`
// }
// }
// return ''
// }
// },
labelLine: {
show: true,
lineStyle: {
color: '#fff'
}
},
label: {
show: true,
position: 'outside',
formatter: '{b} \n{c} {d}%'
},
tooltip: {
backgroundColor: '#033b77',
borderColor: '#21f2c4',
textStyle: {
color: '#fff',
fontSize: 13
},
formatter: (_params: any) => {
// if (
// params.seriesName !== 'mouseoutSeries' &&
// params.seriesName !== 'pie2d'
// ) {
// // 确保params.seriesIndex存在且在option.series范围内
// if (params.seriesIndex !== undefined && option.series && option.series[params.seriesIndex] && option.series[params.seriesIndex].pieData) {
// const bfb = (
// ((option.series[params.seriesIndex].pieData.endRatio || 0) -
// (option.series[params.seriesIndex].pieData.startRatio || 0)) *
// 100
// ).toFixed(2)
// return (
// `${params.seriesName}<br/>` +
// `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
// `${bfb}%`
// )
// }
// // 如果索引无效,返回简单的系列名称
// return `${params.seriesName}`
// }
return ''
}
},
xAxis3D: {
min: -1,
max: 1
},
yAxis3D: {
min: -1,
max: 1
},
zAxis3D: {
min: -1,
max: 1
},
grid3D: {
show: false,
boxHeight: boxHeight, // 圆环的高度
viewControl: {
// 3d效果可以放大、旋转等请自己去查看官方配置
alpha, // 角度
distance, // 调整视角到主体的距离类似调整zoom
rotateSensitivity: 0, // 设置为0无法旋转
zoomSensitivity: 0, // 设置为0无法缩放
panSensitivity: 0, // 设置为0无法平移
autoRotate: false // 自动旋转
}
},
series: series
}
return option
}
/**
* series-surface.parametricEquation
*/
const getParametricEquation = (
startRatio: number,
endRatio: number,
isSelected: boolean,
isHovered: boolean,
k: number,
h: number
): ParametricEquation => {
// 计算
const midRatio = (startRatio + endRatio) / 2
const startRadian = startRatio * Math.PI * 2
const endRadian = endRatio * Math.PI * 2
const midRadian = midRatio * Math.PI * 2
// 如果只有一个扇形,则不实现选中效果。
if (startRatio === 0 && endRatio === 1) {
isSelected = false
}
// 通过扇形内径/外径的值,换算出辅助参数 k默认值 1/3
k = typeof k !== 'undefined' ? k : 1 / 3
// 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0
const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0
const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0
// 计算高亮效果的放大比例(未高亮,则比例为 1
const hoverRate = isHovered ? 1.05 : 1
// 返回曲面参数方程
return {
u: {
min: -Math.PI,
max: Math.PI * 3,
step: Math.PI / 32
},
v: {
min: 0,
max: Math.PI * 2,
step: Math.PI / 20
},
x: function (u: number, v: number): number {
if (u < startRadian) {
return (
offsetX +
Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate
)
}
if (u > endRadian) {
return (
offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate
)
}
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate
},
y: function (u: number, v: number): number {
if (u < startRadian) {
return (
offsetY +
Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate
)
}
if (u > endRadian) {
return (
offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate
)
}
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate
},
z: function (u: number, v: number): number {
if (u < -Math.PI * 0.5) {
return Math.sin(u)
}
if (u > Math.PI * 2.5) {
return Math.sin(u) * h * 0.1
}
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1
}
}
}
/**
* 3d
*/
const getHeight3D = (series: SeriesItem[], height: number): number => {
series.sort((a: SeriesItem, b: SeriesItem) => {
return b.pieData.value - a.pieData.value
})
return (height * 25) / series[0].pieData.value
}
/**
*
*/
const fomatFloat = (num: number, n: number): string | boolean => {
let f = parseFloat(num.toString())
if (isNaN(f)) {
return false
}
f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n) // n 幂
let s = f.toString()
let rs = s.indexOf('.')
// 判定如果是整数增加小数点再补0
if (rs < 0) {
rs = s.length
s += '.'
}
while (s.length <= rs + n) {
s += '0'
}
return s
}
export { getPie3D, getParametricEquation }

View File

@ -0,0 +1,15 @@
import LoadingComponent from "@/components/LoadingComponent.vue";
import ErrorComponent from "@/components/ErrorComponent.vue";
export const asyncComponentConfig = {
loadingComponent: LoadingComponent,
errorComponent: ErrorComponent,
onError: (_error: Error, retry: () => void, fail: () => void, attempts: number) => {
if (attempts <= 3) {
retry();
} else {
fail();
}
}
};

View File

@ -0,0 +1,59 @@
// 定义函数类型,支持任意参数
type PollingCallback = (...args: any[]) => void;
export const requestArray = new Map<string, { callback: PollingCallback; args?: any[] }>();
// 添加函数到 Map
export const addRequest = (key: string, callback: PollingCallback, args?: any[]) => {
requestArray.set(key, { callback, args });
};
// 从 Map 中移除函数
export const removeRequest = (key: string) => {
requestArray.delete(key);
};
export const runImmediatelyByKey = (key: string) => {
const { callback, args } = requestArray.get(key) || {};
if (callback) {
callback(...(args || []));
}
};
export const runImmediatelyAll = () => {
updateTime.value = new Date().getTime();
requestArray.forEach(({ callback, args }) => {
if (args) {
callback(...args);
}else{
callback()
}
});
};
export let updateTime = ref(0);
export const usePolling = () => {
const pollingWorker = new Worker("/js/polling.worker.js");
pollingWorker.onmessage = (_e: any) => {
// 执行所有存储的函数
updateTime.value = new Date().getTime();
requestArray.forEach(({ callback, args }) => {
if (args) {
callback(...args);
} else {
callback();
}
});
};
onMounted(() => {
pollingWorker.postMessage({ command: "start", interval: 1000 * 60 * 60 });
});
onBeforeUnmount(() => {
pollingWorker.postMessage({ command: "stop" });
// 清理所有存储的函数
requestArray.clear();
});
};

View File

@ -0,0 +1,20 @@
import * as ECharts from "echarts";
const HANDLER = "_vue_resize_handler";
export const vEchartResize = {
mounted(el:any,binding:any){
el[HANDLER] = binding.value
? binding.value
: () => {
let chart = ECharts.getInstanceByDom(el);
if (!chart) {
return;
}
chart.resize();
};
window.addEventListener("resize",el[HANDLER]);
},
beforeUnmount(el:any){
window.removeEventListener("resize",el[HANDLER]);
}
}

18
src/main.ts Normal file
View File

@ -0,0 +1,18 @@
import { createApp } from 'vue'
import '@unocss/reset/tailwind-compat.css'
import './style.css'
import 'uno.css';
import App from './App.vue'
// Pinia 持久化
import store from '@/store/index'
//导入路由
import router from '@/router/index'
const app = createApp(App)
// 注册已经加上了持久化的pinia
app.use(store)
app.use(router)
app.mount('#app')

57
src/router/index.ts Normal file
View File

@ -0,0 +1,57 @@
import { createRouter, createWebHistory } from "vue-router";
import { publicRoutes } from "./publicRoutes";
import { privateRoutes } from "./privateRoutes";
import { useUserStore } from "@/store/user";
function getRoutes() {
const routes = [
// 私有路由,请在这里添加
...privateRoutes,
// 公共路由
...publicRoutes,
];
/**
* routes
*/
return routes;
}
const router = createRouter({
history: createWebHistory(),
routes: getRoutes(),
});
// 全局前置守卫,这边可以对身份进行验证
router.beforeEach((to, _from, next) => {
const userStore = useUserStore()
let userRole = "";
let hasLogin = userStore.getAccessToken;
// 如果目标路由没有角色限制
if (!to.meta.role) {
next();
}
// 判断当前用户角色是否在目标路由的允许角色列表中
if ((to.meta.role as string[]).includes(userRole)) {
// 如果角色匹配,允许进入目标路由
next();
}else if(hasLogin){
next();
} else {
// 如果角色不匹配,跳转到 unauthorized 页面
next({ path: "/login" });
}
});
// 监听路由变化,动态设置网页标题
router.afterEach((to) => {
if (to.meta.title) {
document.title = to.meta.title as string;
}
});
export default router;

13
src/router/keepAlive.ts Normal file
View File

@ -0,0 +1,13 @@
import { ComponentInternalInstance, ref } from 'vue'
export const excludes = ref<string[]>([])
export function removeKeepAliveCache(instance: ComponentInternalInstance) {
if (!excludes.value.includes(instance.type.name!)) {
excludes.value.push(instance.type.name!)
}
}
export function resetKeepAliveCache(instance: ComponentInternalInstance) {
excludes.value = excludes.value.filter((item) => item !== instance.type.name)
}

View File

@ -0,0 +1 @@
export const privateRoutes = [];

View File

@ -0,0 +1,20 @@
export const publicRoutes = [
{
path:"/unauthorized",
name:'unauthorized',
meta:{
title:'unauthorized'
},
component:()=>import('../views/unauthorized.vue')
},
{
path:"/",
name:'home',
meta:{
title:'锦泽健康智慧养老服务平台',
},
component:()=>import('../views/home.vue')
},
]

13
src/store/index.ts Normal file
View File

@ -0,0 +1,13 @@
// pinia数据持久化存储
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate'
import { SelfStorage } from './secureStore'
// 第一个参数是应用程序中 store 的唯一 id
const store = createPinia()
store.use(
createPersistedState({
storage: SelfStorage
})
)
export default store

26
src/store/secureStore.ts Normal file
View File

@ -0,0 +1,26 @@
import { StorageLike } from 'pinia-plugin-persistedstate'
import CryptoJS from 'crypto-js'
const SECRET_KEY = import.meta.env.VITE_SECRET_KEY // 自定义加密密钥
// 自定义加密存储
export const SelfStorage: StorageLike = {
setItem(key: string, value: string) {
// 加密值
const encryptedValue = CryptoJS.AES.encrypt(value, SECRET_KEY).toString()
// 存储加密后的值
localStorage.setItem(key, encryptedValue)
},
getItem(key: string): string | null {
// 获取加密值
const encryptedValue = localStorage.getItem(key)
if (encryptedValue) {
// 解密
const bytes = CryptoJS.AES.decrypt(encryptedValue, SECRET_KEY)
const decryptedValue = bytes.toString(CryptoJS.enc.Utf8)
return decryptedValue || null
}
return null
},
}

24
src/store/user.ts Normal file
View File

@ -0,0 +1,24 @@
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
persist:true,
state:()=>({
accessToken:"",
refreshToken:""
}),
getters:{
getAccessToken(state){
return state.accessToken;
},
getRefreshToken(state){
return state.refreshToken
}
},
actions:{
setAccessToken(token:string){
this.accessToken = token;
},
setRefreshToken(token:string){
this.refreshToken = token
}
}
});

5
src/style.css Normal file
View File

@ -0,0 +1,5 @@
@media (max-width: 1919px){
html{
font-size: calc(100vw / 93.75);
}
}

View File

@ -0,0 +1,11 @@
.border-image {
border: 1px solid;
border-image: linear-gradient(
90deg,
#217ac600,
#227cc8,
#217ac600
)
1 1;
opacity: 0.3;
}

View File

@ -0,0 +1,15 @@
.text-color{
position: relative;
color: #8FC8FF;
&::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
z-index: auto;
color: #fff;
-webkit-mask: var(--mask-gradient, linear-gradient(to bottom, transparent, #000));
white-space: nowrap;
padding-right: 4px;
}
}

17
src/styles/utils.scss Normal file
View File

@ -0,0 +1,17 @@
// 使 scss math https://sass-lang.com/documentation/breaking-changes/slash-div
@use "sass:math";
// 稿
$designWidth: 1920;
// 稿
$designHeight: 1080;
// px vw
@function vw($px) {
@return math.div($px, $designWidth) * 100vw;
}
// px vh
@function vh($px) {
@return math.div($px, $designHeight) * 100vh;
}

11
src/types/uni.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
/**
* uni-app API
*/
declare const uni: {
postMessage: (options: { data: Record<string, any> }) => void;
getEnv: (callback: (res: any) => void) => void;
switchTab: (options: { url: string }) => void;
reLaunch: (options: { url: string }) => void;
navigateBack: (options: { delta: number }) => void;
[key: string]: any;
};

View File

@ -0,0 +1,13 @@
export function convertNumber(n: number): string {
if (n >= 10000) {
const value = n / 10000;
return `${value.toString().replace(/\.0$/, '')}W`;
} else if (n >= 1000) {
const value = n / 1000;
return `${value.toString().replace(/\.0$/, '')}K`;
} else if (n >= 1) {
const value = n / 1000;
return `${value.toString().replace(/0+$/, '').replace(/\.$/, '')}K`;
}
return n.toString();
}

34
src/utils/date.ts Normal file
View File

@ -0,0 +1,34 @@
/**
* "月.日 时:分:秒"
* @param timestamp
* @returns "6.12 12:00:00"
*/
export const formatDatetime = (timestamp: number): string => {
const date = new Date(timestamp);
// 获取月份注意getMonth 返回的月份是从0开始的所以需要+1
const month = date.getMonth() + 1;
// 获取日期
const day = date.getDate();
// 获取小时
const hours = date.getHours().toString().padStart(2, '0');
// 获取分钟
const minutes = date.getMinutes().toString().padStart(2, '0');
// 获取秒数
const seconds = date.getSeconds().toString().padStart(2, '0');
// 组合成最终格式
return `${month}.${day} ${hours}:${minutes}:${seconds}`;
};
/**
*
* @returns
*/
export const getCurrentTimestamp = (): number => {
return Date.now();
};

18
src/utils/device.ts Normal file
View File

@ -0,0 +1,18 @@
export const usePlatformType = () => {
const userAgent = navigator.userAgent.toLowerCase();
// 判断是否为移动设备
const isMobile = /mobile|android|iphone|ipad|ipod|windows phone/i.test(userAgent);
// 判断是否为 APP 环境(这里假设 APP 环境会在 userAgent 中包含特定标识)
const isApp = /myapp|appname/i.test(userAgent); // 请根据实际 APP 的标识修改
const isWechat = /micromessenger/i.test(userAgent);
return {
isMobile,
isApp,
isPC: !isMobile,
isWechat
};
}

9
src/utils/echartData.ts Normal file
View File

@ -0,0 +1,9 @@
// 根据设计稿来放大缩小字体
export const fitChartSize = (size:number,defaultWidth = 1920) => {
let clientWidth = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;
if (!clientWidth) return size;
let scale = (clientWidth / defaultWidth);
return Number((size*scale).toFixed(3));
}

51
src/views/home.vue Normal file
View File

@ -0,0 +1,51 @@
<script setup lang="ts">
// import { usePlatformType } from '@/utils/device'
//
// const { isMobile } = usePlatformType()
// URL
const jumpUrls = {
//
mechanism: {
pc: 'https://icaring.cn/operation',
mobile: 'https://icaring.cn/nurse',
icon:"/images/mechanism.webp",
type:'mechanism'
},
//
home: {
pc: 'https://ky.jinzejk.com/admin/login.php',
mobile: 'https://icaring.cn/nurse',
icon: "/images/home.webp",
type:"home"
}
}
//
const handleImageClick = (type: 'mechanism' | 'home') => {
const urls = jumpUrls[type]
const targetUrl = urls.pc
//
window.open(targetUrl, '_blank')
}
</script>
<template>
<div class="min-h-screen w-full bg-[url('/images/background.webp')] bg-cover bg-center bg-no-repeat font-sans flex flex-col relative overflow-auto">
<!-- 顶部logo -->
<div class="flex items-center shrink-0 mt-[2rem] px-10">
<img src="/images/logo.webp" alt="Logo" class="md:h-[4rem] w-auto h-[8rem]" />
</div>
<!-- 底部图片区域 -->
<div class="flex-1 flex items-center justify-center mt-16">
<div class="w-full flex items-center justify-evenly flex-col md:flex-row overflow-hidden">
<div v-for="val in jumpUrls" class="flex justify-center items-center cursor-pointer " @click="handleImageClick(val.type as any)">
<img :src="val.icon" alt="Mechanism" class="w-full h-auto md:max-h-[28rem] object-contain transition-transform duration-300 ease-out overflow-hidden transition-transform duration-300 ease-out hover:scale-105" />
</div>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,3 @@
<template>
<div>401 - Unauthorized</div>
</template>

8
src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}

5
src/window-env.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
interface Window {
}
declare module 'echarts-gl/charts';
declare module 'echarts-gl/components';

28
tsconfig.app.json Normal file
View File

@ -0,0 +1,28 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/composables/useDigitalWatch.js"]
}

13
tsconfig.json Normal file
View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
},
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

25
tsconfig.node.json Normal file
View File

@ -0,0 +1,25 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts","./plugins/*"]
}

27
uno.config.ts Normal file
View File

@ -0,0 +1,27 @@
import { defineConfig, presetIcons,presetUno } from "unocss";
// import presetWind from "@unocss/preset-wind";
import { presetScrollbarHide } from 'unocss-preset-scrollbar-hide'
// import { presetPxToViewport } from "unocss-preset-px-to-vw-or-vh";
export default defineConfig({
presets: [
// presetPxToViewport({
// // 可选:自定义设计尺寸(默认为 1920x1080
// designWidth: 1920,
// designHeight: 1080,
// keyToVw: ["font-size"],
// }),
presetUno(),
// presetWind(),
presetScrollbarHide(),
presetIcons({
scale: 1,
warn: true,
extraProperties: {
display: "inline-block",
"vertical-align": "middle",
},
}),
],
rules: [["pb-safe", { "padding-bottom": "calc(env(safe-area-inset-bottom) + 52rpx)" }]],
});

43
upload.sh Normal file
View File

@ -0,0 +1,43 @@
#!/bin/bash
# 服务器信息
SERVER_USER="root"
SERVER_HOST="106.14.30.150"
SERVER_PATH="/opt/1panel/apps/openresty/openresty/www/sites/screen.jinze.ycymedu.com/index"
PRIVATE_KEY="ALIYUN.pem"
BACKUP_PATH="${SERVER_PATH}-backup-$(date +%Y%m%d%H%M%S).zip"
DINGDING_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=fca104958fea6273c9c7ef3f08b3d552645c214f929066785e8caf6e1885a5a6"
# 在上传之前备份原来的文件并压缩
ssh -i $PRIVATE_KEY $SERVER_USER@$SERVER_HOST "cd $(dirname $SERVER_PATH) && zip -r $(basename $BACKUP_PATH) $(basename $SERVER_PATH)"
# 使用 scp 上传文件
scp -i $PRIVATE_KEY -r dist/* $SERVER_USER@$SERVER_HOST:$SERVER_PATH
# 提示上传完成
if [ $? -eq 0 ]; then
echo "上传成功!备份存储于 $BACKUP_PATH"
# 发送钉钉通知
curl -X POST "$DINGDING_WEBHOOK" \
-H "Content-Type: application/json" \
-d '{
"msgtype": "text",
"text": {
"content": "single html| upload success!! backup to'"$BACKUP_PATH"'"
}
}'
else
echo "上传失败,请检查错误信息。"
# 发送钉钉通知
curl -X POST "$DINGDING_WEBHOOK" \
-H "Content-Type: application/json" \
-d '{
"msgtype": "text",
"text": {
"content": "single html|upload failplease check error info。"
}
}'
fi

71
vite.config.ts Normal file
View File

@ -0,0 +1,71 @@
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "path";
import AutoComplete from "unplugin-auto-import/vite";
import UnoCSS from 'unocss/vite'
import svgBuilder from "./plugins/svgBuilder";
const pathSrc = resolve(__dirname, "src");
// https://vite.dev/config/
export default defineConfig({
assetsInclude: ["**/*.svg"],
base: "./" /* 这个就是webpack里面的publicPath */,
build: {
rollupOptions: {
output: {
// 最小化拆分包
manualChunks: (id) => {
if (id.includes("node_modules")) {
return id.toString().split("node_modules/")[1].split("/")[0].toString();
}
}, // 用于从入口点创建的块的打包输出格式[name]表示文件名,[hash]表示该文件内容hash值
entryFileNames: "js/[name].[hash].js", // 用于命名代码拆分时创建的共享块的输出命名
chunkFileNames: "js/[name].[hash].js", // 用于输出静态资源的命名,[ext]表示文件扩展名
},
},
},
plugins: [
vue(),
UnoCSS(),
svgBuilder(resolve("./public/icons")), // svg存储的名字
AutoComplete({
imports: [
"vue",
"vue-router",
"pinia", // 自动导入 Pinia API如 defineStore
],
dts: resolve(pathSrc, "auto-imports.d.ts"),
}),
],
resolve: {
alias: {
"@/": `${pathSrc}/`,
},
},
server: {
host: "localhost",
port: 3001,
proxy:{
'/api':{
target:'http://192.168.31.149:5006',
changeOrigin:true,
}
}
},
esbuild: {
drop: ["debugger"],
},
optimizeDeps: { // 在开发服务器启动时预构建依赖,将 CommonJS/UMD 模块转换为 ESM 格式,并缓存结果以提高性能。
include: [],
},
css:{
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/utils.scss" as cssUtils;`,
}
}
}
});