Compare commits

..

9 Commits

Author SHA1 Message Date
JenniferW efd1f34181 优化提交 2025-03-07 16:43:02 +08:00
JenniferW 2cf23aaeb3 Merge branch 'master' of https://git.5m.work/demo/ts-bigscreen-vue 2025-03-07 16:42:39 +08:00
JenniferW bc0a2bf0a0 优化 2025-03-07 14:50:53 +08:00
JenniferW 025aecdfb1 优化 2025-03-07 14:44:48 +08:00
JenniferW d8896d965c 提交优化 2025-03-07 14:37:24 +08:00
JenniferW a0f61b52f9 提交优化 2025-03-07 14:23:52 +08:00
JenniferW 481f95337f 优化 2025-03-07 14:14:18 +08:00
JenniferW 0e757e0c9d 文件提交 2025-03-07 13:55:43 +08:00
JenniferW 52521ef457 大屏构建 2025-03-07 11:00:01 +08:00
60 changed files with 13487 additions and 3028 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

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

@ -0,0 +1,3 @@
{
"git.ignoreLimitWarning": true
}

BIN
node_modules.rar Normal file

Binary file not shown.

50
package-lock.json generated
View File

@ -11,7 +11,8 @@
"@jiaminghi/data-view": "^2.7.3",
"@types/echarts": "^4.4.3",
"core-js": "^3.6.4",
"echarts": "^4.6.0",
"echarts": "^4.9.0",
"v-charts": "^1.19.0",
"vue": "^2.6.11",
"vue-awesome": "^4.0.2",
"vue-router": "^3.1.5",
@ -6714,12 +6715,31 @@
},
"node_modules/echarts": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz",
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-4.9.0.tgz",
"integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==",
"dependencies": {
"zrender": "4.3.2"
}
},
"node_modules/echarts-amap": {
"version": "1.0.0-rc.6",
"resolved": "https://registry.npmmirror.com/echarts-amap/-/echarts-amap-1.0.0-rc.6.tgz",
"integrity": "sha512-cYJCKoQdnkZXrGweYrveU1HruZd1c0KmsF1U8o3FtsvgR2jVL5ZUpGFjMmFtpolHOUFqxizk+s+QBLkYuOWL6Q=="
},
"node_modules/echarts-liquidfill": {
"version": "2.0.6",
"resolved": "https://registry.npmmirror.com/echarts-liquidfill/-/echarts-liquidfill-2.0.6.tgz",
"integrity": "sha512-p+AH0O9/BtwXMQQyhjJbMZo+GwRAgWG/DCyK5r27PQzpS0UWrgXu57MyEFc0A8Ub3sRuqEu08BuxwHICBkSWSQ==",
"peerDependencies": {
"echarts": "^4.8.0",
"zrender": "^4.3.1"
}
},
"node_modules/echarts-wordcloud": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/echarts-wordcloud/-/echarts-wordcloud-1.1.3.tgz",
"integrity": "sha512-Et8D5xEAoYkidmHun+hEH+2lF9dhCt6D0JJ390vlr2r/1zwhhZAbcL01CEvG93QcMcJpSvSPK8vRiGkTbMHRxg=="
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -10543,6 +10563,11 @@
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/numerify": {
"version": "1.2.9",
"resolved": "https://registry.npmmirror.com/numerify/-/numerify-1.2.9.tgz",
"integrity": "sha512-X4QzQiytV5ZN3TVLhzbtFzjTarUNnaa1pgNDFqt7u7Nqhxe7FvY2eYrGt4WYHlYXDqgtfC/n/a5nJ2y0LijV8w=="
},
"node_modules/oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@ -14556,6 +14581,11 @@
"integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==",
"dev": true
},
"node_modules/utils-lite": {
"version": "0.1.10",
"resolved": "https://registry.npmmirror.com/utils-lite/-/utils-lite-0.1.10.tgz",
"integrity": "sha512-jlHvdtI8MyWURF/3u+ufIjf1Cs5WjN6WZl9qO8dEkZsVjaI7X5YMUhaCFzkvB69ljt6fo4Dd7V/Oj2NJOFDFOQ=="
},
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@ -14575,6 +14605,22 @@
"uuid": "bin/uuid"
}
},
"node_modules/v-charts": {
"version": "1.19.0",
"resolved": "https://registry.npmmirror.com/v-charts/-/v-charts-1.19.0.tgz",
"integrity": "sha512-vm2HBUmxAsXK0ivwce9LytcpqrItDA5JSPLYVxZXtiuoyhcn80XX1/3dPJd/1GqG1OYv3jfBo1s9ra4q8GowqA==",
"dependencies": {
"echarts-amap": "1.0.0-rc.6",
"echarts-liquidfill": "^2.0.2",
"echarts-wordcloud": "^1.1.3",
"numerify": "1.2.9",
"utils-lite": "0.1.10"
},
"peerDependencies": {
"echarts": ">3.0.0",
"vue": ">2.0.0"
}
},
"node_modules/v8-compile-cache": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz",

View File

@ -11,7 +11,10 @@
"@jiaminghi/data-view": "^2.7.3",
"@types/echarts": "^4.4.3",
"core-js": "^3.6.4",
"echarts": "^4.6.0",
"echarts": "^4.9.0",
"element-ui": "^2.15.0",
"lodash": "^4.17.21",
"v-charts": "^1.19.0",
"vue": "^2.6.11",
"vue-awesome": "^4.0.2",
"vue-router": "^3.1.5",
@ -46,4 +49,4 @@
"> 1%",
"last 2 versions"
]
}
}

BIN
src/assets/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

BIN
src/assets/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 KiB

BIN
src/assets/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
src/assets/school.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View File

@ -96,3 +96,76 @@ $spacing-sizes: (
4: 2,
5: 2.5,
);
// 颜色系统
$primary-color: #409EFF;
$success-color: #67C23A;
$warning-color: #E6A23C;
$danger-color: #F56C6C;
$info-color: #909399;
$text-color: #303133;
$text-color-secondary: #606266;
$text-color-placeholder: #C0C4CC;
$border-color: #DCDFE6;
$border-color-light: #E4E7ED;
$border-color-lighter: #EBEEF5;
$body-bg: #ffffff;
$component-bg: #f5f7fa;
// 字体
$font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
$font-size-base: 14px;
$font-size-lg: 16px;
$font-size-sm: 13px;
$line-height-base: 1.5;
// 间距
$spacing-base: 16px;
$spacing-lg: 24px;
$spacing-sm: 8px;
// 边框
$border-radius: 4px;
$border-radius-lg: 6px;
$border-radius-sm: 2px;
// 断点
$breakpoint-xs: 480px;
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
// 容器
$container-max-width: 1200px;
// z-index管理
$zindex-dropdown: 1000;
$zindex-sticky: 1020;
$zindex-fixed: 1030;
$zindex-modal-backdrop: 1040;
$zindex-modal: 1050;
$zindex-popover: 1060;
$zindex-tooltip: 1070;
// 阴影
$box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
$box-shadow-light: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
$box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12);
// 过渡
$transition-base: all .3s cubic-bezier(.645,.045,.355,1);
$transition-fade: opacity .3s ease;
$transition-transform: transform .3s ease;
// 表格相关
$table-cell-padding: 12px;
$table-border-color: $border-color-lighter;
$table-hover-bg: $component-bg;
$table-header-bg: $component-bg;
// 响应式表格
$table-breakpoint-scroll: $breakpoint-md;

View File

