From 9de42afb45a501ed245135cfa269cd52309f297f Mon Sep 17 00:00:00 2001 From: chenlin Date: Tue, 30 Dec 2025 17:07:46 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E9=A6=96=E9=A1=B5UI=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/Home/Index10.vue | 595 +++++++++++++++++++++++++------------ src/views/Home/Index12.vue | 344 +++++++++++++++++---- src/views/Home/Index13.vue | 345 +++++++++++++++++---- 3 files changed, 998 insertions(+), 286 deletions(-) diff --git a/src/views/Home/Index10.vue b/src/views/Home/Index10.vue index dd6457f..0c7811d 100644 --- a/src/views/Home/Index10.vue +++ b/src/views/Home/Index10.vue @@ -38,13 +38,30 @@
-
区域分布
-
-
- - {{ item.region }} - {{ item.count }}人 - ({{ item.percent }}) +
区域人数分布
+
+ +
+
+
+ {{ item.region }} +
+
+ +
+
人数
+
+ {{ item.count }}人 +
+
+ +
+
占比
+
+ {{ item.percent }} +
@@ -66,27 +83,46 @@
区域风险分布
-
- - - - - - - - - - - - - - - - - - - -
区域一般较大重大
{{ item.area }}{{ item.low || '0' }}{{ item.general || '0' }}{{ item.moderate || '0' }}{{ item.major || '0' }}
+
+ +
+
+
+ {{ item.area }} +
+
+ +
+
+
+ {{ item.low || '0' }} +
+
+ +
+
一般
+
+ {{ item.general || '0' }} +
+
+ +
+
较大
+
+ {{ item.moderate || '0' }} +
+
+ +
+
重大
+
+ {{ item.major || '0' }} +
+
@@ -107,7 +143,10 @@
区域整改状态
-
+
+ 暂无数据 +
+
@@ -118,22 +157,25 @@
已逾期
-
- {{ item.overdue }} +
+ {{ item.overdue ?? 0 }}
处理中
-
- {{ item.processing }} +
+ {{ item.processing ?? 0 }}
已处理
-
- {{ item.processed }} +
+ {{ item.processed ?? 0 }}
@@ -266,12 +308,12 @@ import RegionSelector from '@/views/screen/components/RegionSelector.vue' import { getTableList } from '@/api/design/report' import type { EChartsOption } from 'echarts' import dayjs from 'dayjs' -import { - getHiddenDangerManagementData, - getHiddenDangerManagementDataWeek, +import { + getHiddenDangerManagementData, + getHiddenDangerManagementDataWeek, getHiddenDangerManagementDataMonth, - getOutsourcingManagementData, - getRiskManagementData, + getOutsourcingManagementData, + getRiskManagementData, getHighRiskManagementData, getEmergencyPlanManagementData, getTrainingManagementData @@ -336,22 +378,23 @@ const dateRange = ref(getInitialDateRange()) // 应急预案:/yayl/table/view/1966394259751907330 // 安全培训:/pxks/table/view/1968225010550091777 const openOutsourcingManagement = () => { - window.open('/person/table/view/1959187451673116674', '_blank') + // 不打开新标签页 + router.push('/person/table/view/1959187451673116674') } const openRiskManagement = () => { - window.open('/fx/table/view/1978723750599790594', '_blank') + router.push('/fx/table/view/1978723750599790594') } const openHiddenDangerManagement = () => { - window.open('/fx/table/view/1963446160885366786', '_blank') + router.push('/fx/table/view/1963446160885366786') } const openHighRiskManagement = () => { - window.open('/low/table/view/1964253329070571521', '_blank') + router.push('/low/table/view/1964253329070571521') } const openEmergencyPlanManagement = () => { - window.open('/yayl/table/view/1966394259751907330', '_blank') + router.push('/yayl/table/view/1966394259751907330') } const openTrainingManagement = () => { - window.open('/pxks/table/view/1968225010550091777', '_blank') + router.push('/pxks/table/view/1968225010550091777') } // 外协管理数据 @@ -370,27 +413,27 @@ const initOutsourcingData = async () => { pageNo: 1, pageSize: 10000 }) - + console.log('外协管理接口返回:', response) - + // axios封装后,response就是 { code: 0, data: {...}, msg: "" } // 所以records在 response.data.records const records = response?.records || [] - + if (records && records.length > 0) { // 计算总人数(从records中累加total) const total = records.reduce((sum: number, item: any) => { return sum + Number(item.total || 0) }, 0) - + outsourcingTotal.value = total - + // 处理区域分布数据 outsourcingDistribution.value = records.map((item: any, index: number) => { const count = Number(item.total || 0) const percent = total > 0 ? ((count / total) * 100).toFixed(1) + '%' : '0%' const color = regionColors[index % regionColors.length] - + return { region: item.name, count, @@ -398,7 +441,7 @@ const initOutsourcingData = async () => { color } }) - + console.log('处理后的外协管理数据:', { total: outsourcingTotal.value, distribution: outsourcingDistribution.value @@ -472,7 +515,7 @@ const outsourcingChartOption = computed(() => { name: item.region, itemStyle: { color: item.color } })) - + // 如果没有数据,显示空状态 if (chartData.length === 0 || outsourcingTotal.value === 0) { return { @@ -509,7 +552,7 @@ const outsourcingChartOption = computed(() => { ] } } - + return { tooltip: { trigger: 'item', @@ -559,7 +602,7 @@ const riskChartOption = computed(() => { name: item.level, itemStyle: { color: item.color } })) - + // 如果没有数据,显示空状态 if (chartData.length === 0 || riskTotal.value === 0) { return { @@ -583,7 +626,7 @@ const riskChartOption = computed(() => { }] } } - + return { tooltip: { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, series: [{ @@ -611,17 +654,20 @@ const riskChartOption = computed(() => { const hiddenDangerChartOption = computed(() => { // 提取日期和对应的数据 const dates = hiddenDangerTrend.value.map(item => item.date) - const generalData = hiddenDangerTrend.value.map(item => item.general) - const majorData = hiddenDangerTrend.value.map(item => item.major) - + const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0) + const majorData = hiddenDangerTrend.value.map(item => item.major ?? 0) + + // 判断是否为空数据 + const isEmpty = dates.length === 0 || (generalData.every(v => v === 0) && majorData.every(v => v === 0)) + // 计算Y轴最大值(向上取整到最近的10的倍数) - const maxValue = Math.max( + const maxValue = isEmpty ? 10 : Math.max( ...generalData, ...majorData, 10 // 最小值为10,避免图表显示过小 ) const yAxisMax = Math.ceil(maxValue / 10) * 10 || 10 - + return { tooltip: { trigger: 'axis', @@ -646,18 +692,42 @@ const hiddenDangerChartOption = computed(() => { xAxis: { type: 'category', boundaryGap: false, - data: dates.length > 0 ? dates : [] + data: dates.length > 0 ? dates : [], + show: !isEmpty }, yAxis: { type: 'value', - max: yAxisMax + max: yAxisMax, + show: !isEmpty }, - series: [ + graphic: isEmpty ? [ + { + type: 'group', + left: 'center', + top: 'center', + children: [ + { + type: 'text', + z: 100, + left: 'center', + top: 'center', + style: { + text: '暂无数据', + fontSize: 16, + fontWeight: 'normal', + fill: '#9ca3af', + textAlign: 'center' + } + } + ] + } + ] : [], + series: isEmpty ? [] : [ { name: '一般隐患', type: 'line', smooth: true, - data: generalData.length > 0 ? generalData : [], + data: generalData, itemStyle: { color: '#f59e0b' }, lineStyle: { color: '#f59e0b', width: 2 }, areaStyle: { @@ -678,7 +748,7 @@ const hiddenDangerChartOption = computed(() => { name: '重大隐患', type: 'line', smooth: true, - data: majorData.length > 0 ? majorData : [], + data: majorData, itemStyle: { color: '#ef4444' }, lineStyle: { color: '#ef4444', width: 2 }, areaStyle: { @@ -708,7 +778,7 @@ const highRiskChartOption = computed(() => { name: item.type, itemStyle: { color: item.color } })) - + // 如果没有数据,显示空状态 if (chartData.length === 0 || highRiskTotal.value === 0) { return { @@ -732,7 +802,7 @@ const highRiskChartOption = computed(() => { }] } } - + return { tooltip: { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, series: [{ @@ -758,10 +828,10 @@ const highRiskChartOption = computed(() => { // 应急预案环形进度图配置 const emergencyPlanChartOption = computed(() => { - const percent = emergencyPlanTotal.value > 0 + const percent = emergencyPlanTotal.value > 0 ? ((emergencyPlanCompleted.value / emergencyPlanTotal.value) * 100).toFixed(0) : 0 - + return { tooltip: { trigger: 'item' }, series: [{ @@ -793,12 +863,12 @@ const safetyTrainingChartOption = computed(() => { const regions = trainingBarData.value.regions || [] const trainingCount = trainingBarData.value.trainingCount || [] const participants = trainingBarData.value.participants || [] - + // 计算堆叠后的最大值(培训次数 + 参与人次) const stackedValues = trainingCount.map((count, index) => count + (participants[index] || 0)) const maxValue = Math.max(...stackedValues, 10) // 最小值为10,避免图表显示过小 const yAxisMax = Math.ceil(maxValue / 10) * 10 || 10 - + return { tooltip: { trigger: 'axis', @@ -936,8 +1006,8 @@ const onRegionChange = (item: RegionItem): void => { selectedRegion.value = item.name router.push({ path: '/region', - query: { - region: item.name, + query: { + region: item.name, regionCode: item.code, sDate: dateRange.value[0], eDate: dateRange.value[1] @@ -988,28 +1058,28 @@ const initRiskData = async () => { pageNo: 1, pageSize: 10000 }) - + console.log('风险管理接口返回:', response) - + const records = response?.records || [] - + if (records && records.length > 0) { // 按风险等级分组统计,用于环形图 const levelMap = new Map() - + // 按区域和风险等级分组统计,用于表格 const areaLevelMap = new Map() - + records.forEach((item: any) => { const level = item.name || '' const area = item.area || '' const count = Number(item.total || 0) - + // 统计风险等级分布(用于环形图) if (level) { levelMap.set(level, (levelMap.get(level) || 0) + count) } - + // 统计区域风险分布(用于表格) if (area) { if (!areaLevelMap.has(area)) { @@ -1027,11 +1097,11 @@ const initRiskData = async () => { } } }) - + // 计算总数 const total = Array.from(levelMap.values()).reduce((sum, count) => sum + count, 0) riskTotal.value = total - + // 处理风险等级分布数据(用于环形图) const allLevels = [ { key: '低', level: '低风险', count: 0, percent: '0%', color: '#10b981' }, @@ -1039,7 +1109,7 @@ const initRiskData = async () => { { key: '较大', level: '较大风险', count: 0, percent: '0%', color: '#ef4444' }, { key: '重大', level: '重大风险', count: 0, percent: '0%', color: '#dc2626' } ] - + riskDistribution.value = allLevels.map(defaultItem => { const count = levelMap.get(defaultItem.key) || levelMap.get(defaultItem.level) || 0 const percent = total > 0 ? ((count / total) * 100).toFixed(1) + '%' : '0%' @@ -1050,7 +1120,7 @@ const initRiskData = async () => { color: defaultItem.color } }) - + // 处理区域风险分布表 areaRiskDistribution.value = Array.from(areaLevelMap.entries()) .map(([area, data]) => ({ @@ -1066,7 +1136,7 @@ const initRiskData = async () => { const totalB = (typeof b.low === 'number' ? b.low : 0) + b.general + b.moderate + b.major return totalB - totalA }) - + console.log('处理后的风险管理数据:', { total: riskTotal.value, levelDistribution: riskDistribution.value, @@ -1103,7 +1173,7 @@ const getHiddenDangerApi = (startDate: string, endDate: string) => { const start = dayjs(startDate) const end = dayjs(endDate) const daysDiff = end.diff(start, 'day') + 1 // 包含起始和结束日期 - + // 如果日期范围 <= 7天,使用"天"接口 if (daysDiff <= 7) { return getHiddenDangerManagementData @@ -1122,32 +1192,32 @@ const initDangerData = async () => { try { // 根据日期范围选择接口 const apiFunc = getHiddenDangerApi(dateRange.value[0], dateRange.value[1]) - + const response = await apiFunc({ sDate: dateRange.value[0], eDate: dateRange.value[1], pageNo: 1, pageSize: 10000 }) - + console.log('隐患管理接口返回:', response) - + const records = response?.records || [] - + if (records && records.length > 0) { // 按日期和等级分组统计,用于折线图 const trendMap = new Map() - + // 按区域和状态分组统计,用于整改状态表格 const areaStatusMap = new Map() - + records.forEach((item: any) => { const dayname = item.dayName || item.dayname || '' const level = item.name || '' const status = item.status || '' const area = item.area || '' const count = Number(item.total || 0) - + // 统计趋势数据(按日期和等级) if (dayname) { if (!trendMap.has(dayname)) { @@ -1160,7 +1230,7 @@ const initDangerData = async () => { trend.major += count } } - + // 统计区域整改状态数据 if (area) { if (!areaStatusMap.has(area)) { @@ -1176,7 +1246,7 @@ const initDangerData = async () => { } } }) - + // 转换为数组并按日期排序 hiddenDangerTrend.value = Array.from(trendMap.entries()) .map(([date, counts]) => ({ date, ...counts })) @@ -1189,7 +1259,7 @@ const initDangerData = async () => { const dayB = parseInt(b.date.replace('日', '')) || 0 return (numA || dayA) - (numB || dayB) }) - + // 转换为区域整改状态数组 areaRectificationStatus.value = Array.from(areaStatusMap.entries()) .map(([area, status]) => ({ @@ -1204,7 +1274,7 @@ const initDangerData = async () => { const totalB = b.overdue + b.processing + b.processed return totalB - totalA }) - + console.log('处理后的隐患管理数据:', { trend: hiddenDangerTrend.value, areaStatus: areaRectificationStatus.value @@ -1231,38 +1301,38 @@ const initHighRiskData = async () => { pageNo: 1, pageSize: 10000 }) - + console.log('高危作业接口返回:', response) - + const records = response?.records || [] - + if (records && records.length > 0) { // 按作业类型分组统计,用于环形图 const typeMap = new Map() - + // 按区域分组统计,用于区域分布列表 const areaMap = new Map() - + records.forEach((item: any) => { const itemType = item.item || '' const area = item.area || '' const count = Number(item.total || 0) - + // 统计作业类型 if (itemType) { typeMap.set(itemType, (typeMap.get(itemType) || 0) + count) } - + // 统计区域分布 if (area) { areaMap.set(area, (areaMap.get(area) || 0) + count) } }) - + // 计算总数 const total = Array.from(typeMap.values()).reduce((sum, count) => sum + count, 0) highRiskTotal.value = total - + // 处理作业类型分布数据 operationTypeDistribution.value = Array.from(typeMap.entries()) .map(([type, count]) => ({ @@ -1272,7 +1342,7 @@ const initHighRiskData = async () => { color: operationTypeColors[type] || '#9ca3af' // 如果没有配置颜色,使用灰色 })) .sort((a, b) => b.count - a.count) // 按数量降序排序 - + // 处理区域分布数据 operationDistribution.value = Array.from(areaMap.entries()) .map(([region, count]) => ({ @@ -1280,7 +1350,7 @@ const initHighRiskData = async () => { count })) .sort((a, b) => b.count - a.count) // 按数量降序排序 - + console.log('处理后的高危作业数据:', { total: highRiskTotal.value, typeDistribution: operationTypeDistribution.value, @@ -1310,19 +1380,19 @@ const initEmergencyPlanData = async () => { pageNo: 1, pageSize: 10000 }) - + console.log('应急预案接口返回:', response) - + const records = response?.records || [] - + if (records && records.length > 0) { // 统计应完成演练总数(所有记录的total总和) const total = records.reduce((sum: number, item: any) => { return sum + Number(item.total || 0) }, 0) - + emergencyPlanTotal.value = total - + // 统计已完成演练数(根据状态判断) // 可能的完成状态:已完成、已完成演练、已执行等 const completedCount = records.reduce((sum: number, item: any) => { @@ -1334,18 +1404,18 @@ const initEmergencyPlanData = async () => { } return sum }, 0) - + emergencyPlanCompleted.value = completedCount - + // 按区域统计演练完成率 const areaMap = new Map() - + records.forEach((item: any) => { const area = item.area || '' const count = Number(item.total || 0) const status = item.status || '' const isCompleted = status.includes('完成') || status.includes('已执行') - + if (area) { if (!areaMap.has(area)) { areaMap.set(area, { total: 0, completed: 0 }) @@ -1357,11 +1427,11 @@ const initEmergencyPlanData = async () => { } } }) - + // 转换为数组并计算完成率 regionalDrillProgress.value = Array.from(areaMap.entries()) .map(([region, data]) => { - const percent = data.total > 0 + const percent = data.total > 0 ? ((data.completed / data.total) * 100).toFixed(0) + '%' : '0%' return { region, percent } @@ -1372,7 +1442,7 @@ const initEmergencyPlanData = async () => { const percentB = parseFloat(b.percent) return percentB - percentA }) - + console.log('处理后的应急预案数据:', { total: emergencyPlanTotal.value, completed: emergencyPlanCompleted.value, @@ -1402,25 +1472,25 @@ const initTrainingData = async () => { pageNo: 1, pageSize: 10000 }) - + console.log('安全培训接口返回:', response) - + const records = response?.records || [] - + if (records && records.length > 0) { // 按区域分组统计 const areaMap = new Map() - + records.forEach((item: any) => { // 只统计有区域字段的记录 if (!item.area) { return } - + const area = item.area const trainingCount = Number(item.plannum || 0) // 计划数量作为培训次数 const participants = Number(item.exenum || 0) // 执行数量作为参与人次 - + if (!areaMap.has(area)) { areaMap.set(area, { trainingCount: 0, participants: 0 }) } @@ -1428,7 +1498,7 @@ const initTrainingData = async () => { areaData.trainingCount += trainingCount areaData.participants += participants }) - + // 转换为数组并排序 const areaDataArray = Array.from(areaMap.entries()) .map(([region, data]) => ({ @@ -1443,20 +1513,20 @@ const initTrainingData = async () => { // 按培训次数降序排序 return b.trainingCount - a.trainingCount }) - + // 更新柱状图数据 trainingBarData.value = { regions: areaDataArray.map(item => item.region), trainingCount: areaDataArray.map(item => item.trainingCount), participants: areaDataArray.map(item => item.participants) } - + // 更新区域培训完成率数据 regionalTrainingProgress.value = areaDataArray.map(item => ({ region: item.region, percent: item.percent })) - + console.log('处理后的安全培训数据:', { barData: trainingBarData.value, regionalProgress: regionalTrainingProgress.value @@ -1486,7 +1556,7 @@ const initTrainingData = async () => { const initData = async () => { await initRegionData() initOutsourcingData() - + initRiskData() initDangerData() initHighRiskData() @@ -1540,15 +1610,15 @@ onMounted(async () => { color: white; user-select: none; font-weight: 600; - span { - margin-left: 8px; - font-size: 18px; - color: #6b7280; - } + gap: 5px; &:hover { - background: #e5e7eb; - border-color: #d1d5db; + background: #2563eb; + } + + span { + font-size: 18px; + line-height: 1; } &:active { @@ -1616,16 +1686,17 @@ onMounted(async () => { } @media (max-width: 1200px) { + .high-risk-top, .emergency-plan-top { gap: 10px; } - + .donut-chart-wrapper-small, .progress-chart-wrapper { min-width: 160px; } - + .operation-type-list, .drill-info { min-width: 140px; @@ -1634,12 +1705,13 @@ onMounted(async () => { } @media (max-width: 768px) { + .high-risk-top, .emergency-plan-top { flex-direction: column; align-items: stretch; } - + .donut-chart-wrapper-small, .progress-chart-wrapper { min-width: 100%; @@ -1647,7 +1719,7 @@ onMounted(async () => { height: 220px; min-height: 220px; } - + .operation-type-list, .drill-info { min-width: 100%; @@ -1825,6 +1897,14 @@ onMounted(async () => { font-weight: 600; color: #374151; margin-bottom: 12px; + display: flex; + align-items: center; + justify-content: space-between; + span { + font-size: 14px; + font-weight: 600; + color: #374151; + } } .distribution-list { @@ -1868,55 +1948,62 @@ onMounted(async () => { // 网格样式 .rectification-status-grid { + .empty-data-tip { + text-align: center; + padding: 40px 0; + color: #9ca3af; + font-size: 14px; + } + .grid-wrapper { display: flex; gap: 0; justify-content: flex-start; } - + .grid-column { display: flex; flex-direction: column; align-items: center; min-width: 0; - + &:first-child { align-items: flex-start; margin-right: 20px; flex: 0 0 auto; min-width: 80px; } - + &:not(:first-child) { flex: 1; min-width: 60px; } } - + .grid-header { font-size: 14px; font-weight: bold; margin-bottom: 12px; height: 20px; line-height: 20px; - + &.empty-header { visibility: hidden; } - + &.status-overdue { color: #ef4444; } - + &.status-processing { color: #f59e0b; } - + &.status-processed { color: #10b981; } } - + .grid-park-name { font-size: 13px; color: #333; @@ -1924,12 +2011,12 @@ onMounted(async () => { text-align: left; height: 24px; line-height: 24px; - + &:last-child { margin-bottom: 0; } } - + .grid-number { font-size: 16px; font-weight: 500; @@ -1937,51 +2024,188 @@ onMounted(async () => { text-align: center; height: 24px; line-height: 24px; - + &:last-child { margin-bottom: 0; } - + &.status-overdue { color: #ef4444; } - + &.status-processing { color: #f59e0b; } - + &.status-processed { color: #10b981; } } } -.table-wrapper { - overflow-x: auto; +// 风险管理网格样式(与隐患管理一致) +.risk-distribution-table { + .grid-wrapper { + display: flex; + gap: 0; + justify-content: flex-start; + } + + .grid-column { + display: flex; + flex-direction: column; + align-items: center; + min-width: 0; + + &:first-child { + align-items: flex-start; + margin-right: 20px; + flex: 0 0 auto; + min-width: 80px; + } + + &:not(:first-child) { + flex: 1; + min-width: 60px; + } + } + + .grid-header { + font-size: 14px; + font-weight: bold; + margin-bottom: 12px; + height: 20px; + line-height: 20px; + + &.empty-header { + visibility: hidden; + } + + &.status-low { + color: #117cee; + } + + &.status-general { + color: #fbde28; + } + + &.status-moderate { + color: #ed740c; + } + + &.status-major { + color: #df2a3f; + } + } + + .grid-park-name { + font-size: 13px; + color: #333; + margin-bottom: 8px; + text-align: left; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + } + + .grid-number { + font-size: 16px; + font-weight: 500; + margin-bottom: 8px; + text-align: center; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + + &.status-low { + color: #117cee; + } + + &.status-general { + color: #fbde28; + } + + &.status-moderate { + color: #ed740c; + } + + &.status-major { + color: #df2a3f; + } + } } -.risk-table { - width: 100%; - border-collapse: collapse; - font-size: 13px; - - thead { - background-color: #f9fafb; +// 外协管理网格样式(与隐患管理一致) +.region-distribution { + .grid-wrapper { + display: flex; + gap: 0; + justify-content: flex-start; } - - th, td { - padding: 8px; - text-align: left; - border-bottom: 1px solid #e5e7eb; + + .grid-column { + display: flex; + flex-direction: column; + align-items: center; + min-width: 0; + + &:first-child { + align-items: flex-start; + margin-right: 20px; + flex: 0 0 auto; + min-width: 80px; + } + + &:not(:first-child) { + flex: 1; + min-width: 60px; + } } - - th { + + .grid-header { + font-size: 14px; font-weight: bold; - color: #333; + margin-bottom: 12px; + height: 20px; + line-height: 20px; + color: #374151; + + &.empty-header { + visibility: hidden; + } } - - td { - color: #666; + + .grid-park-name { + font-size: 13px; + color: #333; + margin-bottom: 8px; + text-align: left; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + } + + .grid-number { + font-size: 16px; + font-weight: 500; + margin-bottom: 8px; + text-align: center; + height: 24px; + line-height: 24px; + color: #1f2937; + + &:last-child { + margin-bottom: 0; + } } } @@ -2052,7 +2276,7 @@ onMounted(async () => { box-shadow: 0 2px 4px rgba(139, 92, 246, 0.3); position: relative; overflow: hidden; - + &::after { content: ''; position: absolute; @@ -2060,12 +2284,10 @@ onMounted(async () => { left: 0; bottom: 0; right: 0; - background: linear-gradient( - 90deg, - transparent 0%, - rgba(255, 255, 255, 0.3) 50%, - transparent 100% - ); + background: linear-gradient(90deg, + transparent 0%, + rgba(255, 255, 255, 0.3) 50%, + transparent 100%); animation: shimmer 2s infinite; } } @@ -2084,6 +2306,7 @@ onMounted(async () => { 0% { transform: translateX(-100%); } + 100% { transform: translateX(100%); } diff --git a/src/views/Home/Index12.vue b/src/views/Home/Index12.vue index f531164..a166036 100644 --- a/src/views/Home/Index12.vue +++ b/src/views/Home/Index12.vue @@ -41,16 +41,33 @@
-
园区分布
-
-
- - {{ item.region }} - {{ item.count }}人 - ({{ item.percent }}) -
+
园区人数分布
+
+ +
+
+
+ {{ item.region }}
+
+ +
+
人数
+
+ {{ item.count }}人
+
+ +
+
占比
+
+ {{ item.percent }} +
+
+
+
@@ -69,28 +86,47 @@
园区风险分布
-
- - - - - - - - - - - - - - - - - - - -
园区一般较大重大
{{ item.park }}{{ item.low || '' }}{{ item.general }}{{ item.moderate }}{{ item.major }}
-
+
+ +
+
+
+ {{ item.park }} +
+
+ +
+
+
+ {{ item.low || '0' }} +
+
+ +
+
一般
+
+ {{ item.general || '0' }} +
+
+ +
+
较大
+
+ {{ item.moderate || '0' }} +
+
+ +
+
重大
+
+ {{ item.major || '0' }} +
+
+
@@ -110,7 +146,10 @@
园区整改状态
-
+
+ 暂无数据 +
+
@@ -122,21 +161,21 @@
已逾期
- {{ item.overdue }} + {{ item.overdue ?? 0 }}
处理中
- {{ item.processing }} + {{ item.processing ?? 0 }}
已处理
- {{ item.processed }} + {{ item.processed ?? 0 }}
@@ -329,22 +368,22 @@ const parkOption = ref([]) // 应急预案:/yayl/table/view/1966394259751907330 // 安全培训:/pxks/table/view/1968225010550091777 const openOutsourcingManagement = () => { - window.open('/person/table/view/1959187451673116674', '_blank') + router.push('/person/table/view/1959187451673116674') } const openRiskManagement = () => { - window.open('/fx/table/view/1978723750599790594', '_blank') + router.push('/fx/table/view/1978723750599790594') } const openHiddenDangerManagement = () => { - window.open('/fx/table/view/1963446160885366786', '_blank') + router.push('/fx/table/view/1963446160885366786') } const openHighRiskManagement = () => { - window.open('/low/table/view/1964253329070571521', '_blank') + router.push('/low/table/view/1964253329070571521') } const openEmergencyPlanManagement = () => { - window.open('/yayl/table/view/1966394259751907330', '_blank') + router.push('/yayl/table/view/1966394259751907330') } const openTrainingManagement = () => { - window.open('/pxks/table/view/1968225010550091777', '_blank') + router.push('/pxks/table/view/1968225010550091777') } // 时间选择相关 - 默认当前月起止,如果路由中有日期范围参数则使用 const getCurrentMonthRange = () => { @@ -1130,8 +1169,11 @@ const riskChartOption = computed(() => { // 隐患管理折线图配置 const hiddenDangerChartOption = computed(() => { const dates = hiddenDangerTrend.value.map(item => item.date) - const generalData = hiddenDangerTrend.value.map(item => item.general) - const majorData = hiddenDangerTrend.value.map(item => item.major) + const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0) + const majorData = hiddenDangerTrend.value.map(item => item.major ?? 0) + + // 判断是否为空数据 + const isEmpty = dates.length === 0 || (generalData.every(v => v === 0) && majorData.every(v => v === 0)) return { tooltip: { trigger: 'axis' }, @@ -1139,14 +1181,40 @@ const hiddenDangerChartOption = computed(() => { data: ['一般隐患', '重大隐患'], top: 10 }, - grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, + grid: { left: '3%', right: '4%', bottom: '3%', top: '12%', containLabel: true }, xAxis: { type: 'category', boundaryGap: false, - data: dates + data: dates, + show: !isEmpty }, - yAxis: { type: 'value' }, - series: [ + yAxis: { + type: 'value', + show: !isEmpty + }, + graphic: isEmpty ? [ + { + type: 'group', + left: 'center', + top: 'center', + children: [ + { + type: 'text', + z: 100, + left: 'center', + top: 'center', + style: { + text: '暂无数据', + fontSize: 16, + fontWeight: 'normal', + fill: '#9ca3af', + textAlign: 'center' + } + } + ] + } + ] : [], + series: isEmpty ? [] : [ { name: '一般隐患', type: 'line', @@ -1559,6 +1627,14 @@ onMounted(() => { font-weight: bold; color: #333; margin-bottom: 10px; + display: flex; + align-items: center; + justify-content: space-between; + span { + font-size: 14px; + font-weight: 600; + color: #374151; + } } .distribution-list { @@ -1595,11 +1671,104 @@ onMounted(() => { color: #999; } -.table-wrapper { - overflow-x: auto; +// 风险管理网格样式(与隐患管理一致) +.risk-distribution-table { + .grid-wrapper { + display: flex; + gap: 0; + justify-content: flex-start; + } + + .grid-column { + display: flex; + flex-direction: column; + align-items: center; + min-width: 0; + + &:first-child { + align-items: flex-start; + margin-right: 20px; + flex: 0 0 auto; + min-width: 80px; + } + + &:not(:first-child) { + flex: 1; + min-width: 60px; + } + } + + .grid-header { + font-size: 14px; + font-weight: bold; + margin-bottom: 12px; + height: 20px; + line-height: 20px; + + &.empty-header { + visibility: hidden; + } + + &.status-low { + color: #117cee; + } + + &.status-general { + color: #fbde28; + } + + &.status-moderate { + color: #ed740c; + } + + &.status-major { + color: #df2a3f; + } + } + + .grid-park-name { + font-size: 13px; + color: #333; + margin-bottom: 8px; + text-align: left; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + } + + .grid-number { + font-size: 16px; + font-weight: 500; + margin-bottom: 8px; + text-align: center; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + + &.status-low { + color: #117cee; + } + + &.status-general { + color: #fbde28; + } + + &.status-moderate { + color: #ed740c; + } + + &.status-major { + color: #df2a3f; + } + } } -.risk-table, .status-table { width: 100%; border-collapse: collapse; @@ -1616,7 +1785,7 @@ onMounted(() => { } th { - font-weight: bold; + font-weight: bold; color: #333; } @@ -1627,6 +1796,13 @@ onMounted(() => { // 九宫格样式 .rectification-status-grid { + .empty-data-tip { + text-align: center; + padding: 40px 0; + color: #9ca3af; + font-size: 14px; + } + .grid-wrapper { display: flex; gap: 0; @@ -1715,6 +1891,74 @@ onMounted(() => { } } +// 外协管理网格样式(与隐患管理一致) +.region-distribution { + .grid-wrapper { + display: flex; + gap: 0; + justify-content: flex-start; + } + + .grid-column { + display: flex; + flex-direction: column; + align-items: center; + min-width: 0; + + &:first-child { + align-items: flex-start; + margin-right: 20px; + flex: 0 0 auto; + min-width: 80px; + } + + &:not(:first-child) { + flex: 1; + min-width: 60px; + } + } + + .grid-header { + font-size: 14px; + font-weight: bold; + margin-bottom: 12px; + height: 20px; + line-height: 20px; + color: #374151; + + &.empty-header { + visibility: hidden; + } + } + + .grid-park-name { + font-size: 13px; + color: #333; + margin-bottom: 8px; + text-align: left; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + } + + .grid-number { + font-size: 16px; + font-weight: 500; + margin-bottom: 8px; + text-align: center; + height: 24px; + line-height: 24px; + color: #1f2937; + + &:last-child { + margin-bottom: 0; + } + } +} + .high-risk-top { display: flex; align-items: center; diff --git a/src/views/Home/Index13.vue b/src/views/Home/Index13.vue index 323c1b1..1948ec4 100644 --- a/src/views/Home/Index13.vue +++ b/src/views/Home/Index13.vue @@ -38,16 +38,33 @@
-
供应商分布
-
-
- - {{ item.supplier }} - {{ item.count }}人 - ({{ item.percent }}) -
-
+
供应商人数分布
+
+ +
+
+
+ {{ item.supplier }}
+
+ +
+
人数
+
+ {{ item.count }}人 +
+
+ +
+
占比
+
+ {{ item.percent }} +
+
+
+
@@ -66,28 +83,47 @@
地点风险分布
-
- - - - - - - - - - - - - - - - - - - -
所在地点一般较大重大
{{ item.location }}{{ item.low || '' }}{{ item.general }}{{ item.moderate }}{{ item.major }}
-
+
+ +
+
+
+ {{ item.location }} +
+
+ +
+
+
+ {{ item.low || '0' }} +
+
+ +
+
一般
+
+ {{ item.general || '0' }} +
+
+ +
+
较大
+
+ {{ item.moderate || '0' }} +
+
+ +
+
重大
+
+ {{ item.major || '0' }} +
+
+
@@ -107,7 +143,10 @@
所属公司整改状态
-
+
+ 暂无数据 +
+
@@ -119,21 +158,21 @@
已逾期
- {{ item.overdue }} + {{ item.overdue ?? 0 }}
处理中
- {{ item.processing }} + {{ item.processing ?? 0 }}
已处理
- {{ item.processed }} + {{ item.processed ?? 0 }}
@@ -319,22 +358,22 @@ const route = useRoute() // 应急预案:/yayl/table/view/1966394259751907330 // 安全培训:/pxks/table/view/1968225010550091777 const openOutsourcingManagement = () => { - window.open('/person/table/view/1959187451673116674', '_blank') + router.push('/person/table/view/1959187451673116674') } const openRiskManagement = () => { - window.open('/fx/table/view/1978723750599790594', '_blank') + router.push('/fx/table/view/1978723750599790594') } const openHiddenDangerManagement = () => { - window.open('/fx/table/view/1963446160885366786', '_blank') + router.push('/fx/table/view/1963446160885366786') } const openHighRiskManagement = () => { - window.open('/low/table/view/1964253329070571521', '_blank') + router.push('/low/table/view/1964253329070571521') } const openEmergencyPlanManagement = () => { - window.open('/yayl/table/view/1966394259751907330', '_blank') + router.push('/yayl/table/view/1966394259751907330') } const openTrainingManagement = () => { - window.open('/pxks/table/view/1968225010550091777', '_blank') + router.push('/pxks/table/view/1968225010550091777') } // 园区名称 - 从路由参数获取 const selectedPark = ref('') @@ -1051,8 +1090,11 @@ const riskChartOption = computed(() => { // 隐患管理折线图配置 const hiddenDangerChartOption = computed(() => { const dates = hiddenDangerTrend.value.map(item => item.date) - const generalData = hiddenDangerTrend.value.map(item => item.general) - const majorData = hiddenDangerTrend.value.map(item => item.major) + const generalData = hiddenDangerTrend.value.map(item => item.general ?? 0) + const majorData = hiddenDangerTrend.value.map(item => item.major ?? 0) + + // 判断是否为空数据 + const isEmpty = dates.length === 0 || (generalData.every(v => v === 0) && majorData.every(v => v === 0)) return { tooltip: { trigger: 'axis' }, @@ -1060,14 +1102,41 @@ const hiddenDangerChartOption = computed(() => { data: ['一般隐患', '重大隐患'], top: 10 }, - grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, + grid: { left: '3%', right: '4%', bottom: '3%', top: '12%', containLabel: true }, xAxis: { type: 'category', boundaryGap: false, - data: dates + data: dates, + show: !isEmpty }, - yAxis: { type: 'value', max: 45 }, - series: [ + yAxis: { + type: 'value', + max: 45, + show: !isEmpty + }, + graphic: isEmpty ? [ + { + type: 'group', + left: 'center', + top: 'center', + children: [ + { + type: 'text', + z: 100, + left: 'center', + top: 'center', + style: { + text: '暂无数据', + fontSize: 16, + fontWeight: 'normal', + fill: '#9ca3af', + textAlign: 'center' + } + } + ] + } + ] : [], + series: isEmpty ? [] : [ { name: '一般隐患', type: 'line', @@ -1466,6 +1535,14 @@ onMounted(() => { font-weight: bold; color: #333; margin-bottom: 10px; + display: flex; + align-items: center; + justify-content: space-between; + span { + font-size: 14px; + font-weight: 600; + color: #374151; + } } .distribution-list { @@ -1502,11 +1579,104 @@ onMounted(() => { color: #999; } -.table-wrapper { - overflow-x: auto; +// 风险管理网格样式(与隐患管理一致) +.risk-distribution-table { + .grid-wrapper { + display: flex; + gap: 0; + justify-content: flex-start; + } + + .grid-column { + display: flex; + flex-direction: column; + align-items: center; + min-width: 0; + + &:first-child { + align-items: flex-start; + margin-right: 20px; + flex: 0 0 auto; + min-width: 80px; + } + + &:not(:first-child) { + flex: 1; + min-width: 60px; + } + } + + .grid-header { + font-size: 14px; + font-weight: bold; + margin-bottom: 12px; + height: 20px; + line-height: 20px; + + &.empty-header { + visibility: hidden; + } + + &.status-low { + color: #117cee; + } + + &.status-general { + color: #fbde28; + } + + &.status-moderate { + color: #ed740c; + } + + &.status-major { + color: #df2a3f; + } + } + + .grid-park-name { + font-size: 13px; + color: #333; + margin-bottom: 8px; + text-align: left; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + } + + .grid-number { + font-size: 16px; + font-weight: 500; + margin-bottom: 8px; + text-align: center; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + + &.status-low { + color: #117cee; + } + + &.status-general { + color: #fbde28; + } + + &.status-moderate { + color: #ed740c; + } + + &.status-major { + color: #df2a3f; + } + } } -.risk-table, .status-table { width: 100%; border-collapse: collapse; @@ -1535,6 +1705,13 @@ onMounted(() => { // 九宫格样式 // 九宫格样式 .rectification-status-grid { + .empty-data-tip { + text-align: center; + padding: 40px 0; + color: #9ca3af; + font-size: 14px; + } + .grid-wrapper { display: flex; gap: 0; @@ -1623,6 +1800,74 @@ onMounted(() => { } } +// 外协管理网格样式(与隐患管理一致) +.region-distribution { + .grid-wrapper { + display: flex; + gap: 0; + justify-content: flex-start; + } + + .grid-column { + display: flex; + flex-direction: column; + align-items: center; + min-width: 0; + + &:first-child { + align-items: flex-start; + margin-right: 20px; + flex: 0 0 auto; + min-width: 80px; + } + + &:not(:first-child) { + flex: 1; + min-width: 60px; + } + } + + .grid-header { + font-size: 14px; + font-weight: bold; + margin-bottom: 12px; + height: 20px; + line-height: 20px; + color: #374151; + + &.empty-header { + visibility: hidden; + } + } + + .grid-park-name { + font-size: 13px; + color: #333; + margin-bottom: 8px; + text-align: left; + height: 24px; + line-height: 24px; + + &:last-child { + margin-bottom: 0; + } + } + + .grid-number { + font-size: 16px; + font-weight: 500; + margin-bottom: 8px; + text-align: center; + height: 24px; + line-height: 24px; + color: #1f2937; + + &:last-child { + margin-bottom: 0; + } + } +} + .high-risk-top { display: flex; align-items: center; From f9092305468f5635fa505baedfbbb2f1a414f8a3 Mon Sep 17 00:00:00 2001 From: chenlin Date: Tue, 6 Jan 2026 12:08:08 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E9=A3=8E=E9=99=A9=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/Home/Index10.vue | 272 ++++++------ src/views/Home/Index12.vue | 228 ++++++---- src/views/Home/Index13.vue | 178 ++++++-- src/views/screen/companyScreen.vue | 14 +- .../screen/components/HeaderSelector.vue | 398 ++++++++++++++++++ src/views/screen/mainScreen.vue | 43 +- src/views/screen/regionScreen.vue | 56 ++- 7 files changed, 870 insertions(+), 319 deletions(-) create mode 100644 src/views/screen/components/HeaderSelector.vue diff --git a/src/views/Home/Index10.vue b/src/views/Home/Index10.vue index e69a7e6..57c1c0d 100644 --- a/src/views/Home/Index10.vue +++ b/src/views/Home/Index10.vue @@ -2,12 +2,17 @@
-
-
- {{ currentView }} - ··· -
-
+
@@ -293,9 +298,6 @@
- -
@@ -304,7 +306,7 @@ import { ref, computed, onMounted } from 'vue' import { useRouter, useRoute } from 'vue-router' import { Refresh } from '@element-plus/icons-vue' import Echart from '@/components/Echart/src/Echart.vue' -import RegionSelector from '@/views/screen/components/RegionSelector.vue' +import HeaderSelector from '@/views/screen/components/HeaderSelector.vue' import { getTableList } from '@/api/design/report' import type { EChartsOption } from 'echarts' import dayjs from 'dayjs' @@ -349,9 +351,7 @@ const route = useRoute() // 区域选择相关 const currentView = ref('集团') -const regionSelectorVisible = ref(false) const selectedRegion = ref('') -const regionOption = ref([]) // 时间选择相关 - 默认当前月起止,如果路由中有日期范围参数则使用 const getCurrentMonthRange = () => { @@ -523,6 +523,21 @@ const outsourcingChartOption = computed(() => { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, + graphic: [ + { + type: 'text', + left: 'center', + top: 'center', + style: { + text: `${outsourcingTotal.value}\n外协人员总数`, + fontSize: 16, + fontWeight: 'bold', + fill: '#333', + textAlign: 'center', + textVerticalAlign: 'middle' + } + } + ], series: [ { name: '外协人员', @@ -536,14 +551,7 @@ const outsourcingChartOption = computed(() => { borderWidth: 0 }, label: { - show: true, - position: 'center', - formatter: () => { - return `${outsourcingTotal.value}\n外协人员总数` - }, - fontSize: 16, - fontWeight: 'bold', - color: '#333' + show: false }, data: [ { value: 1, name: '暂无数据', itemStyle: { color: '#e5e7eb' } } @@ -558,6 +566,21 @@ const outsourcingChartOption = computed(() => { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, + graphic: [ + { + type: 'text', + left: 'center', + top: 'center', + style: { + text: `${outsourcingTotal.value}\n外协人员总数`, + fontSize: 16, + fontWeight: 'bold', + fill: '#333', + textAlign: 'center', + textVerticalAlign: 'middle' + } + } + ], series: [ { name: '外协人员', @@ -571,19 +594,12 @@ const outsourcingChartOption = computed(() => { borderWidth: 0 }, label: { - show: true, - position: 'center', - formatter: () => { - return `${outsourcingTotal.value}\n外协人员总数` - }, - fontSize: 16, - fontWeight: 'bold', - color: '#333' + show: false }, emphasis: { label: { show: true, - fontSize: 18, + fontSize: 14, fontWeight: 'bold' } }, @@ -595,40 +611,29 @@ const outsourcingChartOption = computed(() => { // 风险管理环形图配置 const riskChartOption = computed(() => { - const chartData = riskDistribution.value - .filter(item => item.count > 0) // 只显示有数据的风险等级 - .map(item => ({ - value: item.count, - name: item.level, - itemStyle: { color: item.color } - })) - - // 如果没有数据,显示空状态 - if (chartData.length === 0 || riskTotal.value === 0) { - return { - tooltip: { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, - series: [{ - name: '风险', - type: 'pie', - radius: ['55%', '75%'], - center: ['50%', '50%'], - avoidLabelOverlap: false, - itemStyle: { borderRadius: 0, borderColor: 'transparent', borderWidth: 0 }, - label: { - show: true, - position: 'center', - formatter: () => `${riskTotal.value}\n风险总数`, - fontSize: 16, - fontWeight: 'bold', - color: '#333' - }, - data: [{ value: 1, name: '暂无数据', itemStyle: { color: '#e5e7eb' } }] - }] - } - } - + const chartData = riskDistribution.value.map(item => ({ + value: item.count, + name: item.level, + itemStyle: { color: item.color } + })) + return { tooltip: { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, + graphic: [ + { + type: 'text', + left: 'center', + top: 'center', + style: { + text: `${riskTotal.value}\n风险总数`, + fontSize: 16, + fontWeight: 'bold', + fill: '#333', + textAlign: 'center', + textVerticalAlign: 'middle' + } + } + ], series: [{ name: '风险', type: 'pie', @@ -638,13 +643,51 @@ const riskChartOption = computed(() => { itemStyle: { borderRadius: 0, borderColor: 'transparent', borderWidth: 0 }, label: { show: true, - position: 'center', - formatter: () => `${riskTotal.value}\n风险总数`, - fontSize: 16, - fontWeight: 'bold', + alignTo: 'edge', + formatter: (params: any) => { + const value = Number(params.value) || 0 + const total = Number(riskTotal.value) || 0 + if (total === 0) { + return '0%' + } + const percent = ((value / total) * 100).toFixed(2) + '%' + return percent + }, + minMargin: 5, + edgeDistance: 10, + lineHeight: 15, + fontSize: 12, color: '#333' }, - emphasis: { label: { show: true, fontSize: 18, fontWeight: 'bold' } }, + labelLine: { + show: true, + length: 15, + length2: 10, + maxSurfaceAngle: 80 + }, + labelLayout: function (params: any) { + const isLeft = params.labelRect.x < params.labelRect.width + const points = params.labelLinePoints + if (points && points.length >= 3) { + // 调整线条的终点位置 + if (isLeft) { + points[2][0] = params.labelRect.x + } else { + points[2][0] = params.labelRect.x + params.labelRect.width + } + return { + labelLinePoints: points + } + } + return {} + }, + emphasis: { + label: { + show: true, + fontSize: 14, + fontWeight: 'bold' + } + }, data: chartData }] } @@ -783,6 +826,21 @@ const highRiskChartOption = computed(() => { if (chartData.length === 0 || highRiskTotal.value === 0) { return { tooltip: { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, + graphic: [ + { + type: 'text', + left: 'center', + top: 'center', + style: { + text: `${highRiskTotal.value}\n累计作业`, + fontSize: 15, + fontWeight: 'bold', + fill: '#333', + textAlign: 'center', + textVerticalAlign: 'middle' + } + } + ], series: [{ name: '高危作业', type: 'pie', @@ -791,12 +849,7 @@ const highRiskChartOption = computed(() => { avoidLabelOverlap: false, itemStyle: { borderRadius: 0, borderColor: 'transparent', borderWidth: 0 }, label: { - show: true, - position: 'center', - formatter: () => `${highRiskTotal.value}\n累计作业`, - fontSize: 15, - fontWeight: 'bold', - color: '#333' + show: false }, data: [{ value: 1, name: '暂无数据', itemStyle: { color: '#e5e7eb' } }] }] @@ -805,6 +858,21 @@ const highRiskChartOption = computed(() => { return { tooltip: { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, + graphic: [ + { + type: 'text', + left: 'center', + top: 'center', + style: { + text: `${highRiskTotal.value}\n累计作业`, + fontSize: 15, + fontWeight: 'bold', + fill: '#333', + textAlign: 'center', + textVerticalAlign: 'middle' + } + } + ], series: [{ name: '高危作业', type: 'pie', @@ -813,14 +881,9 @@ const highRiskChartOption = computed(() => { avoidLabelOverlap: false, itemStyle: { borderRadius: 0, borderColor: 'transparent', borderWidth: 0 }, label: { - show: true, - position: 'center', - formatter: () => `${highRiskTotal.value}\n累计作业`, - fontSize: 15, - fontWeight: 'bold', - color: '#333' + show: false }, - emphasis: { label: { show: true, fontSize: 20, fontWeight: 'bold' } }, + emphasis: { label: { show: true, fontSize: 16, fontWeight: 'bold' } }, data: chartData }] } @@ -1002,10 +1065,6 @@ const navigateToModule = (path: string): void => { router.push(path) } -const openRegionSelector = (): void => { - regionSelectorVisible.value = true -} - const onRegionChange = (item: RegionItem): void => { selectedRegion.value = item.name router.push({ @@ -1030,28 +1089,6 @@ const refreshData = async () => { initData() } -// 初始化区域数据 -const initRegionData = async () => { - try { - const { records } = await getTableList('park_info_list') - if (records && records.length > 0) { - // 去重region字段,使用Map来确保唯一性 - const regionMap = new Map() - records.forEach((el: any) => { - if (!regionMap.has(el.region)) { - regionMap.set(el.region, { - name: el.region, - code: el.region_id - }) - } - }) - // 转换为数组 - regionOption.value = Array.from(regionMap.values()) - } - } catch (error) { - console.error('初始化区域数据失败:', error) - } -} // 初始化风险管理数据 const initRiskData = async () => { @@ -1108,10 +1145,10 @@ const initRiskData = async () => { // 处理风险等级分布数据(用于环形图) const allLevels = [ - { key: '低', level: '低风险', count: 0, percent: '0%', color: '#10b981' }, - { key: '一般', level: '一般风险', count: 0, percent: '0%', color: '#f59e0b' }, - { key: '较大', level: '较大风险', count: 0, percent: '0%', color: '#ef4444' }, - { key: '重大', level: '重大风险', count: 0, percent: '0%', color: '#dc2626' } + { key: '低', level: '低风险', count: 0, percent: '0%', color: '#117cee' }, + { key: '一般', level: '一般风险', count: 0, percent: '0%', color: '#fbde28' }, + { key: '较大', level: '较大风险', count: 0, percent: '0%', color: '#ed740c' }, + { key: '重大', level: '重大风险', count: 0, percent: '0%', color: '#df2a3f' } ] riskDistribution.value = allLevels.map(defaultItem => { @@ -1150,10 +1187,10 @@ const initRiskData = async () => { // 如果没有数据,设置为默认值 riskTotal.value = 0 riskDistribution.value = [ - { level: '低风险', count: 0, percent: '0%', color: '#10b981' }, - { level: '一般风险', count: 0, percent: '0%', color: '#f59e0b' }, - { level: '较大风险', count: 0, percent: '0%', color: '#ef4444' }, - { level: '重大风险', count: 0, percent: '0%', color: '#dc2626' } + { level: '低风险', count: 0, percent: '0%', color: '#117cee' }, + { level: '一般风险', count: 0, percent: '0%', color: '#fbde28' }, + { level: '较大风险', count: 0, percent: '0%', color: '#ed740c' }, + { level: '重大风险', count: 0, percent: '0%', color: '#df2a3f' } ] areaRiskDistribution.value = [] console.log('风险管理无数据') @@ -1163,10 +1200,10 @@ const initRiskData = async () => { // 如果接口失败,设置为默认值 riskTotal.value = 0 riskDistribution.value = [ - { level: '低风险', count: 0, percent: '0%', color: '#10b981' }, - { level: '一般风险', count: 0, percent: '0%', color: '#f59e0b' }, - { level: '较大风险', count: 0, percent: '0%', color: '#ef4444' }, - { level: '重大风险', count: 0, percent: '0%', color: '#dc2626' } + { level: '低风险', count: 0, percent: '0%', color: '#117cee' }, + { level: '一般风险', count: 0, percent: '0%', color: '#fbde28' }, + { level: '较大风险', count: 0, percent: '0%', color: '#ed740c' }, + { level: '重大风险', count: 0, percent: '0%', color: '#df2a3f' } ] areaRiskDistribution.value = [] } @@ -1558,7 +1595,6 @@ const initTrainingData = async () => { } const initData = async () => { - await initRegionData() initOutsourcingData() initRiskData() diff --git a/src/views/Home/Index12.vue b/src/views/Home/Index12.vue index a166036..5e6f58a 100644 --- a/src/views/Home/Index12.vue +++ b/src/views/Home/Index12.vue @@ -2,15 +2,19 @@
-
- - - -
- {{ selectedRegion }} - ··· -
-
+
@@ -293,16 +297,13 @@
- -
+ + + diff --git a/src/views/screen/mainScreen.vue b/src/views/screen/mainScreen.vue index 5d13d27..a2b945d 100644 --- a/src/views/screen/mainScreen.vue +++ b/src/views/screen/mainScreen.vue @@ -2,11 +2,16 @@
-
-
集团 - ··· -
-
+

总部综合监控大屏

{{ currentDate }} @@ -41,17 +46,13 @@
- - diff --git a/src/views/screen/components/HiddenDangerPanel.vue b/src/views/screen/components/HiddenDangerPanel.vue index 5986464..b048e5b 100644 --- a/src/views/screen/components/HiddenDangerPanel.vue +++ b/src/views/screen/components/HiddenDangerPanel.vue @@ -10,11 +10,13 @@
重大 - {{ hiddenDangerData?.major || 0 }} +
+ {{ hiddenDangerData?.major || 0 }}
一般 - {{ hiddenDangerData?.general || 0 }} +
+ {{ hiddenDangerData?.general || 0 }}
@@ -30,7 +32,8 @@
- +
+
已逾期
已处理
@@ -41,7 +44,8 @@
- +
+
@@ -65,7 +69,8 @@

- {{ hiddenDangerData?.safetyIndex || 0 }} + + {{ hiddenDangerData?.safetyIndex || 0 }}
@@ -77,6 +82,7 @@ import echarts from '@/plugins/echarts' interface Props { + loading?: boolean hiddenDangerData?: { general: number major: number @@ -936,4 +942,32 @@ watch(() => props.hiddenDangerData?.top3Types, (newVal) => { .dot.blue { background-color: #3b82f6; } + +// 骨架屏动画 +.skeleton-pulse { + animation: skeleton-loading-hiddendanger 1.5s ease-in-out infinite; + background-color: #444; + border-radius: 4px; +} + +// 圆形饼图骨架屏 +.skeleton-chart-circle { + width: 120px; + height: 120px; + border-radius: 50%; + margin: 30px auto 50px auto; + background-color: #444; +} + +@keyframes skeleton-loading-hiddendanger { + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + opacity: 1; + } +} diff --git a/src/views/screen/components/HighRiskAlertPanel.vue b/src/views/screen/components/HighRiskAlertPanel.vue index cc59a32..cb588fb 100644 --- a/src/views/screen/components/HighRiskAlertPanel.vue +++ b/src/views/screen/components/HighRiskAlertPanel.vue @@ -4,29 +4,37 @@
+ + +
- {{ alertData?.total || 0 }} +
+ {{ alertData?.total || 0 }}
告警总数 - {{ alertData?.total || 0 }} +
+ {{ alertData?.total || 0 }}
已处理 - {{ alertData?.processed || 0 }} +
+ {{ alertData?.processed || 0 }}
待处理 - {{ alertData?.pending || 0 }} +
+ {{ alertData?.pending || 0 }}
处理中 - {{ alertData?.processing }} +
+ {{ alertData?.processing }}
@@ -45,7 +53,7 @@
--> - +
@@ -73,6 +81,7 @@ interface Props { alertDetails?: AlertItem[] sourceIndex?: number linkUrl?: string + loading?: boolean } // 默认值 @@ -84,7 +93,8 @@ const props = withDefaults(defineProps(), { processing: 0 }), alertDetails: () => [], - sourceIndex: 1 + sourceIndex: 1, + loading: false }) @@ -265,5 +275,104 @@ const props = withDefaults(defineProps(), { } } } + + // 骨架屏样式 + .skeleton-container { + .skeleton-tip-container { + position: relative; + width: 100%; + height: 70px; + + .skeleton-tip-image { + position: absolute; + top: -5px; + right: 10px; + z-index: 2; + + .skeleton-circle { + width: 80px; + height: 80px; + background-color: #3a3a3a; + border-radius: 50%; + } + + .skeleton-number { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 30px; + height: 20px; + background-color: #3a3a3a; + border-radius: 4px; + } + } + + .skeleton-bg { + width: 100%; + height: 70px; + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-tip-content { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + flex-direction: column; + justify-content: space-around; + padding: 8px 15px; + + .skeleton-col-item { + display: flex; + align-items: center; + gap: 8px; + + .skeleton-icon { + width: 23px; + height: 23px; + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-text { + flex: 1; + height: 16px; + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-value { + width: 40px; + height: 18px; + background-color: #3a3a3a; + border-radius: 4px; + } + } + } + } + } + + // 骨架屏动画 + .skeleton-pulse { + animation: skeleton-loading-highrisk 1.5s ease-in-out infinite; + background-color: #444; + border-radius: 4px; + } + + @keyframes skeleton-loading-highrisk { + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + opacity: 1; + } + } } diff --git a/src/views/screen/components/OverviewPanel.vue b/src/views/screen/components/OverviewPanel.vue index ce47b22..8ddf39b 100644 --- a/src/views/screen/components/OverviewPanel.vue +++ b/src/views/screen/components/OverviewPanel.vue @@ -3,7 +3,34 @@
人员管理
-
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
@@ -64,6 +91,7 @@ 各园区统计
+
@@ -74,6 +102,7 @@ import { ref, onMounted, watch, computed } from 'vue' import { rgbToHex } from '@/utils/color' interface Props { + loading?: boolean totalCount: number formalEmployeeCount: number externalStaffCount: number @@ -319,5 +348,141 @@ onMounted(() => { min-height: 17.5vh; } } + + // 骨架屏样式 + .skeleton-container { + .skeleton-card { + display: flex; + padding: 0 20px; + column-gap: 15px; + font-size: 0.8rem; + + .skeleton-left { + display: flex; + height: 12vh; + min-width: 15vw; + padding: 0 10px; + background-image: url('@/assets/imgs/total_count_card_bg.png'); + background-size: cover; + column-gap: 6px; + align-items: center; + + .skeleton-icon { + width: 33px; + height: 33px; + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-text { + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-numbers { + display: flex; + align-items: center; + gap: 2px; + font-size: 0.8rem; + + .skeleton-number { + width: 26px; + height: 50px; + background-color: #3a3a3a; + border-radius: 4px; + } + } + } + + .skeleton-right { + display: flex; + height: 12vh; + min-width: 20vw; + background-image: url('@/assets/imgs/staff_types_bg.png'); + background-position: top center; + background-size: cover; + flex-direction: column; + justify-content: center; + row-gap: 4px; + + .skeleton-item { + display: flex; + align-items: center; + column-gap: 5px; + padding: 0 10px; + + .skeleton-row { + display: flex; + align-items: center; + gap: 4px; + flex: 1; + + .skeleton-icon-small { + width: 18px; + height: 18px; + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-text { + height: 16px; + width: 60px; + background-color: #3a3a3a; + border-radius: 4px; + } + } + + .skeleton-numbers { + display: flex; + align-items: center; + gap: 2px; + font-size: 0.8rem; + + .skeleton-number-small { + width: 14px; + height: 25px; + background-color: #3a3a3a; + border-radius: 2px; + } + } + } + } + } + } + + // 骨架屏动画 + .skeleton-pulse { + animation: skeleton-loading-overview 1.5s ease-in-out infinite; + + } + + // 圆形饼图骨架屏 + .skeleton-chart-circle { + width: 120px; + height: 120px; + border-radius: 50%; + margin: 30px auto 50px auto; + background-color: #444; + } + + // 柱状图骨架屏 + // .skeleton-chart-bar { + // width: 100%; + // height: 17.5vh; + // background-color: #444; + // border-radius: 8px; + // } + + @keyframes skeleton-loading-overview { + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + opacity: 1; + } + } } diff --git a/src/views/screen/components/RiskStatisticsPanel.vue b/src/views/screen/components/RiskStatisticsPanel.vue index 5de6bf4..f43cdb6 100644 --- a/src/views/screen/components/RiskStatisticsPanel.vue +++ b/src/views/screen/components/RiskStatisticsPanel.vue @@ -9,7 +9,31 @@
-
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
{{ item.title }}
@@ -40,7 +64,7 @@
-
+
@@ -85,6 +109,7 @@ const tabCharts = ref>({ }) const props = defineProps<{ + loading?: boolean riskStatistics?: Record }>() @@ -415,5 +440,122 @@ const handleTabClick = (tab: TabType) => { // padding: 5px; // } // } + +// 骨架屏样式 +.skeleton-container { + .skeleton-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; + + .skeleton-card { + background-image: url('@/assets/images/screen/left_top_2_img.png'), + url('@/assets/images/screen/left_center_img.png'), + url('@/assets/images/screen/left_bottom_img.png'); + background-position: top center, left center, bottom center; + background-repeat: no-repeat, no-repeat, no-repeat; + background-size: 100% 90px, cover, 100% 68px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + + .skeleton-title { + width: 120px; + height: 16px; + background-color: #3a3a3a; + border-radius: 4px; + margin-bottom: 10px; + } + + .skeleton-chart { + position: relative; + width: 100px; + height: 100px; + margin-bottom: 10px; + + .skeleton-chart-circle { + width: 100%; + height: 100%; + background-color: #3a3a3a; + border-radius: 50%; + } + + .skeleton-chart-center { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + text-align: center; + + .skeleton-text-small { + width: 40px; + height: 12px; + background-color: #3a3a3a; + border-radius: 4px; + margin-bottom: 4px; + } + + .skeleton-text-large { + width: 30px; + height: 16px; + background-color: #3a3a3a; + border-radius: 4px; + } + } + } + + .skeleton-legend { + width: 100%; + + .skeleton-legend-item { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 6px; + + .skeleton-dot { + width: 8px; + height: 8px; + background-color: #3a3a3a; + border-radius: 50%; + } + + .skeleton-text { + flex: 1; + height: 12px; + background-color: #3a3a3a; + border-radius: 4px; + margin: 0 8px; + } + + .skeleton-value { + width: 20px; + height: 12px; + background-color: #3a3a3a; + border-radius: 4px; + } + } + } + } + } +} + +// 骨架屏动画 +.skeleton-pulse { + animation: skeleton-loading-riskstats 1.5s ease-in-out infinite; +} + +@keyframes skeleton-loading-riskstats { + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + opacity: 1; + } +} diff --git a/src/views/screen/components/TimeoutWorkOrderPanel.vue b/src/views/screen/components/TimeoutWorkOrderPanel.vue index 8dbbd71..860a3d2 100644 --- a/src/views/screen/components/TimeoutWorkOrderPanel.vue +++ b/src/views/screen/components/TimeoutWorkOrderPanel.vue @@ -3,17 +3,21 @@
超时工单
+ +
- {{ timeoutWorkOrders?.total || 0 }} +
+ {{ timeoutWorkOrders?.total || 0 }}
超时工单数 - {{ timeoutWorkOrders?.total || 0 }} +
+ {{ timeoutWorkOrders?.total || 0 }}
@@ -32,7 +36,7 @@ --> - + @@ -52,6 +56,7 @@ interface TimeoutWorkOrders { // Props定义 interface Props { + loading?: boolean timeoutWorkOrders?: TimeoutWorkOrders alertDetails?: AlertItem[] sourceIndex?: number @@ -247,5 +252,104 @@ const props = withDefaults(defineProps(), { } } } + + // 骨架屏样式 + .skeleton-container { + .skeleton-tip-container { + position: relative; + width: 100%; + height: 70px; + + .skeleton-tip-image { + position: absolute; + top: -5px; + right: 10px; + z-index: 2; + + .skeleton-circle { + width: 80px; + height: 80px; + background-color: #3a3a3a; + border-radius: 50%; + } + + .skeleton-number { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 30px; + height: 20px; + background-color: #3a3a3a; + border-radius: 4px; + } + } + + .skeleton-bg { + width: 100%; + height: 70px; + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-tip-content { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + flex-direction: column; + justify-content: center; + padding: 8px 15px; + + .skeleton-col-item { + display: flex; + align-items: center; + gap: 8px; + + .skeleton-icon { + width: 23px; + height: 23px; + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-text { + flex: 1; + height: 16px; + background-color: #3a3a3a; + border-radius: 4px; + } + + .skeleton-value { + width: 40px; + height: 18px; + background-color: #3a3a3a; + border-radius: 4px; + } + } + } + } + } + + // 骨架屏动画 + .skeleton-pulse { + animation: skeleton-loading-timeout 1.5s ease-in-out infinite; + background-color: #444; + border-radius: 4px; + } + + @keyframes skeleton-loading-timeout { + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + opacity: 1; + } + } } diff --git a/src/views/screen/mainScreen.vue b/src/views/screen/mainScreen.vue index 6022d15..a8bd78f 100644 --- a/src/views/screen/mainScreen.vue +++ b/src/views/screen/mainScreen.vue @@ -24,25 +24,28 @@
- -
- -
- +
@@ -100,6 +103,9 @@ const riskStatistics = ref({ }) const dangerDetail = ref() +// 加载状态 +const isFirstLoading = ref(true) + // 动画相关的状态 const isAnimating = ref(false) const animationDuration = 2000 // 动画持续时间(毫秒) @@ -332,6 +338,11 @@ onUnmounted(() => { let isFirstLoad = ref(true) // 数据初始化方法 const loadDashboardData = async (): Promise => { + // 第一次加载时显示骨架屏 + if (isFirstLoading.value) { + console.log('第一次加载,显示骨架屏'); + } + const data = await getDashboardData() if (isFirstLoad.value) { console.log('第一次加载'); @@ -340,8 +351,11 @@ const loadDashboardData = async (): Promise => { } console.log('dashboardData.value>>>>>>>>>>', dashboardData.value); - try { - // 获取总体概览数据 + // 收集所有异步请求 + const promises = [] + + // 获取总体概览数据 + promises.push( getTableList('generalTotal', query).then(generalTotal => { if (generalTotal.records && generalTotal.records.length > 0) { dashboardData.value.totalCount = Number(generalTotal.records[0].totalCount) @@ -355,13 +369,13 @@ const loadDashboardData = async (): Promise => { external: Number(dashboardData.value.externalStaffCount), visitor: Number(dashboardData.value.visitorCount) }) + }).catch(error => { + console.error('获取总体概览数据失败:', error) }) - } catch (error) { - console.error('获取总体概览数据失败:', error) - } + ) - try { - // 获取各园区统计数据 + // 获取各园区统计数据 + promises.push( getTableList('parkscreen_user_info', query).then(parkscreen_user_info => { if (parkscreen_user_info.records && parkscreen_user_info.records.length > 0) { dashboardData.value.parkStatistics = parkscreen_user_info.records.map(el => { @@ -373,13 +387,13 @@ const loadDashboardData = async (): Promise => { } }) } + }).catch(error => { + console.error('获取各园区统计数据失败:', error) }) - } catch (error) { - console.error('获取各园区统计数据失败:', error) - } + ) - try { - // 获取风险预警数据 + // 获取风险预警数据 + promises.push( getTableList('risk_alert_data', query).then(risk_alert_data => { if (risk_alert_data.records && risk_alert_data.records.length > 0) { dashboardData.value.alertData.total = risk_alert_data.records[0].total @@ -390,12 +404,10 @@ const loadDashboardData = async (): Promise => { }).catch(error => { console.error('获取风险预警数据失败:', error) }) - } catch (error) { - console.error('获取风险预警数据失败:', error) - } + ) - try { - // 获取风险预警详情数据 + // 获取风险预警详情数据 + promises.push( getTableList('risk_alert_detail', query).then(risk_alert_detail => { if (risk_alert_detail.records && risk_alert_detail.records.length > 0) { dashboardData.value.alertData.details = risk_alert_detail.records @@ -403,12 +415,10 @@ const loadDashboardData = async (): Promise => { }).catch(error => { console.error('获取风险预警详情数据失败:', error) }) - } catch (error) { - console.error('获取风险预警详情数据失败:', error) - } + ) - try { - // 获取超期工单数据 + // 获取超期工单数据 + promises.push( getTableList('timeout_work_order', query).then(timeout_work_order => { if (timeout_work_order.records && timeout_work_order.records.length >= 0) { dashboardData.value.timeoutWorkOrders.total = timeout_work_order.records.length @@ -417,180 +427,81 @@ const loadDashboardData = async (): Promise => { }).catch(error => { console.error('获取超期工单数据失败:', error) }) + ) + + // 处理风险统计和隐患数据(这些是异步的) + promises.push( + Promise.all([ + handleRiskTabChange('安全类事项'), + handleHiddenDangerPannelData(query) + ]).catch(error => { + console.error('处理风险统计和隐患数据失败:', error) + }) + ) + + // 等待所有异步操作完成 + try { + await Promise.all(promises) + console.log('所有数据加载完成') + + // 第一次加载完成后,隐藏骨架屏 + if (isFirstLoading.value) { + isFirstLoading.value = false + console.log('隐藏骨架屏') + } } catch (error) { - console.error('获取超期工单数据失败:', error) + console.error('数据加载过程中出现错误:', error) + // 即使出错也要隐藏骨架屏,避免界面一直处于加载状态 + if (isFirstLoading.value) { + isFirstLoading.value = false + } } - handleRiskTabChange('安全类事项') - handleHiddenDangerPannelData(query) - console.log('dashboardData.value>>>>>>>>>>', dashboardData.value); } -const handleHiddenDangerPannelData = (query) => { - let _data = { - flag: false, - general: 0, - major: 0, - overdue: 0, - processed: 0, - processing: 0, - pending: 0 - } +const handleHiddenDangerPannelData = async (query) => { + const promises = [] - let _data2 = { - flag: false, - general: 0, - major: 0, - overdue: 0, - processed: 0, - processing: 0, - pending: 0 - } - try { - // 获取隐患排查治理数据 + // 获取隐患排查治理数据 - 系统数据 + promises.push( getTableList('risk_level_count', query).then(res => { if (res.records && res.records.length > 0) { - _data.general = _data.general + Number(res.records[0].general_count) - _data.major = _data.major + Number(res.records[0].major_count) - // 获取隐患排查治理数据 - getTableList('risk_status_count', query).then(res => { - if (res.records && res.records.length > 0) { - // 接口返回的已经是百分比,直接使用 - const record = res.records[0] - _data.overdue = Number(record.overdueCnt) || 0 - _data.processed = Number(record.processedCnt) || 0 - _data.processing = Number(record.processingCnt) || 0 - _data.pending = 0 // 接口没有返回pending,设为0 - _data.flag = true - - console.log('risk_status_count 接口返回数据:', record) - console.log('处理后的 _data:', _data) - - _data2.flag = false - if (_data2.flag) { - // 合并数据 - console.log("请求系统和第三方成功,合并数据", _data, _data2); - let generalCnt = _data.general + _data2.general - let majorCnt = _data.major + _data2.major - dashboardData.value.hiddenDangerData.general = generalCnt - dashboardData.value.hiddenDangerData.major = majorCnt - - // 如果第三方数据也是百分比,需要合并;否则使用系统数据 - // 这里假设系统数据是百分比,第三方数据可能是数量或百分比 - let overdueCnt, processedCnt, processingCnt, pendingCnt - if (_data2.overdue > 1 || _data2.processed > 1 || _data2.processing > 1) { - // 第三方数据可能是百分比,直接使用系统数据(因为系统数据更准确) - overdueCnt = _data.overdue.toFixed(2) - processedCnt = _data.processed.toFixed(2) - processingCnt = _data.processing.toFixed(2) - pendingCnt = _data.pending.toFixed(2) - } else { - // 第三方数据可能是数量,需要计算百分比 - let totalCnt = generalCnt + majorCnt - overdueCnt = totalCnt > 0 ? ((_data.overdue + _data2.overdue) / totalCnt * 100).toFixed(2) : '0.00' - processedCnt = totalCnt > 0 ? ((_data.processed + _data2.processed) / totalCnt * 100).toFixed(2) : '0.00' - processingCnt = totalCnt > 0 ? ((_data.processing + _data2.processing) / totalCnt * 100).toFixed(2) : '0.00' - pendingCnt = totalCnt > 0 ? ((_data.pending + _data2.pending) / totalCnt * 100).toFixed(2) : '0.00' - } - - dashboardData.value.hiddenDangerData.progress = { - overdue: overdueCnt, - processed: processedCnt, - processing: processingCnt, - pending: pendingCnt, - } - console.log('合并后的 progress:', dashboardData.value.hiddenDangerData.progress) - } else { - console.log("请求系统成功,展示数据", _data, _data2); - dashboardData.value.hiddenDangerData.general = _data.general - dashboardData.value.hiddenDangerData.major = _data.major - - // 接口返回的已经是百分比,直接使用 - dashboardData.value.hiddenDangerData.progress = { - overdue: _data.overdue.toFixed(2), - processed: _data.processed.toFixed(2), - processing: _data.processing.toFixed(2), - pending: _data.pending.toFixed(2), - } - console.log('系统数据 progress:', dashboardData.value.hiddenDangerData.progress) - } - } - }) + dashboardData.value.hiddenDangerData.general = Number(res.records[0].general_count) + dashboardData.value.hiddenDangerData.major = Number(res.records[0].major_count) } - }) - - - // 获取隐患排查治理数据 - getTableList('hidden_danger_investigation', query).then(res => { + return getTableList('risk_status_count', query) + }).then(res => { if (res.records && res.records.length > 0) { - _data2.general = Number(res.records[0].general) - _data2.major = Number(res.records[0].major) - - // 安全指数另算,再起一个报表 - // dashboardData.value.hiddenDangerData.safetyIndex = res.records[0].safetyIndex - // 在这里添加获取安全指数的逻辑 - getTableList('hidden_danger_safety_index', query).then(res => { - if (res.records && res.records.length > 0) { - dashboardData.value.hiddenDangerData.safetyIndex = res.records[0].safetyIndex - } - }).catch(error => { - console.error('获取隐患排查治理数据失败:', error) - }) - - // 获取隐患排查治理处理进度数据 - getTableList('hidden_danger_process_progress', query).then(res => { - // if (res.records && res.records.length > 0) { - // _data2.flag = true - // _data2.overdue = Number(res.records[0].overdue) / 100 * (_data2.general + _data2.major) - // _data2.processed = Number(res.records[0].processed) / 100 * (_data2.general + _data2.major) - // _data2.processing = Number(res.records[0].processing) / 100 * (_data2.general + _data2.major) - // _data2.pending = Number(res.records[0].pending) / 100 * (_data2.general + _data2.major) - - // if (_data.flag) { - // console.log("请求第三方和系统成功,合并数据", _data, _data2); - // // 合并数据 - // let generalCnt = _data.general + _data2.general - // let majorCnt = _data.major + _data2.major - // dashboardData.value.hiddenDangerData.general = generalCnt - // dashboardData.value.hiddenDangerData.major = majorCnt - - // let totalCnt = generalCnt + majorCnt - // let overdueCnt = ((_data.overdue + _data2.overdue) / totalCnt * 100).toFixed(2) - // let processedCnt = ((_data.processed + _data2.processed) / totalCnt * 100).toFixed(2) - // let processingCnt = ((_data.processing + _data2.processing) / totalCnt * 100).toFixed(2) - // let pendingCnt = ((_data.pending + _data2.pending) / totalCnt * 100).toFixed(2) - // dashboardData.value.hiddenDangerData.progress = { - // overdue: overdueCnt, - // processed: processedCnt, - // processing: processingCnt, - // pending: pendingCnt, - // } - // } else { - // //显示三方数据 - // console.log("请求第三方成功,展示数据", _data, _data2); - // dashboardData.value.hiddenDangerData.general = _data2.general - // dashboardData.value.hiddenDangerData.major = _data2.major - - // dashboardData.value.hiddenDangerData.progress = { - // overdue: res.records[0].overdue, - // processed: res.records[0].processed, - // processing: res.records[0].processing, - // pending: res.records[0].pending, - // } - // } - // } - }).catch(error => { - console.error('获取隐患排查治理处理进度数据失败:', error) - }) + const record = res.records[0] + dashboardData.value.hiddenDangerData.progress = { + overdue: Number(record.overdueCnt).toFixed(2), + processed: Number(record.processedCnt).toFixed(2), + processing: Number(record.processingCnt).toFixed(2), + pending: '0.00' + } } }).catch(error => { - console.error('获取隐患排查治理数据失败:', error) + console.error('获取系统隐患数据失败:', error) }) - } catch (error) { - console.error('获取隐患排查治理数据失败:', error) - } + ) - try { - // 获取隐患排查治理TOP3类型数据 + // 获取第三方隐患排查治理数据 + promises.push( + getTableList('hidden_danger_investigation', query).then(res => { + if (res.records && res.records.length > 0) { + // 获取安全指数 + return getTableList('hidden_danger_safety_index', query) + } + }).then(res => { + if (res.records && res.records.length > 0) { + dashboardData.value.hiddenDangerData.safetyIndex = res.records[0].safetyIndex + } + }).catch(error => { + console.error('获取第三方隐患数据失败:', error) + }) + ) + + // 获取隐患排查治理TOP3类型数据 + promises.push( getTableList('hidden_danger_top', query).then(hidden_danger_top => { if (hidden_danger_top.records && hidden_danger_top.records.length > 0) { dashboardData.value.hiddenDangerData.top3Types = hidden_danger_top.records @@ -598,9 +509,9 @@ const handleHiddenDangerPannelData = (query) => { }).catch(error => { console.error('获取隐患排查治理TOP3类型数据失败:', error) }) - } catch (error) { - console.error('获取隐患排查治理TOP3类型数据失败:', error) - } + ) + + return Promise.all(promises) } // 处理风险统计tab切换 From c7ff1047e74a99b95dbe03a25cc255c23de15c16 Mon Sep 17 00:00:00 2001 From: chenlin Date: Fri, 16 Jan 2026 13:12:03 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E5=A4=A7=E5=B1=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/screen/companyScreen.vue | 280 ++++++++++++++++++++--------- src/views/screen/mainScreen.vue | 34 ++-- src/views/screen/regionScreen.vue | 58 +++--- src/views/screen/report/index.ts | 28 +-- 4 files changed, 271 insertions(+), 129 deletions(-) diff --git a/src/views/screen/companyScreen.vue b/src/views/screen/companyScreen.vue index 7ad63e8..4b9b791 100644 --- a/src/views/screen/companyScreen.vue +++ b/src/views/screen/companyScreen.vue @@ -34,7 +34,10 @@ 总计
- +
+
+
+ {{ digit }}
@@ -47,9 +50,14 @@ 正式员工
- - {{ digit }} - +
+
+
+
+ + {{ digit }} + +
@@ -59,9 +67,14 @@ 外协人员
- - {{ digit }} - +
+
+
+
+ + {{ digit }} + +
@@ -71,9 +84,14 @@ 访客
- - {{ digit }} - +
+
+
+
+ + {{ digit }} + +
@@ -88,12 +106,14 @@
重大 - {{ +
+ {{ mockData.hiddenDangerData.severityCount }}
一般 - {{ +
+ {{ mockData.hiddenDangerData.generalCount }}
已逾期
@@ -165,7 +186,12 @@
- + --> - @@ -192,34 +218,39 @@
- {{ mockData.alertData.total }} +
+ {{ mockData.alertData.total }}
告警总数 - {{ mockData.alertData.total }} +
+ {{ mockData.alertData.total }}
已处理 - {{ mockData.alertData.processed +
+ {{ mockData.alertData.processed }}
待处理 - {{ mockData.alertData.pending +
+ {{ mockData.alertData.pending }}
处理中 - {{ mockData.alertData.processing +
+ {{ mockData.alertData.processing }}
- +
@@ -229,20 +260,30 @@
- {{ mockData.timeoutWorkOrders.total }} +
+ {{ mockData.timeoutWorkOrders.total }}
超时工单数 - {{ mockData.timeoutWorkOrders.total - }} +
+ {{ mockData.timeoutWorkOrders.total }}
- +
@@ -261,6 +302,9 @@