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.

After

Width:  |  Height:  |  Size: 646 KiB

BIN
public/images/home.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

BIN
public/images/logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

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>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

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>

After

Width:  |  Height:  |  Size: 4.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

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>

After

Width:  |  Height:  |  Size: 3.1 KiB

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>

After

Width:  |  Height:  |  Size: 4.0 KiB

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>

After

Width:  |  Height:  |  Size: 3.8 KiB

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>

After

Width:  |  Height:  |  Size: 3.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

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>

After

Width:  |  Height:  |  Size: 407 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

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>

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 25 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 25 KiB

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>

After

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

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>

After

Width:  |  Height:  |  Size: 4.6 KiB

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>

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.6 KiB

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;`,
}
}
}
});