@ -13,12 +13,14 @@
width: 100%;
height: 100%;
padding: 16px 16px 0 16px;
background-image: url("../assets/pageBg.png");
background-image: url("../assets/bg.jpg");
background-size: cover;
background-position: center center;
}
.host-body {
width: 100%;
height: 100%;
.dv-dec-10,
.dv-dec-10-s {
width: 33.3%;
@ -37,108 +39,92 @@
text-align: center;
background-size: cover;
background-repeat: no-repeat;
img{
width: 25%;
position: absolute;
bottom: 10px;
left: 22%;
transform: translate(-22%);
}
.title-text {
font-size: 24px;
font-size: 40px;
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%);
left: 65%;
transform: translate(-65%);
font-weight: bold;
}
.dv-dec-6 {
position: absolute;
bottom: -30px;
bottom: -10px;
left: 50%;
width: 250px;
height: 8px;
transform: translate(-50%);
}
}
}
}
}
// 第二行
.aside-width {
width: 40%;
}
.react-r-s,
.react-l-s {
background-color: #0f1325;
}
// 平行四边形
.react-right {
&.react-l-s {
text-align: right;
width: 500px;
// 添加响应式样式
.data-table-wrapper {
width: 100%;
overflow-x: auto;
.data-table {
width: 100%;
border-collapse: collapse;
th, td {
padding: 12px;
text-align: left;
border: 1px solid #ddd;
@media screen and (max-width: 768px) {
padding: 8px;
font-size: 14px;
}
font-size: 18px;
width: 300px;
line-height: 50px;
text-align: center;
transform: skewX(-45deg);
.react-after {
position: absolute;
right: -25px;
top: 0;
height: 50px;
width: 50px;
background-color: #0f1325;
transform: skewX(45deg);
}
.text {
display: inline-block;
transform: skewX(45deg);
@media screen and (max-width: 480px) {
padding: 6px;
font-size: 12px;
}
}
.react-left {
&.react-l-s {
width: 500px;
text-align: left;
input {
width: 100%;
padding: 4px;
border: 1px solid #ddd;
border-radius: 4px;
&:focus {
outline: none;
border-color: #409EFF;
}
font-size: 18px;
width: 300px;
height: 50px;
line-height: 50px;
text-align: center;
transform: skewX(45deg);
background-color: #0f1325;
.react-left {
position: absolute;
left: -25px;
top: 0;
height: 50px;
width: 50px;
background-color: #0f1325;
transform: skewX(-45deg);
}
.text {
display: inline-block;
transform: skewX(-45deg);
}
}
.body-box {
margin-top: 16px;
display: flex;
flex-direction: column;
//下方区域的布局
.content-box {
display: grid;
grid-template-columns: 2fr 3fr 5fr 3fr 2fr;
}
// 底部数据
.bottom-box {
margin-top: 10px;
display: grid;
grid-template-columns: repeat(2, 50%);
@media screen and (max-width: 768px) {
padding: 2px;
}
}
}
}
// 响应式布局基础样式
@media screen and (max-width: 1200px) {
.container {
width: 95%;
margin: 0 auto;
}
}
@media screen and (max-width: 768px) {
.row {
flex-direction: column;
}
.col {
width: 100%;
margin-bottom: 15px;
}
}

View File

@ -9,15 +9,16 @@
box-sizing: border-box;
}
html {
margin: 0;
padding: 0;
html, body {
height: 100%;
font-family: $font-family-base;
font-size: $font-size-base;
line-height: $line-height-base;
color: $text-color;
background-color: $body-bg;
}
body {
font-family: Arial, Helvetica, sans-serif;
line-height: 1.2em;
background-color: #f1f1f1;
margin: 0;
padding: 0;
overflow: hidden;
@ -184,3 +185,73 @@ a {
#{$type}: 0;
}
}
// 布局系统
.container {
width: 100%;
max-width: $container-max-width;
margin: 0 auto;
padding: 0 $spacing-base;
@media screen and (max-width: $breakpoint-lg) {
max-width: 100%;
}
}
.row {
display: flex;
flex-wrap: wrap;
margin: 0 (-$spacing-base);
@media screen and (max-width: $breakpoint-md) {
flex-direction: column;
}
}
// 栅格系统
@for $i from 1 through 12 {
.col-#{$i} {
flex: 0 0 percentage($i / 12);
max-width: percentage($i / 12);
padding: 0 $spacing-base;
@media screen and (max-width: $breakpoint-md) {
flex: 0 0 100%;
max-width: 100%;
}
}
}
// 通用工具类
.text-center { text-align: center; }
.text-left { text-align: left; }
.text-right { text-align: right; }
.mt-1 { margin-top: $spacing-base; }
.mb-1 { margin-bottom: $spacing-base; }
.ml-1 { margin-left: $spacing-base; }
.mr-1 { margin-right: $spacing-base; }
// 响应式工具类
@media screen and (max-width: $breakpoint-md) {
.hidden-mobile {
display: none !important;
}
}
@media screen and (min-width: $breakpoint-md) {
.hidden-desktop {
display: none !important;
}
}
// 动画
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}

View File

@ -1,66 +0,0 @@
<template>
<div :id="id" :class="className" :style="{ height: height, width: width }" />
</template>
<script>
import tdTheme from './theme.json' //
import '../map/fujian.js'
export default {
name: 'echart',
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '2.5rem'
},
options: {
type: Object,
default: ()=>({})
}
},
data () {
return {
chart: null
}
},
watch: {
options: {
handler (options) {
// trueechart
this.chart.setOption(options, true)
},
deep: true
}
},
mounted () {
this.$echarts.registerTheme('tdTheme', tdTheme); //
this.initChart();
},
beforeDestroy () {
this.chart.dispose()
this.chart = null
},
methods: {
initChart () {
// echart
this.chart = this.$echarts.init(this.$el, 'tdTheme')
this.chart.setOption(this.options, true)
}
}
}
</script>
<style>
</style>

View File

@ -1,490 +0,0 @@
{
"color": [
"#2d8cf0",
"#19be6b",
"#ff9900",
"#E46CBB",
"#9A66E4",
"#ed3f14"
],
"backgroundColor": "rgba(0,0,0,0)",
"textStyle": {},
"title": {
"textStyle": {
"color": "#516b91"
},
"subtextStyle": {
"color": "#93b7e3"
}
},
"line": {
"itemStyle": {
"normal": {
"borderWidth": "2"
}
},
"lineStyle": {
"normal": {
"width": "2"
}
},
"symbolSize": "6",
"symbol": "emptyCircle",
"smooth": true
},
"radar": {
"itemStyle": {
"normal": {
"borderWidth": "2"
}
},
"lineStyle": {
"normal": {
"width": "2"
}
},
"symbolSize": "6",
"symbol": "emptyCircle",
"smooth": true
},
"bar": {
"itemStyle": {
"normal": {
"barBorderWidth": 0,
"barBorderColor": "#ccc"
},
"emphasis": {
"barBorderWidth": 0,
"barBorderColor": "#ccc"
}
}
},
"pie": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"scatter": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"boxplot": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"parallel": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"sankey": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"funnel": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"gauge": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"candlestick": {
"itemStyle": {
"normal": {
"color": "#edafda",
"color0": "transparent",
"borderColor": "#d680bc",
"borderColor0": "#8fd3e8",
"borderWidth": "2"
}
}
},
"graph": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"lineStyle": {
"normal": {
"width": 1,
"color": "#aaa"
}
},
"symbolSize": "6",
"symbol": "emptyCircle",
"smooth": true,
"color": [
"#2d8cf0",
"#19be6b",
"#f5ae4a",
"#9189d5",
"#56cae2",
"#cbb0e3"
],
"label": {
"normal": {
"textStyle": {
"color": "#eee"
}
}
}
},
"map": {
"itemStyle": {
"normal": {
"areaColor": "#f3f3f3",
"borderColor": "#516b91",
"borderWidth": 0.5
},
"emphasis": {
"areaColor": "rgba(165,231,240,1)",
"borderColor": "#516b91",
"borderWidth": 1
}
},
"label": {
"normal": {
"textStyle": {
"color": "#000"
}
},
"emphasis": {
"textStyle": {
"color": "rgb(81,107,145)"
}
}
}
},
"geo": {
"itemStyle": {
"normal": {
"areaColor": "#f3f3f3",
"borderColor": "#516b91",
"borderWidth": 0.5
},
"emphasis": {
"areaColor": "rgba(165,231,240,1)",
"borderColor": "#516b91",
"borderWidth": 1
}
},
"label": {
"normal": {
"textStyle": {
"color": "#000"
}
},
"emphasis": {
"textStyle": {
"color": "rgb(81,107,145)"
}
}
}
},
"categoryAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#fff"
}
},
"splitLine": {
"show": false,
"lineStyle": {
"color": [
"#eeeeee"
]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"valueAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#fff"
}
},
"splitLine": {
"show": false,
"lineStyle": {
"color": [
"#eeeeee"
]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"logAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#999999"
}
},
"splitLine": {
"show": true,
"lineStyle": {
"color": [
"#eeeeee"
]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"timeAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#999999"
}
},
"splitLine": {
"show": true,
"lineStyle": {
"color": [
"#eeeeee"
]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"toolbox": {
"iconStyle": {
"normal": {
"borderColor": "#999"
},
"emphasis": {
"borderColor": "#666"
}
}
},
"legend": {
"textStyle": {
"color": "#fff"
}
},
"tooltip": {
"axisPointer": {
"lineStyle": {
"color": "#ccc",
"width": 1
},
"crossStyle": {
"color": "#ccc",
"width": 1
}
}
},
"timeline": {
"lineStyle": {
"color": "#8fd3e8",
"width": 1
},
"itemStyle": {
"normal": {
"color": "#8fd3e8",
"borderWidth": 1
},
"emphasis": {
"color": "#8fd3e8"
}
},
"controlStyle": {
"normal": {
"color": "#8fd3e8",
"borderColor": "#8fd3e8",
"borderWidth": 0.5
},
"emphasis": {
"color": "#8fd3e8",
"borderColor": "#8fd3e8",
"borderWidth": 0.5
}
},
"checkpointStyle": {
"color": "#8fd3e8",
"borderColor": "rgba(138,124,168,0.37)"
},
"label": {
"normal": {
"textStyle": {
"color": "#8fd3e8"
}
},
"emphasis": {
"textStyle": {
"color": "#8fd3e8"
}
}
}
},
"visualMap": {
"color": [
"#516b91",
"#59c4e6",
"#a5e7f0"
]
},
"dataZoom": {
"backgroundColor": "rgba(0,0,0,0)",
"dataBackgroundColor": "rgba(255,255,255,0.3)",
"fillerColor": "rgba(167,183,204,0.4)",
"handleColor": "#a7b7cc",
"handleSize": "100%",
"textStyle": {
"color": "#333"
}
},
"markPoint": {
"label": {
"normal": {
"textStyle": {
"color": "#eee"
}
},
"emphasis": {
"textStyle": {
"color": "#eee"
}
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,271 @@
<template>
<div class="asset-overview">
<div class="content">
<div class="asset-summary">
<div class="total-assets">
<div class="value">{{ formatCurrency(assetData.totalAssets) }}</div>
<div class="label">总资产万元</div>
</div>
<div class="asset-categories">
<div
class="category-item"
v-for="(item, index) in assetData.assetCategories"
:key="index"
>
<span class="label">{{ item.name }}</span>
<span class="value">{{ formatNumber(item.value) }}</span>
</div>
</div>
</div>
<div class="table-container">
<el-table
:data="displayData"
style="width: 100%"
class="animated-table custom-table"
:row-class-name="tableRowClassName"
:header-cell-style="{
background: 'transparent',
color: '#4a90e2',
height: '40px',
fontWeight: 'bold',
fontSize: '14px',
}"
:row-style="{ height: '35px' }"
:cell-style="{ padding: '0' }"
>
<el-table-column
prop="月份"
label="月份"
width="180"
align="center"
/>
<el-table-column
prop="资产总值"
label="资产总值(万元)"
align="center"
>
<template #default="scope">
{{ formatNumber(scope.row.资产总值) }}
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
import { assetData } from "../data/dashboardData";
import { formatNumber, formatCurrency } from "../utils/format";
export default {
name: "AssetOverview",
components: {},
data() {
return {
assetData,
};
},
computed: {
displayData() {
return [
...this.assetData.assetTrendData.rows,
...this.assetData.assetTrendData.rows,
];
},
},
methods: {
formatNumber,
formatCurrency,
tableRowClassName({ rowIndex }) {
return `row-${rowIndex}`;
},
},
};
</script>
<style lang="scss" scoped>
.asset-overview {
height: 100%;
color: #fff;
.content {
height: calc(100% - 80px);
margin-top: 15px;
.asset-summary {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
.total-assets {
text-align: center;
&:hover {
transform: translateY(-2px);
.label {
color: rgba(255, 255, 255, 0.9);
}
}
.value {
font-size: 24px;
font-weight: bold;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.label {
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
margin-top: 5px;
}
}
.asset-categories {
display: flex;
gap: 20px;
.category-item {
text-align: center;
.label {
display: block;
font-size: 12px;
color: rgba(255, 255, 255, 0.7);
}
.value {
display: block;
font-size: 16px;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-top: 5px;
}
}
}
}
.table-container {
height: 160px;
position: relative;
overflow: hidden;
border-radius: 8px;
background: rgba(74, 144, 226, 0.05);
backdrop-filter: blur(5px);
.custom-table {
::v-deep {
.el-table__cell {
border: none !important;
transition: all 0.3s ease;
}
.el-table__header-wrapper {
th {
background: transparent;
border: none;
position: relative;
&::after {
content: "";
position: absolute;
bottom: 0;
left: 10%;
width: 80%;
height: 2px;
background: linear-gradient(
90deg,
transparent 0%,
rgba(74, 144, 226, 0.5) 50%,
transparent 100%
);
}
.cell {
font-weight: bold;
background: linear-gradient(to top, #4a90e2, #ffffff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
.el-table__body-wrapper {
background: transparent;
overflow: hidden;
td {
background: transparent;
border: none;
position: relative;
&::after {
content: "";
position: absolute;
bottom: 0;
left: 5%;
width: 90%;
height: 1px;
background: linear-gradient(
90deg,
transparent 0%,
rgba(74, 144, 226, 0.1) 50%,
transparent 100%
);
}
}
.el-table__row {
transition: all 0.3s ease;
&:hover {
background: rgba(74, 144, 226, 0.1);
transform: scale(1.01);
td {
color: #4a90e2;
}
}
}
.el-table__body {
animation: scroll 20s linear infinite;
&:hover {
animation-play-state: paused;
}
}
}
@keyframes scroll {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-50%);
}
}
.el-table__inner-wrapper::after,
.el-table--border::after {
display: none;
}
}
}
}
}
.el-table {
background-color: transparent;
}
::v-deep .el-table th,
::v-deep .el-table tr,
::v-deep .el-table td {
background-color: transparent;
border: none;
color: rgba(255, 255, 255, 0.8);
}
}
</style>

View File

@ -0,0 +1,302 @@
<template>
<div class="card-overview">
<div class="content">
<div class="statistics">
<div class="stat-item">
<div class="icon-wrapper">
<i class="el-icon-bank-card"></i>
</div>
<div class="stat-content">
<div class="value">{{ formatNumber(cardData.totalCards) }}</div>
<div class="label">发卡总量</div>
</div>
</div>
<div class="stat-item">
<div class="icon-wrapper">
<i class="el-icon-data-line"></i>
</div>
<div class="stat-content">
<div class="value">{{ formatNumber(cardData.dailyUsage) }}</div>
<div class="label">日均使用量</div>
</div>
</div>
</div>
<div class="usage-scenes">
<div class="scene-header">
<i class="el-icon-place"></i>
<h4>使用场景分布</h4>
</div>
<div class="scene-list">
<div
class="scene-item"
v-for="(item, index) in cardData.usageScenes"
:key="index"
>
<div class="scene-info">
<div class="icon-box" :style="getSceneStyle(index)">
<i :class="getSceneIcon(item.name)"></i>
</div>
<div class="scene-details">
<span class="name">{{ item.name }}</span>
<el-progress
:percentage="getPercentage(item.count)"
:color="getSceneColor(index)"
:show-text="false"
:stroke-width="4"
/>
</div>
</div>
<span class="value">{{ formatNumber(item.count) }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { cardData } from "../data/dashboardData";
import { formatNumber } from "../utils/format";
export default {
name: "CardOverview",
components: {},
data() {
return {
cardData,
};
},
methods: {
formatNumber,
getSceneIcon(name) {
const iconMap = {
食堂: "el-icon-food",
图书馆: "el-icon-reading",
宿舍: "el-icon-house",
教学楼: "el-icon-school",
超市: "el-icon-shopping-cart-full",
其他: "el-icon-more",
};
return iconMap[name] || "el-icon-place";
},
getSceneColor(index) {
const colors = [
"#4a90e2", //
"#00CED1", //
"#9561e2", //
"#64B5F6", //
"#ff9f43", //
"#4CAF50", // 绿
];
return colors[index % colors.length];
},
getSceneStyle(index) {
const color = this.getSceneColor(index);
return {
background: `linear-gradient(135deg, ${color}22, ${color}44)`,
borderColor: `${color}66`,
};
},
getPercentage(count) {
const max = Math.max(
...this.cardData.usageScenes.map((scene) => scene.count)
);
return (count / max) * 100;
},
},
};
</script>
<style lang="scss" scoped>
.card-overview {
height: 100%;
color: #fff;
.content {
height: 100%;
display: flex;
flex-direction: column;
gap: 20px;
padding: 5px;
.statistics {
display: flex;
justify-content: space-around;
gap: 20px;
.stat-item {
flex: 1;
display: flex;
align-items: center;
gap: 15px;
// padding: 15px;
// background: rgba(74, 144, 226, 0.05);
// border-radius: 10px;
// border: 1px solid rgba(74, 144, 226, 0.1);
backdrop-filter: blur(5px);
transition: all 0.3s ease;
&:hover {
transform: translateY(-2px);
border-color: rgba(74, 144, 226, 0.2);
box-shadow: 0 4px 12px rgba(74, 144, 226, 0.1);
.icon-wrapper {
i {
transform: scale(1.1);
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
.icon-wrapper {
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
// border-radius: 12px;
// background: rgba(74, 144, 226, 0.1);
i {
font-size: 24px;
color: #4a90e2;
transition: all 0.3s ease;
}
}
.stat-content {
flex: 1;
.value {
font-size: 22px;
font-weight: bold;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
transition: all 0.3s ease;
}
.label {
font-size: 13px;
color: rgba(255, 255, 255, 0.7);
margin-top: 4px;
}
}
}
}
.usage-scenes {
flex: 1;
background: rgba(74, 144, 226, 0.05);
border-radius: 10px;
border: 1px solid rgba(74, 144, 226, 0.1);
backdrop-filter: blur(5px);
padding: 15px;
.scene-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
i {
font-size: 18px;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
h4 {
font-size: 14px;
font-weight: 500;
color: rgba(255, 255, 255, 0.9);
margin: 0;
}
}
.scene-list {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
.scene-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
// background: rgba(255, 255, 255, 0.03);
// border-radius: 8px;
transition: all 0.3s ease;
&:hover {
background: rgba(255, 255, 255, 0.05);
transform: translateX(2px);
.icon-box {
transform: scale(1.05);
}
.value {
}
}
.scene-info {
display: flex;
align-items: center;
gap: 12px;
flex: 1;
.icon-box {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
border: 1px solid;
transition: all 0.3s ease;
i {
font-size: 16px;
color: rgba(255, 255, 255, 0.9);
}
}
.scene-details {
flex: 1;
min-width: 0;
.name {
display: block;
font-size: 13px;
color: rgba(255, 255, 255, 0.9);
margin-bottom: 6px;
}
.el-progress {
margin-top: 4px;
}
}
}
.value {
font-size: 13px;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
transition: all 0.3s ease;
margin-left: 8px;
white-space: nowrap;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,86 @@
<template>
<div class="common-header">
<div class="title-wrapper">
<div class="title-decoration"></div>
<h3 class="gradient-text" @click="$emit('click-more')">{{ title }}</h3>
</div>
<!-- <el-button type="text" @click="$emit('click-more')">更多</el-button> -->
</div>
</template>
<script>
export default {
name: "CommonHeader",
props: {
title: {
type: String,
required: true,
},
},
};
</script>
<style lang="scss" scoped>
.common-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
// padding: 10px;
.title-wrapper {
display: flex;
align-items: center;
gap: 8px;
position: relative;
.title-decoration {
width: 3px;
height: 16px;
background: linear-gradient(to bottom, #4a90e2, #36d1dc);
border-radius: 2px;
position: relative;
&::after {
content: "";
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(to bottom, #4a90e2, #36d1dc);
filter: blur(4px);
opacity: 0.5;
border-radius: 2px;
z-index: -1;
}
}
h3 {
margin: 0;
font-size: 22px;
background: linear-gradient(to bottom, #ffffff, #4a90e2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 10px rgba(74, 144, 226, 0.2);
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: translateX(2px);
background: linear-gradient(to bottom, #ffffff, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 15px rgba(54, 209, 220, 0.3);
}
}
}
.el-button {
color: #4a90e2;
font-size: 12px;
font-weight: bold;
}
}
</style>

View File

@ -0,0 +1,86 @@
<template>
<div class="education-overview">
<div class="charts">
<ve-line
:data="educationData.evaluationData"
:settings="educationData.chartSettings"
:extend="chartStyles.education.extend"
height="200px"
/>
<div class="info-cards">
<div class="info-card">
<div class="label">课程通过率</div>
<div class="value pass-rate">
{{ educationData.statistics.passRate }}%
</div>
</div>
<div class="info-card">
<div class="label">毕业率</div>
<div class="value graduation-rate">
{{ educationData.statistics.graduationRate }}%
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { educationData, chartStyles } from "../data/dashboardData";
export default {
name: "EducationOverview",
components: {},
data() {
return {
educationData,
chartStyles,
};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.education-overview {
height: 100%;
color: #fff;
padding: 10px;
.charts {
height: calc(100% - 80px);
margin-top: 10px;
.info-cards {
display: flex;
justify-content: space-around;
margin-top: -40px;
.info-card {
text-align: center;
padding: 15px 25px;
&:hover {
transform: translateY(-2px);
.label {
color: rgba(255, 255, 255, 0.9);
}
}
.label {
font-size: 13px;
color: rgba(255, 255, 255, 0.7);
margin-bottom: 8px;
}
.value {
font-size: 24px;
font-weight: bold;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
transition: all 0.3s ease;
}
}
}
}
}
</style>

View File

@ -0,0 +1,265 @@
<template>
<div class="literature-overview">
<div class="content">
<div class="total-info">
<div class="total-number">
{{ formatNumber(literatureData.totalLiterature) }}
</div>
<div class="label">馆藏总量</div>
</div>
<el-carousel
ref="carousel"
:interval="6000"
indicator-position="none"
height="180px"
@mouseenter="pauseCarousel"
@mouseleave="startCarousel"
>
<el-carousel-item>
<ve-histogram
ref="histogram"
:data="literatureData.chartData"
:settings="literatureData.chartSettings"
:extend="extendChartOptions"
height="200px"
:after-config="handleAfterConfig"
/>
</el-carousel-item>
<el-carousel-item>
<div class="subject-distribution">
<h4>学科分布 TOP5</h4>
<div class="distribution-list">
<div
class="distribution-item"
v-for="(item, index) in literatureData.subjectDistribution"
:key="index"
>
<span class="name">{{ item.name }}</span>
<el-progress
:percentage="item.percentage"
:color="getProgressColor(index)"
:show-text="false"
/>
<span class="value">{{ formatNumber(item.count) }}</span>
</div>
</div>
</div>
</el-carousel-item>
</el-carousel>
</div>
</div>
</template>
<script>
import { literatureData, chartStyles } from "../data/dashboardData";
import { formatNumber } from "../utils/format";
export default {
name: "LiteratureOverview",
components: {},
data() {
return {
literatureData,
chartStyles,
carousel: null,
};
},
computed: {
extendChartOptions() {
return {
...this.chartStyles.research.extend,
grid: {
top: "10%",
left: "3%",
right: "4%",
bottom: "8%",
containLabel: true,
},
animation: {
duration: 2000,
easing: "cubicInOut",
},
};
},
},
methods: {
formatNumber,
pauseCarousel() {
if (this.carousel) {
this.carousel.pause();
}
},
startCarousel() {
if (this.carousel) {
this.carousel.start();
}
},
handleAfterConfig(options) {
//
this.$nextTick(() => {
if (this.$refs.histogram) {
this.$refs.histogram.echarts.resize();
}
});
return options;
},
getProgressColor(index) {
// 5
const colors = [
'#4a90e2', //
'#00CED1', //
'#9561e2', //
'#64B5F6', //
'#ff9f43' //
];
return colors[index % colors.length];
},
},
mounted() {
this.carousel = this.$refs.carousel;
//
this.$nextTick(() => {
if (this.$refs.histogram) {
this.$refs.histogram.echarts.resize();
}
});
},
activated() {
// keep-alive
if (this.$refs.histogram) {
this.$refs.histogram.echarts.resize();
}
},
};
</script>
<style lang="scss" scoped>
.literature-overview {
height: 100%;
color: #fff;
.content {
height: calc(100% - 80px);
margin-top: 20px;
.total-info {
text-align: center;
margin-bottom: 15px;
margin-top: -15px;
.total-number {
font-size: 24px;
font-weight: bold;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.label {
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
margin-top: 5px;
}
}
.subject-distribution {
padding: 0 10px;
h4 {
font-size: 14px;
margin-bottom: 15px;
color: rgba(255, 255, 255, 0.9);
font-weight: 500;
}
.distribution-list {
.distribution-item {
display: flex;
align-items: center;
margin-bottom: 12px;
transition: all 0.3s ease;
&:hover {
transform: translateX(5px);
.name {
color: rgba(255, 255, 255, 0.9);
}
.value {
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.name {
width: 70px;
font-size: 13px;
color: rgba(255, 255, 255, 0.7);
transition: color 0.3s ease;
}
.el-progress {
flex: 1;
margin: 0 12px;
::v-deep .el-progress-bar__outer {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 4px;
height: 12px !important;
background-image: repeating-linear-gradient(
to right,
transparent,
transparent 4px,
rgba(255, 255, 255, 0.1) 4px,
rgba(255, 255, 255, 0.1) 6px
);
}
::v-deep .el-progress-bar__inner {
border-radius: 4px;
transition: all 0.3s ease;
position: relative;
background-image: repeating-linear-gradient(
to right,
transparent,
transparent 4px,
rgba(255, 255, 255, 0.2) 4px,
rgba(255, 255, 255, 0.2) 6px
);
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: inherit;
filter: brightness(1.2);
border-radius: 4px;
opacity: 0;
transition: opacity 0.3s ease;
}
}
&:hover {
::v-deep .el-progress-bar__inner::after {
opacity: 1;
}
}
}
.value {
width: 60px;
font-size: 13px;
color: #4a90e2;
text-align: right;
transition: all 0.3s ease;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,89 @@
<template>
<div class="research-overview">
<div class="content">
<ve-histogram
:data="chartData"
:settings="researchData.chartSettings"
:extend="chartStyles.research.extend"
height="260px"
/>
<div class="statistics">
<div
class="stat-item"
v-for="(item, index) in researchData.statistics"
:key="index"
>
<div class="number">{{ item.value }}</div>
<div class="label">{{ item.label }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { researchData, chartStyles } from "../data/dashboardData";
export default {
name: "ResearchOverview",
components: {},
data() {
return {
researchData,
chartStyles,
chartData: researchData.chartData,
};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.research-overview {
height: 100%;
color: #fff;
.content {
height: calc(100% - 80px);
margin-top: 20px;
padding: 0 10px;
.statistics {
display: flex;
justify-content: space-between;
margin-top: -30px;
padding: 0 20px;
.stat-item {
text-align: center;
min-width: 120px;
transition: all 0.3s ease;
&:hover {
transform: translateY(-2px);
.label {
color: rgba(255, 255, 255, 0.9);
}
}
.number {
font-size: 24px;
font-weight: bold;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
transition: all 0.3s ease;
}
.label {
font-size: 13px;
color: rgba(255, 255, 255, 0.7);
margin-top: 8px;
transition: all 0.3s ease;
}
}
}
}
}
</style>

View File

@ -0,0 +1,148 @@
<template>
<div class="staff-overview">
<div class="content">
<div class="total-info">
<span class="number">{{ formatNumber(staffData.totalStaff) }}</span>
<span class="label">教职工总数</span>
</div>
<div class="chart-and-structure">
<div class="charts">
<ve-ring
:data="titleChartData"
:settings="staffData.chartSettings"
:extend="staffData.chartSettings"
height="240px"
/>
</div>
<div class="education-structure">
<h4>学历结构</h4>
<div class="structure-items">
<div
class="structure-item"
v-for="(item, index) in staffData.educationStructure"
:key="index"
>
<span class="label">{{ item.label }}</span>
<span class="value">{{ item.value }}%</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { staffData } from "../data/dashboardData";
import { formatNumber } from "../utils/format";
export default {
name: "StaffOverview",
data() {
return {
staffData,
};
},
methods: {
formatNumber,
},
computed: {
titleChartData() {
return {
columns: ["职称", "人数"],
rows: this.staffData.titleData.rows,
};
},
},
};
</script>
<style lang="scss" scoped>
.staff-overview {
height: 100%;
color: #fff;
.content {
height: calc(100% - 80px);
margin-top: 20px;
.total-info {
text-align: center;
margin-bottom: 15px;
margin-top: -15px;
&:hover {
transform: translateY(-2px);
.label {
color: rgba(255, 255, 255, 0.9);
}
}
.number {
font-size: 24px;
font-weight: bold;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.label {
font-size: 14px;
margin-left: 10px;
color: rgba(255, 255, 255, 0.7);
}
}
.chart-and-structure {
display: flex;
align-items: center;
.charts {
width: 75%;
}
.education-structure {
width: 20%;
margin-left: 5%;
h4 {
font-size: 14px;
margin-bottom: 15px;
text-align: center;
color: rgba(255, 255, 255, 0.9);
}
.structure-items {
display: flex;
flex-wrap: wrap;
.structure-item {
width: 100%;
margin-bottom: 12px;
display: flex;
justify-content: space-between;
padding: 8px 12px;
transition: all 0.3s ease;
&:hover {
transform: translateX(4px);
}
.label {
color: rgba(255, 255, 255, 0.7);
font-size: 13px;
}
.value {
background: linear-gradient(135deg, #4a90e2, #36d1dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 13px;
font-weight: 500;
transition: all 0.3s ease;
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,254 @@
<template>
<div class="student-overview">
<common-header
:title="'学生概况'"
:total="localStudentData.totalStudents"
:unit="'人'"
@more-click="handleMoreClick"
/>
<div class="content">
<div class="map-container">
<three-map
:marker-position="localStudentData.location"
:marker-label="localStudentData.location.name"
/>
<div class="info-overlay">
<div class="info-panel total-panel">
<div class="total-students">
<i class="el-icon-user-solid"></i>
<div class="total-details">
<div class="total-label">在校学生总数</div>
<div class="total-value">
{{ localStudentData.totalStudents }}
</div>
</div>
</div>
</div>
<div class="info-panel grade-panel">
<h3>
<i class="el-icon-reading"></i>
年级分布
</h3>
<div class="info-grid">
<div
v-for="item in localStudentData.gradeData"
:key="item.name"
class="info-item"
>
<div class="info-details">
<div class="info-label">{{ item.name }}</div>
<div class="info-value">{{ item.value }}</div>
</div>
</div>
</div>
</div>
<div class="info-panel gender-panel">
<h3>
<i class="el-icon-user"></i>
性别比例
</h3>
<div class="info-grid">
<div
v-for="item in localStudentData.genderData"
:key="item.name"
class="info-item"
>
<div class="info-details">
<div class="info-label">
<i
:class="
item.name === '男' ? 'el-icon-male' : 'el-icon-female'
"
></i>
{{ item.name }}
</div>
<div class="info-value">{{ item.value }}</div>
<div class="info-percentage">
{{
Math.round(
(item.value / localStudentData.totalStudents) * 100
)
}}%
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import CommonHeader from "./CommonHeader.vue";
// import ThreeMap from "./ThreeMap.vue";
import { studentData } from "../data/dashboardData";
export default {
name: "StudentOverview",
components: {
CommonHeader,
// ThreeMap,
},
data() {
return {
localStudentData: JSON.parse(JSON.stringify(studentData)),
};
},
computed: {
totalStudents() {
return this.localStudentData.totalStudents;
},
},
methods: {
handleMoreClick() {
this.$router.push("/student/detail");
},
handleDataChange(newData) {
this.localStudentData = JSON.parse(JSON.stringify(newData));
},
},
};
</script>
<style scoped>
.student-overview {
height: 100%;
display: flex;
flex-direction: column;
background: rgba(0, 20, 40, 0.7);
border-radius: 4px;
padding: 16px;
}
.content {
flex: 1;
margin-top: 16px;
min-height: 400px;
}
.map-container {
position: relative;
width: 100%;
height: 100%;
min-height: 400px;
background: rgba(0, 30, 60, 0.5);
border-radius: 4px;
overflow: hidden;
}
.info-overlay {
position: absolute;
top: 20px;
right: 20px;
display: flex;
flex-direction: column;
gap: 16px;
max-width: 300px;
pointer-events: none;
}
.info-panel {
background: rgba(0, 0, 0, 0.7);
border-radius: 8px;
padding: 16px;
backdrop-filter: blur(10px);
}
.info-panel h3 {
color: #fff;
font-size: 16px;
margin: 0 0 16px;
display: flex;
align-items: center;
gap: 8px;
}
.info-panel h3 i {
font-size: 18px;
color: #409eff;
}
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.info-item {
background: rgba(255, 255, 255, 0.1);
border-radius: 6px;
padding: 10px;
transition: all 0.3s ease;
}
.info-details {
text-align: center;
}
.info-label {
color: rgba(255, 255, 255, 0.7);
font-size: 14px;
margin-bottom: 4px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}
.info-label i {
font-size: 16px;
}
.el-icon-male {
color: #409eff;
}
.el-icon-female {
color: #f56c6c;
}
.info-value {
color: #fff;
font-size: 18px;
font-weight: bold;
margin-bottom: 2px;
}
.info-percentage {
color: rgba(255, 255, 255, 0.5);
font-size: 12px;
}
.total-panel {
background: rgba(0, 0, 0, 0.8);
}
.total-students {
display: flex;
align-items: center;
gap: 16px;
}
.total-students i {
font-size: 32px;
color: #409eff;
}
.total-details {
flex: 1;
}
.total-label {
color: rgba(255, 255, 255, 0.7);
font-size: 14px;
margin-bottom: 4px;
}
.total-value {
color: #fff;
font-size: 24px;
font-weight: bold;
}
</style>

View File

@ -1,150 +0,0 @@
<template>
<div>
<!-- 年度开工率 -->
<Echart
:options="options"
id="bottomLeftChart"
height="480px"
width="100%"
></Echart>
</div>
</template>
<script>
import Echart from '@/common/echart'
export default {
data () {
return {
options: {},
};
},
components: {
Echart,
},
props: {
cdata: {
type: Object,
default: () => ({})
},
},
watch: {
cdata: {
handler (newData) {
this.options = {
tooltip: {
trigger: "axis",
backgroundColor: "rgba(255,255,255,0.1)",
axisPointer: {
type: "shadow",
label: {
show: true,
backgroundColor: "#7B7DDC"
}
}
},
legend: {
data: ["论文", "获奖", "专利",],
textStyle: {
color: "#B4B4B4"
},
top: "0%"
},
grid: {
x: "8%",
width: "88%",
y: "4%"
},
xAxis: {
data: newData.category,
axisLine: {
lineStyle: {
color: "#B4B4B4"
}
},
axisTick: {
show: false
}
},
yAxis: [
{
splitLine: { show: false },
axisLine: {
lineStyle: {
color: "#B4B4B4"
}
},
axisLabel: {
formatter: "{value} "
}
},
{
splitLine: { show: false },
axisLine: {
lineStyle: {
color: "#B4B4B4"
}
},
axisLabel: {
formatter: "{value} "
}
}
],
series: [
{
name: "论文",
type: "line",
smooth: true,
showAllSymbol: true,
symbol: "emptyCircle",
symbolSize: 8,
yAxisIndex: 1,
itemStyle: {
normal: {
color: "#F02FC2"
}
},
data: newData.rateData
},
{
name: "获奖",
type: "bar",
barWidth: 10,
itemStyle: {
normal: {
barBorderRadius: 5,
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#956FD4" },
{ offset: 1, color: "#3EACE5" }
])
}
},
data: newData.barData
},
{
name: "专利",
type: "bar",
barGap: "-100%",
barWidth: 10,
itemStyle: {
normal: {
barBorderRadius: 5,
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "rgba(156,107,211,0.8)" },
{ offset: 0.2, color: "rgba(156,107,211,0.5)" },
{ offset: 1, color: "rgba(156,107,211,0.2)" }
])
}
},
z: -12,
data: newData.lineData
}
]
}
},
immediate: true,
deep: true
},
},
}
</script>

View File

@ -1,84 +0,0 @@
<template>
<div>
<Chart :cdata="cdata" />
</div>
</template>
<script>
import Chart from './chart.vue'
export default {
data () {
return {
cdata: {
category: [
"2012",
"2013",
"2014",
"2015",
"2016",
"2017",
"2018",
"2019",
"2020",
"2021",
"2022",
"2023",
"2024",
"2025",
],
lineData: [
18092,
20728,
24045,
28348,
32808,
36097,
39867,
44715,
48444,
50415,
56061,
62677,
59521,
67560,
],
barData: [
4600,
5000,
5500,
6500,
7500,
8500,
9900,
12500,
14000,
21500,
23200,
24450,
25250,
33300,
],
rateData: []
}
};
},
components: {
Chart,
},
mounted () {
this.setData();
},
methods: {
//
setData () {
for (let i = 0; i < this.cdata.barData.length -1; i++) {
let rate = this.cdata.barData[i] / this.cdata.lineData[i];
this.cdata.rateData.push(rate.toFixed(2));
}
},
}
};
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,358 +0,0 @@
<template>
<div>
<Echart
:options="options"
id="centreLeft1Chart"
height="480px"
width="100%"
></Echart>
</div>
</template>
<script>
import Echart from '@/common/echart'
export default {
data() {
return {
options: {},
//
colorList: {
linearYtoG: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 1,
colorStops: [
{
offset: 0,
color: '#f5b44d'
},
{
offset: 1,
color: '#28f8de'
}
]
},
linearGtoB: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{
offset: 0,
color: '#43dfa2'
},
{
offset: 1,
color: '#28f8de'
}
]
},
linearBtoG: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{
offset: 0,
color: '#1c98e8'
},
{
offset: 1,
color: '#28f8de'
}
]
},
areaBtoG: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(35,184,210,.2)'
},
{
offset: 1,
color: 'rgba(35,184,210,0)'
}
]
}
}
}
},
components: {
Echart
},
props: {
cdata: {
type: Object,
default: () => ({})
}
},
watch: {
cdata: {
handler(newData) {
this.options = {
title: {
text: '',
textStyle: {
color: '#D3D6DD',
fontSize: 24,
fontWeight: 'normal'
},
subtext: newData.year + '/' + newData.weekCategory[6],
subtextStyle: {
color: '#fff',
fontSize: 16
},
top: 50,
left: 80
},
legend: {
top: 120,
left: 80,
orient: 'vertical',
itemGap: 15,
itemWidth: 12,
itemHeight: 12,
data: ['平均指标', '我的指标'],
textStyle: {
color: '#fff',
fontSize: 14
}
},
tooltip: {
trigger: 'item'
},
radar: {
center: ['68%', '27%'],
radius: '40%',
name: {
color: '#fff'
},
splitNumber: 8,
axisLine: {
lineStyle: {
color: this.colorList.linearYtoG,
opacity: 0.6
}
},
splitLine: {
lineStyle: {
color: this.colorList.linearYtoG,
opacity: 0.6
}
},
splitArea: {
areaStyle: {
color: '#fff',
opacity: 0.1,
shadowBlur: 25,
shadowColor: '#000',
shadowOffsetX: 0,
shadowOffsetY: 5
}
},
indicator: [
{
name: '服务态度',
max: newData.maxData
},
{
name: '产品质量',
max: 10
},
{
name: '任务效率',
max: 12
},
{
name: '售后保障',
max: 3.5
}
]
},
grid: {
left: 90,
right: 80,
bottom: 40,
top: '60%'
},
xAxis: {
type: 'category',
position: 'bottom',
axisLine: true,
axisLabel: {
color: 'rgba(255,255,255,.8)',
fontSize: 12
},
data: newData.weekCategory
},
// Y
yAxis: {
name: '工单',
nameLocation: 'end',
nameGap: 24,
nameTextStyle: {
color: 'rgba(255,255,255,.5)',
fontSize: 14
},
max: newData.maxData,
splitNumber: 4,
axisLine: {
lineStyle: {
opacity: 0
}
},
splitLine: {
show: true,
lineStyle: {
color: '#fff',
opacity: 0.1
}
},
axisLabel: {
color: 'rgba(255,255,255,.8)',
fontSize: 12
}
},
series: [
{
name: '',
type: 'radar',
symbolSize: 0,
data: [
{
value: newData.radarDataAvg[6],
name: '平均指标',
itemStyle: {
normal: {
color: '#f8d351'
}
},
lineStyle: {
normal: {
opacity: 0
}
},
areaStyle: {
normal: {
color: '#f8d351',
shadowBlur: 25,
shadowColor: 'rgba(248,211,81,.3)',
shadowOffsetX: 0,
shadowOffsetY: -10,
opacity: 1
}
}
},
{
value: newData.radarData[6],
name: '我的指标',
itemStyle: {
normal: {
color: '#43dfa2'
}
},
lineStyle: {
normal: {
opacity: 0
}
},
areaStyle: {
normal: {
color: this.colorList.linearGtoB,
shadowBlur: 15,
shadowColor: 'rgba(0,0,0,.2)',
shadowOffsetX: 0,
shadowOffsetY: 5,
opacity: 0.8
}
}
}
]
},
{
name: '',
type: 'line',
smooth: true,
symbol: 'emptyCircle',
symbolSize: 8,
itemStyle: {
normal: {
color: '#fff'
}
},
lineStyle: {
normal: {
color: this.colorList.linearBtoG,
width: 3
}
},
areaStyle: {
normal: {
color: this.colorList.areaBtoG
}
},
data: newData.weekLineData,
lineSmooth: true,
markLine: {
silent: true,
data: [
{
type: 'average',
name: '平均值'
}
],
precision: 0,
label: {
normal: {
formatter: '平均值: \n {c}'
}
},
lineStyle: {
normal: {
color: 'rgba(248,211,81,.7)'
}
}
},
tooltip: {
position: 'top',
formatter: '{c} m',
backgroundColor: 'rgba(28,152,232,.2)',
padding: 6
}
},
{
name: '占位背景',
type: 'bar',
itemStyle: {
normal: {
show: true,
color: '#000',
opacity: 0
}
},
silent: true,
barWidth: '50%',
data: newData.weekMaxData,
animation: false
}
]
}
},
immediate: true,
deep: true
}
}
}
</script>

View File

@ -1,89 +0,0 @@
<template>
<div>
<Chart :cdata="cdata" />
</div>
</template>
<script>
import Chart from './chart.vue'
export default {
data () {
return {
drawTiming: null,
cdata: {
year: null,
weekCategory: [],
radarData: [],
radarDataAvg: [],
maxData: 12000,
weekMaxData: [],
weekLineData: []
}
}
},
components: {
Chart,
},
mounted () {
this.drawTimingFn();
},
beforeDestroy () {
clearInterval(this.drawTiming);
},
methods: {
drawTimingFn () {
this.setData();
this.drawTiming = setInterval(() => {
this.setData();
}, 6000);
},
setData () {
//
this.cdata.weekCategory = [];
this.cdata.weekMaxData = [];
this.cdata.weekLineData = [];
this.cdata.radarData = [];
this.cdata.radarDataAvg = [];
let dateBase = new Date();
this.cdata.year = dateBase.getFullYear();
//
for (let i = 0; i < 7; i++) {
//
let date = new Date();
this.cdata.weekCategory.unshift([date.getMonth() + 1, date.getDate()-i].join("/"));
// 线
this.cdata.weekMaxData.push(this.cdata.maxData);
let distance = Math.round(Math.random() * 11000 + 500);
this.cdata.weekLineData.push(distance);
//
//
let averageSpeed = +(Math.random() * 5 + 3).toFixed(3);
let maxSpeed = averageSpeed + +(Math.random() * 3).toFixed(2);
let hour = +(distance / 1000 / averageSpeed).toFixed(1);
let radarDayData = [distance, averageSpeed, maxSpeed, hour];
this.cdata.radarData.unshift(radarDayData);
//
let distanceAvg = Math.round(Math.random() * 8000 + 4000);
let averageSpeedAvg = +(Math.random() * 4 + 4).toFixed(3);
let maxSpeedAvg = averageSpeedAvg + +(Math.random() * 2).toFixed(2);
let hourAvg = +(distance / 1000 / averageSpeed).toFixed(1);
let radarDayDataAvg = [
distanceAvg,
averageSpeedAvg,
maxSpeedAvg,
hourAvg
];
this.cdata.radarDataAvg.unshift(radarDayDataAvg);
}
}
}
};
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,104 +0,0 @@
<template>
<div>
<!-- 通过率/达标率 -->
<Echart
:options="options"
:id="id"
height="100px"
width="100px"
></Echart>
</div>
</template>
<script>
import Echart from '@/common/echart'
export default {
data () {
return {
options: {},
};
},
components: {
Echart,
},
props: {
id: {
type: String,
required: true,
default: "chartRate"
},
tips: {
type: Number,
required: true,
default: 50
},
colorObj: {
type: Object,
default: function () {
return {
textStyle: "#3fc0fb",
series: {
color: ["#00bcd44a", "transparent"],
dataColor: {
normal: "#03a9f4",
shadowColor: "#97e2f5"
}
}
};
}
}
},
watch: {
// tips
tips: {
handler (newData) {
this.options = {
title:{
text: newData * 1 + "%",
x: "center",
y: "center",
textStyle: {
color: this.colorObj.textStyle,
fontSize: 16
}
},
series: [
{
type: "pie",
radius: ["75%", "80%"],
center: ["50%", "50%"],
hoverAnimation: false,
color: this.colorObj.series.color,
label: {
normal: {
show: false
}
},
data: [
{
value: newData,
itemStyle: {
normal: {
color: this.colorObj.series.dataColor.normal,
shadowBlur: 10,
shadowColor: this.colorObj.series.dataColor.shadowColor
}
}
},
{
value: 100 - newData
}
]
}
]
}
},
immediate: true,
deep: true
}
}
};
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,81 +0,0 @@
<template>
<div>
<Echart
:options="options"
id="centreLeft1Chart"
height="220px"
width="260px"
></Echart>
</div>
</template>
<script>
import Echart from '@/common/echart'
export default {
data () {
return {
options: {},
};
},
components: {
Echart,
},
props: {
cdata: {
type: Object,
default: () => ({})
},
},
watch: {
cdata: {
handler (newData) {
this.options = {
color: [
"#37a2da",
"#32c5e9",
"#9fe6b8",
"#ffdb5c",
"#ff9f7f",
"#fb7293",
"#e7bcf3",
"#8378ea"
],
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
toolbox: {
show: true
},
calculable: true,
legend: {
orient: "horizontal",
icon: "circle",
bottom: 0,
x: "center",
data: newData.xData,
textStyle: {
color: "#fff"
}
},
series: [
{
name: "通过率统计",
type: "pie",
radius: [10, 50],
roseType: "area",
center: ["50%", "40%"],
data: newData.seriesData
}
]
}
},
immediate: true,
deep: true
}
}
};
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,36 +0,0 @@
<template>
<div>
<Chart :cdata="cdata" />
</div>
</template>
<script>
import Chart from './chart.vue';
export default {
data () {
return {
cdata: {
xData: ["data1", "data2", "data3", "data4", "data5", "data6"],
seriesData: [
{ value: 10, name: "data1" },
{ value: 5, name: "data2" },
{ value: 15, name: "data3" },
{ value: 25, name: "data4" },
{ value: 20, name: "data5" },
{ value: 35, name: "data6" }
]
}
}
},
components: {
Chart,
},
mounted () {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,290 +0,0 @@
<template>
<div>
<Echart
id="centreLeft2Chart"
ref="centreLeft2ChartRef"
:options="options"
height="360px"
width="330px"
></Echart>
</div>
</template>
<script>
import Echart from '@/common/echart';
export default {
data() {
return {
options: {},
};
},
components: {
Echart,
},
props: {
cdata: {
type: Array,
default: () => [],
},
},
watch: {
cdata: {
handler(newData) {
// ()
const geoCoordMap = {
厦门市: [118.11022, 24.490474, 20],
福州市: [119.206239, 26.275302, 20],
泉州市: [118.589421, 24.908853, 20],
漳州市: [117.561801, 24.510897, 20],
龙岩市: [116.82978, 25.391603, 20],
莆田市: [119.007558, 25.591011, 20],
三明市: [117.435001, 26.465444, 20],
南平市: [118.178459, 27.535627, 20],
宁德市: [119.527082, 27.15924, 20],
};
let seriesData = [
{
name: '厦门市',
},
{
name: '福州市',
},
{
name: '泉州市',
},
{
name: '漳州市',
},
{
name: '龙岩市',
},
{
name: '莆田市',
},
{
name: '三明市',
},
{
name: '南平市',
},
{
name: '宁德市',
},
];
let convertData = function (data) {
let scatterData = [];
for (var i = 0; i < data.length; i++) {
var geoCoord = geoCoordMap[data[i].name];
if (geoCoord) {
scatterData.push({
name: data[i].name,
value: geoCoord.concat(data[i].value),
});
}
}
return scatterData;
};
this.options = {
showLegendSymbol: true,
tooltip: {
trigger: 'item',
textStyle: {
fontSize: 14,
lineHeight: 22,
},
position: point => {
//
return [point[0] + 50, point[1] - 20];
},
// tooltip使formatter
/*
formatter: params => {
return `<div style=""> ... </div>`
}
*/
},
visualMap: {
min: 0,
max: 10,
show: false,
seriesIndex: 0,
//
inRange: {
color: ['rgba(41,166,206, .5)', 'rgba(69,117,245, .9)'],
},
},
//
geo: {
show: true,
aspectScale: 0.85, //
zoom: 1.2,
top: '10%',
left: '16%',
map: '福建',
roam: false,
itemStyle: {
normal: {
areaColor: 'rgba(0,0,0,0)',
shadowColor: 'rgba(7,114,204, .8)',
shadowOffsetX: 5,
shadowOffsetY: 5,
},
emphasis: {
areaColor: '#00aeef',
},
},
},
series: [
{
name: '相关指数',
type: 'map',
aspectScale: 0.85, //
zoom: 1.2,
mapType: '福建', //
top: '10%',
left: '16%',
itemStyle: {
normal: {
color: 'red',
areaColor: 'rgba(19,54,162, .5)',
borderColor: 'rgba(0,242,252,.3)',
borderWidth: 1,
shadowBlur: 7,
shadowColor: '#00f2fc',
},
emphasis: {
areaColor: '#4f7fff',
borderColor: 'rgba(0,242,252,.6)',
borderWidth: 2,
shadowBlur: 10,
shadowColor: '#00f2fc',
},
},
label: {
formatter: params => `${params.name}`,
show: true,
position: 'insideRight',
textStyle: {
fontSize: 14,
color: '#efefef',
},
emphasis: {
textStyle: {
color: '#fff',
},
},
},
data: newData,
},
{
type: 'effectScatter',
coordinateSystem: 'geo',
symbolSize: 7,
effectType: 'ripple',
legendHoverLink: false,
showEffectOn: 'render',
rippleEffect: {
period: 4,
scale: 2.5,
brushType: 'stroke',
},
zlevel: 1,
itemStyle: {
normal: {
color: '#99FBFE',
shadowBlur: 5,
shadowColor: '#fff',
},
},
data: convertData(seriesData),
},
],
};
//
this.handleMapRandomSelect();
},
immediate: true,
deep: true,
},
},
methods: {
//
startInterval() {
const _self = this;
// 5s
const time = 2000;
if (this.intervalId !== null) {
clearInterval(this.intervalId);
}
this.intervalId = setInterval(() => {
_self.reSelectMapRandomArea();
}, time);
},
//
reSelectMapRandomArea() {
const length = 9;
this.$nextTick(() => {
try {
const map = this.$refs.centreLeft2ChartRef.chart;
let index = Math.floor(Math.random() * length);
while (index === this.preSelectMapIndex || index >= length) {
index = Math.floor(Math.random() * length);
}
map.dispatchAction({
type: 'mapUnSelect',
seriesIndex: 0,
dataIndex: this.preSelectMapIndex,
});
map.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: index,
});
map.dispatchAction({
type: 'mapSelect',
seriesIndex: 0,
dataIndex: index,
});
this.preSelectMapIndex = index;
} catch (error) {
console.log(error)
}
});
},
handleMapRandomSelect() {
this.$nextTick(() => {
try {
const map = this.$refs.centreLeft2ChartRef.chart;
const _self = this;
setTimeout(() => {
_self.reSelectMapRandomArea();
}, 0);
//
map.on('mouseover', function (params) {
clearInterval(_self.intervalId);
map.dispatchAction({
type: 'mapUnSelect',
seriesIndex: 0,
dataIndex: _self.preSelectMapIndex,
});
map.dispatchAction({
type: 'mapSelect',
seriesIndex: 0,
dataIndex: params.dataIndex,
});
_self.preSelectMapIndex = params.dataIndex;
});
//
map.on('globalout', function () {
_self.reSelectMapRandomArea();
_self.startInterval();
});
this.startInterval();
} catch (error) {
console.log(error)
}
});
},
},
};
</script>

View File

@ -1,67 +0,0 @@
<template>
<div>
<Chart :cdata="cdata" />
</div>
</template>
<script>
import Chart from './chart.vue';
export default {
data () {
return {
cdata: [
{
// common/map/fujian.js
name: '福州市',
value: 10,
elseData:{
// tooltip
}
},
{
name: '厦门市',
value: 9,
},
{
name: '漳州市',
value: 8,
},
{
name: '泉州市',
value: 7,
},
{
name: '三明市',
value: 6,
},
{
name: '莆田市',
value: 5,
},
{
name: '南平市',
value: 4,
},
{
name: '龙岩市',
value: 3,
},
{
name: '宁德市',
value: 2,
}
]
}
},
components: {
Chart,
},
mounted () {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,132 +0,0 @@
<template>
<div>
<Echart
:options="options"
id="centreRight2Chart1"
height="200px"
width="260px"
></Echart>
</div>
</template>
<script>
import Echart from '@/common/echart'
export default {
data () {
return {
options: {},
};
},
components: {
Echart,
},
props: {
cdata: {
type: Object,
default: () => ({})
},
},
watch: {
cdata: {
handler (newData) {
//
let lineStyle = {
normal: {
width: 1,
opacity: 0.5
}
};
this.options = {
radar: {
indicator: newData.indicatorData,
shape: "circle",
splitNumber: 5,
radius: ["0%", "65%"],
name: {
textStyle: {
color: "rgb(238, 197, 102)"
}
},
splitLine: {
lineStyle: {
color: [
"rgba(238, 197, 102, 0.1)",
"rgba(238, 197, 102, 0.2)",
"rgba(238, 197, 102, 0.4)",
"rgba(238, 197, 102, 0.6)",
"rgba(238, 197, 102, 0.8)",
"rgba(238, 197, 102, 1)"
].reverse()
}
},
splitArea: {
show: false
},
axisLine: {
lineStyle: {
color: "rgba(238, 197, 102, 0.5)"
}
}
},
series: [
{
name: "北京",
type: "radar",
lineStyle: lineStyle,
data: newData.dataBJ,
symbol: "none",
itemStyle: {
normal: {
color: "#F9713C"
}
},
areaStyle: {
normal: {
opacity: 0.1
}
}
},
{
name: "上海",
type: "radar",
lineStyle: lineStyle,
data: newData.dataSH,
symbol: "none",
itemStyle: {
normal: {
color: "#B3E4A1"
}
},
areaStyle: {
normal: {
opacity: 0.05
}
}
},
{
name: "广州",
type: "radar",
lineStyle: lineStyle,
data: newData.dataGZ,
symbol: "none",
itemStyle: {
normal: {
color: "rgb(238, 197, 102)"
}
},
areaStyle: {
normal: {
opacity: 0.05
}
}
} //end
]
}
},
immediate: true,
deep: true
}
}
};
</script>

View File

@ -1,55 +0,0 @@
<template>
<div>
<Chart :cdata="cdata" />
</div>
</template>
<script>
import Chart from './chart.vue';
export default {
data () {
return {
cdata: {
indicatorData: [
{ name: "data1", max: 300 },
{ name: "data2", max: 250 },
{ name: "data3", max: 300 },
{ name: "data4", max: 5},
{ name: "data5", max: 200 },
{ name: "data6", max: 100 }
],
dataBJ: [
[94, 69, 114, 2.08, 73, 39, 22],
[99, 73, 110, 2.43, 76, 48, 23],
[31, 12, 30, 0.5, 32, 16, 24],
[42, 27, 43, 1, 53, 22, 25],
[154, 117, 157, 3.05, 92, 58, 26],
[234, 185, 230, 4.09, 123, 69, 27],
[160, 120, 186, 2.77, 91, 50, 28]
],
dataGZ: [
[84, 94, 140, 2.238, 68, 18, 22],
[93, 77, 104, 1.165, 53, 7, 23],
[99, 130, 227, 3.97, 55, 15, 24],
[146, 84, 139, 1.094, 40, 17, 25],
[113, 108, 137, 1.481, 48, 15, 26],
[81, 48, 62, 1.619, 26, 3, 27],
[56, 48, 68, 1.336, 37, 9, 28]
],
dataSH: [
[91, 45, 125, 0.82, 34, 23, 1],
[65, 27, 78, 0.86, 45, 29, 2],
[83, 60, 84, 1.09, 73, 27, 3],
[109, 81, 121, 1.28, 68, 51, 4],
[106, 77, 114, 1.07, 55, 51, 5],
[109, 81, 121, 1.28, 68, 51, 6],
[106, 77, 114, 1.07, 55, 51, 7]
]
}
}
},
components: {
Chart,
}
}
</script>

419
src/data/dashboardData.js Normal file
View File

@ -0,0 +1,419 @@
// 科研概况数据
export const researchData = {
chartSettings: {
dimension: ["季度"],
metrics: ["论文", "专利", "获奖", "著作"],
legend: {
show: true,
textStyle: {
color: "#fff",
},
},
grid: {
show: true,
borderColor: "rgba(255, 255, 255, 0.1)",
backgroundColor: "transparent",
},
backgroundColor: "rgba(0, 0, 0, 0.5)",
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
},
chartData: {
columns: ["季度", "论文", "专利", "获奖", "著作"],
rows: [
{ 季度: "Q1", 论文: 20, 专利: 15, 获奖: 5, 著作: 3 },
{ 季度: "Q2", 论文: 25, 专利: 18, 获奖: 8, 著作: 4 },
{ 季度: "Q3", 论文: 30, 专利: 20, 获奖: 10, 著作: 5 },
{ 季度: "Q4", 论文: 35, 专利: 25, 获奖: 12, 著作: 6 },
],
},
statistics: [
{ label: "论文总数", value: 110 },
{ label: "专利数量", value: 78 },
{ label: "获奖数量", value: 35 },
{ label: "著作数量", value: 18 },
],
};
// 教务概况数据
export const educationData = {
chartSettings: {
area: true,
axisSite: { right: ["评教得分"] },
yAxisName: ["得分"],
},
evaluationData: {
columns: ["月份", "评教得分"],
rows: [
{ 月份: "1月", 评教得分: 85 },
{ 月份: "2月", 评教得分: 93 },
{ 月份: "3月", 评教得分: 90 },
{ 月份: "4月", 评教得分: 74 },
{ 月份: "5月", 评教得分: 95 },
{ 月份: "6月", 评教得分: 92 },
],
},
statistics: {
passRate: 95.6,
graduationRate: 98.2,
},
};
// 图表样式配置
export const chartStyles = {
research: {
colors: [
"rgba(64, 158, 255, 0.95)", // 亮蓝色
"rgba(0, 206, 209, 0.95)", // 青色
"rgba(149, 97, 226, 0.95)", // 紫色
"rgba(100, 181, 246, 0.95)", // 天蓝色
],
extend: {
series: (v) => {
if (!v) return [];
const gradientColors = [
["rgba(64, 158, 255, 0.95)", "rgba(64, 158, 255, 0.2)"], // 亮蓝色
["rgba(0, 206, 209, 0.95)", "rgba(0, 206, 209, 0.2)"], // 青色
["rgba(149, 97, 226, 0.95)", "rgba(149, 97, 226, 0.2)"], // 紫色
["rgba(100, 181, 246, 0.95)", "rgba(100, 181, 246, 0.2)"], // 天蓝色
];
return v.map((series, index) => ({
...series,
itemStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: gradientColors[index][0] },
{ offset: 1, color: gradientColors[index][1] },
],
},
borderRadius: [10, 10, 0, 0],
shadowColor: "rgba(0, 0, 0, 0.5)",
shadowBlur: 10,
shadowOffsetY: 5,
},
emphasis: {
itemStyle: {
color: gradientColors[index][0],
shadowBlur: 20,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.8)",
},
},
animationDuration: 2000,
animationEasing: "elasticOut",
}));
},
yAxis: {
axisLabel: {
color: "#fff",
fontSize: 12,
},
splitLine: {
lineStyle: {
color: "rgba(255, 255, 255, 0.1)",
},
},
},
xAxis: {
axisLabel: {
color: "#fff",
fontSize: 12,
},
},
legend: {
textStyle: {
color: "#fff",
},
emphasis: {
textStyle: {
color: "#4a90e2",
},
},
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
shadowStyle: {
color: "rgba(74, 144, 226, 0.1)",
},
},
textStyle: {
color: "#fff",
fontSize: 12,
},
},
},
},
education: {
extend: {
yAxis: {
min: 60,
max: 100,
axisLabel: {
color: "#fff",
fontSize: 12,
},
splitLine: {
show: false
},
},
xAxis: {
axisLabel: {
color: "#fff",
fontSize: 12,
},
splitLine: {
show: false
}
},
legend: {
textStyle: {
color: "#fff",
}
},
series: {
smooth: true,
lineStyle: {
width: 2,
color: {
type: "linear",
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{
offset: 0,
color: "#4a90e2",
},
{
offset: 1,
color: "#36d1dc",
},
],
global: false,
},
},
areaStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "rgba(74, 144, 226, 0.3)",
},
{
offset: 1,
color: "rgba(54, 209, 220, 0.05)",
},
],
global: false,
},
},
animationDuration: 200,
animationEasing: "cubicOut",
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "line",
lineStyle: {
color: "#4a90e2",
type: "dashed",
shadowColor: "rgba(0, 0, 0, 0.3)",
shadowBlur: 5,
},
},
textStyle: {
color: "#fff",
fontSize: 12,
},
formatter: function (params) {
const param = params[0];
return `${param.name}<br/>${param.seriesName}<span style="color:${param.color}">${param.value}</span>`;
}
},
},
},
};
// 资产概况数据
export const assetData = {
totalAssets: 580000,
assetTrendData: {
columns: ["月份", "资产总值"],
rows: [
{ 月份: "1月", 资产总值: 380000 },
{ 月份: "2月", 资产总值: 535000 },
{ 月份: "3月", 资产总值: 445000 },
{ 月份: "4月", 资产总值: 520000 },
{ 月份: "5月", 资产总值: 570000 },
{ 月份: "6月", 资产总值: 480000 },
],
},
assetCategories: [
{ name: "固定资产", value: 420000 },
{ name: "流动资产", value: 120000 },
{ name: "无形资产", value: 40000 },
],
};
// 一卡通概况数据
export const cardData = {
totalCards: 28500,
dailyUsage: 85600,
chartSettings: {
area: true,
axisSite: { right: ["使用次数"] },
yAxisName: ["次数"],
},
usageData: {
columns: ["时间", "使用次数"],
rows: [
{ 时间: "6:00", 使用次数: 2000 },
{ 时间: "9:00", 使用次数: 15000 },
{ 时间: "12:00", 使用次数: 25000 },
{ 时间: "15:00", 使用次数: 18000 },
{ 时间: "18:00", 使用次数: 20000 },
{ 时间: "21:00", 使用次数: 5600 },
],
},
usageScenes: [
{ name: "食堂消费", count: 35000 },
{ name: "门禁通行", count: 28000 },
{ name: "图书借阅", count: 12000 },
{ name: "水电缴费", count: 8000 },
],
};
// 文献概况数据
export const literatureData = {
totalLiterature: 1250000,
chartSettings: {
dimension: ["类型"],
metrics: ["纸质", "电子"],
legend: {
show: true,
textStyle: { color: "#fff" },
},
grid: {
show: true,
borderColor: "rgba(255, 255, 255, 0.1)",
backgroundColor: "transparent",
},
backgroundColor: "rgba(0, 0, 0, 0.5)",
tooltip: {
trigger: "axis",
axisPointer: { type: "shadow" },
},
},
chartData: {
columns: ["类型", "纸质", "电子"],
rows: [
{ 类型: "图书", 纸质: 450000, 电子: 350000 },
{ 类型: "期刊", 纸质: 120000, 电子: 180000 },
{ 类型: "论文", 纸质: 50000, 电子: 100000 },
],
},
subjectDistribution: [
{ name: "工学", count: 320000, percentage: 85, color: "#409EFF" },
{ name: "理学", count: 280000, percentage: 75, color: "#67C23A" },
{ name: "经管", count: 220000, percentage: 65, color: "#E6A23C" },
{ name: "文学", count: 180000, percentage: 55, color: "#F56C6C" },
{ name: "艺术", count: 150000, percentage: 45, color: "#909399" },
],
};
// 教职工概况数据
export const staffData = {
totalStaff: 1256,
chartSettings: {
radius: ["35%", "65%"],
offsetY: "60%",
color: [
"#4a90e2", // 亮蓝色
"#00CED1", // 青色
"#64B5F6", // 天蓝色
"#9561e2", // 紫色
],
label: {
show: true,
position: "outside",
formatter: "{b}:{c}({d}%)",
color: "#fff",
fontSize: 12,
},
legend: {
show: true,
textStyle: {
color: "#fff",
fontSize: 12
}
},
itemStyle: {
borderRadius: 4,
borderColor: "#fff",
borderWidth: 2
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
},
titleData: {
columns: ["职称", "人数"],
rows: [
{ 职称: "正高", 人数: 180 },
{ 职称: "副高", 人数: 320 },
{ 职称: "中级", 人数: 450 },
{ 职称: "初级", 人数: 306 },
],
},
educationStructure: [
{ label: "博士", value: 35 },
{ label: "硕士", value: 45 },
{ label: "学士", value: 18 },
{ label: "其他", value: 2 },
],
};
export const studentData = {
totalStudents: 12000,
location: {
name: "唐山师范学院",
coordinates: [118.154, 39.630],
address: "河北省唐山市路北区建设路156号"
},
gradeData: [
{ name: "大一", value: 3200 },
{ name: "大二", value: 3100 },
{ name: "大三", value: 2900 },
{ name: "大四", value: 2800 }
],
genderData: [
{ name: "男", value: 5500 },
{ name: "女", value: 6500 }
]
};

View File

@ -1,7 +1,10 @@
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import VCharts from 'v-charts'
import dataV from '@jiaminghi/data-view';
// 引入全局css
import './assets/scss/style.scss';
@ -16,8 +19,8 @@ import 'vue-awesome/icons/align-left.js';
//引入echart
//4.x 引用方式
import echarts from 'echarts'
//5.x 引用方式为按需引用
//希望使用5.x版本的话,需要在package.json中更新版本号,并切换引用方式
// //5.x 引用方式为按需引用
// //希望使用5.x版本的话,需要在package.json中更新版本号,并切换引用方式
//import * as echarts from 'echarts'
Vue.prototype.$echarts = echarts
Vue.config.productionTip = false;
@ -25,9 +28,11 @@ Vue.config.productionTip = false;
// 全局注册
Vue.component('icon', Icon);
Vue.use(dataV);
Vue.use(ElementUI);
Vue.use(VCharts);
new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#app');
render: h => h(App)
}).$mount('#app')

View File

@ -3,11 +3,55 @@ import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [{
path: '/',
name: 'index',
component: () => import('../views/index.vue')
}]
const routes = [
{
path: '/',
name: 'index',
component: () => import('../views/index.vue')
},
// 教务详情
{
path: '/education-detail',
name: 'EducationDetail',
component: () => import('@/views/detail/EducationDetail.vue')
},
// 科研详情
{
path: '/research-detail',
name: 'ResearchDetail',
component: () => import('@/views/detail/ResearchDetail.vue')
},
// 学生详情
{
path: '/student-detail',
name: 'StudentDetail',
component: () => import('@/views/detail/StudentDetail.vue')
},
// 教职工详情
{
path: '/staff-detail',
name: 'StaffDetail',
component: () => import('@/views/detail/StaffDetail.vue')
},
// 资产详情
{
path: '/asset-detail',
name: 'AssetDetail',
component: () => import('@/views/detail/AssetDetail.vue')
},
// 文献详情
{
path: '/literature-detail',
name: 'LiteratureDetail',
component: () => import('@/views/detail/LiteratureDetail.vue')
},
// 一卡通详情页面
{
path: '/card-detail',
name: 'CardDetail',
component: () => import('@/views/detail/CardDetail.vue')
},
]
const router = new VueRouter({
routes
})

56
src/utils/chartMixin.js Normal file
View File

@ -0,0 +1,56 @@
export default {
data() {
return {
// 通用图表配置
baseChartExtend: {
yAxis: {
axisLabel: {
color: '#fff',
fontSize: 12
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
xAxis: {
axisLabel: {
color: '#fff',
fontSize: 12
}
},
legend: {
textStyle: {
color: '#fff'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line',
lineStyle: {
color: '#e1e2e2',
type: 'dashed',
shadowColor: 'rgba(0, 0, 0, 0.3)',
shadowBlur: 5
}
},
textStyle: {
color: '#fff',
fontSize: 12
}
}
}
}
},
methods: {
// 合并图表配置
mergeChartExtend(customExtend) {
return {
...this.baseChartExtend,
...customExtend
}
}
}
}

18
src/utils/format.js Normal file
View File

@ -0,0 +1,18 @@
/**
* 格式化数字添加千位分隔符
* @param {number} num - 要格式化的数字
* @returns {string} - 格式化后的字符串
*/
export const formatNumber = (num) => {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};
/**
* 格式化金额添加千位分隔符和货币符号
* @param {number} amount - 要格式化的金额
* @param {string} symbol - 货币符号默认为 ¥
* @returns {string} - 格式化后的金额字符串
*/
export const formatCurrency = (amount, symbol = '¥') => {
return `${symbol} ${formatNumber(amount)}`;
};

View File

@ -1,52 +0,0 @@
<template>
<div id="bottomLeft">
<div class="bg-color-black">
<div class="d-flex pt-2 pl-2">
<span>
<icon name="chart-bar" class="text-icon"></icon>
</span>
<div class="d-flex">
<span class="fs-xl text mx-2">科研概况</span>
</div>
</div>
<div>
<BottomLeftChart />
</div>
</div>
</div>
</template>
<script>
import BottomLeftChart from '@/components/echart/bottom/bottomLeftChart'
export default {
components: {
BottomLeftChart
}
}
</script>
<style lang="scss" scoped>
$box-height: 520px;
$box-width: 100%;
#bottomLeft {
padding: 20px 16px;
height: $box-height;
width: $box-width;
border-radius: 5px;
.bg-color-black {
height: $box-height - 35px;
border-radius: 10px;
}
.text {
color: #c3cbde;
}
.chart-box {
margin-top: 16px;
width: 170px;
height: 170px;
.active-ring-name {
padding-top: 10px;
}
}
}
</style>

View File

@ -1,60 +0,0 @@
<template>
<div id="bottomRight">
<div class="bg-color-black">
<div class="d-flex pt-2 pl-2">
<span>
<icon name="chart-area" class="text-icon"></icon>
</span>
<div class="d-flex">
<span class="fs-xl text mx-2">工单修复以及满意度统计图</span>
<div class="decoration2">
<dv-decoration-2 :reverse="true" style="width:5px;height:6rem;" />
</div>
</div>
</div>
<div>
<BottomRightChart />
</div>
</div>
</div>
</template>
<script>
import BottomRightChart from "@/components/echart/bottom/bottomRightChart";
export default {
components: {
BottomRightChart
}
};
</script>
<style lang="scss" class>
$box-height: 520px;
$box-width: 100%;
#bottomRight {
padding: 14px 16px;
height: $box-height;
width: $box-width;
border-radius: 5px;
.bg-color-black {
height: $box-height - 30px;
border-radius: 10px;
}
.text {
color: #c3cbde;
}
//线
.decoration2 {
position: absolute;
right: 0.125rem;
}
.chart-box {
margin-top: 16px;
width: 170px;
height: 170px;
.active-ring-name {
padding-top: 10px;
}
}
}
</style>

View File

@ -1,283 +0,0 @@
<template>
<div id="center">
<div class="up">
<div
class="bg-color-black item"
v-for="item in titleItem"
:key="item.title"
>
<p class="ml-3 colorBlue fw-b fs-xl">{{ item.title }}</p>
<div>
<dv-digital-flop
class="dv-dig-flop ml-1 mt-2 pl-3"
:config="item.number"
/>
</div>
</div>
</div>
<div class="down">
<div class="ranking bg-color-black">
<span>
<icon name="chart-pie" class="text-icon"></icon>
</span>
<span class="fs-xl text mx-2 mb-1 pl-3">年度负责人组件达标榜</span>
<dv-scroll-ranking-board class="dv-scr-rank-board mt-1" :config="ranking" />
</div>
<div class="percent">
<div class="item bg-color-black">
<span>今日任务通过率</span>
<CenterChart
:id="rate[0].id"
:tips="rate[0].tips"
:colorObj="rate[0].colorData"
/>
</div>
<div class="item bg-color-black">
<span>今日任务达标率</span>
<CenterChart
:id="rate[1].id"
:tips="rate[1].tips"
:colorObj="rate[1].colorData"
/>
</div>
<div class="water">
<dv-water-level-pond class="dv-wa-le-po" :config="water" />
</div>
</div>
</div>
</div>
</template>
<script>
import CenterChart from '@/components/echart/center/centerChartRate'
export default {
data() {
return {
titleItem: [
{
title: '今年累计任务建次数',
number: {
number: [120],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 26
}
}
},
{
title: '本月累计任务次数',
number: {
number: [18],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 26
}
}
},
{
title: '今日累计任务次数',
number: {
number: [2],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 26
}
}
},
{
title: '今年失败任务次数',
number: {
number: [14],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 26
}
}
},
{
title: '今年成功任务次数',
number: {
number: [106],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 26
}
}
},
{
title: '今年达标任务个数',
number: {
number: [100],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 26
}
}
}
],
ranking: {
data: [
{
name: '周口',
value: 55
},
{
name: '南阳',
value: 120
},
{
name: '西峡',
value: 78
},
{
name: '驻马店',
value: 66
},
{
name: '新乡',
value: 80
},
{
name: '新乡2',
value: 80
},
{
name: '新乡3',
value: 80
},
{
name: '新乡4',
value: 80
},
{
name: '新乡5',
value: 80
},
{
name: '新乡6',
value: 80
}
],
carousel: 'single',
unit: '人'
},
water: {
data: [24, 45],
shape: 'roundRect',
formatter: '{value}%',
waveNum: 3
},
//
rate: [
{
id: 'centerRate1',
tips: 60,
colorData: {
textStyle: '#3fc0fb',
series: {
color: ['#00bcd44a', 'transparent'],
dataColor: {
normal: '#03a9f4',
shadowColor: '#97e2f5'
}
}
}
},
{
id: 'centerRate2',
tips: 40,
colorData: {
textStyle: '#67e0e3',
series: {
color: ['#faf3a378', 'transparent'],
dataColor: {
normal: '#ff9800',
shadowColor: '#fcebad'
}
}
}
}
]
}
},
components: {
CenterChart
}
}
</script>
<style lang="scss" scoped>
#center {
display: flex;
flex-direction: column;
.up {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
.item {
border-radius: 6px;
padding-top: 8px;
margin-top: 8px;
width: 32%;
height: 70px;
.dv-dig-flop {
width: 150px;
height: 30px;
}
}
}
.down {
padding: 6px 4px;
padding-bottom: 0;
width: 100%;
display: flex;
height: 255px;
justify-content: space-between;
.bg-color-black {
border-radius: 5px;
}
.ranking {
padding: 10px;
width: 59%;
.dv-scr-rank-board {
height: 225px;
}
}
.percent {
width: 40%;
display: flex;
flex-wrap: wrap;
.item {
width: 50%;
height: 120px;
span {
margin-top: 8px;
font-size: 14px;
display: flex;
justify-content: center;
}
}
.water {
width: 100%;
.dv-wa-le-po {
height: 120px;
}
}
}
}
}
</style>

View File

@ -1,169 +0,0 @@
<template>
<div id="centerLeft1">
<div class="bg-color-black">
<div class="d-flex pt-2 pl-2">
<span>
<icon name="chart-bar" class="text-icon"></icon>
</span>
<div class="d-flex">
<span class="fs-xl text mx-2">教务概况</span>
<!-- <dv-decoration-3 class="dv-dec-3" /> -->
</div>
</div>
<div class="d-flex jc-center">
<CenterLeft1Chart />
</div>
<!-- 4个主要的数据 -->
<div class="bottom-data">
<div
class="item-box mt-2"
v-for="(item, index) in numberData"
:key="index"
>
<div class="d-flex">
<span class="coin"></span>
<dv-digital-flop class="dv-digital-flop" :config="item.number" />
</div>
<p class="text" style="text-align: center;">
{{ item.text }}
<span class="colorYellow">()</span>
</p>
</div>
</div>
</div>
</div>
</template>
<script>
import CenterLeft1Chart from '@/components/echart/centerLeft/centerLeft1Chart'
export default {
data() {
return {
numberData: [
{
number: {
number: [15],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 24
}
},
text: '教务概况'
},
{
number: {
number: [1144],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 24
}
},
text: '科研概况'
},
{
number: {
number: [361],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 24
}
},
text: '学生概况'
},
{
number: {
number: [157],
toFixed: 1,
textAlign: 'left',
content: '{nt}',
style: {
fontSize: 24
}
},
text: '教职工概况'
}
]
}
},
components: {
CenterLeft1Chart
},
mounted() {
this.changeTiming()
},
methods: {
changeTiming() {
setInterval(() => {
this.changeNumber()
}, 3000)
},
changeNumber() {
this.numberData.forEach((item, index) => {
item.number.number[0] += ++index
item.number = { ...item.number }
})
}
}
}
</script>
<style lang="scss" scoped>
$box-width: 300px;
$box-height: 410px;
#centerLeft1 {
padding: 16px;
height: $box-height;
width: $box-width;
border-radius: 10px;
.bg-color-black {
height: $box-height - 30px;
border-radius: 10px;
}
.text {
color: #c3cbde;
}
.dv-dec-3 {
position: relative;
width: 100px;
height: 20px;
top: -3px;
}
.bottom-data {
.item-box {
& > div {
padding-right: 5px;
}
font-size: 14px;
float: right;
position: relative;
width: 50%;
color: #d3d6dd;
.dv-digital-flop {
width: 120px;
height: 30px;
}
//
.coin {
position: relative;
top: 6px;
font-size: 20px;
color: #ffc107;
}
.colorYellow {
color: yellowgreen;
}
p {
text-align: center;
}
}
}
}
</style>

View File

@ -1,59 +0,0 @@
<template>
<div id="centerLeft1">
<div class="bg-color-black">
<div class="d-flex pt-2 pl-2">
<span>
<icon name="chart-pie" class="text-icon"></icon>
</span>
<div class="d-flex">
<span class="fs-xl text mx-2">地图数据</span>
<dv-decoration-1 class="dv-dec-1" />
</div>
</div>
<div class="d-flex jc-center">
<CenterLeft2Chart />
</div>
</div>
</div>
</template>
<script>
import CenterLeft2Chart from "@/components/echart/centerLeft/centerLeft2Chart";
export default {
components: {
CenterLeft2Chart
},
};
</script>
<style lang="scss" scoped>
#centerLeft1 {
$box-width: 300px;
$box-height: 410px;
padding: 16px;
height: $box-height;
min-width: $box-width;
border-radius: 5px;
.bg-color-black {
height: $box-height - 30px;
border-radius: 10px;
}
.text {
color: #c3cbde;
}
.dv-dec-1 {
position: relative;
width: 100px;
height: 20px;
top: -3px;
}
.chart-box {
margin-top: 16px;
width: 170px;
height: 170px;
.active-ring-name {
padding-top: 10px;
}
}
}
</style>

View File

@ -1,76 +0,0 @@
<template>
<div id="centerRight1">
<div class="bg-color-black">
<div class="d-flex pt-2 pl-2">
<span>
<icon name="chart-line" class="text-icon"></icon>
</span>
<div class="d-flex">
<span class="fs-xl text mx-2">任务完成排行榜</span>
</div>
</div>
<div class="d-flex jc-center body-box">
<dv-scroll-board class="dv-scr-board" :config="config" />
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
config: {
header: ['组件', '分支', '覆盖率'],
data: [
['组件1', 'dev-1', "<span class='colorGrass'>↑75%</span>"],
['组件2', 'dev-2', "<span class='colorRed'>↓33%</span>"],
['组件3', 'dev-3', "<span class='colorGrass'>↑100%</span>"],
['组件4', 'rea-1', "<span class='colorGrass'>↑94%</span>"],
['组件5', 'rea-2', "<span class='colorGrass'>↑95%</span>"],
['组件6', 'fix-2', "<span class='colorGrass'>↑63%</span>"],
['组件7', 'fix-4', "<span class='colorGrass'>↑84%</span>"],
['组件8', 'fix-7', "<span class='colorRed'>↓46%</span>"],
['组件9', 'dev-2', "<span class='colorRed'>↓13%</span>"],
['组件10', 'dev-9', "<span class='colorGrass'>↑76%</span>"]
],
rowNum: 7, //
headerHeight: 35,
headerBGC: '#0f1325', //
oddRowBGC: '#0f1325', //
evenRowBGC: '#171c33', //
index: true,
columnWidth: [50],
align: ['center']
}
}
}
}
</script>
<style lang="scss" scoped>
$box-height: 410px;
$box-width: 300px;
#centerRight1 {
padding: 16px;
padding-top: 20px;
height: $box-height;
width: $box-width;
border-radius: 5px;
.bg-color-black {
height: $box-height - 30px;
border-radius: 10px;
}
.text {
color: #c3cbde;
}
.body-box {
border-radius: 10px;
overflow: hidden;
.dv-scr-board {
width: 270px;
height: 340px;
}
}
}
</style>

