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