Browse Source

feat(waterSupply): 首页GIS设施点位改用状态色语义并统一图例调色板

Kazerin 1 month ago
parent
commit
65a332c6ce

+ 29 - 3
src/utils/waterHomeModel.js

@@ -1,5 +1,5 @@
 import { normalizeDeviceRow } from './waterSupplyUiModel.js'
-import { getFacilityPointIcon, getMonitoringPointIcon, getMonitoringPointStatus } from './gisMapColors.js'
+import { getMonitoringPointIcon, getMonitoringPointStatus } from './gisMapColors.js'
 
 /**
  * 供水首页工作台数据模型(T05 #48)。
@@ -283,12 +283,37 @@ function hasCoordinates(point = {}) {
   return lng !== null && lat !== null
 }
 
+// 首页设施点位与设备共用状态色语义:绿-正常、红-报警/异常、蓝-工单/检修、黄-预警/欠费。
+// 管网不落点位,仅以管线呈现;状态缺失时按正常处理。
+const HOME_FACILITY_STATUS_META = {
+  source: {
+    0: { key: 'normal', text: '正常' },
+    1: { key: 'alarm', text: '异常' }
+  },
+  plant: {
+    0: { key: 'normal', text: '正常' },
+    1: { key: 'alarm', text: '停产' }
+  },
+  pumpStation: {
+    0: { key: 'normal', text: '正常' },
+    1: { key: 'alarm', text: '故障停运' },
+    2: { key: 'workOrder', text: '检修中' }
+  },
+  user: {
+    0: { key: 'normal', text: '正常' },
+    1: { key: 'warning', text: '欠费' },
+    2: { key: 'alarm', text: '停用' }
+  }
+}
+
 function normalizeHomeOverviewPoint(point, kind) {
   const lng = finiteCoordinate(point?.lng ?? point?.longitude)
   const lat = finiteCoordinate(point?.lat ?? point?.latitude)
   if (lng === null || lat === null) return null
 
   if (kind === 'facility') {
+    if (point?.type === 'pipe') return null
+    const statusMeta = HOME_FACILITY_STATUS_META[point?.type]?.[String(point?.status)] || { key: 'normal', text: '正常' }
     return {
       ...point,
       id: point?.id ?? point?.featureId,
@@ -297,8 +322,9 @@ function normalizeHomeOverviewPoint(point, kind) {
       code: point?.code || point?.facilityCode || '-',
       lng,
       lat,
-      statusKey: 'normal',
-      iconUrl: getFacilityPointIcon(point?.type),
+      statusKey: statusMeta.key,
+      statusText: statusMeta.text,
+      iconUrl: getMonitoringPointIcon({ statusKey: statusMeta.key }),
       meta: point?.road || '供水设施'
     }
   }

+ 8 - 8
src/views/subSystem/waterSupply/components/WaterSupplyHome.vue

@@ -62,11 +62,11 @@
             <div class="card-title">
               <el-icon><MapLocation /></el-icon><span>全域态势</span>
               <div class="map-legend">
-                <i class="legend-dot dot-alarm" />报警
-                <i class="legend-dot dot-workorder" />工单
-                <i class="legend-dot dot-warning" />预警
-                <i class="legend-dot dot-offline" />离线
-                <i class="legend-dot dot-normal" />正常
+                <i class="legend-dot" :style="{ background: gisPointStatusColors.alarm }" />报警/异常
+                <i class="legend-dot" :style="{ background: gisPointStatusColors.workOrder }" />工单/检修中
+                <i class="legend-dot" :style="{ background: gisPointStatusColors.warning }" />预警/欠费
+                <i class="legend-dot" :style="{ background: gisPointStatusColors.offline }" />离线
+                <i class="legend-dot" :style="{ background: gisPointStatusColors.normal }" />正常
               </div>
               <div class="panel-links">
                 <el-button link type="primary" class="panel-link" @click="goPage('/facility/gis')">设施</el-button>
@@ -104,7 +104,7 @@
                 <p>{{ overviewDetail.code }}</p>
                 <div class="status-tags">
                   <el-tag size="small" :type="gisStatusTagType(overviewDetail.statusKey)">
-                    {{ gisStatusLabel(overviewDetail.statusKey) }}
+                    {{ overviewDetail.statusText || gisStatusLabel(overviewDetail.statusKey) }}
                   </el-tag>
                   <el-tag v-if="overviewDetail.meta" size="small" type="info">{{ overviewDetail.meta }}</el-tag>
                 </div>
@@ -115,7 +115,7 @@
                   <dt>名称</dt><dd>{{ overviewDetail.name }}</dd>
                   <dt>编码</dt><dd>{{ overviewDetail.code }}</dd>
                   <dt>类别</dt><dd>{{ overviewKindLabel(overviewDetail.kind) }}</dd>
-                  <dt>状态</dt><dd>{{ gisStatusLabel(overviewDetail.statusKey) }}</dd>
+                  <dt>状态</dt><dd>{{ overviewDetail.statusText || gisStatusLabel(overviewDetail.statusKey) }}</dd>
                   <dt>类型 / 报警</dt><dd>{{ overviewDetail.meta }}</dd>
                   <dt>经度</dt><dd>{{ overviewDetail.lng }}</dd>
                   <dt>纬度</dt><dd>{{ overviewDetail.lat }}</dd>
@@ -289,7 +289,7 @@ import { getAlarmLedgerDashboard, getAlarmStats, getDeviceGisAllPoints, getDevic
 import { listWorkOrder, workOrderStatusCount } from '@/api/pipeNetwork/ops/workOrder'
 import { normalizeGeoJson, normalizePage, unwrapResponse } from '@/utils/waterSupplyModel'
 import { normalizeDeviceGisPoints } from '@/utils/waterSupplyUiModel'
-import { gisPointStatusLabels, gisPointStatusTagTypes } from '@/utils/gisMapColors'
+import { gisPointStatusColors, gisPointStatusLabels, gisPointStatusTagTypes } from '@/utils/gisMapColors'
 import { buildFacilityMapModel } from '@/utils/waterFacilityGisModel'
 import GisMapCanvas from '@/components/GisMapCanvas.vue'
 import {

+ 44 - 0
tests/waterHomeModel.test.mjs

@@ -306,6 +306,50 @@ test('home GIS overview aggregates facilities, devices and alarms with alarm pri
   assert.deepEqual(empty, { points: [], lines: [] })
 })
 
+test('home GIS facility points share device status color semantics by facility status', () => {
+  const overview = buildHomeGisOverview({
+    facilityPoints: [
+      { id: 'src-abnormal', type: 'source', name: '一水源地', lng: 110.08, lat: 28.05, status: 1 },
+      { id: 'src-normal', type: 'source', name: '二水源地', lng: 110.09, lat: 28.06, status: 0 },
+      { id: 'src-unknown', type: 'source', name: '三水源地', lng: 110.15, lat: 28.12 },
+      { id: 'plant-stopped', type: 'plant', name: '一水厂', lng: 110.1, lat: 28.07, status: 1 },
+      { id: 'pump-maintaining', type: 'pumpStation', name: '城南泵站', lng: 110.11, lat: 28.08, status: 2 },
+      { id: 'pump-fault', type: 'pumpStation', name: '城北泵站', lng: 110.12, lat: 28.09, status: 1 },
+      { id: 'user-arrears', type: 'user', name: '用水户A', lng: 110.13, lat: 28.1, status: 1 },
+      { id: 'user-stopped', type: 'user', name: '用水户B', lng: 110.14, lat: 28.11, status: 2 },
+      { id: 'pipe-point', type: 'pipe', name: '管网占位点', lng: 110.16, lat: 28.13 }
+    ]
+  })
+
+  const byId = id => overview.points.find(point => point.id === id)
+
+  assert.equal(byId('src-abnormal').statusKey, 'alarm')
+  assert.equal(byId('src-abnormal').statusText, '异常')
+  assert.match(byId('src-abnormal').iconUrl, /T_MarkPoint_Red\.png/u)
+  assert.equal(byId('src-normal').statusKey, 'normal')
+  assert.equal(byId('src-normal').statusText, '正常')
+  assert.match(byId('src-normal').iconUrl, /T_MarkPoint_Green\.png/u)
+  assert.equal(byId('src-unknown').statusKey, 'normal')
+  assert.equal(byId('src-unknown').statusText, '正常')
+
+  assert.equal(byId('plant-stopped').statusKey, 'alarm')
+  assert.equal(byId('plant-stopped').statusText, '停产')
+
+  assert.equal(byId('pump-maintaining').statusKey, 'workOrder')
+  assert.equal(byId('pump-maintaining').statusText, '检修中')
+  assert.match(byId('pump-maintaining').iconUrl, /T_MarkPoint_Blue\.png/u)
+  assert.equal(byId('pump-fault').statusKey, 'alarm')
+  assert.equal(byId('pump-fault').statusText, '故障停运')
+
+  assert.equal(byId('user-arrears').statusKey, 'warning')
+  assert.equal(byId('user-arrears').statusText, '欠费')
+  assert.match(byId('user-arrears').iconUrl, /T_MarkPoint_Yellow\.png/u)
+  assert.equal(byId('user-stopped').statusKey, 'alarm')
+  assert.equal(byId('user-stopped').statusText, '停用')
+
+  assert.equal(byId('pipe-point'), undefined)
+})
+
 test('home quick entries cover the four workbench jumps', () => {
   assert.deepEqual(HOME_QUICK_ENTRIES.map(item => item.label), ['设备异常管理', '报警管理', '报警审核', '监测报警一张图'])
   assert.ok(HOME_QUICK_ENTRIES.every(item => item.suffix.startsWith('/')))

+ 11 - 0
tests/waterSupplyHomeContract.test.mjs

@@ -78,3 +78,14 @@ test('home overview map fills the full map card body', async () => {
   assert.match(source, /\.map-panel[\s\S]{0,160}?display:\s*flex/u)
   assert.match(source, /\.map-stage[\s\S]{0,140}?flex:\s*1/u)
 })
+
+test('home overview legend and detail cover unified device and facility status colors', async () => {
+  const source = await readFile(homePath, 'utf8')
+
+  assert.match(source, /gisPointStatusColors\.alarm[\s\S]{0,20}报警\/异常/u)
+  assert.match(source, /gisPointStatusColors\.workOrder[\s\S]{0,20}工单\/检修中/u)
+  assert.match(source, /gisPointStatusColors\.warning[\s\S]{0,20}预警\/欠费/u)
+  assert.match(source, /gisPointStatusColors\.offline[\s\S]{0,20}离线/u)
+  assert.match(source, /gisPointStatusColors\.normal[\s\S]{0,20}正常/u)
+  assert.match(source, /overviewDetail\.statusText \|\| gisStatusLabel\(overviewDetail\.statusKey\)/u)
+})