View File

@ -1,80 +0,0 @@
<template>
<div id="centerRight2">
<div class="bg-color-black">
<div class="d-flex pt-2 pl-2">
<span>
<icon name="align-left" class="text-icon"></icon>
</span>
<span class="fs-xl text mx-2">产品销售渠道分析</span>
</div>
<div class="d-flex ai-center flex-column body-box">
<dv-capsule-chart class="dv-cap-chart" :config="config" />
<centerRight2Chart1 />
</div>
</div>
</div>
</template>
<script>
import centerRight2Chart1 from '@/components/echart/centerRight/centerRightChart'
export default {
data() {
return {
config: {
data: [
{
name: '南阳',
value: 167
},
{
name: '周口',
value: 67
},
{
name: '漯河',
value: 123
},
{
name: '郑州',
value: 55
},
{
name: '西峡',
value: 98
}
]
}
}
},
components: { centerRight2Chart1 }
}
</script>
<style lang="scss" scoped>
#centerRight2 {
$box-height: 410px;
$box-width: 340px;
padding: 5px;
height: $box-height;
width: $box-width;
border-radius: 5px;
.bg-color-black {
padding: 5px;
height: $box-height;
width: $box-width;
border-radius: 10px;
}
.text {
color: #c3cbde;
}
.body-box {
border-radius: 10px;
overflow: hidden;
.dv-cap-chart {
width: 100%;
height: 160px;
}
}
}
</style>

