import test from 'node:test' import assert from 'node:assert/strict' import fs from 'node:fs' import { buildPipeNetworkStatisticsQuery, FACILITY_SECTION_LABELS, FACILITY_SECTION_TYPES, FACILITY_STATUS_TAG_TYPES, getFacilityStatusOptions, flattenStatisticMetrics, formatStatisticRow, normalizeStatisticKey, resolveDistributionValueLabel, resolveFacilitySectionLabel, resolveStatisticMetricDescription, resolveStatisticMetricLabel, resolveFacilityStatusLabel } from '../src/utils/waterFacilityStatisticsModel.js' test('statistics query mirrors dashboard and export filters', () => { assert.deepEqual( buildPipeNetworkStatisticsQuery({ facilityTypes: ['plant', 'pipe', ''], status: '1' }), { facilityTypes: 'plant,pipe', status: '1' } ) }) test('statistics status filter returns to the all-state contract', () => { assert.equal(buildPipeNetworkStatisticsQuery({ facilityTypes: ['pipe'], status: '' }).status, undefined) assert.equal(buildPipeNetworkStatisticsQuery({ facilityTypes: ['pipe'], status: null }).status, undefined) }) test('statistics query omits empty filters instead of requesting empty datasets', () => { assert.deepEqual(buildPipeNetworkStatisticsQuery(), {}) assert.deepEqual(buildPipeNetworkStatisticsQuery({ facilityTypes: ['', ' '], status: '' }), {}) }) test('statistics page prevents empty facility-type requests and export', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) assert.match(source, /buildPipeNetworkStatisticsQuery/u) assert.match(source, /:disabled="!selectedTypes\.length"/u) assert.match(source, /请至少选择一类设施/u) assert.match(source, /if \(!selectedTypes\.value\.length\)/u) }) test('statistics status filter follows the facility status contract', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) assert.match(source, /getFacilityStatusOptions/u) assert.match(source, /resolveFacilityStatusLabel/u) assert.match(source, /label="展示全部" value=""/u) assert.doesNotMatch(source, /@clear="/u) assert.match(source, /warningCount/u) assert.match(source, /unknownCount/u) }) test('statistics table uses Chinese field labels and explicit hints', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) assert.match(source, /formatStatisticRow/u) assert.match(source, /el-tooltip content="按设施类型汇总的关键统计指标"/u) assert.match(source, /el-tooltip content="当前行的统计口径和数据来源"/u) }) test('statistics status rows use the agreed unknown label', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) const model = fs.readFileSync('src/utils/waterFacilityStatisticsModel.js', 'utf8') assert.match(model, /resolveFacilityStatusLabel\(facilityType, item\.name\)/u) assert.match(source, /category === 'normal' \? '正常' : '未知'/u) assert.doesNotMatch(source, /未填报/u) }) test('statistics status filter returns to the unfiltered contract', () => { assert.deepEqual( buildPipeNetworkStatisticsQuery({ facilityTypes: ['plant'], status: null }), { facilityTypes: 'plant' } ) assert.doesNotMatch( JSON.stringify(buildPipeNetworkStatisticsQuery({ facilityTypes: ['plant'], status: '' })), /"status"/u ) }) test('facility status labels follow the per-facility-type contract', () => { assert.equal(resolveFacilityStatusLabel('source', 0), '正常') assert.equal(resolveFacilityStatusLabel('source', 1), '异常') assert.equal(resolveFacilityStatusLabel('plant', 1), '停产') assert.equal(resolveFacilityStatusLabel('pumpStation', 1), '故障停运') assert.equal(resolveFacilityStatusLabel('pumpStation', 2), '检修中') assert.equal(resolveFacilityStatusLabel('pipe', 1), '维护中') assert.equal(resolveFacilityStatusLabel('pipe', 2), '异常') assert.equal(resolveFacilityStatusLabel('user', 1), '欠费') assert.equal(resolveFacilityStatusLabel('user', 2), '停用') assert.equal(resolveFacilityStatusLabel('source', null), '未知') }) test('dashboard sections map to the shared facility status contract', () => { assert.deepEqual(FACILITY_SECTION_TYPES, { pipeNetwork: 'pipe', waterPlant: 'plant', waterSource: 'source', waterUser: 'user', pumpStation: 'pumpStation' }) assert.equal(resolveFacilityStatusLabel(FACILITY_SECTION_TYPES.waterSource, 1), '异常') assert.equal(resolveFacilityStatusLabel(FACILITY_SECTION_TYPES.waterPlant, 1), '停产') assert.equal(resolveFacilityStatusLabel(FACILITY_SECTION_TYPES.pipeNetwork, 1), '维护中') assert.equal(resolveFacilityStatusLabel(FACILITY_SECTION_TYPES.pipeNetwork, 2), '异常') assert.equal(resolveFacilityStatusLabel(FACILITY_SECTION_TYPES.waterUser, 1), '欠费') assert.deepEqual(FACILITY_SECTION_LABELS, { pipeNetwork: '管网', waterPlant: '水厂', waterSource: '水源地', waterUser: '用水户', pumpStation: '泵站' }) }) test('facility status colors follow the per-facility-type contract', () => { assert.deepEqual(FACILITY_STATUS_TAG_TYPES.source, { 0: 'success', 1: 'danger' }) assert.deepEqual(FACILITY_STATUS_TAG_TYPES.plant, { 0: 'success', 1: 'danger' }) assert.deepEqual(FACILITY_STATUS_TAG_TYPES.pumpStation, { 0: 'success', 1: 'danger', 2: 'warning' }) assert.deepEqual(FACILITY_STATUS_TAG_TYPES.pipe, { 0: 'success', 1: 'warning', 2: 'danger' }) assert.deepEqual(FACILITY_STATUS_TAG_TYPES.user, { 0: 'success', 1: 'warning', 2: 'danger' }) }) test('status options only expose values valid for selected facility types', () => { assert.deepEqual(getFacilityStatusOptions(['source']), [ { value: '0', label: '水源地: 正常' }, { value: '1', label: '水源地: 异常' } ]) assert.deepEqual(getFacilityStatusOptions(['source', 'pumpStation', 'user']), [ { value: '0', label: '正常' }, { value: '1', label: '异常 / 故障停运 / 欠费' }, { value: '2', label: '检修中 / 停用' } ]) assert.deepEqual(getFacilityStatusOptions([]), []) }) test('dashboard provides an explicit path back to the unfiltered state', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) assert.match(source, /@change="handleStatusChange"/u) assert.match(source, /statusFilter\.value = String\(value \?\? ''\)/u) }) test('changing facility types normalizes a stale status filter before loading data', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) assert.match(source, /@change="handleTypeChange"/u) assert.match( source, /const handleTypeChange = \(\) => \{\s*const options = getFacilityStatusOptions\(selectedTypes\.value\)\s*if \(!options\.some\(option => option\.value === statusFilter\.value\)\) statusFilter\.value = ''\s*loadData\(\)\s*\}/u ) }) test('statistics cards and charts use a non-overlapping technical layout', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) assert.match(source, /\.metric-icon \{\s*[^}]*position: static/u) assert.match(source, /grid-template-columns: repeat\(5, minmax\(160px, 1fr\)\)/u) assert.match(source, /radius: \['52%', '72%'\]/u) assert.doesNotMatch(source, /roseType:/u) }) test('statistics charts hide status series without data', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) const model = fs.readFileSync('src/utils/waterFacilityStatisticsModel.js', 'utf8') assert.match(source, /\.filter\(series => facilityOverview\.some\(item => Number\(item\[series\.key\] \|\| 0\) > 0\)\)/u) assert.match(model, /resolveFacilityStatusLabel\(facilityType, item\.name\)/u) assert.doesNotMatch(source, /未填报/u) }) test('statistics metric keys accept both snake_case and camelCase', () => { assert.equal(normalizeStatisticKey('total_count'), 'totalCount') assert.equal(normalizeStatisticKey('totalCount'), 'totalCount') assert.equal(normalizeStatisticKey('annual_water_consumption'), 'annualWaterConsumption') assert.equal(resolveStatisticMetricLabel('total_count'), '总数') assert.equal(resolveStatisticMetricLabel('total_length'), '总长度') assert.equal(resolveStatisticMetricLabel('average_diameter'), '平均管径') assert.equal(resolveStatisticMetricLabel('design_capacity'), '设计规模') assert.equal(resolveStatisticMetricLabel('current_capacity'), '实际规模') assert.equal(resolveStatisticMetricLabel('pump_count'), '水泵数量') assert.equal(resolveStatisticMetricLabel('design_flow'), '设计流量') assert.equal(resolveStatisticMetricLabel('design_head'), '设计扬程') assert.equal(resolveStatisticMetricLabel('power_capacity'), '装机容量') assert.equal(resolveStatisticMetricLabel('annual_water_consumption'), '年用水量') assert.equal(resolveStatisticMetricLabel('capacity_utilization'), '产能利用率') assert.equal(resolveStatisticMetricLabel('totalCount'), '总数') }) test('statistics detail table never falls back to english keys or codes', () => { assert.equal(resolveStatisticMetricLabel('unknown_metric_xyz'), '其他指标') assert.equal(resolveStatisticMetricDescription('unknown_metric_xyz'), '按当前筛选条件统计') assert.equal(resolveStatisticMetricDescription('total_length'), '当前筛选条件下的管网总长度') assert.equal(resolveFacilitySectionLabel('unknownSection'), '总览') assert.equal(resolveFacilitySectionLabel('pipeNetwork'), '管网') }) test('statistics distribution groups translate coded values', () => { assert.equal(resolveDistributionValueLabel('materialDistribution', 'PE'), '聚乙烯') assert.equal(resolveDistributionValueLabel('materialDistribution', 'PVC-U'), '硬聚氯乙烯') assert.equal(resolveDistributionValueLabel('materialDistribution', '铸铁'), '铸铁') assert.equal(resolveDistributionValueLabel('materialDistribution', null), '未填报') assert.equal(resolveDistributionValueLabel('waterSourceTypeDistribution', '地下水'), '地下水') }) test('statistics detail rows render backend payload without english text', () => { const payload = { pipeNetwork: { total_count: 996, total_length: 18819.43, average_diameter: 334.53, materialDistribution: [ { name: 'PE', value: 277, unit: '条' }, { name: '铸铁', value: 183, unit: '条' } ], statusDistribution: [{ name: '2', value: 4, unit: '条' }] }, waterPlant: { design_capacity: 5, current_capacity: 4, capacity_utilization: 80, capacityUtilization: { value: 80, unit: '%' } }, waterSource: { qualityDistribution: [{ name: 'Ⅳ类', value: 1, unit: '处' }] } } const rows = Object.entries(payload) .flatMap(([section, value]) => flattenStatisticMetrics(section, value)) .map(item => formatStatisticRow(item.section, item, { levelLabel: name => `第${name}级` })) const cells = rows.map(row => `${row.section}|${row.name}|${row.description}`).join('\n') assert.doesNotMatch(cells, /[A-Za-z]{2,}/u) assert.doesNotMatch(cells, /\bvalue\b|\bunit\b/u) assert.equal(rows.find(row => row.section === '管网 - 总数').name, '总数') assert.equal(rows.find(row => row.section === '管网 - 总长度').value, 18819.43) assert.equal(rows.find(row => row.section === '管网 - 管材分布').name, '聚乙烯') assert.equal(rows.find(row => row.section === '管网 - 管材分布').value, 277) assert.equal(rows.find(row => row.section === '管网 - 状态分布').name, '异常') assert.equal(rows.find(row => row.section === '水厂 - 产能利用率').name, '产能利用率') assert.equal(rows.find(row => row.section === '水源地 - 水质等级分布').name, 'Ⅳ类') }) test('statistics detail table uses the shared chinese label helpers', () => { const source = fs.readFileSync( 'src/views/subSystem/waterSupply/components/WaterFacilityDashboard.vue', 'utf8' ) assert.match(source, /flattenStatisticMetrics/u) assert.match(source, /formatStatisticRow\(item\.section, item, \{ levelLabel: resolveLevelLabel \}\)/u) assert.match(source, /resolveLevelLabel/u) assert.doesNotMatch(source, /STATISTIC_LABELS/u) assert.doesNotMatch(source, /\|\| rawMetricKey/u) })