docs(database): 更新数据库设计规范和核心数据表结构
- 新增数据库基础规范、API映射规范、安全规范等详细设计要求- 增加读写分离、分库分表、数据生命周期管理等策略说明 - 新建核心业务表结构,包括用户表、贷款申请表、保险申请表等 - 优化索引设计,提高查询效率
This commit is contained in:
73670
frontend/dashboard/node_modules/.vite/deps/echarts.js
generated
vendored
Normal file
73670
frontend/dashboard/node_modules/.vite/deps/echarts.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
frontend/dashboard/node_modules/.vite/deps/echarts.js.map
generated
vendored
Normal file
7
frontend/dashboard/node_modules/.vite/deps/echarts.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1141
frontend/dashboard/package-lock.json
generated
Normal file
1141
frontend/dashboard/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "farming-management",
|
||||
"name": "dashboard",
|
||||
"version": "1.0.0",
|
||||
"description": "锡林郭勒盟安格斯牛养殖管理系统",
|
||||
"description": "锡林郭勒盟安格斯牛养殖产业大屏可视化系统",
|
||||
"author": "xlxumu team",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -10,16 +10,16 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.2.0",
|
||||
"vue-router": "^4.0.0",
|
||||
"ant-design-vue": "^3.0.0",
|
||||
"echarts": "^5.0.0",
|
||||
"pinia": "^2.0.0",
|
||||
"echarts": "^5.0.0"
|
||||
"vue": "^3.2.0",
|
||||
"vue-router": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.0.0",
|
||||
"@vitejs/plugin-vue": "^3.0.0",
|
||||
"vite": "^3.0.0",
|
||||
"typescript": "^4.0.0",
|
||||
"@types/node": "^18.0.0"
|
||||
"vite": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,5 +13,36 @@ export default {
|
||||
<style>
|
||||
#app {
|
||||
height: 100vh;
|
||||
font-family: 'Arial', sans-serif;
|
||||
background: #0a1929;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 滚动条样式 */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(76, 175, 80, 0.5);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(76, 175, 80, 0.8);
|
||||
}
|
||||
</style>
|
||||
@@ -6,10 +6,12 @@ import router from './router'
|
||||
import 'ant-design-vue/dist/antd.css'
|
||||
import './styles/global.css'
|
||||
|
||||
// DataV组件按需引入,避免Vue 3兼容性问题
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
app.use(Antd)
|
||||
|
||||
|
||||
app.mount('#app')
|
||||
17
frontend/dashboard/src/router/index.js
Normal file
17
frontend/dashboard/src/router/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import Dashboard from '@/views/Dashboard.vue'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Dashboard',
|
||||
component: Dashboard
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -4,10 +4,10 @@
|
||||
--secondary-color: #388E3C;
|
||||
--accent-color: #FF9800;
|
||||
--light-color: #f5f5f5;
|
||||
--dark-color: #333;
|
||||
--text-color: #333;
|
||||
--border-radius: 4px;
|
||||
--box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
--dark-color: #0a1929;
|
||||
--text-color: #ffffff;
|
||||
--border-radius: 8px;
|
||||
--box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -17,81 +17,91 @@
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: var(--text-color);
|
||||
background-color: #fff;
|
||||
background-color: var(--dark-color);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100vh;
|
||||
background: linear-gradient(135deg, #0c2d48, #145da0);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 通用按钮样式 */
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: var(--border-radius);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--primary-color);
|
||||
background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--accent-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #F57C00;
|
||||
}
|
||||
|
||||
/* 通用卡片样式 */
|
||||
.card {
|
||||
background: white;
|
||||
padding: 1.5rem;
|
||||
border-radius: var(--border-radius);
|
||||
background: linear-gradient(45deg, var(--secondary-color), #2E7D32);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--box-shadow);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* 通用表单样式 */
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
/* 滚动条样式 */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: var(--border-radius);
|
||||
font-size: 1rem;
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(76, 175, 80, 0.5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(76, 175, 80, 0.8);
|
||||
}
|
||||
|
||||
/* DataV组件样式覆盖 */
|
||||
.dv-border-box-content {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.dv-scroll-board .header {
|
||||
color: #4CAF50 !important;
|
||||
background: rgba(76, 175, 80, 0.1) !important;
|
||||
}
|
||||
|
||||
.dv-scroll-board .row {
|
||||
color: #fff !important;
|
||||
background: rgba(255, 255, 255, 0.05) !important;
|
||||
}
|
||||
|
||||
.dv-scroll-board .row:hover {
|
||||
background: rgba(76, 175, 80, 0.2) !important;
|
||||
}
|
||||
605
frontend/dashboard/src/views/Dashboard.vue
Normal file
605
frontend/dashboard/src/views/Dashboard.vue
Normal file
@@ -0,0 +1,605 @@
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<div class="dashboard-container">
|
||||
<!-- 头部标题区域 -->
|
||||
<div class="dashboard-header">
|
||||
<div class="header-decoration left"></div>
|
||||
<div class="header-title">
|
||||
<h1>锡林郭勒盟安格斯牛养殖产业数据大屏</h1>
|
||||
</div>
|
||||
<div class="header-decoration right"></div>
|
||||
|
||||
<div class="header-info">
|
||||
<span>实时数据更新时间: {{ currentTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="dashboard-main">
|
||||
<!-- 左侧区域 -->
|
||||
<div class="left-section">
|
||||
<!-- 关键指标 -->
|
||||
<div class="metric-cards">
|
||||
<div class="metric-card" v-for="(metric, index) in keyMetrics" :key="index">
|
||||
<div class="metric-border">
|
||||
<div class="metric-content">
|
||||
<div class="metric-title">{{ metric.title }}</div>
|
||||
<div class="metric-value">{{ metric.value }}</div>
|
||||
<div class="metric-change" :class="metric.change > 0 ? 'positive' : 'negative'">
|
||||
{{ metric.change > 0 ? '↑' : '↓' }} {{ Math.abs(metric.change) }}%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 区域分布图表 -->
|
||||
<div class="chart-container">
|
||||
<div class="chart-border">
|
||||
<div class="chart-title">区域养殖分布</div>
|
||||
<div ref="regionChart" class="chart-wrapper"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间区域 -->
|
||||
<div class="center-section">
|
||||
<!-- 核心数据 -->
|
||||
<div class="center-top">
|
||||
<div class="center-border">
|
||||
<div class="center-content">
|
||||
<div class="total-count">
|
||||
<div class="count-title">养殖总数</div>
|
||||
<div class="count-value">12,860</div>
|
||||
<div class="count-unit">头</div>
|
||||
</div>
|
||||
<div class="growth-rate">
|
||||
<div class="rate-title">同比增长</div>
|
||||
<div class="rate-value positive">+5.2%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中心图表 -->
|
||||
<div class="center-middle">
|
||||
<div class="center-chart-border">
|
||||
<div class="chart-title">养殖规模趋势</div>
|
||||
<div ref="breedingChart" class="chart-wrapper"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 风险预警 -->
|
||||
<div class="center-bottom">
|
||||
<div class="center-border">
|
||||
<div class="risk-content">
|
||||
<div class="risk-title">风险预警</div>
|
||||
<div class="risk-list">
|
||||
<div class="risk-item" v-for="(risk, index) in riskData" :key="index">
|
||||
<div class="risk-time">{{ risk.time }}</div>
|
||||
<div class="risk-type">{{ risk.type }}</div>
|
||||
<div class="risk-desc">{{ risk.desc }}</div>
|
||||
<div class="risk-status" :class="risk.status">{{ risk.status }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧区域 -->
|
||||
<div class="right-section">
|
||||
<!-- 交易数据 -->
|
||||
<div class="chart-container">
|
||||
<div class="chart-border">
|
||||
<div class="chart-title">交易数据分析</div>
|
||||
<div ref="transactionChart" class="chart-wrapper"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 雷达图 -->
|
||||
<div class="chart-container">
|
||||
<div class="chart-border">
|
||||
<div class="chart-title">综合风险评估</div>
|
||||
<div ref="riskRadarChart" class="chart-wrapper"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部信息 -->
|
||||
<div class="dashboard-footer">
|
||||
<div class="footer-decoration left"></div>
|
||||
<div class="footer-content">
|
||||
<p>锡林郭勒盟安格斯牛养殖产业数字化管理平台</p>
|
||||
</div>
|
||||
<div class="footer-decoration right"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
setup() {
|
||||
const currentTime = ref(new Date().toLocaleString())
|
||||
const breedingChart = ref(null)
|
||||
const transactionChart = ref(null)
|
||||
const regionChart = ref(null)
|
||||
const riskRadarChart = ref(null)
|
||||
|
||||
let breedingChartInstance = null
|
||||
let transactionChartInstance = null
|
||||
let regionChartInstance = null
|
||||
let riskRadarChartInstance = null
|
||||
let timer = null
|
||||
|
||||
// 关键指标数据
|
||||
const keyMetrics = ref([
|
||||
{ title: '本月交易额', value: '¥860万', change: 5.7 },
|
||||
{ title: '平均体重', value: '420kg', change: 0.8 },
|
||||
{ title: '疫苗接种率', value: '98.6%', change: 2.1 },
|
||||
{ title: '风险事件', value: '12起', change: -15.2 }
|
||||
])
|
||||
|
||||
// 风险数据
|
||||
const riskData = ref([
|
||||
{ time: '08-19 10:23', type: '健康问题', desc: '某牧场发现疑似疫情', status: '处理中' },
|
||||
{ time: '08-19 09:45', type: '环境异常', desc: '气温过高,注意防暑', status: '已处理' },
|
||||
{ time: '08-19 08:30', type: '交易风险', desc: '一笔交易存在争议', status: '处理中' },
|
||||
{ time: '08-18 16:15', type: '运输风险', desc: '运输路线受阻', status: '已处理' }
|
||||
])
|
||||
|
||||
// 初始化图表
|
||||
const initCharts = () => {
|
||||
// 养殖规模趋势图
|
||||
breedingChartInstance = echarts.init(breedingChart.value)
|
||||
breedingChartInstance.setOption({
|
||||
title: { text: '' },
|
||||
tooltip: { trigger: 'axis' },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['1月', '2月', '3月', '4月', '5月', '6月']
|
||||
},
|
||||
yAxis: { type: 'value' },
|
||||
series: [{
|
||||
data: [8200, 9100, 10500, 11200, 12100, 12860],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: { color: '#4CAF50' },
|
||||
areaStyle: { color: 'rgba(76, 175, 80, 0.3)' }
|
||||
}]
|
||||
})
|
||||
|
||||
// 交易数据分析图
|
||||
transactionChartInstance = echarts.init(transactionChart.value)
|
||||
transactionChartInstance.setOption({
|
||||
tooltip: { trigger: 'item' },
|
||||
legend: { bottom: '0' },
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
data: [
|
||||
{ value: 335, name: '线上交易' },
|
||||
{ value: 310, name: '线下交易' },
|
||||
{ value: 234, name: '跨区域交易' },
|
||||
{ value: 135, name: '本地交易' }
|
||||
],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}]
|
||||
})
|
||||
|
||||
// 区域分布图
|
||||
regionChartInstance = echarts.init(regionChart.value)
|
||||
regionChartInstance.setOption({
|
||||
tooltip: { trigger: 'item' },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['东乌旗', '西乌旗', '锡市', '镶黄旗', '正蓝旗', '太仆寺旗']
|
||||
},
|
||||
yAxis: { type: 'value' },
|
||||
series: [{
|
||||
data: [1200, 1800, 2400, 1600, 2100, 1900],
|
||||
type: 'bar',
|
||||
itemStyle: { color: '#388E3C' }
|
||||
}]
|
||||
})
|
||||
|
||||
// 风险雷达图
|
||||
riskRadarChartInstance = echarts.init(riskRadarChart.value)
|
||||
riskRadarChartInstance.setOption({
|
||||
title: { text: '' },
|
||||
tooltip: { trigger: 'item' },
|
||||
radar: {
|
||||
indicator: [
|
||||
{ name: '健康问题', max: 100 },
|
||||
{ name: '交易风险', max: 100 },
|
||||
{ name: '环境异常', max: 100 },
|
||||
{ name: '运输风险', max: 100 },
|
||||
{ name: '市场波动', max: 100 }
|
||||
]
|
||||
},
|
||||
series: [{
|
||||
type: 'radar',
|
||||
data: [{
|
||||
value: [60, 30, 50, 20, 40],
|
||||
name: '风险指数',
|
||||
itemStyle: { color: '#FF9800' },
|
||||
areaStyle: { color: 'rgba(255, 152, 0, 0.3)' }
|
||||
}]
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
// 更新时间
|
||||
const updateTime = () => {
|
||||
currentTime.value = new Date().toLocaleString()
|
||||
}
|
||||
|
||||
// 窗口大小改变时重绘图表
|
||||
const resizeCharts = () => {
|
||||
if (breedingChartInstance) breedingChartInstance.resize()
|
||||
if (transactionChartInstance) transactionChartInstance.resize()
|
||||
if (regionChartInstance) regionChartInstance.resize()
|
||||
if (riskRadarChartInstance) riskRadarChartInstance.resize()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initCharts()
|
||||
timer = setInterval(updateTime, 1000)
|
||||
window.addEventListener('resize', resizeCharts)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(timer)
|
||||
window.removeEventListener('resize', resizeCharts)
|
||||
if (breedingChartInstance) breedingChartInstance.dispose()
|
||||
if (transactionChartInstance) transactionChartInstance.dispose()
|
||||
if (regionChartInstance) regionChartInstance.dispose()
|
||||
if (riskRadarChartInstance) riskRadarChartInstance.dispose()
|
||||
})
|
||||
|
||||
return {
|
||||
currentTime,
|
||||
keyMetrics,
|
||||
riskData,
|
||||
breedingChart,
|
||||
transactionChart,
|
||||
regionChart,
|
||||
riskRadarChart
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dashboard {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #0f2027, #20555d, #2c5364);
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dashboard-container {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
height: 100px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.header-decoration {
|
||||
width: 200px;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header-decoration::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, #4CAF50, transparent);
|
||||
}
|
||||
|
||||
.header-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header-title h1 {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
background: linear-gradient(to right, #4CAF50, #8BC34A);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header-info {
|
||||
font-size: 16px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.dashboard-main {
|
||||
display: flex;
|
||||
height: calc(100% - 180px);
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.left-section, .right-section {
|
||||
width: 25%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.center-section {
|
||||
width: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.metric-cards {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
height: 30%;
|
||||
}
|
||||
|
||||
.metric-card {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.metric-border {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 15px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 8px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.metric-content {
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.metric-title {
|
||||
font-size: 16px;
|
||||
color: #ccc;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.metric-change {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.metric-change.positive {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.metric-change.negative {
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.chart-border {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 8px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.center-top {
|
||||
height: 20%;
|
||||
}
|
||||
|
||||
.center-middle {
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.center-bottom {
|
||||
height: 30%;
|
||||
}
|
||||
|
||||
.center-border, .center-chart-border {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 8px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.center-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.total-count {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.count-title {
|
||||
font-size: 18px;
|
||||
color: #ccc;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.count-value {
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.count-unit {
|
||||
font-size: 16px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.growth-rate {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rate-title {
|
||||
font-size: 18px;
|
||||
color: #ccc;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.rate-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.rate-value.positive {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.risk-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.risk-title {
|
||||
font-size: 18px;
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.risk-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.risk-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.risk-time {
|
||||
width: 15%;
|
||||
font-size: 14px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.risk-type {
|
||||
width: 20%;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.risk-desc {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.risk-status {
|
||||
width: 15%;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.risk-status.处理中 {
|
||||
background: rgba(255, 152, 0, 0.2);
|
||||
color: #FF9800;
|
||||
}
|
||||
|
||||
.risk-status.已处理 {
|
||||
background: rgba(76, 175, 80, 0.2);
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.chart-wrapper {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
|
||||
.dashboard-footer {
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
margin-top: 20px;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.footer-decoration {
|
||||
width: 300px;
|
||||
height: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.footer-decoration::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, #4CAF50, transparent);
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #4CAF50;
|
||||
}
|
||||
</style>
|
||||
@@ -20,9 +20,5 @@ export default defineConfig({
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
}
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
assetsDir: 'assets'
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user