@ -0,0 +1,24 @@ |
|||
# 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? |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"recommendations": ["Vue.volar"] |
|||
} |
@ -0,0 +1,9 @@ |
|||
# Vue 3 + TypeScript + Vite |
|||
|
|||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more. |
|||
|
|||
## Recommended Setup |
|||
|
|||
- [VS Code](https://code.visualstudio.com/) + [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously Volar) and disable Vetur |
|||
|
|||
- Use [vue-tsc](https://github.com/vuejs/language-tools/tree/master/packages/tsc) for performing the same type checking from the command line, or for generating d.ts files for SFCs. |
@ -0,0 +1,9 @@ |
|||
/* eslint-disable */ |
|||
/* prettier-ignore */ |
|||
// @ts-nocheck
|
|||
// noinspection JSUnusedGlobalSymbols
|
|||
// Generated by unplugin-auto-import
|
|||
export {} |
|||
declare global { |
|||
|
|||
} |
@ -0,0 +1,18 @@ |
|||
/* eslint-disable */ |
|||
// @ts-nocheck
|
|||
// Generated by unplugin-vue-components
|
|||
// Read more: https://github.com/vuejs/core/pull/3399
|
|||
export {} |
|||
|
|||
/* prettier-ignore */ |
|||
declare module 'vue' { |
|||
export interface GlobalComponents { |
|||
ElCol: typeof import('element-plus/es')['ElCol'] |
|||
ElDialog: typeof import('element-plus/es')['ElDialog'] |
|||
ElProgress: typeof import('element-plus/es')['ElProgress'] |
|||
ElRow: typeof import('element-plus/es')['ElRow'] |
|||
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] |
|||
RouterLink: typeof import('vue-router')['RouterLink'] |
|||
RouterView: typeof import('vue-router')['RouterView'] |
|||
} |
|||
} |
After Width: | Height: | Size: 293 KiB |
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 268 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 18 KiB |
@ -0,0 +1,18 @@ |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<link rel="icon" type="image/svg+xml" href="./vite.svg" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|||
<title>Vite + Vue + TS</title> |
|||
<script type="module" crossorigin src="./assets/index-DOfL5DGB.js"></script> |
|||
<script type="module">import.meta.url;import("_").catch(()=>1);(async function*(){})().next();if(location.protocol!="file:"){window.__vite_is_modern_browser=true}</script> |
|||
<script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script> |
|||
</head> |
|||
<body> |
|||
<div id="app"></div> |
|||
<script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script> |
|||
<script nomodule crossorigin id="vite-legacy-polyfill" src="./assets/polyfills-legacy-BoP4WWJT.js"></script> |
|||
<script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/index-legacy-BceoyPKk.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script> |
|||
</body> |
|||
</html> |
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,13 @@ |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|||
<title>Vite + Vue + TS</title> |
|||
</head> |
|||
<body> |
|||
<div id="app"></div> |
|||
<script type="module" src="/src/main.ts"></script> |
|||
</body> |
|||
</html> |
@ -0,0 +1,38 @@ |
|||
{ |
|||
"name": "hukou", |
|||
"private": true, |
|||
"version": "0.0.0", |
|||
"type": "module", |
|||
"scripts": { |
|||
"dev": "vite", |
|||
"build": "vue-tsc && vite build", |
|||
"preview": "vite preview", |
|||
"build:no-vue-tsc": "vite build" |
|||
}, |
|||
"dependencies": { |
|||
"axios": "^1.7.2", |
|||
"echarts": "^5.5.1", |
|||
"echarts-gl": "^2.0.9", |
|||
"echarts-wordcloud": "^2.1.0", |
|||
"element-plus": "^2.7.5", |
|||
"element-ui": "^2.15.14", |
|||
"vue": "^3.4.21", |
|||
"vue-count-to": "^1.0.13", |
|||
"vue-router": "^4.3.2", |
|||
"vue3-seamless-scroll": "^2.0.1" |
|||
}, |
|||
"devDependencies": { |
|||
"@types/node": "^20.14.2", |
|||
"@vitejs/plugin-legacy": "^5.4.1", |
|||
"@vitejs/plugin-vue": "^5.0.4", |
|||
"less": "^4.2.0", |
|||
"terser": "^5.31.1", |
|||
"typescript": "^5.2.2", |
|||
"unplugin-auto-import": "^0.17.6", |
|||
"unplugin-vue-components": "^0.27.0", |
|||
"vite": "^5.2.12", |
|||
"vite-plugin-svg-icons": "^2.0.1", |
|||
"vite-plugin-windicss": "^1.9.3", |
|||
"vue-tsc": "^2.0.6" |
|||
} |
|||
} |
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,13 @@ |
|||
<script setup lang="ts"> |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<router-view></router-view> |
|||
</div> |
|||
</template> |
|||
|
|||
<style> |
|||
</style> |
|||
<style scoped> |
|||
</style> |
@ -0,0 +1,207 @@ |
|||
import axios, { AxiosInstance } from 'axios'; |
|||
import { ElMessage } from 'element-plus'; |
|||
import { Local, Session } from './storage'; |
|||
|
|||
// 配置新建一个 axios 实例
|
|||
export const service = axios.create({ |
|||
baseURL: 'http://127.0.0.1:5000', |
|||
timeout: 10000, |
|||
headers: { 'Content-Type': 'application/json' }, |
|||
}) |
|||
|
|||
// token 键定义
|
|||
export const accessTokenKey = 'access-token'; |
|||
export const refreshAccessTokenKey = `x-${accessTokenKey}`; |
|||
|
|||
// 获取 token
|
|||
export const getToken = () => { |
|||
return Local.get(accessTokenKey); |
|||
}; |
|||
|
|||
// 清除 token
|
|||
export const clearAccessTokens = () => { |
|||
Local.remove(accessTokenKey); |
|||
Local.remove(refreshAccessTokenKey); |
|||
|
|||
// 清除其他
|
|||
Session.clear(); |
|||
|
|||
// 刷新浏览器
|
|||
window.location.reload(); |
|||
}; |
|||
|
|||
// axios 默认实例
|
|||
export const axiosInstance: AxiosInstance = axios; |
|||
|
|||
// 添加请求拦截器
|
|||
service.interceptors.request.use( |
|||
(config: any) => { |
|||
// // 在发送请求之前做些什么 token
|
|||
// if (Session.get('token')) {
|
|||
// (<any>config.headers).common['Authorization'] = `${Session.get('token')}`;
|
|||
// }
|
|||
|
|||
// 获取本地的 token
|
|||
const accessToken = Local.get(accessTokenKey); |
|||
if (accessToken) { |
|||
// 将 token 添加到请求报文头中
|
|||
config.headers!['Authorization'] = `Bearer ${accessToken}`; |
|||
|
|||
// 判断 accessToken 是否过期
|
|||
const jwt: any = decryptJWT(accessToken); |
|||
const exp = getJWTDate(jwt.exp as number); |
|||
|
|||
// token 已经过期
|
|||
if (new Date() >= exp) { |
|||
// 获取刷新 token
|
|||
const refreshAccessToken = Local.get(refreshAccessTokenKey); |
|||
|
|||
// 携带刷新 token
|
|||
if (refreshAccessToken) { |
|||
config.headers!['X-Authorization'] = `Bearer ${refreshAccessToken}`; |
|||
} |
|||
} |
|||
// debugger
|
|||
// get请求映射params参数
|
|||
if (config.method?.toLowerCase() === 'get' && config.data) { |
|||
let url = config.url + '?' + tansParams(config.data); |
|||
url = url.slice(0, -1); |
|||
config.data = {}; |
|||
config.url = url; |
|||
} |
|||
} |
|||
return config; |
|||
}, |
|||
(error: any) => { |
|||
// 对请求错误做些什么
|
|||
return Promise.reject(error); |
|||
} |
|||
); |
|||
|
|||
// 添加响应拦截器
|
|||
service.interceptors.response.use( |
|||
(res: any) => { |
|||
// 获取状态码和返回数据
|
|||
var status = res.status; |
|||
var serve = res.data; |
|||
|
|||
// 处理 401
|
|||
if (status === 401) { |
|||
clearAccessTokens(); |
|||
} |
|||
|
|||
// 处理未进行规范化处理的
|
|||
if (status >= 400) { |
|||
throw new Error(res.statusText || 'Request Error.'); |
|||
} |
|||
|
|||
// 处理规范化结果错误
|
|||
if (serve && serve.hasOwnProperty('errors') && serve.errors) { |
|||
throw new Error(JSON.stringify(serve.errors || 'Request Error.')); |
|||
} |
|||
|
|||
// 读取响应报文头 token 信息
|
|||
var accessToken = res.headers[accessTokenKey]; |
|||
var refreshAccessToken = res.headers[refreshAccessTokenKey]; |
|||
|
|||
// 判断是否是无效 token
|
|||
if (accessToken === 'invalid_token') { |
|||
clearAccessTokens(); |
|||
} |
|||
// 判断是否存在刷新 token,如果存在则存储在本地
|
|||
else if (refreshAccessToken && accessToken && accessToken !== 'invalid_token') { |
|||
Local.set(accessTokenKey, accessToken); |
|||
Local.set(refreshAccessTokenKey, refreshAccessToken); |
|||
} |
|||
|
|||
// 响应拦截及自定义处理
|
|||
if (serve.code === 401) { |
|||
clearAccessTokens(); |
|||
} else if (serve.code === undefined) { |
|||
return Promise.resolve(res); |
|||
} else if (serve.code !== 200) { |
|||
var message; |
|||
// 判断 serve.message 是否为对象
|
|||
if (serve.message && typeof serve.message == 'object') { |
|||
message = JSON.stringify(serve.message); |
|||
} else { |
|||
message = serve.message; |
|||
} |
|||
ElMessage.error(message); |
|||
throw new Error(message); |
|||
} |
|||
|
|||
return res; |
|||
}, |
|||
(error: any) => { |
|||
// 处理响应错误
|
|||
if (error.response) { |
|||
if (error.response.status === 401) { |
|||
clearAccessTokens(); |
|||
} |
|||
} |
|||
|
|||
// console.log(99, error)
|
|||
// 对响应错误做点什么
|
|||
if (error.message.indexOf('timeout') != -1) { |
|||
ElMessage.error('网络超时'); |
|||
} else if (error.message == 'Network Error') { |
|||
ElMessage.error('网络连接错误'); |
|||
} else { |
|||
if (error) ElMessage.error(error); |
|||
else ElMessage.error('接口路径找不到'); |
|||
} |
|||
|
|||
return Promise.reject(error); |
|||
} |
|||
); |
|||
|
|||
/** |
|||
* 参数处理 |
|||
* @param {*} params 参数 |
|||
*/ |
|||
export function tansParams(params: any) { |
|||
let result = ''; |
|||
for (const propName of Object.keys(params)) { |
|||
const value = params[propName]; |
|||
var part = encodeURIComponent(propName) + '='; |
|||
if (value !== null && value !== '' && typeof value !== 'undefined') { |
|||
if (typeof value === 'object') { |
|||
for (const key of Object.keys(value)) { |
|||
if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') { |
|||
let params = propName + '[' + key + ']'; |
|||
var subPart = encodeURIComponent(params) + '='; |
|||
result += subPart + encodeURIComponent(value[key]) + '&'; |
|||
} |
|||
} |
|||
} else { |
|||
result += part + encodeURIComponent(value) + '&'; |
|||
} |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 解密 JWT token 的信息 |
|||
* @param token jwt token 字符串 |
|||
* @returns <any>object |
|||
*/ |
|||
export function decryptJWT(token: string): any { |
|||
token = token.replace(/_/g, '/').replace(/-/g, '+'); |
|||
var json = decodeURIComponent(escape(window.atob(token.split('.')[1]))); |
|||
return JSON.parse(json); |
|||
} |
|||
|
|||
/** |
|||
* 将 JWT 时间戳转换成 Date |
|||
* @description 主要针对 `exp`,`iat`,`nbf` |
|||
* @param timestamp 时间戳 |
|||
* @returns Date 对象 |
|||
*/ |
|||
export function getJWTDate(timestamp: number): Date { |
|||
return new Date(timestamp * 1000); |
|||
} |
|||
|
|||
// 导出 axios 实例
|
|||
export default service; |
@ -0,0 +1,58 @@ |
|||
/** |
|||
* window.localStorage 浏览器永久缓存 |
|||
* @method set 设置永久缓存 |
|||
* @method get 获取永久缓存 |
|||
* @method remove 移除永久缓存 |
|||
* @method clear 移除全部永久缓存 |
|||
*/ |
|||
export const Local = { |
|||
// 查看 v2.4.3版本更新日志
|
|||
setKey(key: string) { |
|||
// @ts-ignore
|
|||
return `${key}`; |
|||
}, |
|||
// 设置永久缓存
|
|||
set<T>(key: string, val: T) { |
|||
window.localStorage.setItem(Local.setKey(key), JSON.stringify(val)); |
|||
}, |
|||
// 获取永久缓存
|
|||
get(key: string) { |
|||
let json = <string>window.localStorage.getItem(Local.setKey(key)); |
|||
return JSON.parse(json); |
|||
}, |
|||
// 移除永久缓存
|
|||
remove(key: string) { |
|||
window.localStorage.removeItem(Local.setKey(key)); |
|||
}, |
|||
// 移除全部永久缓存
|
|||
clear() { |
|||
window.localStorage.clear(); |
|||
}, |
|||
}; |
|||
|
|||
/** |
|||
* window.sessionStorage 浏览器临时缓存 |
|||
* @method set 设置临时缓存 |
|||
* @method get 获取临时缓存 |
|||
* @method remove 移除临时缓存 |
|||
* @method clear 移除全部临时缓存 |
|||
*/ |
|||
export const Session = { |
|||
// 设置临时缓存
|
|||
set<T>(key: string, val: T) { |
|||
window.sessionStorage.setItem(Local.setKey(key), JSON.stringify(val)); |
|||
}, |
|||
// 获取临时缓存
|
|||
get(key: string) { |
|||
let json = <string>window.sessionStorage.getItem(Local.setKey(key)); |
|||
return JSON.parse(json); |
|||
}, |
|||
// 移除临时缓存
|
|||
remove(key: string) { |
|||
window.sessionStorage.removeItem(Local.setKey(key)); |
|||
}, |
|||
// 移除全部临时缓存
|
|||
clear() { |
|||
window.sessionStorage.clear(); |
|||
}, |
|||
}; |
@ -0,0 +1,18 @@ |
|||
import request from './request'; |
|||
// import type { ResultData } from './common';
|
|||
|
|||
export function getInfo(data: any) { |
|||
return request({ |
|||
url: '/api/data', |
|||
method: 'post', |
|||
data, |
|||
}); |
|||
} |
|||
// export function list(params: any) {
|
|||
// return request({
|
|||
// eslint-disable-next-line no-irregular-whitespace
|
|||
// url: "/list",
|
|||
// method: "get",
|
|||
// params,
|
|||
// });
|
|||
// }
|
@ -0,0 +1,40 @@ |
|||
DS-Font's TrueType Fonts |
|||
Font name: DS-Digital (Normal, Bold, Italic, Bold Italic), Version 1.0 |
|||
Author: Dusit Supasawat |
|||
Web Site: http://ds-font.hypermart.net |
|||
Contact me: Dusit Supasawat, 325/38 Suksawat32 Ratburana Bangkok Thailand 10140 |
|||
Email address: dusit@mailcity.com |
|||
|
|||
Thanks for trying! We hope you really enjoy this my typeface. This font is |
|||
distributed as shareware. You can use this font for a long time as you want. |
|||
After all, when you think this font can be usefulness for you. You can send |
|||
me some money, that would be way cool. |
|||
|
|||
I'm only asking $20 US shareware fee per this typeface for personal use. |
|||
And $45 US is the usual amount per this typeface for commercial use. |
|||
|
|||
Distribution: You are free to distribute this archive so long as this text |
|||
file is distributed with the archive, the font file have not been modified, |
|||
and it is understood that the font's copyright remains with the original |
|||
author (Dusit Supasawat). |
|||
|
|||
To register send your payment to: |
|||
|
|||
Dusit Supasawat |
|||
325/38 Suksawat32 Ratburana |
|||
Bangkok Thailand 10140 |
|||
|
|||
And fill out something as this order form, and send it in with your payment. |
|||
|
|||
Font name:_________________________________________ |
|||
Your information |
|||
Name:______________________________________________ |
|||
Address:___________________________________________ |
|||
City, State : _____________________________________ |
|||
Zip Code:__________________________________________ |
|||
Country:___________________________________________ |
|||
E-MAIL address:____________________________________ |
|||
|
|||
|
|||
You will receive fonts which you order by Email after registration. These fonts |
|||
will be generated for you by specify your name in font information. |
After Width: | Height: | Size: 293 KiB |
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 268 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 634 B |
After Width: | Height: | Size: 647 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,38 @@ |
|||
<script setup lang="ts"> |
|||
import { ref } from 'vue' |
|||
|
|||
defineProps<{ msg: string }>() |
|||
|
|||
const count = ref(0) |
|||
</script> |
|||
|
|||
<template> |
|||
<h1>{{ msg }}</h1> |
|||
|
|||
<div class="card"> |
|||
<button type="button" @click="count++">count is {{ count }}</button> |
|||
<p> |
|||
Edit |
|||
<code>components/HelloWorld.vue</code> to test HMR |
|||
</p> |
|||
</div> |
|||
|
|||
<p> |
|||
Check out |
|||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank" |
|||
>create-vue</a |
|||
>, the official Vue + Vite starter |
|||
</p> |
|||
<p> |
|||
Install |
|||
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a> |
|||
in your IDE for a better DX |
|||
</p> |
|||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.read-the-docs { |
|||
color: #888; |
|||
} |
|||
</style> |
@ -0,0 +1,5 @@ |
|||
import { createApp } from 'vue' |
|||
// import './style.css'
|
|||
import App from './App.vue' |
|||
import router from './router' |
|||
createApp(App).use(router).mount('#app') |
@ -0,0 +1,22 @@ |
|||
import { createRouter, createWebHashHistory } from "vue-router"; |
|||
|
|||
const routes = [ |
|||
{ |
|||
path: '/', |
|||
name: 'home', |
|||
component: () => |
|||
import(/* webpackChunkName: "about" */ '../views/home.vue'), |
|||
}, |
|||
{ |
|||
path: '/test', |
|||
name: 'test', |
|||
component: () => |
|||
import(/* webpackChunkName: "about" */ '../views/test.vue'), |
|||
}, |
|||
] |
|||
const router = createRouter({ |
|||
history: createWebHashHistory(import.meta.env.BASE_URL), |
|||
routes, |
|||
}); |
|||
|
|||
export default router; |
@ -0,0 +1,251 @@ |
|||
<template> |
|||
<div class="count-flop" :key="state.compKey"> |
|||
<div :class="item!='.'?'data_cage':'count-flop-point'" v-for="(item, index) in state.value" :key="index"> |
|||
<div v-if="item!='.'" class="count-flop-content" :class="['rolling_' + item]"> |
|||
<!-- <div v-if="item!='.'" class="count-flop-content" :style="{transform: `translateY(-${item}0%)`}"> --> |
|||
<div v-for="(item2,index2) in state.numberList" :key="index2" class="count-flop-num">{{item2}}</div> |
|||
</div> |
|||
<div v-else class="count-flop-content">.</div> |
|||
</div> |
|||
<div v-if="suffix" class="count-flop-unit">{{suffix}}</div> |
|||
</div> |
|||
<!-- <div class="count-flop" :key="state.compKey"> |
|||
<div :class="item!='.'?'count-flop-box':'count-flop-point'" v-for="(item, index) in state.value" :key="index"> |
|||
<div v-if="item!='.'" class="count-flop-content" :class="['rolling_' + item]"> |
|||
<div v-for="(item2,index2) in state.numberList" :key="index2" class="count-flop-num">{{item2}}</div> |
|||
</div> |
|||
<div v-else class="count-flop-content">.</div> |
|||
</div> |
|||
<div v-if="suffix" class="count-flop-unit">{{suffix}}</div> |
|||
</div> --> |
|||
</template> |
|||
<script lang="ts" setup name="CountFlop"> |
|||
// import { number } from 'echarts'; |
|||
import { reactive, onMounted, watch } from 'vue'; |
|||
// 定义父组件传过来的值 |
|||
const props = defineProps({ |
|||
val: { |
|||
type: Number, |
|||
default: () => 0, |
|||
}, |
|||
suffix: { |
|||
type: String, |
|||
default: () => '', |
|||
}, |
|||
}); |
|||
const state = reactive({ |
|||
value: [0,0,0,0] as any , |
|||
numberList: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], |
|||
compKey: 0 |
|||
}); |
|||
watch( |
|||
() => props.val, |
|||
() => { |
|||
init(); |
|||
} |
|||
); |
|||
onMounted(() => { |
|||
init(); |
|||
}); |
|||
const init = () => { |
|||
let arr = props.val.toString().split(''); |
|||
if(arr.length < 4) { |
|||
for(let i = arr.length; i < 4; i++) { |
|||
arr.unshift('0'); |
|||
} |
|||
} |
|||
state.value = arr; |
|||
// state.compKey += 1; |
|||
} |
|||
</script> |
|||
<style scoped> |
|||
@font-face{font-family:electronicFont;src:url(../assets/font/DS-DIGIT.TTF)} |
|||
.data_cage { |
|||
display: block; |
|||
background-image: url(../assets/img/data_bg.png); |
|||
height: 100%; |
|||
width: 38px; |
|||
float: left; |
|||
margin-left: 1px; |
|||
color: white; |
|||
text-align: center; |
|||
font-size: 40px; |
|||
line-height: 52px; |
|||
background-repeat: no-repeat; |
|||
background-size: 100%; |
|||
} |
|||
.count-flop-num { |
|||
font-family: 'electronicFont'; |
|||
} |
|||
.count-flop { |
|||
margin: 0 10px; |
|||
display: inline-block; |
|||
font-size: 0; |
|||
/* 可更改 */ |
|||
height: 50px; |
|||
line-height: 50px; |
|||
font-size: 36px; |
|||
color: #4898f1; |
|||
} |
|||
.count-flop > div { |
|||
position: relative; |
|||
display: inline-block; |
|||
overflow: hidden; |
|||
height: 100%; |
|||
} |
|||
.count-flop-box { |
|||
/* 可更改 */ |
|||
margin-right: 5px; |
|||
width: 36px; |
|||
border: 1px solid rgba(72, 152, 241, 0.3); |
|||
line-height: 48px; |
|||
border-radius: 6px; |
|||
} |
|||
|
|||
.count-flop-point { |
|||
/* 可更改 */ |
|||
margin-right: 5px; |
|||
width: 10px; |
|||
} |
|||
|
|||
.count-flop-content { |
|||
font-family: MicrosoftYaHei-Bold; |
|||
text-align: center; |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
width: 100%; |
|||
animation-fill-mode: forwards !important; |
|||
transition: transform 2s linear; |
|||
} |
|||
|
|||
.rolling_0 { |
|||
animation: rolling_0 2.1s ease; |
|||
} |
|||
|
|||
@keyframes rolling_0 { |
|||
from { |
|||
transform: translateY(-90%); |
|||
} |
|||
to { |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
|
|||
.rolling_1 { |
|||
animation: rolling_1 3s ease; |
|||
} |
|||
|
|||
@keyframes rolling_1 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-10%); |
|||
} |
|||
} |
|||
|
|||
.rolling_2 { |
|||
animation: rolling_2 2.1s ease; |
|||
} |
|||
|
|||
@keyframes rolling_2 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-20%); |
|||
} |
|||
} |
|||
|
|||
.rolling_3 { |
|||
animation: rolling_3 3s ease; |
|||
} |
|||
|
|||
@keyframes rolling_3 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-30%); |
|||
} |
|||
} |
|||
|
|||
.rolling_4 { |
|||
animation: rolling_4 2.1s ease; |
|||
} |
|||
|
|||
@keyframes rolling_4 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-40%); |
|||
} |
|||
} |
|||
|
|||
.rolling_5 { |
|||
animation: rolling_5 3s ease; |
|||
} |
|||
|
|||
@keyframes rolling_5 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-50%); |
|||
} |
|||
} |
|||
|
|||
.rolling_6 { |
|||
animation: rolling_6 2.1s ease; |
|||
} |
|||
|
|||
@keyframes rolling_6 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-60%); |
|||
} |
|||
} |
|||
|
|||
.rolling_7 { |
|||
animation: rolling_7 3.1s ease; |
|||
} |
|||
|
|||
@keyframes rolling_7 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-70%); |
|||
} |
|||
} |
|||
|
|||
.rolling_8 { |
|||
animation: rolling_8 2.1s ease; |
|||
} |
|||
|
|||
@keyframes rolling_8 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-80%); |
|||
} |
|||
} |
|||
|
|||
.rolling_9 { |
|||
animation: rolling_9 3.6s ease; |
|||
} |
|||
|
|||
@keyframes rolling_9 { |
|||
from { |
|||
transform: translateY(0); |
|||
} |
|||
to { |
|||
transform: translateY(-90%); |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,129 @@ |
|||
<template> |
|||
<div class="boxnav" ref="geneRef" style="padding: 0 10px;"> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts" name="gene"> |
|||
import { reactive, onMounted, ref} from 'vue'; |
|||
import * as echarts from 'echarts'; |
|||
// 定义变量内容 |
|||
const geneRef = ref() |
|||
const state = reactive({ |
|||
charts: { |
|||
theme: '', |
|||
bgColor: '', |
|||
color: '#303133', |
|||
}, |
|||
}); |
|||
// 数据 |
|||
const setPie = () => { |
|||
var myChart = echarts.init(geneRef.value); |
|||
let data1 = ['肝癌','肺癌','胃癌','结直肠癌','食管癌','胰腺癌','脑胶质瘤','肾癌','膀胱癌','前列腺癌'] |
|||
let data2 = ['肝癌','肺癌','胃癌','结直肠癌','食管癌','甲状腺癌','卵巢瘤','乳腺癌','宫颈癌','子宫内膜癌'] |
|||
var option = { |
|||
color: "#04CFE4", |
|||
grid: { |
|||
top: 20, |
|||
left: 10, |
|||
right: 0, |
|||
bottom: 40 |
|||
}, |
|||
xAxis: { |
|||
type: 'category', |
|||
axisTick: false, |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: "rgba(255, 129, 109,.1)", |
|||
width: 1, //这里是为了突出显示加上的 |
|||
}, |
|||
}, |
|||
axisLabel: { |
|||
interval: 0, |
|||
color: '#08DFFE', |
|||
rotate: 30, |
|||
fontSize: 12 |
|||
}, |
|||
data: data1 |
|||
}, |
|||
yAxis: { |
|||
show: false, |
|||
type: 'value', |
|||
interval: 1, |
|||
axisLine: { |
|||
lineStyle: { |
|||
color: "rgba(255, 129, 109, 0.1)", |
|||
width: 1, //这里是为了突出显示加上的 |
|||
}, |
|||
}, |
|||
axisLabel: { |
|||
color: '#fff' |
|||
}, |
|||
splitArea: { |
|||
areaStyle: { |
|||
color: "rgba(255,255,255,.5)", |
|||
}, |
|||
}, |
|||
splitLine: { |
|||
show: true, |
|||
lineStyle: { |
|||
color: "rgba(255, 129, 109, 0.1)", |
|||
width: 0.5, |
|||
type: "dashed", |
|||
}, |
|||
}, |
|||
}, |
|||
series: [ |
|||
{ |
|||
data: [1.23, 0.86, 2.11, 1.23, 0.92, 1.92, 2.92, 0.32, 0.12, 2.92], |
|||
type: "pictorialBar", |
|||
barCategoryGap: "0%", |
|||
symbol: "path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z", |
|||
label: { |
|||
show: true, |
|||
position: "top", |
|||
// distance: 15, |
|||
color: "#08DFFE", |
|||
fontWeight: "bolder", |
|||
fontSize: 12, |
|||
formatter: (a:any)=> { |
|||
return a.data + '%' |
|||
} |
|||
}, |
|||
itemStyle: { |
|||
normal: { |
|||
color: { |
|||
type: "linear", |
|||
x: 0, |
|||
y: 0, |
|||
x2: 0, |
|||
y2: 1, |
|||
colorStops: [ |
|||
{ |
|||
offset: 0, |
|||
color: "#9A11FF", |
|||
}, |
|||
{ |
|||
offset: 1, |
|||
color: "#08DFFE", |
|||
}, |
|||
], |
|||
global: false, // 缺省为 false |
|||
}, |
|||
}, |
|||
emphasis: { |
|||
opacity: 1, |
|||
}, |
|||
}, |
|||
} |
|||
] |
|||
} |
|||
myChart.setOption(option); |
|||
}; |
|||
// 页面加载时 |
|||
onMounted(() => { |
|||
setPie(); |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
</style> |
@ -0,0 +1,615 @@ |
|||
<template> |
|||
<div class="videobg style1"></div> |
|||
<div class="mainbox" style="width: 100%; height: 100%"> |
|||
<div class="head fadeInDown"> |
|||
<h1><span>湖口县全民健康大数据平台</span></h1> |
|||
<div class="timebox"> |
|||
{{state.time}}<span>{{ state.weekday }}</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<ul style="height: calc(100vh - 85px); padding: 15px 15px 15px 15px"> |
|||
<li style="width: 27%"> |
|||
<div class="box card fadeIn delay06" style="height: calc(31% - 10px)"> |
|||
<div class="tit">湖口县概况</div> |
|||
<div class="boxnav" id=""> |
|||
<ul class="drqk clearfix"> |
|||
<li> |
|||
<div class="icon"><img src="../assets/img/icon1.png" /></div> |
|||
<div> |
|||
<span>总面积</span> |
|||
<p><em>673</em><i>平方公里</i></p> |
|||
</div> |
|||
</li> |
|||
<li> |
|||
<div class="icon"><img src="../assets/img/icon2.png" /></div> |
|||
<div> |
|||
<span>户籍人口</span> |
|||
<p><em>28.67</em><i>万人</i></p> |
|||
</div> |
|||
</li> |
|||
<li> |
|||
<div class="icon"><img src="../assets/img/icon3.png" /></div> |
|||
<div> |
|||
<span>常住人口</span> |
|||
<p><em>22.06</em><i>万人</i></p> |
|||
</div> |
|||
</li> |
|||
<li> |
|||
<div class="icon"><img src="../assets/img/icon4.png" /></div> |
|||
<div> |
|||
<span>邮政编码</span> |
|||
<p><em>332500</em><i></i></p> |
|||
</div> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="box card fadeIn delay06" style="height: calc(33.33% - 10px)"> |
|||
<div class="tit">居民构成</div> |
|||
<div class="boxnav"> |
|||
<People /> |
|||
</div> |
|||
</div> |
|||
<div class="box card fadeIn delay06" style="height: calc(34%)"> |
|||
<div class="tit">医院就诊监控</div> |
|||
<Hospital /> |
|||
</div> |
|||
</li> |
|||
<li style="width: 46%"> |
|||
<div class="fadeIn delay06" style="height: calc(100% - 10px)"> |
|||
<div class="linebox"> |
|||
<span class="line1"><img src="../assets/img/line1.png" /></span> |
|||
<span class="line2"><img src="../assets/img/line2.png" /></span> |
|||
<span class="line3"><img src="../assets/img/line3.png" /></span> |
|||
<span class="line4"><img src="../assets/img/line4.png" /></span> |
|||
<span class="line5"><img src="../assets/img/line5.png" /></span> |
|||
<span class="line6"><img src="../assets/img/line6.png" /></span> |
|||
<span class="line7"><img src="../assets/img/line7.png" /></span> |
|||
</div> |
|||
|
|||
<div class="maptabs"> |
|||
<ul> |
|||
<li :class="maptabsCurrent==1? 'active':''" @click="maptabsClick(1)"><a href="#">健康数据</a></li> |
|||
<li :class="maptabsCurrent==0? 'active':''" @click="maptabsClick(0)"><a href="#">人口分布</a></li> |
|||
</ul> |
|||
</div> |
|||
|
|||
<div style="position: absolute; top: 20px; width: 100%"> |
|||
<ul class="txtnum txtnum2 clearfix"> |
|||
<li> |
|||
<div> |
|||
<p>13153</p> |
|||
<span>癌症患者管理数</span> |
|||
</div> |
|||
</li> |
|||
<li> |
|||
<div> |
|||
<p>84.8%</p> |
|||
<span>癌症患者就诊率</span> |
|||
</div> |
|||
</li> |
|||
<li> |
|||
<div> |
|||
<p>13</p> |
|||
<span>服务医院(家)</span> |
|||
</div> |
|||
</li> |
|||
<li> |
|||
<div> |
|||
<p>71.15%</p> |
|||
<span>电子健康档案开发率</span> |
|||
</div> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
<div class="mapbox" id="map" style="width: 100%; height: 100%"></div> |
|||
</div> |
|||
</li> |
|||
<li style="width: 27%"> |
|||
<div |
|||
class="box card fadeIn delay06" |
|||
style="height: calc(33.33% - 10px)" |
|||
> |
|||
<div class="tit">出生死亡人口监控</div> |
|||
<div class="boxnav" id="echarts2"> |
|||
<div class="born-box"> |
|||
<span class="p_a01">今日出生人口</span> |
|||
<CountFlop :val="state.born" /> |
|||
<div class="p_a01" style="font-size: 12px;"> |
|||
环比 |
|||
<img src="../assets/img/iconup.png" height="16" style="vertical-align: sub;" alt=""> |
|||
3% |
|||
</div> |
|||
</div> |
|||
<div class="born-box"> |
|||
<span class="p_a01">今日死亡人口</span> |
|||
<CountFlop :val="state.die" /> |
|||
<div class="p_a01" style="font-size: 12px;"> |
|||
环比 |
|||
<img src="../assets/img/icondown.png" height="16" style="vertical-align: sub;" alt=""> |
|||
3% |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div |
|||
class="box card fadeIn delay06" |
|||
style="height: calc(33.33% - 10px)" |
|||
> |
|||
<div class="tit">基因健康风险数据</div> |
|||
<Gene /> |
|||
</div> |
|||
<div |
|||
class="box card fadeIn delay06" |
|||
style="height: calc(33.33% - 10px)" |
|||
> |
|||
<div class="tit">高危疾病排名TOP10</div> |
|||
<Cancer /> |
|||
</div> |
|||
</li> |
|||
</ul> |
|||
<TownDialog ref="townRef" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import './style.css' |
|||
import { reactive, onMounted, ref } from 'vue'; |
|||
import * as echarts from 'echarts'; |
|||
import 'echarts-gl'; |
|||
import gdMap from './map.json' |
|||
import People from './people.vue'; |
|||
import Hospital from './hospital.vue'; |
|||
import TownDialog from './townDialog.vue'; |
|||
import Gene from './gene.vue'; |
|||
import Cancer from './cancer.vue'; |
|||
import CountFlop from './countFlop.vue'; |
|||
const timer = ref<NodeJS.Timeout | null>(null); |
|||
const townRef = ref(); |
|||
const chinaGeoCoordMap = ref<any> ({ |
|||
双钟镇: [116.23,29.7], |
|||
流泗镇: [116.36,29.73809724307942], |
|||
马影镇: [116.29,29.68], |
|||
武山镇: [116.34,29.55], |
|||
城山镇: [116.191,29.601], |
|||
大垅乡: [116.37,29.69], |
|||
凰村镇: [116.308,29.706], |
|||
张青乡: [116.33,29.652], |
|||
均桥镇: [116.31,29.592], |
|||
付垅乡: [116.34,29.61], |
|||
舜德乡: [116.19,29.52], |
|||
流芳乡: [116.248,29.52], |
|||
}); |
|||
const state = reactive({ |
|||
list: [], |
|||
born: 16, |
|||
die: 28, |
|||
time: '', |
|||
weekday: '', |
|||
mapdata1: [ |
|||
{ name: '双钟镇', value: 150 }, |
|||
{ name: '流泗镇', value: 190 }, |
|||
{ name: '马影镇', value: 120 }, |
|||
{ name: '武山镇', value: 40 }, |
|||
{ name: '城山镇', value: 110 }, |
|||