View File

@ -0,0 +1,291 @@
<template>
<div class="asset-detail">
<div class="header">
<el-page-header @back="goBack" content="资产详情" />
<div class="filters">
<el-select v-model="selectedYear" placeholder="选择年份">
<el-option
v-for="year in years"
:key="year"
:label="year"
:value="year"
/>
</el-select>
</div>
</div>
<el-row :gutter="20" class="overview-cards">
<el-col :span="6" v-for="(item, index) in overviewData" :key="index">
<el-card shadow="hover" class="overview-card">
<div class="card-content">
<div class="value">{{ item.value }}</div>
<div class="label">{{ item.label }}</div>
<div class="trend" :class="item.trend">
{{ item.trendValue }}%
<i
:class="item.trend === 'up' ? 'el-icon-top' : 'el-icon-bottom'"
></i>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>资产类型分布</span>
</div>
<ve-pie
:data="assetTypeData"
:settings="pieSettings"
height="300px"
/>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>资产价值趋势</span>
</div>
<ve-line
:data="assetValueData"
:settings="lineSettings"
height="300px"
/>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>设备使用率</span>
</div>
<ve-gauge
:data="equipmentUsageData"
:settings="gaugeSettings"
height="300px"
/>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>预算执行情况</span>
</div>
<ve-histogram
:data="budgetData"
:settings="histogramSettings"
height="300px"
/>
</el-card>
</el-col>
</el-row>
<el-card class="table-card">
<div slot="header">
<span>资产采购计划</span>
<el-button style="float: right" type="text">查看全部</el-button>
</div>
<el-table :data="purchaseData" style="width: 100%">
<el-table-column prop="name" label="采购项目" />
<el-table-column prop="department" label="申请部门" />
<el-table-column prop="budget" label="预算金额(万)" />
<el-table-column prop="status" label="状态">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="progress" label="进度">
<template slot-scope="scope">
<el-progress :percentage="scope.row.progress" />
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
name: "AssetDetail",
data() {
return {
selectedYear: "2024",
years: ["2024", "2023", "2022", "2021"],
overviewData: [
{ label: "总资产(万元)", value: "580,000", trend: "up", trendValue: 8 },
{ label: "设备数量(台)", value: "12,586", trend: "up", trendValue: 5 },
{ label: "设备完好率", value: "96.8%", trend: "up", trendValue: 2 },
{ label: "预算执行率", value: "85.2%", trend: "up", trendValue: 10 },
],
assetTypeData: {
columns: ["类型", "金额"],
rows: [
{ 类型: "房屋建筑", 金额: 280000 },
{ 类型: "教学设备", 金额: 150000 },
{ 类型: "科研设备", 金额: 100000 },
{ 类型: "办公设备", 金额: 30000 },
{ 类型: "其他资产", 金额: 20000 },
],
},
pieSettings: {
radius: "65%",
offsetY: "60%",
},
assetValueData: {
columns: ["月份", "资产总值"],
rows: [
{ 月份: "1月", 资产总值: 550000 },
{ 月份: "2月", 资产总值: 555000 },
{ 月份: "3月", 资产总值: 562000 },
{ 月份: "4月", 资产总值: 568000 },
{ 月份: "5月", 资产总值: 575000 },
{ 月份: "6月", 资产总值: 580000 },
],
},
lineSettings: {
area: true,
},
equipmentUsageData: {
columns: ["type", "value"],
rows: [{ type: "设备使用率", value: 85.6 }],
},
gaugeSettings: {
dataName: {
设备使用率: "使用率",
},
seriesMap: {
设备使用率: {
min: 0,
max: 100,
splitNumber: 10,
},
},
},
budgetData: {
columns: ["月份", "预算金额", "实际支出"],
rows: [
{ 月份: "1月", 预算金额: 1000, 实际支出: 850 },
{ 月份: "2月", 预算金额: 1200, 实际支出: 1000 },
{ 月份: "3月", 预算金额: 1500, 实际支出: 1300 },
{ 月份: "4月", 预算金额: 1800, 实际支出: 1600 },
{ 月份: "5月", 预算金额: 2000, 实际支出: 1750 },
{ 月份: "6月", 预算金额: 2200, 实际支出: 1900 },
],
},
histogramSettings: {
metrics: ["预算金额", "实际支出"],
},
purchaseData: [
{
name: "实验室设备更新",
department: "物理学院",
budget: 500,
status: "审批中",
progress: 30,
},
{
name: "智慧教室建设",
department: "教务处",
budget: 800,
status: "已立项",
progress: 10,
},
{
name: "图书馆设备采购",
department: "图书馆",
budget: 300,
status: "采购中",
progress: 60,
},
{
name: "体育场地维护",
department: "体育部",
budget: 200,
status: "已完成",
progress: 100,
},
],
};
},
methods: {
goBack() {
this.$router.push("/");
},
getStatusType(status) {
const types = {
审批中: "warning",
已立项: "primary",
采购中: "success",
已完成: "info",
};
return types[status] || "info";
},
},
};
</script>
<style lang="scss" scoped>
.asset-detail {
padding: 20px;
background: #f0f2f5;
min-height: 100vh;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.overview-cards {
margin-bottom: 20px;
.overview-card {
.card-content {
text-align: center;
.value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.label {
font-size: 14px;
color: #909399;
margin: 8px 0;
}
.trend {
font-size: 12px;
&.up {
color: #67c23a;
}
&.down {
color: #f56c6c;
}
}
}
}
}
.charts-row {
margin-bottom: 20px;
.chart-card {
height: 400px;
}
}
.table-card {
margin-bottom: 20px;
}
}
</style>

