ts-bigscreen-vue/src/views/index.vue

571 lines
15 KiB
Vue

<template>
<div id="index" ref="appRef">
<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">
<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"
/>
</div>
<dv-decoration-10 class="dv-dec-10-s" />
</div>
<!-- 学校概况信息卡片 -->
<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="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>
<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="dashboard-container">
<div class="left-panel">
<!-- 科研概况 -->
<common-header
title="科研概况"
@click-more="(title) => getRouterByTitle('科研概况')"
/>
<div class="panel-item">
<research-overview />
</div>
<!-- 教职工概况 -->
<common-header
title="教职工概况"
@click-more="(title) => getRouterByTitle('教职工概况')"
/>
<div class="panel-item">
<staff-overview />
</div>
</div>
<!-- 中间面板 -->
<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>
</div>
</div>
</template>
<script>
import { formatNumber } from "@/utils/format";
import drawMixin from "../utils/drawMixin";
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 {
loading: true,
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: {
CommonHeader,
EducationOverview,
ResearchOverview,
StaffOverview,
AssetOverview,
LiteratureOverview,
CardOverview,
},
mounted() {
this.cancelLoading();
},
methods: {
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";
.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>