数据看板优化

This commit is contained in:
chenlin
2025-11-27 18:12:53 +08:00
parent 9d2ae9b0b4
commit 26e1f9a181
3 changed files with 1163 additions and 1751 deletions

View File

@@ -7,7 +7,8 @@ import {
MapChart,
PictorialBarChart,
RadarChart,
GaugeChart
GaugeChart,
CandlestickChart
} from 'echarts/charts'
import {
@@ -41,7 +42,8 @@ echarts.use([
CanvasRenderer,
PictorialBarChart,
RadarChart,
GaugeChart
GaugeChart,
CandlestickChart
])
export default echarts

View File

@@ -3,6 +3,9 @@
<!-- 顶部标题栏 -->
<div class="header-container">
<div class="header-left">
<el-icon class="back-arrow" @click="returnToHeadquarters">
<ArrowLeft />
</el-icon>
<div class="back-button" @click="openRegionSelector">
{{ selectedPark || selectedRegion }}
<span>···</span>
@@ -138,9 +141,9 @@
<el-button type="text" class="manage-btn">管理</el-button>
</div>
<div class="card-content">
<div class="high-risk-content">
<div class="high-risk-top">
<div class="donut-chart-wrapper-small">
<Echart :options="highRiskChartOption" width="100%" height="180px" />
<Echart :options="highRiskChartOption" width="100%" height="250px" />
</div>
<div class="operation-type-list">
<div class="operation-type-item" v-for="item in operationTypeDistribution" :key="item.type">
@@ -174,9 +177,9 @@
<el-button type="text" class="manage-btn">管理</el-button>
</div>
<div class="card-content">
<div class="emergency-plan-content">
<div class="emergency-plan-top">
<div class="progress-chart-wrapper">
<Echart :options="emergencyPlanChartOption" width="100%" height="180px" />
<Echart :options="emergencyPlanChartOption" width="100%" height="250px" />
</div>
<div class="drill-info">
<div class="drill-item">
@@ -243,7 +246,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { Refresh } from '@element-plus/icons-vue'
import { Refresh, ArrowLeft } from '@element-plus/icons-vue'
import Echart from '@/components/Echart/src/Echart.vue'
import RegionSelector from '@/views/screen/components/RegionSelector.vue'
import { getTableList } from '@/api/design/report'
@@ -262,6 +265,8 @@ interface RegionItem {
interface DistributionItem {
region?: string
park?: string
level?: string
type?: string
count: number
percent?: string
color: string
@@ -323,7 +328,11 @@ const emergencyPlanCompleted = ref<number>(0)
const parkDrillProgress = ref<DistributionItem[]>([])
// 安全培训数据
const trainingChartData = ref<any>({})
const trainingBarData = ref<{ regions: string[]; trainingCount: number[]; participants: number[] }>({
regions: [],
trainingCount: [],
participants: []
})
const parkTrainingProgress = ref<DistributionItem[]>([])
// 区域颜色配置
@@ -366,6 +375,13 @@ const initRegionData = async () => {
}
}
// 返回总部页面
const returnToHeadquarters = () => {
router.push({
path: '/index'
})
}
// 打开区域选择器
const openRegionSelector = (): void => {
regionSelectorVisible.value = true
@@ -375,7 +391,7 @@ const openRegionSelector = (): void => {
const onRegionChange = (item: RegionItem): void => {
selectedPark.value = item.name
router.push({
path: '/home/park',
path: '/park',
query: { region: selectedRegion.value, regionCode: route.query.regionCode, park: item.name, parkCode: item.code }
})
}
@@ -487,9 +503,9 @@ const initHighRiskData = async () => {
]
parkOperationDistribution.value = [
{ park: '雄安园区', count: 42 },
{ park: '重庆园区', count: 31 },
{ park: '北京园区', count: 21 }
{ park: '雄安园区', count: 42, color: '#3b82f6' },
{ park: '重庆园区', count: 31, color: '#8b5cf6' },
{ park: '北京园区', count: 21, color: '#06b6d4' }
]
}
@@ -499,25 +515,25 @@ const initEmergencyPlanData = async () => {
emergencyPlanTotal.value = 36
emergencyPlanCompleted.value = 28
parkDrillProgress.value = [
{ park: '雄安园区', percent: '85%', color: '#10b981' },
{ park: '重庆园区', percent: '78%', color: '#10b981' },
{ park: '北京园区', percent: '70%', color: '#10b981' }
{ park: '雄安园区', percent: '85%', color: '#10b981', count: 0 },
{ park: '重庆园区', percent: '78%', color: '#10b981', count: 0 },
{ park: '北京园区', percent: '70%', color: '#10b981', count: 0 }
]
}
// 初始化安全培训数据
const initSafetyTrainingData = async () => {
// TODO: 调用安全培训API
trainingChartData.value = {
parks: ['雄安', '重庆', '北京'],
trainingCount: [12, 10, 8],
participants: [25, 15, 12]
trainingBarData.value = {
regions: ['雄安园区', '重庆园区', '北京园区'],
trainingCount: [25, 15, 12],
participants: [12, 10, 8]
}
parkTrainingProgress.value = [
{ park: '雄安园区', percent: '92%', color: '#8b5cf6' },
{ park: '重庆园区', percent: '88%', color: '#8b5cf6' },
{ park: '北京园区', percent: '85%', color: '#8b5cf6' }
{ park: '雄安园区', percent: '92%', color: '#8b5cf6', count: 0 },
{ park: '重庆园区', percent: '88%', color: '#8b5cf6', count: 0 },
{ park: '北京园区', percent: '85%', color: '#8b5cf6', count: 0 }
]
}
@@ -651,19 +667,19 @@ const highRiskChartOption = computed<EChartsOption>(() => {
series: [{
name: '高危作业',
type: 'pie',
radius: ['55%', '75%'],
center: ['50%', '50%'],
radius: ['60%', '75%'],
center: ['50%', '45%'],
avoidLabelOverlap: false,
itemStyle: { borderRadius: 0, borderColor: 'transparent', borderWidth: 0 },
label: {
show: true,
position: 'center',
formatter: () => `${highRiskTotal.value}\n本月作业`,
fontSize: 16,
fontSize: 18,
fontWeight: 'bold',
color: '#333'
},
emphasis: { label: { show: true, fontSize: 18, fontWeight: 'bold' } },
emphasis: { label: { show: true, fontSize: 20, fontWeight: 'bold' } },
data: operationTypeDistribution.value.map(item => ({
value: item.count,
name: item.type,
@@ -684,15 +700,15 @@ const emergencyPlanChartOption = computed<EChartsOption>(() => {
series: [{
name: '演练完成率',
type: 'pie',
radius: ['55%', '75%'],
center: ['50%', '50%'],
radius: ['60%', '75%'],
center: ['50%', '45%'],
avoidLabelOverlap: false,
itemStyle: { borderRadius: 0, borderColor: 'transparent', borderWidth: 0, color: '#10b981' },
label: {
show: true,
position: 'center',
formatter: () => `${percent}%\n演练完成率`,
fontSize: 16,
fontSize: 18,
fontWeight: 'bold',
color: '#333'
},
@@ -712,24 +728,33 @@ const safetyTrainingChartOption = computed<EChartsOption>(() => {
data: ['培训次数', '参与人次'],
top: 10
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
grid: { left: '6%', right: '4%', bottom: '8%', containLabel: true },
xAxis: {
type: 'category',
data: trainingChartData.value.parks || []
data: trainingBarData.value.regions,
axisLine: { lineStyle: { color: '#d1d5db' } }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#d1d5db' } },
splitLine: { lineStyle: { color: '#f3f4f6' } }
},
yAxis: { type: 'value' },
series: [
{
name: '培训次数',
type: 'bar',
data: trainingChartData.value.trainingCount || [],
itemStyle: { color: '#8b5cf6' }
data: trainingBarData.value.trainingCount,
barWidth: 24,
itemStyle: { color: '#8b5cf6' },
label: { show: true, position: 'insideBottom', color: '#fff' }
},
{
name: '参与人次',
type: 'bar',
data: trainingChartData.value.participants || [],
itemStyle: { color: '#3b82f6' }
data: trainingBarData.value.participants,
barWidth: 24,
itemStyle: { color: '#c4b5fd' },
label: { show: true, position: 'top', color: '#7c3aed' }
}
]
}
@@ -774,7 +799,19 @@ onMounted(() => {
.header-left {
display: flex;
align-items: center;
gap: 15px;
gap: 10px;
}
.back-arrow {
font-size: 20px;
color: #3b82f6;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
color: #2563eb;
transform: translateX(-2px);
}
}
.back-button {
@@ -981,17 +1018,27 @@ onMounted(() => {
}
}
.high-risk-content {
.high-risk-top {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 15px;
}
.donut-chart-wrapper-small {
flex: 1.5;
min-width: 0;
display: flex;
align-items: center;
}
.operation-type-list {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
gap: 8px;
min-width: 0;
justify-content: center;
}
.operation-type-item {
@@ -1001,8 +1048,8 @@ onMounted(() => {
}
.operation-name {
width: 80px;
font-size: 13px;
width: 70px;
font-size: 12px;
color: #666;
flex-shrink: 0;
}
@@ -1020,27 +1067,37 @@ onMounted(() => {
border-radius: 4px;
}
.emergency-plan-content {
.emergency-plan-top {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 15px;
}
.progress-chart-wrapper {
flex: 1.5;
min-width: 0;
display: flex;
align-items: center;
}
.drill-info {
display: flex;
flex-direction: column;
gap: 10px;
gap: 8px;
flex: 1;
min-width: 0;
justify-content: center;
}
.drill-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
padding: 8px 10px;
background-color: #f0fdf4;
border-radius: 4px;
font-size: 13px;
font-size: 12px;
color: #666;
}

File diff suppressed because it is too large Load Diff