View File

@ -0,0 +1,305 @@
<template>
<div class="card-detail">
<div class="header">
<el-page-header @back="goBack" content="一卡通详情" />
<div class="filters">
<el-select v-model="selectedYear" placeholder="选择年份">
<el-option
v-for="year in years"
:key="year"
:label="year"
:value="year"
/>
</el-select>
<el-date-picker
v-model="selectedDate"
type="date"
placeholder="选择日期"
size="small"
/>
</div>
</div>
<el-row :gutter="20" class="overview-cards">
<el-col :span="6" v-for="(item, index) in overviewData" :key="index">
<el-card shadow="hover" class="overview-card">
<div class="card-content">
<div class="value">{{ item.value }}</div>
<div class="label">{{ item.label }}</div>
<div class="trend" :class="item.trend">
{{ item.trendValue }}%
<i
:class="item.trend === 'up' ? 'el-icon-top' : 'el-icon-bottom'"
></i>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>消费趋势分析</span>
</div>
<ve-line
:data="consumptionData"
:settings="lineSettings"
height="300px"
/>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>消费场所分布</span>
</div>
<ve-pie :data="locationData" :settings="pieSettings" height="300px" />
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>门禁使用分析</span>
</div>
<ve-histogram
:data="accessData"
:settings="histogramSettings"
height="300px"
/>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>卡务办理统计</span>
</div>
<ve-bar :data="cardServiceData" height="300px" />
</el-card>
</el-col>
</el-row>
<el-card class="table-card">
<div slot="header">
<span>异常记录</span>
<el-button style="float: right" type="text">查看全部</el-button>
</div>
<el-table :data="abnormalRecords" style="width: 100%">
<el-table-column prop="time" label="时间" width="180" />
<el-table-column prop="cardNo" label="卡号" width="120" />
<el-table-column prop="location" label="地点" />
<el-table-column prop="type" label="类型" width="120">
<template slot-scope="scope">
<el-tag :type="getAbnormalType(scope.row.type)">
{{ scope.row.type }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="处理状态" width="120">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
name: "CardDetail",
data() {
return {
selectedYear: "2024",
selectedDate: new Date(),
years: ["2024", "2023", "2022", "2021"],
overviewData: [
{ label: "发卡总量", value: "28,586", trend: "up", trendValue: 3 },
{
label: "日均消费额(元)",
value: "256,890",
trend: "up",
trendValue: 5,
},
{ label: "日均使用次数", value: "85,630", trend: "up", trendValue: 8 },
{ label: "卡片完好率", value: "99.2%", trend: "up", trendValue: 0.5 },
],
consumptionData: {
columns: ["时间", "消费金额", "消费笔数"],
rows: [
{ 时间: "6:00", 消费金额: 5000, 消费笔数: 500 },
{ 时间: "8:00", 消费金额: 25000, 消费笔数: 2500 },
{ 时间: "12:00", 消费金额: 85000, 消费笔数: 8500 },
{ 时间: "15:00", 消费金额: 45000, 消费笔数: 4500 },
{ 时间: "18:00", 消费金额: 65000, 消费笔数: 6500 },
{ 时间: "21:00", 消费金额: 35000, 消费笔数: 3500 },
],
},
lineSettings: {
axisSite: { right: ["消费笔数"] },
yAxisType: ["normal", "normal"],
yAxisName: ["金额", "笔数"],
},
locationData: {
columns: ["场所", "消费额"],
rows: [
{ 场所: "食堂", 消费额: 150000 },
{ 场所: "超市", 消费额: 50000 },
{ 场所: "图书馆", 消费额: 20000 },
{ 场所: "浴室", 消费额: 25000 },
{ 场所: "其他", 消费额: 10000 },
],
},
pieSettings: {
radius: "65%",
offsetY: "60%",
},
accessData: {
columns: ["时间段", "图书馆", "宿舍", "教学楼"],
rows: [
{ 时间段: "6:00-9:00", 图书馆: 500, 宿舍: 2500, 教学楼: 1500 },
{ 时间段: "9:00-12:00", 图书馆: 2500, 宿舍: 1000, 教学楼: 3500 },
{ 时间段: "12:00-15:00", 图书馆: 1800, 宿舍: 1800, 教学楼: 2500 },
{ 时间段: "15:00-18:00", 图书馆: 2000, 宿舍: 1500, 教学楼: 2000 },
{ 时间段: "18:00-22:00", 图书馆: 1500, 宿舍: 3500, 教学楼: 1000 },
],
},
histogramSettings: {
stack: { 类型: ["图书馆", "宿舍", "教学楼"] },
},
cardServiceData: {
columns: ["服务类型", "数量"],
rows: [
{ 服务类型: "新卡办理", 数量: 256 },
{ 服务类型: "挂失", 数量: 158 },
{ 服务类型: "解挂", 数量: 142 },
{ 服务类型: "补办", 数量: 86 },
{ 服务类型: "注销", 数量: 35 },
],
},
abnormalRecords: [
{
time: "2023-06-20 08:25:36",
cardNo: "2023001",
location: "图书馆",
type: "重复刷卡",
status: "已处理",
},
{
time: "2023-06-20 12:15:42",
cardNo: "2023158",
location: "食堂",
type: "余额异常",
status: "处理中",
},
{
time: "2023-06-20 15:30:18",
cardNo: "2023286",
location: "宿舍",
type: "刷卡失败",
status: "未处理",
},
{
time: "2023-06-20 18:45:55",
cardNo: "2023425",
location: "超市",
type: "重复消费",
status: "已处理",
},
],
};
},
methods: {
goBack() {
this.$router.push("/");
},
getAbnormalType(type) {
const types = {
重复刷卡: "warning",
余额异常: "danger",
刷卡失败: "info",
重复消费: "warning",
};
return types[type] || "info";
},
getStatusType(status) {
const types = {
已处理: "success",
处理中: "primary",
未处理: "danger",
};
return types[status] || "info";
},
},
};
</script>
<style lang="scss" scoped>
.card-detail {
padding: 20px;
background: #f0f2f5;
min-height: 100vh;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
.filters {
display: flex;
gap: 10px;
}
}
.overview-cards {
margin-bottom: 20px;
.overview-card {
.card-content {
text-align: center;
.value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.label {
font-size: 14px;
color: #909399;
margin: 8px 0;
}
.trend {
font-size: 12px;
&.up {
color: #67c23a;
}
&.down {
color: #f56c6c;
}
}
}
}
}
.charts-row {
margin-bottom: 20px;
.chart-card {
height: 400px;
}
}
.table-card {
margin-bottom: 20px;
}
}
</style>

