本笔记只依据本地票面、领域文档、后端源码和已有测试进行静态研究。未修改后端或前端源码,未构建、运行测试、调试、访问 HTTP 或浏览器,未处理或关闭其它票。下文将“现状事实”“票面要求”“建议契约”分开,建议不是现有接口已经承诺的行为。
EMPTY 计入监测点总数与状态分布;类型/行业不可推导应保留未知,片区不可推导应为未分区。坐标未校验只决定能否上图,不决定统计资格。依据:执行票:18–24、68–73、领域文档:35–41、领域文档:91–93。coordinateVerified 改成 true,也不要从 GS/PS/RQ 编码、名称或行业猜片区。票面明确坐标来源另属票 24;真实适配器也明确无可信校核字段。依据:执行票:68–81、分布适配器:37–40。typeCode 只在关联设备类型唯一时赋值;无设备时 district=null、typeCode=null、devices=[],coordinateVerified=false。这层没有丢点。依据:分布适配器:82–115;已有测试直接断言无设备点 typeCode/district 为 null:适配器测试:78–85。SourceMonitoringPoint 已含设备事实与可空类型、可空片区,不必为 distribution 改快照构造器。响应的行业是普通 String,DeviceType 的 code/name 也不限制非空,因此可保持 industry=null、deviceType={code:null,name:null},片区由现有构造器输出 district=null,districtName="未分区"。依据:分布快照:99–125、分布响应:210–220、分布响应:299–338。EMPTY 应继续由公共状态解析器基于真实设备列表产生,空列表返回 EMPTY;无需新造点位状态或借用 freshness 的 EMPTY。依据:状态解析器:12–16。typeCode==null 判断无设备:有设备但混合类型、字典缺失也会使 typeCode 为 null。依据:分布适配器:90–111、分布服务:257–270。GAS/WATER_SUPPLY/DRAINAGE/MANHOLE 或某设备类型时未知点不匹配。district=UNASSIGNED 可包含这些点,正式片区不可包含。不要扩展 industry=UNKNOWN 请求枚举来完成本票:当前 industry 白名单只接四行业。依据:分布服务:613–633、地图服务:219–228。pointCount=1,deviceCount=0,statusCounts.empty=1,从而各分布点位数可汇总对账;不建立伪造的 SourceType/第五行业。当前 String 键桶使用 LinkedHashMap,排序已 nullsLast,Accumulator 能保存 null 名称/行业,结构允许实现;这是建议的新契约,应补测试和注释。依据:分布服务:393–408、分布服务:514–517、540–578、Accumulator:815–838。classify(type);无类型进入 UNKNOWN_TYPE,而排除量用 devices.size(),空列表加 0 后 continue,因此统计、列表、排除计数均看不到对象。非空点位也按设备数记排除,和点位 marker 按 1 计数不一致。独立设备排除则按 1。依据:分布服务:252–270、分布服务:319–334。pagination.total 现有单位是 监测点对象数 + 未关联设备对象数,不是监测点数,也不是设备数;六态总量同样同时累加这两类对象。分布行的 pointCount 只算点位,deviceCount 算点位所带设备加独立设备,statusCounts 则算对象状态而非所带设备状态。实现时必须保留这些区分。依据:分布服务:398–424、Accumulator:815–822。票面验收“excluded 各计数之和 = 总数 − 纳入数”需要随方案 A 澄清:如果坐标不可绘制对象仍纳入统计,就不能把 invalidCoordinateCount 和真正类型排除相加后解释统计差额。这是票面两个要求同时执行时的必然结论。依据:执行票:69–77、领域文档:91–93。
建议保持现有 JSON 字段,收紧其语义,不为兼容性而继续丢统计对象:
| 字段/集合 | 建议单位与含义 | 与统计集合关系 |
|---|---|---|
| unknownTypeCount / typeKindMismatchCount / nonFormalIndustryCount | 真正因类型口径不纳入的对象数,点位按点位 1,独立设备按设备 1 | 三者互斥;合法无设备未知点不计入排除 |
| invalidCoordinateCount | 已选入统计对象中 coordinateValidation.renderable=false 的对象数,点位/独立设备各按 1 |
是纳入集合子集,表示暂不上图,不再参与统计排除差额 |
| pagination.total | 全量筛后监测点数 + 全量筛后未关联设备数 | 包含暂不上图对象 |
该表为建议契约,来源是现有响应字段 Excluded:383–400、现有总量 分布服务:424–431 及领域的统计/呈现分离要求 领域文档:91–93。
建议对账公式:
P = 筛后纳入监测点(含无设备、不可上图)
U = 筛后纳入未关联设备(含不可上图)
S = |P| + |U| = pagination.total = sum(pointStatusDistribution.count)
C = count(P ∪ U 中 renderable=false) = invalidCoordinateCount
renderableObjectCount = S - C
未筛全量的合法身份候选 N = S + unknownTypeCount
+ typeKindMismatchCount + nonFormalIndustryCount
这套公式需先按编码去重且剔除“全量设备中已关联设备”,否则 N 不会是独立业务对象集合。筛选时还要区分“被用户筛掉”与“口径排除”:当前类型排除在 industry/deviceType 筛选前发生,坐标排除又在 district/status 筛选前发生,所以旧 excluded 并不是统一筛后集合;不能声称任意筛选组合下都直接满足 原始 N − pagination.total = sum(excluded)。建议最小保留前三个排除字段的全源诊断范围,把坐标诊断移动到所有业务筛选成功后计数,并明确对账全量前提;若要统一所有字段的筛后范围,需要另行定义未知类型如何匹配行业,不能静默改变。依据:分布服务:257–299、324–369。
坐标字段名称虽叫 invalidCoordinateCount,目前也包含 UNVERIFIED;验证器首先检查 verified=false,再检查缺失/越界,因此“有真实经纬度但未核验”仍返回 UNVERIFIED/UNVERIFIED_COORDINATE,不应改成合法位置,也不应改写为 EMPTY。保留名称可减少破坏,注释必须写成“不可上图诊断(包含未校验)”。依据:坐标验证器:11–31、坐标响应:3–19。
SourceMonitoringPoint(pointCode,null)。快照点位只有 pointCode/typeCode,无法单凭点位对象辨别上述三者。依据:概览适配器:75–101、概览快照:73–83。countMonitoringPoints 丢弃 type=null 或非 SMART_DEVICE,造成现网六个无设备点数量 0。它还有一项不对称:未筛行业时并未校验四个正式行业,但设备循环会校验。不能通过“删除 type 校验”把有设备但坏类型的点也全部放进来。依据:概览服务:266–292、概览服务:142–161。mapFilter.pointCodes 只来自筛后设备的 pointCode。即使只修 countMonitoringPoints,六个空点仍不会回显。响应本身已有 pointCodes,无需增加 JSON 字段。依据:概览服务:179–186、214–241、概览响应:197–213。online/(online+offline+stale),UNKNOWN 不进分母。只有点位没有设备时在线率 EMPTY/NO_RESOLVED_DEVICES 是正确的设备指标说明,不能为了总点数非零伪造在线率。依据:概览服务:186–199、227–236、概览适配器测试:103–109。hasResolved=!deviceCodes.isEmpty() 使用只在坐标通过后收集的设备集合,因此坐标未校验会被误报 NO_RESOLVED_DEVICES。坐标与统计分离后,这个问题自然消除一部分,但“有合法 EMPTY 点、确实无设备”仍会让整个点位台账 freshness=EMPTY。建议分布信封以纳入对象集合是否非空判有内容,有点位即 CURRENT/READY;没有任何统计对象仍保留 EMPTY/NO_RESOLVED_DEVICES,以减少已有空查询断言变更。依据:分布服务:277–301、444–460、分布控制器测试:250–260。type=null 不能继续调用 type.getIndustry/getCode/getName;筛选和 Marker 构造要先得到可空局部字段,并在需要明确匹配时排掉未知。这是放开 UNKNOWN_TYPE 分支的直接空指针风险。依据:分布服务:271–275、302–308。| 已有测试/来源 | 已证明什么 | T28 还需补什么 |
|---|---|---|
| 分布控制器测试:424–429、468–474 | EMPTY fixture 预先带 WATER_SUPPLY_SENSOR 且 verified=true | 真实形状:type=null、district=null、devices=[]、verified=false;必须留列表、EMPTY 桶与分页 |
| 分布适配器测试:78–85 | 适配器保留空点并输出 null 类型/片区 | 再串接 Service 验证对象不被抹掉,不能只测 adapter |
| 分布控制器测试:79–151、463–465 | 旧坐标排除契约:越界 EQ-FREE-005 不计入 total=8 | 新口径应 total=9、独立设备 4、NORMAL 2,其 GAS/片区/类型/设备回显数量同步增加;invalidCoordinateCount 仍 1 |
| 分布控制器测试:351–382 | 设备增量改变统计,旧消息/未知设备被忽略 | 越界 NORMAL 设备纳入后初始 NORMAL 从 1→2、增量后从 2→3;不要把这当成增量回归 |
| 概览控制器测试:242–263 | 所有声明点都有合法类型;没有真实空点 fixture | 6 个无设备点独立构造,断言 monitoringPointCount=6 且 pointCodes 恰含 6 编码、equipmentCount=0、设备分母=0 |
| 概览适配器测试:87–109 | 已有无设备声明点场景,但只断言设备在线率 | 加点位数量与 pointCodes 断言,避免以为已测过空点计数 |
| 概览控制器测试:128–140 | 真正空快照返回 EMPTY、在线率 0.0000 | 保留真空场景,区分“仅有 EMPTY 点”与完全无业务对象 |
建议追加的最小行为矩阵(来自本票验收 执行票:68–77 和上述实现风险):
total = 所有六态 count 之和。这些是应补/修改的测试建议,本次研究没有执行测试,不能声称测试通过。
industryLabel(...) || regionText(...),regionText 空值用未分区,这是既有展示复用造成的词义问题。不要为了规避 UI 文案就把未知点伪分配到正式行业;可向前端后续票报告,当前只读研究不修改。依据:前端行业行:507–511、行业翻译:89–92、regionText:103–105。pagination.total 显示成“监测点总数”,但后端单位实际还含独立设备;其坐标说明注释仍写“只统计可上图对象”。修复后不要借 T28 后端改动偷偷改变分页含义,记录前端消费风险即可。依据:前端总数及坐标行:546–564、后端总量:424。以上清单分别受本笔记第 2–8 节引用的源码与 T28 范围/验收 支持;不包含坐标校核来源建设、其它模式统一口径、前端展示修复或其它票处理。