fc
24
.gitignore
vendored
Normal file
@ -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?
|
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||||
|
}
|
BIN
781700210223_.pic.jpg
Normal file
After Width: | Height: | Size: 134 KiB |
7
README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Vue 3 + Vite
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 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 IDE Setup
|
||||||
|
|
||||||
|
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
13
index.html
Normal file
@ -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</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
1683
package-lock.json
generated
Normal file
20
package.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "btgxq-population-bigdata",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"echarts": "^5.4.3",
|
||||||
|
"stylus": "^0.61.0",
|
||||||
|
"vue": "^3.3.8"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^4.5.0",
|
||||||
|
"vite": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/assets/imgs/bg.png
Normal file
After Width: | Height: | Size: 320 KiB |
BIN
public/assets/imgs/card/bg1.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
public/assets/imgs/card/bg2.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
public/assets/imgs/card/bg3.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
public/assets/imgs/card/bg4.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
public/assets/imgs/card/bg5.png
Normal file
After Width: | Height: | Size: 466 B |
BIN
public/assets/imgs/card/bg6.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
public/assets/imgs/card/bg7.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
public/assets/imgs/card/bg8.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
public/assets/imgs/icon/man.png
Normal file
After Width: | Height: | Size: 669 B |
BIN
public/assets/imgs/icon/women.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
public/assets/imgs/shbz/cjr.png
Normal file
After Width: | Height: | Size: 378 B |
BIN
public/assets/imgs/shbz/lnr.png
Normal file
After Width: | Height: | Size: 394 B |
BIN
public/assets/imgs/shbz/shjz.png
Normal file
After Width: | Height: | Size: 383 B |
BIN
public/assets/imgs/shbz/ty.png
Normal file
After Width: | Height: | Size: 372 B |
1
public/vite.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
64
src/App.vue
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main">
|
||||||
|
<CardTwoCount/>
|
||||||
|
<PersonCount2 :bg-type="2"/>
|
||||||
|
<PersonCount2/>
|
||||||
|
<PersonCount1/>
|
||||||
|
<PersonPercent/>
|
||||||
|
<CardCount2/>
|
||||||
|
<CardCount1 bg="assets/imgs/card/bg2.png"/>
|
||||||
|
<Process/>
|
||||||
|
<CircleWave/>
|
||||||
|
<Bar id="bar" w="300" h="250" :x-data="barChart.xData" :data="barChart.data" />
|
||||||
|
<BarSpike id="barSpike" w="300" h="250" :x-data="barChart.xData" :data="barChart.data" />
|
||||||
|
<PolarHalf id="polarHalf" w="600" :data="polarHalfChart.data" :unit="polarHalfChart.unit" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
import Bar from './components/echarts/Bar.vue';
|
||||||
|
import BarSpike from './components/echarts/BarSpike.vue';
|
||||||
|
import PolarHalf from './components/echarts/PolarHalf.vue';
|
||||||
|
import CircleWave from './components/circle/CircleWave.vue';
|
||||||
|
import Process from './components/process/Process.vue';
|
||||||
|
import CardCount1 from './components/card/CardCount1.vue';
|
||||||
|
import CardCount2 from './components/card/CardCount2.vue';
|
||||||
|
import PersonPercent from './components/card/PersonPercent.vue';
|
||||||
|
import PersonCount1 from './components/card/PersonCount1.vue';
|
||||||
|
import PersonCount2 from './components/card/PersonCount2.vue';
|
||||||
|
import CardTwoCount from './components/card/CardTwoCount.vue';
|
||||||
|
|
||||||
|
const barChart = reactive({
|
||||||
|
xData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
||||||
|
data: [120, 200, 150, 80, 70, 110, 130]
|
||||||
|
})
|
||||||
|
|
||||||
|
const polarHalfChart = reactive({
|
||||||
|
unit: '人',
|
||||||
|
data: [{
|
||||||
|
name: '矛盾纠纷类',
|
||||||
|
value: 40
|
||||||
|
}, {
|
||||||
|
name: '涉邪人员',
|
||||||
|
value: 10
|
||||||
|
}, {
|
||||||
|
name: '吸毒人员',
|
||||||
|
value: 20
|
||||||
|
}, {
|
||||||
|
name: '社会治安',
|
||||||
|
value: 10
|
||||||
|
}, {
|
||||||
|
name: '重点上访',
|
||||||
|
value: 900
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.main
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
background-image url('assets/imgs/bg.png')
|
||||||
|
</style>
|
1
src/assets/vue.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
After Width: | Height: | Size: 496 B |
58
src/components/card/CardCount1.vue
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container" :style="{backgroundImage: `url(${props.bg})`}">
|
||||||
|
<div class="top">{{ props.title }}</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<div class="left">{{ props.value }}</div>
|
||||||
|
<div class="right">{{ props.unit }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, defineProps} from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
bg: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '标题'
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
unit: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.container
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
justify-content space-between
|
||||||
|
width 200px
|
||||||
|
height 55px
|
||||||
|
padding 5px 30px
|
||||||
|
background-repeat no-repeat
|
||||||
|
background-size 100% 100%
|
||||||
|
color #FFFFFF
|
||||||
|
.top
|
||||||
|
font-size 18px
|
||||||
|
font-weight bold
|
||||||
|
.bottom
|
||||||
|
display flex
|
||||||
|
justify-content space-between
|
||||||
|
align-items center
|
||||||
|
height 30px
|
||||||
|
.left
|
||||||
|
font-size 22px
|
||||||
|
.right
|
||||||
|
font-size 14px
|
||||||
|
</style>
|
92
src/components/card/CardCount2.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card-count2-container">
|
||||||
|
<div class="top">
|
||||||
|
<div class="value">{{ props.value }}</div>
|
||||||
|
<div class="title">
|
||||||
|
<span>{{ props.title }}</span>
|
||||||
|
<span>({{ props.unit }})</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<div class="title">
|
||||||
|
<div class="name">占比</div>
|
||||||
|
<div class="value">{{ props.percent * 100 }}%</div>
|
||||||
|
</div>
|
||||||
|
<div class="process">
|
||||||
|
<div class="value" :style="{width: props.percent * 100 +'px'}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {defineProps} from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '标题'
|
||||||
|
},
|
||||||
|
unit: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
percent: {
|
||||||
|
type: Number,
|
||||||
|
default: 0.5
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: 'black'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.card-count2-container
|
||||||
|
width 140px
|
||||||
|
height 120px
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
.top
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
.value
|
||||||
|
padding 5px
|
||||||
|
text-align center
|
||||||
|
font-weight bold
|
||||||
|
font-size 22px
|
||||||
|
.title
|
||||||
|
padding 0 5px
|
||||||
|
text-align center
|
||||||
|
font-size 14px
|
||||||
|
color #FFFFFF
|
||||||
|
.bottom
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
align-items center
|
||||||
|
margin-top 10px
|
||||||
|
padding 0 10px
|
||||||
|
.title
|
||||||
|
display flex
|
||||||
|
justify-content space-between
|
||||||
|
font-size 12px
|
||||||
|
width 110px
|
||||||
|
color #FFFFFF
|
||||||
|
.process
|
||||||
|
width 110px
|
||||||
|
height 20px
|
||||||
|
background-color #1b4d70
|
||||||
|
position relative
|
||||||
|
.value
|
||||||
|
position absolute
|
||||||
|
width 100px
|
||||||
|
height 6px
|
||||||
|
top 7px
|
||||||
|
left 5px
|
||||||
|
background linear-gradient(90deg, #02b1f7, #FFF)
|
||||||
|
|
||||||
|
</style>
|
35
src/components/card/CardTwoCount.vue
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<CardCount2 class="left"/>
|
||||||
|
<CardCount2 class="right"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, defineProps} from 'vue';
|
||||||
|
import CardCount2 from './CardCount2.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.container
|
||||||
|
width 360px
|
||||||
|
height 180px
|
||||||
|
background-image url(assets/imgs/card/bg8.png)
|
||||||
|
background-size 100% 100%
|
||||||
|
background-repeat no-repeat
|
||||||
|
position relative
|
||||||
|
.left
|
||||||
|
width 120px
|
||||||
|
position absolute
|
||||||
|
top 6px
|
||||||
|
left 50px
|
||||||
|
.right
|
||||||
|
width 120px
|
||||||
|
position absolute
|
||||||
|
top 6px
|
||||||
|
right 44px
|
||||||
|
</style>
|
37
src/components/card/PersonCount1.vue
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="text">人员共计<spa class="value">{{ props.value }}</spa>人</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.container
|
||||||
|
width 140px
|
||||||
|
height 70px
|
||||||
|
background-color rgba(0, 0, 0, 0.3)
|
||||||
|
background-image url(assets/imgs/card/bg5.png)
|
||||||
|
background-repeat no-repeat
|
||||||
|
background-size 100% 40%
|
||||||
|
background-position bottom
|
||||||
|
.text
|
||||||
|
font-size 18px
|
||||||
|
font-weight bold
|
||||||
|
color #FFFFFF
|
||||||
|
text-align center
|
||||||
|
.value
|
||||||
|
padding 5px
|
||||||
|
font-size 28px
|
||||||
|
color yellow
|
||||||
|
</style>
|
47
src/components/card/PersonCount2.vue
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container" :style="{backgroundImage: `url(${bg})`}">
|
||||||
|
<div class="value">{{ props.value }}</div>
|
||||||
|
<div class="title">{{ props.title }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, defineProps} from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '标题'
|
||||||
|
},
|
||||||
|
bgType: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(props.bg);
|
||||||
|
|
||||||
|
const bg = ref('assets/imgs/card/bg6.png');
|
||||||
|
if(props.bgType === 2) {
|
||||||
|
bg.value = 'assets/imgs/card/bg7.png';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.container
|
||||||
|
width 120px
|
||||||
|
height 80px
|
||||||
|
background-size 140% 100%
|
||||||
|
background-position center
|
||||||
|
text-align center
|
||||||
|
color #FFF
|
||||||
|
.value
|
||||||
|
font-size 20px
|
||||||
|
font-weight bold
|
||||||
|
.title
|
||||||
|
font-size 12px
|
||||||
|
</style>
|
50
src/components/card/PersonPercent.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<img class="icon" src="assets/imgs/icon/man.png">
|
||||||
|
<div class="value">{{ props.value }}%</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'man'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const color = ref('#00bab4');
|
||||||
|
if(props.type != 'man') {
|
||||||
|
color.value = '#ff5329';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.container
|
||||||
|
width 150px
|
||||||
|
height 100px
|
||||||
|
padding 20px 10px
|
||||||
|
position relative
|
||||||
|
&:after
|
||||||
|
content ' '
|
||||||
|
width 40px
|
||||||
|
height 2px
|
||||||
|
background-color v-bind(color)
|
||||||
|
position absolute
|
||||||
|
top 22px
|
||||||
|
left 48px
|
||||||
|
.icon
|
||||||
|
width 40px
|
||||||
|
.value
|
||||||
|
font-size 20px
|
||||||
|
font-weight bold
|
||||||
|
color v-bind(color)
|
||||||
|
position absolute
|
||||||
|
top 6px
|
||||||
|
left 92px
|
||||||
|
</style>
|
42
src/components/circle/CircleWave.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<svg class="svg" width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!-- Wave -->
|
||||||
|
<g id="wave">
|
||||||
|
<path id="wave-2" :fill="color" d="M 0 100 C 133.633 85.12 51.54 116.327 200 100 A 95 95 0 0 1 0 100 Z">
|
||||||
|
<animate dur="5s" repeatCount="indefinite" attributeName="d" attributeType="XML" values="M0 100 C90 28, 92 179, 200 100 A95 95 0 0 1 0 100 Z;
|
||||||
|
M0 100 C145 100, 41 100, 200 100 A95 95 0 0 1 0 100 Z;
|
||||||
|
M0 100 C90 28, 92 179, 200 100 A95 95 0 0 1 0 100 Z"></animate>
|
||||||
|
</path>
|
||||||
|
</g>
|
||||||
|
<text text-anchor="middle" font-size="42px" transform="translate(100,120)" :style="{fill: props.textColor}">{{ props.value }}%</text>
|
||||||
|
<circle cx="100" cy="100" r="96" stroke-width="6" stroke="rgba(255,255,255,0.5)" fill="transparent"></circle>
|
||||||
|
<circle cx="100" cy="100" r="98" stroke-width="2" :stroke="color" fill="none" class="percentage-pie-svg"></circle>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, defineProps} from 'vue';
|
||||||
|
const props = defineProps({
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: 'blue'
|
||||||
|
},
|
||||||
|
textColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'white'
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
default: 20.0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const color = ref(props.color);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.container
|
||||||
|
.svg
|
||||||
|
filter drop-shadow(0 0 5px v-bind(color))
|
||||||
|
</style>
|
69
src/components/echarts/Bar.vue
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div :id="domId" :style="{ width: w, height: h }"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, defineProps, inject } from 'vue';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
w: {
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
h: {
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '柱状图'
|
||||||
|
},
|
||||||
|
xData: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const echarts = inject('echarts');
|
||||||
|
const domId = ref(props.id);
|
||||||
|
const w = ref(`${props.w}px`);
|
||||||
|
const h = ref(`${props.h}px`);
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
var chart = echarts.init(document.getElementById(domId.value));
|
||||||
|
chart.setOption({
|
||||||
|
title: {
|
||||||
|
text: props.title
|
||||||
|
},
|
||||||
|
tooltip: {},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: props.xData
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 1
|
||||||
|
},
|
||||||
|
data: props.data,
|
||||||
|
type: 'bar'
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
</style>
|
77
src/components/echarts/BarSpike.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div :id="domId" :style="{ width: w, height: h }"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, defineProps, inject } from 'vue';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
w: {
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
h: {
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '尖峰图'
|
||||||
|
},
|
||||||
|
xData: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const echarts = inject('echarts');
|
||||||
|
const domId = ref(props.id);
|
||||||
|
const w = ref(`${props.w}px`);
|
||||||
|
const h = ref(`${props.h}px`);
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
var chart = echarts.init(document.getElementById(domId.value));
|
||||||
|
chart.setOption({
|
||||||
|
title: {
|
||||||
|
text: props.title
|
||||||
|
},
|
||||||
|
tooltip: {},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: props.xData
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
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',
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.6
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
z: 10,
|
||||||
|
data: props.data,
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
</style>
|
226
src/components/echarts/PolarHalf.vue
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container" :style="{ width: w, height: h }">
|
||||||
|
<div class="card" :style="{scale: cardScale, left: cardL, top: cardT}">
|
||||||
|
<div :id="domId" class="chart"></div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="label" v-for="item in infoLabelDataArray" :key="item">
|
||||||
|
<span class="color" :style="{backgroundColor: item.color}">{{ item.item }}</span>
|
||||||
|
<span class="title">{{ item.title }}</span>
|
||||||
|
<span class="percent">{{ item.percent }}%</span>
|
||||||
|
<span class="count">
|
||||||
|
<span :style="{color: item.color}">{{ item.value }}</span>{{ props.unit }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, defineProps, inject, reactive } from 'vue';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import { listColorArray } from '../../utils/utils'
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
w: {
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '极坐标-半圆'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
unit: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const echarts = inject('echarts');
|
||||||
|
const domId = ref(props.id);
|
||||||
|
const cardScale = ref(props.w / 600);
|
||||||
|
const w = ref(`${props.w}px`);
|
||||||
|
const h = ref(`${300 * cardScale.value}px`);
|
||||||
|
const cardL = ref(`${ (props.w - 600) / 4 }px`);
|
||||||
|
const cardT = ref(`${ (props.w - 600) / 4 }px`);
|
||||||
|
const colors = listColorArray();
|
||||||
|
const bgColor = '#0C1B32';
|
||||||
|
const infoLabelDataArray = reactive([]);
|
||||||
|
const init = () => {
|
||||||
|
// 标签
|
||||||
|
let labelArray = [];
|
||||||
|
// 背景
|
||||||
|
let seriesBgArray = [];
|
||||||
|
let dataArray = [];
|
||||||
|
let totalValue = 0;
|
||||||
|
props.data.forEach((item, index) => {
|
||||||
|
totalValue += item.value
|
||||||
|
});
|
||||||
|
props.data.forEach((item, index) => {
|
||||||
|
labelArray.push(item.name);
|
||||||
|
seriesBgArray.push({
|
||||||
|
value: 180,
|
||||||
|
itemStyle: {
|
||||||
|
color: bgColor
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dataArray.push({
|
||||||
|
value: (item.value / totalValue).toFixed(2) * 180,
|
||||||
|
itemStyle: {
|
||||||
|
color: colors[index],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
infoLabelDataArray.push({
|
||||||
|
color: colors[index],
|
||||||
|
title: item.name,
|
||||||
|
percent: (item.value / totalValue * 100).toFixed(2),
|
||||||
|
value: item.value
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var chart = echarts.init(document.getElementById(domId.value));
|
||||||
|
chart.setOption({
|
||||||
|
title: {
|
||||||
|
text: props.title
|
||||||
|
},
|
||||||
|
polar: {
|
||||||
|
radius: [30, '80%'],
|
||||||
|
},
|
||||||
|
angleAxis: {
|
||||||
|
max: 360,
|
||||||
|
startAngle: 90,
|
||||||
|
clockwise: false,
|
||||||
|
axisLine: false,
|
||||||
|
splitLine: false,
|
||||||
|
},
|
||||||
|
radiusAxis: {
|
||||||
|
type: 'category',
|
||||||
|
axisLine: false,
|
||||||
|
data: labelArray,
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: 9,
|
||||||
|
z: 1,
|
||||||
|
animationDuration: 1500, // 动画时间
|
||||||
|
coordinateSystem: 'polar',
|
||||||
|
barGap: '-100%',
|
||||||
|
showBackground: false,
|
||||||
|
backgroundStyle: {
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 1,
|
||||||
|
y: 0,
|
||||||
|
x2: 0,
|
||||||
|
y2: 0,
|
||||||
|
colorStops: [
|
||||||
|
{ offset: 1, color: bgColor },
|
||||||
|
{ offset: 1, color: bgColor },
|
||||||
|
{ offset: 1, color: bgColor },
|
||||||
|
{ offset: 1, color: bgColor },
|
||||||
|
{ offset: 1, color: bgColor },
|
||||||
|
],
|
||||||
|
global: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: seriesBgArray,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: 10,
|
||||||
|
z: 2,
|
||||||
|
coordinateSystem: 'polar',
|
||||||
|
showBackground: true,
|
||||||
|
backgroundStyle: {
|
||||||
|
color: 'transparent',
|
||||||
|
},
|
||||||
|
data: dataArray
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.container
|
||||||
|
position relative
|
||||||
|
.card
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
.chart
|
||||||
|
width 300px
|
||||||
|
height: 300px
|
||||||
|
.info
|
||||||
|
position absolute
|
||||||
|
top 25px
|
||||||
|
left 155px
|
||||||
|
width 350px
|
||||||
|
height 250px
|
||||||
|
background-color blue
|
||||||
|
padding 0 20px
|
||||||
|
box-sizing border-box
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
justify-content space-around
|
||||||
|
.label
|
||||||
|
font-size 14px
|
||||||
|
cursor pointer
|
||||||
|
padding 3px 0
|
||||||
|
span
|
||||||
|
display inline-block
|
||||||
|
height 30px
|
||||||
|
line-height 30px
|
||||||
|
vertical-align middle
|
||||||
|
color #FFFFFF
|
||||||
|
font-weight bold
|
||||||
|
margin 0 5px
|
||||||
|
.color
|
||||||
|
width 30px
|
||||||
|
height 15px
|
||||||
|
background-color yellow
|
||||||
|
.title
|
||||||
|
width 100px
|
||||||
|
.percent
|
||||||
|
width 60px
|
||||||
|
text-align right
|
||||||
|
.count
|
||||||
|
width 80px
|
||||||
|
text-align right
|
||||||
|
&:hover
|
||||||
|
background linear-gradient(90deg, transparent, black)
|
||||||
|
position relative
|
||||||
|
&::after
|
||||||
|
content ' '
|
||||||
|
width 18px
|
||||||
|
height 30px
|
||||||
|
display block
|
||||||
|
box-sizing border-box
|
||||||
|
border-style solid
|
||||||
|
border-color transparent transparent transparent black
|
||||||
|
border-top-width 18px
|
||||||
|
border-left-width 9px
|
||||||
|
border-right-width 9px
|
||||||
|
border-bottom-width 18px
|
||||||
|
position absolute
|
||||||
|
top 0px
|
||||||
|
right -18px
|
||||||
|
.divider
|
||||||
|
width 5px
|
||||||
|
height 105px
|
||||||
|
top 32px
|
||||||
|
left 158px
|
||||||
|
background-color #EEEEEE
|
||||||
|
position absolute
|
||||||
|
|
||||||
|
</style>
|
93
src/components/process/Process.vue
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="left" v-if="props.icon">
|
||||||
|
<img :src="props.icon"/>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="top">
|
||||||
|
<div class="title">{{ props.title }}</div>
|
||||||
|
<div class="sub-title">{{ props.value }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<div class="process">
|
||||||
|
<div class="value" :style="{width: (props.process * 300) + 'px'}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: 'rgba(0, 0, 255)'
|
||||||
|
},
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'rgba(0, 0, 255, 0.3)'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '标题'
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '0'
|
||||||
|
},
|
||||||
|
process: {
|
||||||
|
type: Number,
|
||||||
|
default: 0.8
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const color = ref(props.color)
|
||||||
|
const bgColor = ref(props.bgColor)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.container
|
||||||
|
display flex
|
||||||
|
.left
|
||||||
|
margin-right 10px
|
||||||
|
img
|
||||||
|
width 50px
|
||||||
|
height 50px
|
||||||
|
.right
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
.top
|
||||||
|
display flex
|
||||||
|
justify-content space-between
|
||||||
|
align-items center
|
||||||
|
height 22px
|
||||||
|
margin 5px 0
|
||||||
|
.title
|
||||||
|
font-size 16px
|
||||||
|
.sub-title
|
||||||
|
font-size 12px
|
||||||
|
color v-bind(color)
|
||||||
|
.bottom
|
||||||
|
width 300px
|
||||||
|
.process
|
||||||
|
background-color v-bind(bgColor)
|
||||||
|
width 100%
|
||||||
|
height 10px
|
||||||
|
position relative
|
||||||
|
.value
|
||||||
|
background linear-gradient(90deg, v-bind(color), #FFF)
|
||||||
|
box-shadow 0 0 3px rgba(0, 0, 0, 0.3)
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
width 120px
|
||||||
|
height: 10px
|
||||||
|
border-radius 0 5px 5px 0
|
||||||
|
|
||||||
|
</style>
|
0
src/components/table/ScrollTable.vue
Normal file
14
src/main.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import './style.css'
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
const createEcharts = {
|
||||||
|
install(app, options) {
|
||||||
|
app.provide('echarts', echarts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = createApp(App);
|
||||||
|
app.use(createEcharts);
|
||||||
|
app.mount('#app');
|
20
src/style.css
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
:root {
|
||||||
|
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
height: 100%
|
||||||
|
}
|
3
src/utils/utils.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const listColorArray = () => {
|
||||||
|
return ['red', 'orange', 'yello', 'green', 'blue', 'grey'];
|
||||||
|
}
|
7
vite.config.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
})
|