View File

@ -0,0 +1,235 @@
<template>
<div class="education-detail">
<div class="header">
<el-page-header @back="goBack" content="教务详情" />
<div class="filter">
<el-select v-model="selectedYear" placeholder="选择年份">
<el-option
v-for="year in years"
:key="year"
:label="year"
:value="year"
/>
</el-select>
<el-select v-model="selectedSemester" placeholder="选择学期">
<el-option
v-for="item in semesters"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
<el-row :gutter="20" class="data-overview">
<el-col :span="8" v-for="(item, index) in overviewData" :key="index">
<el-card shadow="hover">
<div class="data-item">
<div class="icon">
<i :class="item.icon"></i>
</div>
<div class="info">
<div class="value">{{ item.value }}</div>
<div class="label">{{ item.label }}</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-container">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>课程通过率趋势</span>
</div>
<ve-line
:data="passRateData"
:settings="passRateSettings"
height="300px"
/>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>学生评教分布</span>
</div>
<ve-histogram
:data="evaluationData"
:settings="evaluationSettings"
height="300px"
/>
</el-card>
</el-col>
</el-row>
<el-card class="resource-usage">
<div slot="header">
<span>教学资源使用情况</span>
</div>
<el-table :data="resourceData" style="width: 100%">
<el-table-column prop="name" label="资源名称" />
<el-table-column prop="total" label="总量" />
<el-table-column prop="used" label="已使用" />
<el-table-column prop="usage" label="使用率">
<template slot-scope="scope">
<el-progress
:percentage="scope.row.usage"
:color="getProgressColor(scope.row.usage)"
/>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
name: "EducationDetail",
data() {
return {
selectedYear: "2024",
selectedSemester: "1",
years: ["2024", "2023", "2022", "2021"],
semesters: [
{ label: "第一学期", value: "1" },
{ label: "第二学期", value: "2" },
],
overviewData: JSON.parse(JSON.stringify([
{ label: "课程总数", value: "1,256", icon: "el-icon-reading" },
{ label: "在线课程数", value: "368", icon: "el-icon-monitor" },
{ label: "授课教师数", value: "526", icon: "el-icon-user" },
])),
passRateData: JSON.parse(JSON.stringify({
columns: ["月份", "通过率"],
rows: [
{ 月份: "1月", 通过率: 92 },
{ 月份: "2月", 通过率: 93 },
{ 月份: "3月", 通过率: 95 },
{ 月份: "4月", 通过率: 94 },
{ 月份: "5月", 通过率: 96 },
{ 月份: "6月", 通过率: 95 },
],
})),
passRateSettings: {
area: true,
yAxisName: ["通过率(%)"],
},
evaluationData: {
columns: ["分数段", "课程数"],
rows: [
{ 分数段: "90-100", 课程数: 320 },
{ 分数段: "80-89", 课程数: 580 },
{ 分数段: "70-79", 课程数: 250 },
{ 分数段: "60-69", 课程数: 80 },
{ 分数段: "60以下", 课程数: 26 },
],
},
evaluationSettings: {
yAxisName: ["课程数量"],
},
resourceData: JSON.parse(JSON.stringify([
{ name: "多媒体教室", total: 120, used: 98, usage: 82 },
{ name: "实验室", total: 45, used: 35, usage: 78 },
{ name: "在线课程平台", total: 368, used: 320, usage: 87 },
{ name: "教学软件", total: 50, used: 42, usage: 84 },
])),
};
},
created() {
this.initializeData();
},
methods: {
initializeData() {
// Add any additional initialization logic here
},
goBack() {
this.$router.push("/");
},
getProgressColor(percentage) {
if (percentage < 60) return "#F56C6C";
if (percentage < 80) return "#E6A23C";
return "#67C23A";
},
handleDataChange(newData) {
this.resourceData = JSON.parse(JSON.stringify(newData.resourceData));
this.passRateData = JSON.parse(JSON.stringify(newData.passRateData));
this.overviewData = JSON.parse(JSON.stringify(newData.overviewData));
},
},
watch: {
selectedYear() {
this.initializeData();
},
selectedSemester() {
this.initializeData();
},
},
};
</script>
<style lang="scss" scoped>
.education-detail {
padding: 20px;
background: #f0f2f5;
min-height: 100vh;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
.filter {
display: flex;
gap: 10px;
}
}
.data-overview {
margin-bottom: 20px;
.data-item {
display: flex;
align-items: center;
.icon {
font-size: 48px;
color: #409eff;
margin-right: 20px;
}
.info {
.value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.label {
font-size: 14px;
color: #909399;
margin-top: 5px;
}
}
}
}
.charts-container {
margin-bottom: 20px;
.chart-card {
height: 400px;
}
}
.resource-usage {
.el-progress {
margin-top: 8px;
}
}
}
</style>

View File

@ -0,0 +1,272 @@
<template>
<div class="literature-detail">
<div class="header">
<el-page-header @back="goBack" content="文献详情" />
<div class="filters">
<el-select v-model="selectedYear" placeholder="选择年份">
<el-option
v-for="year in years"
:key="year"
:label="year"
:value="year"
/>
</el-select>
</div>
</div>
<el-row :gutter="20" class="overview-cards">
<el-col :span="6" v-for="(item, index) in overviewData" :key="index">
<el-card shadow="hover" class="overview-card">
<div class="card-content">
<div class="value">{{ item.value }}</div>
<div class="label">{{ item.label }}</div>
<div class="trend" :class="item.trend">
{{ item.trendValue }}%
<i
:class="item.trend === 'up' ? 'el-icon-top' : 'el-icon-bottom'"
></i>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>馆藏资源分布</span>
</div>
<ve-pie :data="resourceData" :settings="pieSettings" height="300px" />
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>借阅趋势分析</span>
</div>
<ve-line
:data="borrowingData"
:settings="lineSettings"
height="300px"
/>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>学科分布</span>
</div>
<ve-radar :data="subjectData" height="300px" />
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>数据库访问量</span>
</div>
<ve-histogram
:data="databaseData"
:settings="histogramSettings"
height="300px"
/>
</el-card>
</el-col>
</el-row>
<el-card class="table-card">
<div slot="header">
<span>热门借阅排行</span>
<el-button style="float: right" type="text">查看全部</el-button>
</div>
<el-table :data="popularBooks" style="width: 100%">
<el-table-column prop="rank" label="排名" width="80" />
<el-table-column prop="name" label="书名" />
<el-table-column prop="author" label="作者" width="150" />
<el-table-column prop="category" label="分类" width="120" />
<el-table-column prop="borrowCount" label="借阅次数" width="120" />
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
name: "LiteratureDetail",
data() {
return {
selectedYear: "2024",
years: ["2024", "2023", "2022", "2021"],
overviewData: [
{ label: "馆藏总量", value: "1,256,890", trend: "up", trendValue: 5 },
{ label: "电子资源量", value: "856,230", trend: "up", trendValue: 12 },
{ label: "年度借阅量", value: "286,530", trend: "up", trendValue: 8 },
{ label: "数据库数量", value: "168", trend: "up", trendValue: 3 },
],
resourceData: {
columns: ["类型", "数量"],
rows: [
{ 类型: "纸质图书", 数量: 580000 },
{ 类型: "电子图书", 数量: 420000 },
{ 类型: "期刊", 数量: 156000 },
{ 类型: "学位论文", 数量: 85000 },
{ 类型: "其他资源", 数量: 15890 },
],
},
pieSettings: {
radius: "65%",
offsetY: "60%",
},
borrowingData: {
columns: ["月份", "纸质借阅", "电子访问"],
rows: [
{ 月份: "1月", 纸质借阅: 15000, 电子访问: 45000 },
{ 月份: "2月", 纸质借阅: 18000, 电子访问: 52000 },
{ 月份: "3月", 纸质借阅: 22000, 电子访问: 58000 },
{ 月份: "4月", 纸质借阅: 25000, 电子访问: 65000 },
{ 月份: "5月", 纸质借阅: 28000, 电子访问: 72000 },
{ 月份: "6月", 纸质借阅: 30000, 电子访问: 78000 },
],
},
lineSettings: {
area: true,
},
subjectData: {
columns: ["学科", "藏书量"],
rows: [
{ 学科: "理学", 藏书量: 250000 },
{ 学科: "工学", 藏书量: 320000 },
{ 学科: "文学", 藏书量: 180000 },
{ 学科: "经管", 藏书量: 150000 },
{ 学科: "医学", 藏书量: 120000 },
{ 学科: "其他", 藏书量: 80000 },
],
},
databaseData: {
columns: ["数据库", "访问量"],
rows: [
{ 数据库: "CNKI", 访问量: 85000 },
{ 数据库: "Web of Science", 访问量: 52000 },
{ 数据库: "ScienceDirect", 访问量: 48000 },
{ 数据库: "Springer", 访问量: 35000 },
{ 数据库: "IEEE", 访问量: 32000 },
],
},
histogramSettings: {
metrics: ["访问量"],
},
popularBooks: [
{
rank: 1,
name: "人工智能导论",
author: "李明",
category: "计算机",
borrowCount: 256,
status: "可借",
},
{
rank: 2,
name: "高等数学",
author: "张三",
category: "数学",
borrowCount: 235,
status: "已借出",
},
{
rank: 3,
name: "经济学原理",
author: "王五",
category: "经济",
borrowCount: 198,
status: "可借",
},
{
rank: 4,
name: "大学物理",
author: "刘六",
category: "物理",
borrowCount: 186,
status: "已借出",
},
],
};
},
methods: {
goBack() {
this.$router.push("/");
},
getStatusType(status) {
return status === "可借" ? "success" : "warning";
},
},
};
</script>
<style lang="scss" scoped>
.literature-detail {
padding: 20px;
background: #f0f2f5;
min-height: 100vh;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.overview-cards {
margin-bottom: 20px;
.overview-card {
.card-content {
text-align: center;
.value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.label {
font-size: 14px;
color: #909399;
margin: 8px 0;
}
.trend {
font-size: 12px;
&.up {
color: #67c23a;
}
&.down {
color: #f56c6c;
}
}
}
}
}
.charts-row {
margin-bottom: 20px;
.chart-card {
height: 400px;
}
}
.table-card {
margin-bottom: 20px;
}
}
</style>

View File

@ -0,0 +1,228 @@
<template>
<div class="research-detail">
<div class="header">
<el-page-header @back="goBack" content="科研详情" />
<el-select v-model="selectedYear" placeholder="选择年份">
<el-option
v-for="year in years"
:key="year"
:label="year"
:value="year"
/>
</el-select>
</div>
<el-row :gutter="20" class="statistics">
<el-col :span="6" v-for="(item, index) in statisticsData" :key="index">
<el-card shadow="hover" class="stat-card">
<div class="stat-content">
<div class="value">{{ item.value }}</div>
<div class="label">{{ item.label }}</div>
<div class="trend" :class="item.trend">
{{ item.trendValue }}%
<i
:class="item.trend === 'up' ? 'el-icon-top' : 'el-icon-bottom'"
></i>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>项目经费分布</span>
</div>
<ve-pie :data="fundingData" :settings="pieSettings" height="300px" />
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>成果发表趋势</span>
</div>
<ve-line
:data="publicationData"
:settings="lineSettings"
height="300px"
/>
</el-card>
</el-col>
</el-row>
<el-card class="project-list">
<div slot="header">
<span>重点项目进展</span>
<el-button style="float: right" type="text">查看全部</el-button>
</div>
<el-table :data="projectData" style="width: 100%">
<el-table-column prop="name" label="项目名称" />
<el-table-column prop="leader" label="负责人" width="120" />
<el-table-column prop="funding" label="经费(万)" width="120" />
<el-table-column prop="status" label="状态" width="120">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="progress" label="进度" width="180">
<template slot-scope="scope">
<el-progress :percentage="scope.row.progress" />
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
name: "ResearchDetail",
data() {
return {
selectedYear: "2024",
years: ["2024", "2023", "2022", "2021"],
statisticsData: [
{ label: "项目总数", value: "186", trend: "up", trendValue: 15 },
{ label: "发表论文", value: "253", trend: "up", trendValue: 8 },
{ label: "授权专利", value: "68", trend: "up", trendValue: 12 },
{ label: "科研经费(万)", value: "2,860", trend: "up", trendValue: 20 },
],
fundingData: {
columns: ["类型", "金额"],
rows: [
{ 类型: "国家级", 金额: 1200 },
{ 类型: "省部级", 金额: 800 },
{ 类型: "横向项目", 金额: 600 },
{ 类型: "其他", 金额: 260 },
],
},
pieSettings: {
radius: "65%",
offsetY: "60%",
},
publicationData: {
columns: ["月份", "SCI论文", "EI论文", "核心期刊"],
rows: [
{ 月份: "1月", SCI论文: 8, EI论文: 12, 核心期刊: 15 },
{ 月份: "2月", SCI论文: 10, EI论文: 15, 核心期刊: 18 },
{ 月份: "3月", SCI论文: 12, EI论文: 18, 核心期刊: 20 },
{ 月份: "4月", SCI论文: 15, EI论文: 20, 核心期刊: 25 },
{ 月份: "5月", SCI论文: 18, EI论文: 23, 核心期刊: 28 },
{ 月份: "6月", SCI论文: 20, EI论文: 25, 核心期刊: 30 },
],
},
lineSettings: {
stack: { 类型: ["SCI论文", "EI论文", "核心期刊"] },
},
projectData: [
{
name: "人工智能基础理论研究",
leader: "张三",
funding: 500,
status: "进行中",
progress: 65,
},
{
name: "新能源材料开发",
leader: "李四",
funding: 300,
status: "已完成",
progress: 100,
},
{
name: "智慧校园建设",
leader: "王五",
funding: 200,
status: "待启动",
progress: 0,
},
{
name: "生物医药研发",
leader: "赵六",
funding: 400,
status: "进行中",
progress: 45,
},
],
};
},
methods: {
goBack() {
this.$router.push("/");
},
getStatusType(status) {
const types = {
进行中: "primary",
已完成: "success",
待启动: "info",
};
return types[status] || "info";
},
},
};
</script>
<style lang="scss" scoped>
.research-detail {
padding: 20px;
background: #f0f2f5;
min-height: 100vh;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.statistics {
margin-bottom: 20px;
.stat-card {
.stat-content {
text-align: center;
.value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.label {
font-size: 14px;
color: #909399;
margin: 8px 0;
}
.trend {
font-size: 12px;
&.up {
color: #67c23a;
}
&.down {
color: #f56c6c;
}
}
}
}
}
.charts {
margin-bottom: 20px;
.chart-card {
height: 400px;
}
}
.project-list {
.el-table {
margin-top: 15px;
}
}
}
</style>

View File

@ -0,0 +1,274 @@
<template>
<div class="staff-detail">
<div class="header">
<el-page-header @back="goBack" content="教职工详情" />
<div class="filters">
<el-select v-model="selectedYear" placeholder="选择年份">
<el-option
v-for="year in years"
:key="year"
:label="year"
:value="year"
/>
</el-select>
</div>
</div>
<el-row :gutter="20" class="overview-cards">
<el-col :span="6" v-for="(item, index) in overviewData" :key="index">
<el-card shadow="hover" class="overview-card">
<div class="card-content">
<div class="value">{{ item.value }}</div>
<div class="label">{{ item.label }}</div>
<div class="trend" :class="item.trend">
{{ item.trendValue }}%
<i
:class="item.trend === 'up' ? 'el-icon-top' : 'el-icon-bottom'"
></i>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>职称分布</span>
</div>
<ve-pie :data="titleData" :settings="pieSettings" height="300px" />
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>学历结构</span>
</div>
<ve-ring
:data="educationData"
:settings="ringSettings"
height="300px"
/>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>人员变动趋势</span>
</div>
<ve-line
:data="staffChangeData"
:settings="lineSettings"
height="300px"
/>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>绩效考核分布</span>
</div>
<ve-histogram :data="performanceData" height="300px" />
</el-card>
</el-col>
</el-row>
<el-card class="table-card">
<div slot="header">
<span>招聘进度</span>
</div>
<el-table :data="recruitmentData" style="width: 100%">
<el-table-column prop="position" label="岗位" />
<el-table-column prop="department" label="部门" />
<el-table-column prop="candidates" label="应聘人数" width="100" />
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="progress" label="进度" width="180">
<template slot-scope="scope">
<el-progress :percentage="scope.row.progress" />
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
name: "StaffDetail",
data() {
return {
selectedYear: "2024",
years: ["2024", "2023", "2022", "2021"],
overviewData: [
{ label: "教职工总数", value: "1,256", trend: "up", trendValue: 5 },
{ label: "新入职人数", value: "86", trend: "up", trendValue: 15 },
{ label: "离职人数", value: "32", trend: "down", trendValue: 8 },
{ label: "在招岗位", value: "25", trend: "up", trendValue: 20 },
],
titleData: {
columns: ["职称", "人数"],
rows: [
{ 职称: "正高级", 人数: 180 },
{ 职称: "副高级", 人数: 320 },
{ 职称: "中级", 人数: 450 },
{ 职称: "初级", 人数: 306 },
],
},
pieSettings: {
radius: "65%",
offsetY: "60%",
},
educationData: {
columns: ["学历", "人数"],
rows: [
{ 学历: "博士", 人数: 420 },
{ 学历: "硕士", 人数: 580 },
{ 学历: "本科", 人数: 236 },
{ 学历: "其他", 人数: 20 },
],
},
ringSettings: {
radius: ["40%", "65%"],
offsetY: "60%",
},
staffChangeData: {
columns: ["月份", "入职人数", "离职人数"],
rows: [
{ 月份: "1月", 入职人数: 15, 离职人数: 5 },
{ 月份: "2月", 入职人数: 12, 离职人数: 4 },
{ 月份: "3月", 入职人数: 18, 离职人数: 6 },
{ 月份: "4月", 入职人数: 20, 离职人数: 8 },
{ 月份: "5月", 入职人数: 16, 离职人数: 5 },
{ 月份: "6月", 入职人数: 14, 离职人数: 4 },
],
},
lineSettings: {
area: true,
},
performanceData: {
columns: ["等级", "人数"],
rows: [
{ 等级: "A", 人数: 320 },
{ 等级: "B", 人数: 520 },
{ 等级: "C", 人数: 280 },
{ 等级: "D", 人数: 120 },
{ 等级: "E", 人数: 16 },
],
},
recruitmentData: [
{
position: "教授",
department: "计算机学院",
candidates: 25,
status: "面试中",
progress: 60,
},
{
position: "副教授",
department: "经管学院",
candidates: 18,
status: "筛选中",
progress: 30,
},
{
position: "讲师",
department: "外语学院",
candidates: 35,
status: "已完成",
progress: 100,
},
{
position: "实验员",
department: "物理学院",
candidates: 12,
status: "待面试",
progress: 20,
},
],
};
},
methods: {
goBack() {
this.$router.push("/");
},
getStatusType(status) {
const types = {
面试中: "primary",
筛选中: "warning",
已完成: "success",
待面试: "info",
};
return types[status] || "info";
},
},
};
</script>
<style lang="scss" scoped>
.staff-detail {
padding: 20px;
background: #f0f2f5;
min-height: 100vh;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.overview-cards {
margin-bottom: 20px;
.overview-card {
.card-content {
text-align: center;
.value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.label {
font-size: 14px;
color: #909399;
margin: 8px 0;
}
.trend {
font-size: 12px;
&.up {
color: #67c23a;
}
&.down {
color: #f56c6c;
}
}
}
}
}
.charts-row {
margin-bottom: 20px;
.chart-card {
height: 400px;
}
}
.table-card {
margin-bottom: 20px;
}
}
</style>

View File

@ -0,0 +1,262 @@
<template>
<div class="student-detail">
<div class="header">
<el-page-header @back="goBack" content="学生详情" />
<div class="filters">
<el-select v-model="selectedYear" placeholder="选择年份">
<el-option
v-for="year in years"
:key="year"
:label="year"
:value="year"
/>
</el-select>
</div>
</div>
<el-row :gutter="20" class="overview-cards">
<el-col :span="8" v-for="(item, index) in overviewData" :key="index">
<el-card shadow="hover" class="overview-card">
<div class="card-content">
<i :class="item.icon"></i>
<div class="info">
<div class="value">{{ item.value }}</div>
<div class="label">{{ item.label }}</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>各年级学生分布</span>
</div>
<ve-pie :data="gradeData" :settings="pieSettings" height="300px" />
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>学生活动参与情况</span>
</div>
<ve-histogram
:data="activityData"
:settings="histogramSettings"
height="300px"
/>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" class="charts-row">
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>心理咨询预约趋势</span>
</div>
<ve-line
:data="counselingData"
:settings="lineSettings"
height="300px"
/>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card">
<div slot="header">
<span>社团活动分布</span>
</div>
<ve-radar :data="clubData" height="300px" />
</el-card>
</el-col>
</el-row>
<el-card class="table-card">
<div slot="header">
<span>学生活动记录</span>
<el-button style="float: right" type="text">查看全部</el-button>
</div>
<el-table :data="activityRecords" style="width: 100%">
<el-table-column prop="name" label="活动名称" />
<el-table-column prop="type" label="类型" width="120" />
<el-table-column prop="date" label="日期" width="120" />
<el-table-column prop="participants" label="参与人数" width="120" />
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
name: "StudentDetail",
data() {
return {
selectedYear: "2024",
years: ["2024", "2023", "2022", "2021"],
overviewData: [
{ label: "在校生总数", value: "25,368", icon: "el-icon-user" },
{ label: "参与社团人数", value: "15,623", icon: "el-icon-connection" },
{ label: "志愿服务时长", value: "125,890h", icon: "el-icon-time" },
],
gradeData: {
columns: ["年级", "人数"],
rows: [
{ 年级: "大一", 人数: 6500 },
{ 年级: "大二", 人数: 6200 },
{ 年级: "大三", 人数: 5800 },
{ 年级: "大四", 人数: 5400 },
{ 年级: "研究生", 人数: 1468 },
],
},
pieSettings: {
radius: "65%",
offsetY: "60%",
},
activityData: {
columns: ["月份", "文体活动", "学术活动", "志愿服务"],
rows: [
{ 月份: "1月", 文体活动: 20, 学术活动: 15, 志愿服务: 25 },
{ 月份: "2月", 文体活动: 25, 学术活动: 20, 志愿服务: 30 },
{ 月份: "3月", 文体活动: 35, 学术活动: 25, 志愿服务: 35 },
{ 月份: "4月", 文体活动: 45, 学术活动: 30, 志愿服务: 40 },
{ 月份: "5月", 文体活动: 50, 学术活动: 35, 志愿服务: 45 },
{ 月份: "6月", 文体活动: 40, 学术活动: 30, 志愿服务: 35 },
],
},
histogramSettings: {
stack: { 类型: ["文体活动", "学术活动", "志愿服务"] },
},
counselingData: {
columns: ["月份", "预约人次", "实际咨询"],
rows: [
{ 月份: "1月", 预约人次: 120, 实际咨询: 100 },
{ 月份: "2月", 预约人次: 140, 实际咨询: 115 },
{ 月份: "3月", 预约人次: 160, 实际咨询: 130 },
{ 月份: "4月", 预约人次: 180, 实际咨询: 150 },
{ 月份: "5月", 预约人次: 200, 实际咨询: 170 },
{ 月份: "6月", 预约人次: 220, 实际咨询: 190 },
],
},
lineSettings: {
area: true,
},
clubData: {
columns: ["类型", "人数"],
rows: [
{ 类型: "文学社", 人数: 2500 },
{ 类型: "体育类", 人数: 3500 },
{ 类型: "科技类", 人数: 3000 },
{ 类型: "艺术类", 人数: 2800 },
{ 类型: "公益类", 人数: 2600 },
],
},
activityRecords: [
{
name: "校园文化节",
type: "文化活动",
date: "2023-05-20",
participants: 1200,
status: "已完成",
},
{
name: "科技创新大赛",
type: "学术活动",
date: "2023-05-15",
participants: 500,
status: "进行中",
},
{
name: "志愿者服务日",
type: "志愿活动",
date: "2023-05-10",
participants: 800,
status: "已完成",
},
{
name: "心理健康讲座",
type: "讲座活动",
date: "2023-05-05",
participants: 300,
status: "已完成",
},
],
};
},
methods: {
goBack() {
this.$router.push("/");
},
getStatusType(status) {
return status === "进行中" ? "primary" : "success";
},
},
};
</script>
<style lang="scss" scoped>
.student-detail {
padding: 20px;
background: #f0f2f5;
min-height: 100vh;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.overview-cards {
margin-bottom: 20px;
.overview-card {
.card-content {
display: flex;
align-items: center;
i {
font-size: 48px;
color: #409eff;
margin-right: 20px;
}
.info {
.value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.label {
font-size: 14px;
color: #909399;
margin-top: 5px;
}
}
}
}
}
.charts-row {
margin-bottom: 20px;
.chart-card {
height: 400px;
}
}
.table-card {
margin-bottom: 20px;
}
}
</style>

View File

@ -3,82 +3,209 @@
<div class="bg">
<dv-loading v-if="loading">Loading...</dv-loading>
<div v-else class="host-body">
<!-- 顶部标题部分 -->
<div class="d-flex jc-center">
<dv-decoration-10 class="dv-dec-10" />
<div class="d-flex jc-center">
<dv-decoration-8 class="dv-dec-8" :color="decorationColor" />
<div class="title">
<span class="title-text">唐山师范学校数据中台</span>
<dv-decoration-6 class="dv-dec-6" :reverse="true" :color="['#50e3c2', '#67a1e5']" />
<div class="title-part">
<img src="@/assets/logo.png" alt="icon" class="logo" />
<span class="title-text">智慧校园</span>
</div>
<dv-decoration-6
class="dv-dec-6"
:reverse="true"
:color="['#50e3c2', '#67a1e5']"
/>
</div>
<dv-decoration-8 class="dv-dec-8" :reverse="true" :color="decorationColor" />
<dv-decoration-8
class="dv-dec-8"
:reverse="true"
:color="decorationColor"
/>
</div>
<dv-decoration-10 class="dv-dec-10-s" />
</div>
<!-- 第二行 -->
<div class="d-flex jc-between px-2">
<div class="d-flex aside-width">
<div class="react-left ml-4 react-l-s">
<span class="react-left"></span>
<span class="text">数据分析1</span>
</div>
<div class="react-left ml-3">
<span class="text">数据分析2</span>
<!-- 学校概况信息卡片 -->
<div class="school-info-cards">
<div class="info-card">
<i class="el-icon-school"></i>
<div class="info-content">
<div class="main-info">
<div class="info-label">在校生总数</div>
<div class="info-value">
{{ formatNumber(schoolData.totalStudents) }}<b></b>
</div>
</div>
<div class="sub-info-container">
<div class="sub-info">
本科生 {{ formatNumber(schoolData.undergrads) }}
</div>
<div class="sub-info">
研究生 {{ formatNumber(schoolData.graduates) }}
</div>
</div>
</div>
</div>
<div class="d-flex aside-width">
<div class="react-right bg-color-blue mr-3">
<span class="text">数据分析1</span>
<div class="info-card">
<i class="el-icon-user"></i>
<div class="info-content">
<div class="main-info">
<div class="info-label">教职工总数</div>
<div class="info-value">
{{ formatNumber(schoolData.totalStaff) }}<b></b>
</div>
</div>
<div class="sub-info-container">
<div class="sub-info">
专任教师 {{ formatNumber(schoolData.teachers) }}
</div>
<div class="sub-info">
博士学位 {{ formatNumber(schoolData.doctors) }}
</div>
</div>
</div>
<div class="react-right mr-4 react-l-s">
<span class="react-after"></span>
<span class="text">{{ dateYear }} {{ dateWeek }} {{ dateDay }}</span>
</div>
<div class="info-card">
<i class="el-icon-notebook-2"></i>
<div class="info-content">
<div class="main-info">
<div class="info-label">本科专业数</div>
<div class="info-value">{{ schoolData.majors }}<b></b></div>
</div>
<div class="sub-info-container">
<div class="sub-info">
硕士点 {{ schoolData.masterPrograms }}
</div>
<div class="sub-info">
重点学科 {{ schoolData.keyDisciplines }}
</div>
</div>
</div>
</div>
<div class="info-card">
<i class="el-icon-office-building"></i>
<div class="info-content">
<div class="main-info">
<div class="info-label">校园面积</div>
<div class="info-value">
{{ formatNumber(schoolData.campusArea) }}<b></b>
</div>
</div>
<div class="sub-info-container">
<div class="sub-info">
建筑 {{ schoolData.buildingArea }}
</div>
<div class="sub-info">实验室 {{ schoolData.labs }}</div>
</div>
</div>
</div>
<div class="info-card">
<i class="el-icon-reading"></i>
<div class="info-content">
<div class="main-info">
<div class="info-label">图书馆藏</div>
<div class="info-value">{{ schoolData.books }}<b>万册</b></div>
</div>
<div class="sub-info-container">
<div class="sub-info">电子图书 {{ schoolData.ebooks }}万册</div>
<div class="sub-info">期刊 {{ schoolData.journals }}</div>
</div>
</div>
</div>
<div class="info-card">
<i class="el-icon-connection"></i>
<div class="info-content">
<div class="main-info">
<div class="info-label">国际合作</div>
<div class="info-value">
{{ formatNumber(schoolData.partnerships) }}<b></b>
</div>
</div>
<div class="sub-info-container">
<div class="sub-info">
留学生 {{ formatNumber(schoolData.internationalStudents) }}
</div>
<div class="sub-info">
交换生 {{ formatNumber(schoolData.exchangeStudents) }}/
</div>
</div>
</div>
</div>
</div>
<div class="body-box">
<!-- 第三行数据 -->
<div class="content-box">
<div>
<dv-border-box-12>
<centerLeft1 />
</dv-border-box-12>
<div class="dashboard-container">
<div class="left-panel">
<!-- 科研概况 -->
<common-header
title="科研概况"
@click-more="(title) => getRouterByTitle('科研概况')"
/>
<div class="panel-item">
<research-overview />
</div>
<div>
<dv-border-box-12>
<centerLeft1 />
</dv-border-box-12>
</div>
<!-- <div>
<dv-border-box-12>
<centerLeft2 />
</dv-border-box-12>
</div>-->
<!-- 中间 -->
<div>
<center />
</div>
<!-- 中间 -->
<div>
<centerRight2 />
</div>
<div>
<dv-border-box-13>
<centerRight1 />
</dv-border-box-13>
<!-- 教职工概况 -->
<common-header
title="教职工概况"
@click-more="(title) => getRouterByTitle('教职工概况')"
/>
<div class="panel-item">
<staff-overview />
</div>
</div>
<!-- 第四行数据 -->
<div class="bottom-box">
<dv-border-box-13>
<bottomLeft />
</dv-border-box-13>
<dv-border-box-12>
<bottomRight />
</dv-border-box-12>
<!-- 中间面板 -->
<div class="center-panel">
<div class="center-top">
<img
src="../assets/school.png"
alt="校园图片"
class="school-image"
/>
</div>
<div class="center-bottom">
<!-- 教务概况 -->
<div class="bottom-item">
<common-header
title="教务概况"
@click-more="(title) => getRouterByTitle('教务概况')"
/>
<div class="panel-item">
<education-overview />
</div>
</div>
<!-- 资产概况 -->
<div class="bottom-item">
<common-header
title="资产概况"
@click-more="(title) => getRouterByTitle('资产概况')"
/>
<div class="panel-item">
<asset-overview />
</div>
</div>
</div>
</div>
<div class="right-panel">
<!-- 一卡通概况 -->
<common-header
title="一卡通概况"
@click-more="(title) => getRouterByTitle('一卡通概况')"
/>
<div class="panel-item">
<card-overview />
</div>
<!-- 文献概况 -->
<common-header
title="文献概况"
@click-more="(title) => getRouterByTitle('文献概况')"
/>
<div class="panel-item">
<literature-overview />
</div>
</div>
</div>
</div>
@ -87,62 +214,358 @@
</template>
<script>
import { formatNumber } from "@/utils/format";
import drawMixin from "../utils/drawMixin";
import { formatTime } from "../utils/index.js";
import centerLeft1 from "./centerLeft1";
// import centerLeft2 from "./centerLeft2";
import centerRight1 from "./centerRight1";
import centerRight2 from "./centerRight2";
import center from "./center";
import bottomLeft from "./bottomLeft";
import bottomRight from "./bottomRight";
import CommonHeader from "@/components/CommonHeader";
import EducationOverview from "@/components/EducationOverview";
import ResearchOverview from "@/components/ResearchOverview";
import StaffOverview from "@/components/StaffOverview";
import AssetOverview from "@/components/AssetOverview";
import LiteratureOverview from "@/components/LiteratureOverview";
import CardOverview from "@/components/CardOverview";
export default {
mixins: [drawMixin],
data() {
return {
timing: null,
loading: true,
dateDay: null,
dateYear: null,
dateWeek: null,
weekday: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
decorationColor: ["#568aea", "#000000"]
decorationColor: ["#568aea", "#000000"],
schoolData: {
totalStudents: 18000,
undergrads: 16000,
graduates: 500,
internationalStudents: 100,
exchangeStudents: 100,
totalStaff: 1200,
teachers: 900,
doctors: 300,
majors: 60,
masterPrograms: 10,
keyDisciplines: 4,
campusArea: 1000,
buildingArea: 50,
labs: 100,
books: 200,
ebooks: 300,
journals: 2000,
partnerships: 50,
},
routerMap: {
科研概况: "/research-detail",
教务概况: "/education-detail",
教职工概况: "/staff-detail",
资产概况: "/asset-detail",
文献概况: "/literature-detail",
一卡通概况: "/card-detail",
},
};
},
components: {
centerLeft1,
// centerLeft2,
centerRight1,
centerRight2,
center,
bottomLeft,
bottomRight
CommonHeader,
EducationOverview,
ResearchOverview,
StaffOverview,
AssetOverview,
LiteratureOverview,
CardOverview,
},
mounted() {
this.timeFn();
this.cancelLoading();
},
beforeDestroy() {
clearInterval(this.timing);
},
methods: {
timeFn() {
this.timing = setInterval(() => {
this.dateDay = formatTime(new Date(), "HH: mm: ss");
this.dateYear = formatTime(new Date(), "yyyy-MM-dd");
this.dateWeek = this.weekday[new Date().getDay()];
}, 1000);
},
cancelLoading() {
setTimeout(() => {
this.loading = false;
}, 500);
}
}
},
getRouterByTitle(title) {
const path = this.routerMap[title];
if (path) {
this.$router.push(path);
}
},
formatNumber,
},
};
</script>
<style lang="scss" scoped>
@import "../assets/scss/index.scss";
</style>
.title {
position: relative;
padding: 0 50px;
margin-bottom: 10px;
.title-text {
font-size: 36px;
font-weight: bold;
background: linear-gradient(to top, #4a90e2, #ffffff);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
// text-shadow: 0 0 10px rgba(74, 144, 226, 0.3);
font-family: "Microsoft YaHei", sans-serif;
}
}
.school-info-cards {
display: flex;
justify-content: space-between;
margin: 10px 20px;
background: rgba(74, 144, 226, 0.05);
border-radius: 15px;
backdrop-filter: blur(5px);
position: relative;
border: 1px solid rgba(74, 144, 226, 0.1);
overflow: hidden;
box-shadow: 0 0 20px rgba(74, 144, 226, 0.05);
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(
90deg,
transparent 0%,
rgba(74, 144, 226, 0.5) 50%,
transparent 100%
);
}
&::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(
90deg,
transparent 0%,
rgba(74, 144, 226, 0.3) 50%,
transparent 100%
);
}
.info-card {
flex: 1;
display: flex;
align-items: flex-start;
gap: 15px;
padding: 20px 10px;
position: relative;
transition: all 0.3s ease;
min-width: 240px;
&:not(:last-child)::after {
content: "";
position: absolute;
right: 0;
top: 15%;
height: 70%;
width: 1px;
background: linear-gradient(
to bottom,
transparent 0%,
rgba(74, 144, 226, 0.15) 50%,
transparent 100%
);
}
&:hover {
transform: translateY(-5px);
background: rgba(74, 144, 226, 0.08);
border-radius: 12px;
box-shadow: 0 5px 15px rgba(74, 144, 226, 0.1);
i {
transform: scale(1.1) translateY(-2px);
background: linear-gradient(135deg, #4a90e2, #36d1dc);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 2px 4px rgba(74, 144, 226, 0.2));
}
.info-content {
.main-info {
.info-value {
transform: scale(1.05);
filter: drop-shadow(0 2px 4px rgba(74, 144, 226, 0.3));
}
}
.sub-info-container {
.sub-info {
color: rgba(74, 144, 226, 0.9);
transform: translateX(-5px);
}
}
}
}
i {
font-size: 40px;
color: #4a90e2;
transition: all 0.3s ease;
margin-top: 20px;
opacity: 0.9;
filter: drop-shadow(0 2px 2px rgba(74, 144, 226, 0.1));
}
.info-content {
flex: 1;
display: flex;
justify-content: space-between;
gap: 10px;
.main-info {
flex: 1;
margin: 0 -5px;
.info-label {
color: rgba(255, 255, 255, 0.9);
font-size: 18px;
margin-bottom: 10px;
font-weight: 500;
}
.info-value {
font-size: 34px;
font-weight: bold;
transition: all 0.3s ease;
background: linear-gradient(135deg, #4a90e2, #36d1dc);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
b {
font-size: 16px;
font-weight: normal;
// margin-left: 4px;
}
}
}
.sub-info-container {
display: flex;
flex-direction: column;
justify-content: center;
gap: 8px;
padding-left: 15px;
position: relative;
min-width: 100px;
&::before {
content: "";
position: absolute;
left: 0;
top: 10%;
height: 80%;
width: 1px;
background: linear-gradient(
to bottom,
transparent,
rgba(74, 144, 226, 0.1),
transparent
);
}
.sub-info {
color: rgba(255, 255, 255, 0.7);
font-size: 13px;
transition: all 0.3s ease;
text-align: left;
white-space: nowrap;
&:hover {
color: rgba(74, 144, 226, 0.9);
transform: translateX(5px);
}
}
}
}
}
}
.dashboard-container {
display: flex;
width: 100%;
height: calc(95% - 150px);
padding: 0 20px 20px;
gap: 20px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 0;
background: transparent;
}
.left-panel,
.right-panel {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
height: 100%;
.panel-item {
flex: 1;
min-height: 0;
background: rgba(255, 255, 255, 0.05);
padding: 15px;
display: flex;
flex-direction: column;
border-radius: 12px;
}
}
.center-panel {
flex: 2;
display: flex;
flex-direction: column;
gap: 20px;
height: 100%;
.center-top {
flex: 3;
display: flex;
align-items: center;
justify-content: center;
.school-image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: 12px;
}
}
.center-bottom {
flex: 2;
display: flex;
gap: 20px;
.bottom-item {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
.panel-item {
flex: 1;
min-height: 0;
background: rgba(255, 255, 255, 0.05);
padding: 0 15px;
display: flex;
flex-direction: column;
border-radius: 12px;
}
}
}
}
}
</style>

View File

@ -1 +0,0 @@
test

8773
yarn.lock Normal file

File diff suppressed because it is too large Load Diff

BIN
第一版.zip Normal file

Binary file not shown.

BIN
第三版.zip Normal file

Binary file not shown.

BIN
第二版.zip Normal file

Binary file not shown.