@caoguo/maplibre-pipeline 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/burst/index.cjs +708 -0
  2. package/dist/burst/index.cjs.map +1 -0
  3. package/dist/burst/index.d.cts +74 -0
  4. package/dist/burst/index.d.ts +74 -0
  5. package/dist/burst/index.js +4 -0
  6. package/dist/burst/index.js.map +1 -0
  7. package/dist/burstClass-CGMjcAYy.d.cts +161 -0
  8. package/dist/burstClass-Cf2p71LE.d.ts +161 -0
  9. package/dist/chunk-CDEYJ67B.js +80 -0
  10. package/dist/chunk-CDEYJ67B.js.map +1 -0
  11. package/dist/chunk-GCDA7KJM.js +289 -0
  12. package/dist/chunk-GCDA7KJM.js.map +1 -0
  13. package/dist/chunk-GEJRE2OR.js +351 -0
  14. package/dist/chunk-GEJRE2OR.js.map +1 -0
  15. package/dist/chunk-HCT6NSNS.js +532 -0
  16. package/dist/chunk-HCT6NSNS.js.map +1 -0
  17. package/dist/chunk-HIRNJVCV.js +13 -0
  18. package/dist/chunk-HIRNJVCV.js.map +1 -0
  19. package/dist/chunk-J3AEVXT4.js +164 -0
  20. package/dist/chunk-J3AEVXT4.js.map +1 -0
  21. package/dist/chunk-QVY4WJLM.js +256 -0
  22. package/dist/chunk-QVY4WJLM.js.map +1 -0
  23. package/dist/chunk-VA2TQWL3.js +340 -0
  24. package/dist/chunk-VA2TQWL3.js.map +1 -0
  25. package/dist/chunk-YBLESEN4.js +133 -0
  26. package/dist/chunk-YBLESEN4.js.map +1 -0
  27. package/dist/chunk-YS2ICFVK.js +101 -0
  28. package/dist/chunk-YS2ICFVK.js.map +1 -0
  29. package/dist/graph/index.cjs +382 -0
  30. package/dist/graph/index.cjs.map +1 -0
  31. package/dist/graph/index.d.cts +211 -0
  32. package/dist/graph/index.d.ts +211 -0
  33. package/dist/graph/index.js +4 -0
  34. package/dist/graph/index.js.map +1 -0
  35. package/dist/health/index.cjs +348 -0
  36. package/dist/health/index.cjs.map +1 -0
  37. package/dist/health/index.d.cts +210 -0
  38. package/dist/health/index.d.ts +210 -0
  39. package/dist/health/index.js +3 -0
  40. package/dist/health/index.js.map +1 -0
  41. package/dist/index.cjs +2295 -0
  42. package/dist/index.cjs.map +1 -0
  43. package/dist/index.d.cts +10 -0
  44. package/dist/index.d.ts +10 -0
  45. package/dist/index.js +12 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/leakage/index.cjs +358 -0
  48. package/dist/leakage/index.cjs.map +1 -0
  49. package/dist/leakage/index.d.cts +212 -0
  50. package/dist/leakage/index.d.ts +212 -0
  51. package/dist/leakage/index.js +3 -0
  52. package/dist/leakage/index.js.map +1 -0
  53. package/dist/nlpg/index.cjs +136 -0
  54. package/dist/nlpg/index.cjs.map +1 -0
  55. package/dist/nlpg/index.d.cts +51 -0
  56. package/dist/nlpg/index.d.ts +51 -0
  57. package/dist/nlpg/index.js +3 -0
  58. package/dist/nlpg/index.js.map +1 -0
  59. package/dist/style/index.cjs +379 -0
  60. package/dist/style/index.cjs.map +1 -0
  61. package/dist/style/index.d.cts +119 -0
  62. package/dist/style/index.d.ts +119 -0
  63. package/dist/style/index.js +4 -0
  64. package/dist/style/index.js.map +1 -0
  65. package/dist/topology/index.cjs +317 -0
  66. package/dist/topology/index.cjs.map +1 -0
  67. package/dist/topology/index.d.cts +69 -0
  68. package/dist/topology/index.d.ts +69 -0
  69. package/dist/topology/index.js +4 -0
  70. package/dist/topology/index.js.map +1 -0
  71. package/dist/types/index.cjs +15 -0
  72. package/dist/types/index.cjs.map +1 -0
  73. package/dist/types/index.d.cts +214 -0
  74. package/dist/types/index.d.ts +214 -0
  75. package/dist/types/index.js +3 -0
  76. package/dist/types/index.js.map +1 -0
  77. package/package.json +81 -0
@@ -0,0 +1,348 @@
1
+ 'use strict';
2
+
3
+ // src/health/healthScorer.ts
4
+ var DEFAULT_WEIGHTS = {
5
+ age: 0.25,
6
+ material: 0.2,
7
+ soil: 0.15,
8
+ history: 0.2,
9
+ pressure: 0.1,
10
+ protection: 0.1
11
+ };
12
+ var MATERIAL_RISK = {
13
+ cast_iron: 0.85,
14
+ // 铸铁 = 高风险(旧管网)
15
+ ductile_iron: 0.2,
16
+ // 球墨铸铁
17
+ steel: 0.4,
18
+ pe: 0.1,
19
+ pvc: 0.15,
20
+ concrete: 0.3,
21
+ hdpe: 0.05,
22
+ copper: 0.1,
23
+ unknown: 0.5
24
+ };
25
+ function scorePipeHealth(input, weights = DEFAULT_WEIGHTS) {
26
+ const dims = {
27
+ age: scoreAge(input, weights.age),
28
+ material: scoreMaterial(input, weights.material),
29
+ soil: scoreSoil(input, weights.soil),
30
+ history: scoreHistory(input, weights.history),
31
+ pressure: scorePressure(input, weights.pressure),
32
+ protection: scoreProtection(input, weights.protection)
33
+ };
34
+ const total = dims.age.score * dims.age.weight + dims.material.score * dims.material.weight + dims.soil.score * dims.soil.weight + dims.history.score * dims.history.weight + dims.pressure.score * dims.pressure.weight + dims.protection.score * dims.protection.weight;
35
+ let final = total;
36
+ if (input.status === "damaged") final *= 0.5;
37
+ else if (input.status === "under_repair") final *= 0.7;
38
+ else if (input.status === "abandoned") final = 0;
39
+ return {
40
+ score: Math.round(final),
41
+ level: toLevel(final),
42
+ dimensions: dims
43
+ };
44
+ }
45
+ function toLevel(score) {
46
+ if (score >= 80) return "excellent";
47
+ if (score >= 60) return "good";
48
+ if (score >= 40) return "fair";
49
+ if (score >= 20) return "poor";
50
+ return "critical";
51
+ }
52
+ function scoreAge(input, weight) {
53
+ if (!input.installDate) {
54
+ return { score: 50, weight, reason: "\u672A\u77E5\u5B89\u88C5\u65E5\u671F\uFF0C\u6309\u4E2D\u7B49\u8BA1" };
55
+ }
56
+ const ageYears = (Date.now() - new Date(input.installDate).getTime()) / (365.25 * 24 * 3600 * 1e3);
57
+ if (ageYears < 0) return { score: 100, weight, reason: "\u672A\u6765\u65E5\u671F\uFF0C\u89C6\u4E3A\u4F18\u79C0" };
58
+ if (ageYears < 5) return { score: 100, weight, reason: "\u65B0\u5EFA\u7BA1\u7EBF (<5\u5E74)" };
59
+ if (ageYears < 15) return { score: 85, weight, reason: "\u8F83\u65B0 (5-15\u5E74)" };
60
+ if (ageYears < 25) return { score: 65, weight, reason: "\u4E2D\u9F84 (15-25\u5E74)" };
61
+ if (ageYears < 40) return { score: 40, weight, reason: "\u8001\u9F84 (25-40\u5E74)" };
62
+ if (ageYears < 60) return { score: 20, weight, reason: "\u8D85\u671F (>40\u5E74)" };
63
+ return { score: 5, weight, reason: "\u8D85\u671F (>60\u5E74)" };
64
+ }
65
+ function scoreMaterial(input, weight) {
66
+ if (!input.material) {
67
+ return { score: 50, weight, reason: "\u672A\u77E5\u6750\u8D28\uFF0C\u6309\u4E2D\u7B49\u8BA1" };
68
+ }
69
+ const risk = MATERIAL_RISK[input.material] ?? 0.5;
70
+ const score = Math.round((1 - risk) * 100);
71
+ const labels = {
72
+ cast_iron: "\u94F8\u94C1\uFF08\u9AD8\u98CE\u9669\uFF09",
73
+ ductile_iron: "\u7403\u58A8\u94F8\u94C1",
74
+ steel: "\u94A2",
75
+ pe: "PE\uFF08\u4F4E\u98CE\u9669\uFF09",
76
+ pvc: "PVC",
77
+ concrete: "\u6DF7\u51DD\u571F",
78
+ hdpe: "HDPE\uFF08\u6700\u4F73\uFF09",
79
+ copper: "\u94DC",
80
+ unknown: "\u672A\u77E5"
81
+ };
82
+ return {
83
+ score,
84
+ weight,
85
+ reason: labels[input.material] ?? input.material
86
+ };
87
+ }
88
+ function scoreSoil(input, weight) {
89
+ const c = input.soilCorrosion ?? 0.5;
90
+ const score = Math.round((1 - c) * 100);
91
+ return {
92
+ score,
93
+ weight,
94
+ reason: c === 0.5 && !input.soilCorrosion ? "\u65E0\u571F\u58E4\u6570\u636E\uFF0C\u6309\u5E73\u5747\u8BA1" : `\u571F\u58E4\u8150\u8680\u6307\u6570 ${c.toFixed(2)}`
95
+ };
96
+ }
97
+ function scoreHistory(input, weight) {
98
+ const fail = input.failureCount ?? 0;
99
+ if (fail === 0) return { score: 100, weight, reason: "\u5386\u53F2\u65E0\u6545\u969C" };
100
+ if (fail === 1) return { score: 75, weight, reason: "\u5386\u53F2 1 \u6B21\u6545\u969C" };
101
+ if (fail === 2) return { score: 50, weight, reason: "\u5386\u53F2 2 \u6B21\u6545\u969C" };
102
+ if (fail === 3) return { score: 25, weight, reason: "\u5386\u53F2 3 \u6B21\u6545\u969C" };
103
+ return { score: 0, weight, reason: `\u5386\u53F2 \u2265${fail} \u6B21\u6545\u969C` };
104
+ }
105
+ function scorePressure(input, weight) {
106
+ if (!input.pressure) {
107
+ return { score: 75, weight, reason: "\u65E0\u538B\u529B\u6570\u636E\uFF0C\u6309\u4E2D\u7B49\u504F\u597D\u8BA1" };
108
+ }
109
+ if (!input.ratedPressure) {
110
+ return { score: 75, weight, reason: "\u4EC5\u77E5\u5F53\u524D\u538B\u529B" };
111
+ }
112
+ const ratio = input.pressure / input.ratedPressure;
113
+ if (ratio < 0.5) return { score: 60, weight, reason: "\u538B\u529B\u504F\u4F4E (\u4F7F\u7528\u7387 <50%)" };
114
+ if (ratio < 0.8) return { score: 90, weight, reason: "\u538B\u529B\u6B63\u5E38 (\u4F7F\u7528\u7387 50-80%)" };
115
+ if (ratio < 1) return { score: 75, weight, reason: "\u538B\u529B\u504F\u9AD8 (\u4F7F\u7528\u7387 80-100%)" };
116
+ if (ratio < 1.2) return { score: 30, weight, reason: "\u538B\u529B\u8D85\u9650 (100-120%)" };
117
+ return { score: 0, weight, reason: "\u538B\u529B\u4E25\u91CD\u8D85\u9650 (>120%)" };
118
+ }
119
+ function scoreProtection(input, weight) {
120
+ if (input.hasCathodicProtection === true) {
121
+ return { score: 90, weight, reason: "\u6709\u9634\u6781\u4FDD\u62A4" };
122
+ }
123
+ if (input.hasCathodicProtection === false) {
124
+ return { score: 30, weight, reason: "\u65E0\u9634\u6781\u4FDD\u62A4" };
125
+ }
126
+ return { score: 50, weight, reason: "\u9634\u4FDD\u72B6\u6001\u672A\u77E5" };
127
+ }
128
+ function scorePipes(inputs, weights = DEFAULT_WEIGHTS) {
129
+ return inputs.map((i) => scorePipeHealth(i, weights));
130
+ }
131
+
132
+ // src/health/riskHeatmap.ts
133
+ function aggregateHeatmap(points, options = {}) {
134
+ const cell = options.cellSize ?? 500;
135
+ const agg = options.aggregation ?? "average";
136
+ if (points.length === 0) return [];
137
+ const refLat = points[0].lat;
138
+ const refLng = points[0].lng;
139
+ const mPerDegLat = 110540;
140
+ const mPerDegLng = 111320 * Math.cos(refLat * Math.PI / 180);
141
+ const grid = /* @__PURE__ */ new Map();
142
+ for (const p of points) {
143
+ const x = (p.lng - refLng) * mPerDegLng;
144
+ const y = (p.lat - refLat) * mPerDegLat;
145
+ const cx = Math.floor(x / cell);
146
+ const cy = Math.floor(y / cell);
147
+ const key = `${cx}:${cy}`;
148
+ const cur = grid.get(key);
149
+ if (!cur) {
150
+ grid.set(key, {
151
+ acc: p.healthScore,
152
+ count: 1,
153
+ minS: p.healthScore,
154
+ maxS: p.healthScore,
155
+ lng: p.lng,
156
+ lat: p.lat
157
+ });
158
+ } else {
159
+ cur.acc += p.healthScore;
160
+ cur.count += 1;
161
+ if (p.healthScore < cur.minS) cur.minS = p.healthScore;
162
+ if (p.healthScore > cur.maxS) cur.maxS = p.healthScore;
163
+ cur.lng = (cur.lng * (cur.count - 1) + p.lng) / cur.count;
164
+ cur.lat = (cur.lat * (cur.count - 1) + p.lat) / cur.count;
165
+ }
166
+ }
167
+ const cells = [];
168
+ for (const v of grid.values()) {
169
+ let score;
170
+ if (agg === "min") score = v.minS;
171
+ else if (agg === "max") score = v.maxS;
172
+ else score = v.acc / v.count;
173
+ cells.push({
174
+ lng: v.lng,
175
+ lat: v.lat,
176
+ healthScore: Math.round(score),
177
+ pipeCount: v.count
178
+ });
179
+ }
180
+ return cells;
181
+ }
182
+ function heatmapToGeoJSON(cells) {
183
+ return {
184
+ type: "FeatureCollection",
185
+ features: cells.map((c) => ({
186
+ type: "Feature",
187
+ geometry: { type: "Point", coordinates: [c.lng, c.lat] },
188
+ properties: {
189
+ healthScore: c.healthScore,
190
+ pipeCount: c.pipeCount
191
+ }
192
+ }))
193
+ };
194
+ }
195
+ function prioritizeMaintenance(pipes, topN = 10) {
196
+ return [...pipes].sort((a, b) => a.healthScore - b.healthScore).slice(0, topN);
197
+ }
198
+
199
+ // src/health/PipelineHealth.ts
200
+ var PipelineHealth = class {
201
+ map;
202
+ dataset;
203
+ cellSize;
204
+ layerPrefix;
205
+ listeners = /* @__PURE__ */ new Set();
206
+ lastResult = null;
207
+ layerIds = [];
208
+ constructor(options) {
209
+ this.map = options.map;
210
+ this.dataset = options.dataset;
211
+ this.cellSize = options.cellSize ?? 500;
212
+ this.layerPrefix = options.layerPrefix ?? "cg-health";
213
+ }
214
+ /** 评估全网管线健康度 */
215
+ evaluate(weights = DEFAULT_WEIGHTS) {
216
+ const t0 = typeof performance !== "undefined" ? performance.now() : Date.now();
217
+ const nodeById = new Map(this.dataset.nodes.map((n) => [n.id, n]));
218
+ const scores = this.dataset.pipes.map((p) => {
219
+ const input = {
220
+ installDate: p.properties?.installDate,
221
+ material: p.properties?.material,
222
+ failureCount: void 0,
223
+ pressure: p.properties?.pressure,
224
+ ratedPressure: p.properties?.ratedPressure,
225
+ hasCathodicProtection: void 0,
226
+ status: p.properties?.status
227
+ };
228
+ return { pipeId: p.id, score: scorePipeHealth(input, weights) };
229
+ });
230
+ const points = scores.flatMap((s, i) => {
231
+ const pipe = this.dataset.pipes[i];
232
+ const from = nodeById.get(pipe.fromNode);
233
+ const to = nodeById.get(pipe.toNode);
234
+ if (!from || !to) return [];
235
+ return [
236
+ {
237
+ lng: (from.lng + to.lng) / 2,
238
+ lat: (from.lat + to.lat) / 2,
239
+ healthScore: s.score.score
240
+ }
241
+ ];
242
+ });
243
+ const heatmap = aggregateHeatmap(points, { cellSize: this.cellSize });
244
+ const maintenance = prioritizeMaintenance(
245
+ scores.flatMap((s, i) => {
246
+ const pipe = this.dataset.pipes[i];
247
+ const from = nodeById.get(pipe.fromNode);
248
+ const to = nodeById.get(pipe.toNode);
249
+ if (!from || !to) return [];
250
+ return [
251
+ {
252
+ id: pipe.id,
253
+ healthScore: s.score.score,
254
+ lng: (from.lng + to.lng) / 2,
255
+ lat: (from.lat + to.lat) / 2,
256
+ label: pipe.id
257
+ }
258
+ ];
259
+ })
260
+ );
261
+ const durationMs = (typeof performance !== "undefined" ? performance.now() : Date.now()) - t0;
262
+ const result = { scores, heatmap, maintenance, durationMs };
263
+ this.lastResult = result;
264
+ this.renderHeatmap(result);
265
+ for (const l of this.listeners) l(result);
266
+ return result;
267
+ }
268
+ /** 清空图层 */
269
+ clear() {
270
+ for (const id of this.layerIds) {
271
+ this.map.removeLayer(id);
272
+ }
273
+ this.layerIds = [];
274
+ }
275
+ /** 销毁 */
276
+ destroy() {
277
+ this.clear();
278
+ this.listeners.clear();
279
+ this.lastResult = null;
280
+ }
281
+ /** 订阅结果 */
282
+ onResult(fn) {
283
+ this.listeners.add(fn);
284
+ return () => this.listeners.delete(fn);
285
+ }
286
+ /** 取最后一次结果 */
287
+ getLastResult() {
288
+ return this.lastResult;
289
+ }
290
+ renderHeatmap(result) {
291
+ this.clear();
292
+ const mlMap = this.map.instance;
293
+ const data = heatmapToGeoJSON(result.heatmap);
294
+ const sourceId = `${this.layerPrefix}-heat-src`;
295
+ const layerId = `${this.layerPrefix}-heat-point`;
296
+ if (!mlMap.getSource(sourceId)) mlMap.addSource(sourceId, data);
297
+ try {
298
+ mlMap.addLayer({
299
+ id: layerId,
300
+ type: "heatmap",
301
+ source: sourceId,
302
+ paint: {
303
+ "heatmap-weight": [
304
+ "interpolate",
305
+ ["linear"],
306
+ ["get", "healthScore"],
307
+ 0,
308
+ 1,
309
+ 50,
310
+ 0.5,
311
+ 100,
312
+ 0
313
+ ],
314
+ "heatmap-intensity": 1,
315
+ "heatmap-color": [
316
+ "interpolate",
317
+ ["linear"],
318
+ ["heatmap-density"],
319
+ 0,
320
+ "rgba(34,197,94,0)",
321
+ 0.2,
322
+ "rgba(34,197,94,0.5)",
323
+ 0.5,
324
+ "rgba(245,158,11,0.7)",
325
+ 0.8,
326
+ "rgba(239,68,68,0.8)",
327
+ 1,
328
+ "rgba(127,29,29,0.9)"
329
+ ],
330
+ "heatmap-radius": 25,
331
+ "heatmap-opacity": 0.7
332
+ }
333
+ });
334
+ this.layerIds.push(layerId);
335
+ } catch {
336
+ }
337
+ }
338
+ };
339
+
340
+ exports.DEFAULT_WEIGHTS = DEFAULT_WEIGHTS;
341
+ exports.PipelineHealth = PipelineHealth;
342
+ exports.aggregateHeatmap = aggregateHeatmap;
343
+ exports.heatmapToGeoJSON = heatmapToGeoJSON;
344
+ exports.prioritizeMaintenance = prioritizeMaintenance;
345
+ exports.scorePipeHealth = scorePipeHealth;
346
+ exports.scorePipes = scorePipes;
347
+ //# sourceMappingURL=index.cjs.map
348
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/health/healthScorer.ts","../../src/health/riskHeatmap.ts","../../src/health/PipelineHealth.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * 管线健康度评分(healthScorer)\n *\n * 6 维加权评分(PRD §4.4.2):\n * health_score = age (0.25) + material (0.20) + soil (0.15) +\n * history (0.20) + pressure (0.10) + protection (0.10)\n *\n * 每维 0-100,最终加权求和。\n * 评分模型可解释:每个维度的评分依据清晰可见。\n */\n\nimport type { PipeMaterial, PipeStatus } from '../types';\n\nexport interface PipeHealthInput {\n /** 安装日期 ISO */\n installDate?: string;\n /** 材质 */\n material?: PipeMaterial;\n /** 当前故障次数 */\n failureCount?: number;\n /** 当前压力(MPa) */\n pressure?: number;\n /** 最高允许压力(MPa) */\n ratedPressure?: number;\n /** 是否阴极保护 */\n hasCathodicProtection?: boolean;\n /** 土壤腐蚀指数 0-1(无数据时 0.5) */\n soilCorrosion?: number;\n /** 状态(damaged / under_repair 直接影响评分) */\n status?: PipeStatus;\n}\n\nexport interface PipeHealthScore {\n /** 总分 0-100 */\n score: number;\n /** 等级 */\n level: 'excellent' | 'good' | 'fair' | 'poor' | 'critical';\n /** 6 维细分 */\n dimensions: {\n age: { score: number; weight: number; reason: string };\n material: { score: number; weight: number; reason: string };\n soil: { score: number; weight: number; reason: string };\n history: { score: number; weight: number; reason: string };\n pressure: { score: number; weight: number; reason: string };\n protection: { score: number; weight: number; reason: string };\n };\n}\n\n/** 默认权重 */\nexport const DEFAULT_WEIGHTS = {\n age: 0.25,\n material: 0.2,\n soil: 0.15,\n history: 0.2,\n pressure: 0.1,\n protection: 0.1,\n};\n\nconst MATERIAL_RISK: Record<PipeMaterial, number> = {\n cast_iron: 0.85, // 铸铁 = 高风险(旧管网)\n ductile_iron: 0.2, // 球墨铸铁\n steel: 0.4,\n pe: 0.1,\n pvc: 0.15,\n concrete: 0.3,\n hdpe: 0.05,\n copper: 0.1,\n unknown: 0.5,\n};\n\n/**\n * 计算单根管线的健康度\n */\nexport function scorePipeHealth(input: PipeHealthInput, weights = DEFAULT_WEIGHTS): PipeHealthScore {\n const dims = {\n age: scoreAge(input, weights.age),\n material: scoreMaterial(input, weights.material),\n soil: scoreSoil(input, weights.soil),\n history: scoreHistory(input, weights.history),\n pressure: scorePressure(input, weights.pressure),\n protection: scoreProtection(input, weights.protection),\n };\n\n const total =\n dims.age.score * dims.age.weight +\n dims.material.score * dims.material.weight +\n dims.soil.score * dims.soil.weight +\n dims.history.score * dims.history.weight +\n dims.pressure.score * dims.pressure.weight +\n dims.protection.score * dims.protection.weight;\n\n // 损坏或维修中额外惩罚\n let final = total;\n if (input.status === 'damaged') final *= 0.5;\n else if (input.status === 'under_repair') final *= 0.7;\n else if (input.status === 'abandoned') final = 0;\n\n return {\n score: Math.round(final),\n level: toLevel(final),\n dimensions: dims,\n };\n}\n\nfunction toLevel(score: number): PipeHealthScore['level'] {\n if (score >= 80) return 'excellent';\n if (score >= 60) return 'good';\n if (score >= 40) return 'fair';\n if (score >= 20) return 'poor';\n return 'critical';\n}\n\nfunction scoreAge(input: PipeHealthInput, weight: number): PipeHealthScore['dimensions']['age'] {\n if (!input.installDate) {\n return { score: 50, weight, reason: '未知安装日期,按中等计' };\n }\n const ageYears = (Date.now() - new Date(input.installDate).getTime()) / (365.25 * 24 * 3600 * 1000);\n if (ageYears < 0) return { score: 100, weight, reason: '未来日期,视为优秀' };\n if (ageYears < 5) return { score: 100, weight, reason: '新建管线 (<5年)' };\n if (ageYears < 15) return { score: 85, weight, reason: '较新 (5-15年)' };\n if (ageYears < 25) return { score: 65, weight, reason: '中龄 (15-25年)' };\n if (ageYears < 40) return { score: 40, weight, reason: '老龄 (25-40年)' };\n if (ageYears < 60) return { score: 20, weight, reason: '超期 (>40年)' };\n return { score: 5, weight, reason: '超期 (>60年)' };\n}\n\nfunction scoreMaterial(input: PipeHealthInput, weight: number): PipeHealthScore['dimensions']['material'] {\n if (!input.material) {\n return { score: 50, weight, reason: '未知材质,按中等计' };\n }\n const risk = MATERIAL_RISK[input.material] ?? 0.5;\n const score = Math.round((1 - risk) * 100);\n const labels: Record<string, string> = {\n cast_iron: '铸铁(高风险)',\n ductile_iron: '球墨铸铁',\n steel: '钢',\n pe: 'PE(低风险)',\n pvc: 'PVC',\n concrete: '混凝土',\n hdpe: 'HDPE(最佳)',\n copper: '铜',\n unknown: '未知',\n };\n return {\n score,\n weight,\n reason: labels[input.material] ?? input.material,\n };\n}\n\nfunction scoreSoil(input: PipeHealthInput, weight: number): PipeHealthScore['dimensions']['soil'] {\n const c = input.soilCorrosion ?? 0.5;\n const score = Math.round((1 - c) * 100);\n return {\n score,\n weight,\n reason: c === 0.5 && !input.soilCorrosion ? '无土壤数据,按平均计' : `土壤腐蚀指数 ${c.toFixed(2)}`,\n };\n}\n\nfunction scoreHistory(input: PipeHealthInput, weight: number): PipeHealthScore['dimensions']['history'] {\n const fail = input.failureCount ?? 0;\n if (fail === 0) return { score: 100, weight, reason: '历史无故障' };\n if (fail === 1) return { score: 75, weight, reason: '历史 1 次故障' };\n if (fail === 2) return { score: 50, weight, reason: '历史 2 次故障' };\n if (fail === 3) return { score: 25, weight, reason: '历史 3 次故障' };\n return { score: 0, weight, reason: `历史 ≥${fail} 次故障` };\n}\n\nfunction scorePressure(input: PipeHealthInput, weight: number): PipeHealthScore['dimensions']['pressure'] {\n if (!input.pressure) {\n return { score: 75, weight, reason: '无压力数据,按中等偏好计' };\n }\n if (!input.ratedPressure) {\n return { score: 75, weight, reason: '仅知当前压力' };\n }\n const ratio = input.pressure / input.ratedPressure;\n if (ratio < 0.5) return { score: 60, weight, reason: '压力偏低 (使用率 <50%)' };\n if (ratio < 0.8) return { score: 90, weight, reason: '压力正常 (使用率 50-80%)' };\n if (ratio < 1.0) return { score: 75, weight, reason: '压力偏高 (使用率 80-100%)' };\n if (ratio < 1.2) return { score: 30, weight, reason: '压力超限 (100-120%)' };\n return { score: 0, weight, reason: '压力严重超限 (>120%)' };\n}\n\nfunction scoreProtection(input: PipeHealthInput, weight: number): PipeHealthScore['dimensions']['protection'] {\n if (input.hasCathodicProtection === true) {\n return { score: 90, weight, reason: '有阴极保护' };\n }\n if (input.hasCathodicProtection === false) {\n return { score: 30, weight, reason: '无阴极保护' };\n }\n return { score: 50, weight, reason: '阴保状态未知' };\n}\n\n/**\n * 批量评分(按需遍历)\n */\nexport function scorePipes(inputs: PipeHealthInput[], weights = DEFAULT_WEIGHTS): PipeHealthScore[] {\n return inputs.map((i) => scorePipeHealth(i, weights));\n}\n","/**\n * 风险热力图(riskHeatmap)\n *\n * 把 scorePipeHealth 输出按地理网格聚合,输出每个网格的平均分/最高风险,\n * 用于地图热力图(heat-map layer)。\n *\n * 输入:管线数组 [{ lng, lat, healthScore }]\n * 输出:GeoJSON FeatureCollection<Point>(含 healthScore 属性)\n */\n\nexport interface HeatmapCell {\n lng: number;\n lat: number;\n healthScore: number;\n /** 网格内管段数 */\n pipeCount: number;\n}\n\nexport interface PipeHealthPoint {\n lng: number;\n lat: number;\n healthScore: number;\n}\n\nexport interface RiskHeatmapOptions {\n /** 网格尺寸(m),默认 500 */\n cellSize?: number;\n /** 聚合方式 */\n aggregation?: 'average' | 'min' | 'max';\n}\n\nexport function aggregateHeatmap(\n points: PipeHealthPoint[],\n options: RiskHeatmapOptions = {}\n): HeatmapCell[] {\n const cell = options.cellSize ?? 500;\n const agg = options.aggregation ?? 'average';\n\n // 经纬度 → 米近似(以第一个点为原点)\n if (points.length === 0) return [];\n\n const refLat = points[0].lat;\n const refLng = points[0].lng;\n const mPerDegLat = 110_540;\n const mPerDegLng = 111_320 * Math.cos((refLat * Math.PI) / 180);\n\n const grid = new Map<string, { acc: number; count: number; minS: number; maxS: number; lng: number; lat: number }>();\n for (const p of points) {\n const x = (p.lng - refLng) * mPerDegLng;\n const y = (p.lat - refLat) * mPerDegLat;\n const cx = Math.floor(x / cell);\n const cy = Math.floor(y / cell);\n const key = `${cx}:${cy}`;\n const cur = grid.get(key);\n if (!cur) {\n grid.set(key, {\n acc: p.healthScore,\n count: 1,\n minS: p.healthScore,\n maxS: p.healthScore,\n lng: p.lng,\n lat: p.lat,\n });\n } else {\n cur.acc += p.healthScore;\n cur.count += 1;\n if (p.healthScore < cur.minS) cur.minS = p.healthScore;\n if (p.healthScore > cur.maxS) cur.maxS = p.healthScore;\n cur.lng = (cur.lng * (cur.count - 1) + p.lng) / cur.count;\n cur.lat = (cur.lat * (cur.count - 1) + p.lat) / cur.count;\n }\n }\n\n const cells: HeatmapCell[] = [];\n for (const v of grid.values()) {\n let score: number;\n if (agg === 'min') score = v.minS;\n else if (agg === 'max') score = v.maxS;\n else score = v.acc / v.count;\n cells.push({\n lng: v.lng,\n lat: v.lat,\n healthScore: Math.round(score),\n pipeCount: v.count,\n });\n }\n return cells;\n}\n\nexport function heatmapToGeoJSON(cells: HeatmapCell[]): GeoJSON.FeatureCollection<GeoJSON.Point> {\n return {\n type: 'FeatureCollection',\n features: cells.map((c) => ({\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [c.lng, c.lat] },\n properties: {\n healthScore: c.healthScore,\n pipeCount: c.pipeCount,\n },\n })),\n };\n}\n\n/** 优先维护建议列表(风险最高的 Top N 管线) */\nexport function prioritizeMaintenance(\n pipes: Array<{ id: string; healthScore: number; lng: number; lat: number; label?: string }>,\n topN = 10\n) {\n return [...pipes].sort((a, b) => a.healthScore - b.healthScore).slice(0, topN);\n}\n","/**\n * PipelineHealth 组件类(地图集成层)\n */\n\nimport type { Map as CaoguoMap } from '@caoguo/maplibre';\nimport { scorePipeHealth, type PipeHealthInput, type PipeHealthScore, DEFAULT_WEIGHTS } from './healthScorer';\nimport { aggregateHeatmap, heatmapToGeoJSON, type HeatmapCell, prioritizeMaintenance } from './riskHeatmap';\nimport type { PipelineTopologyDataset } from '../types';\n\nexport interface PipelineHealthOptions {\n map: CaoguoMap;\n dataset: PipelineTopologyDataset;\n cellSize?: number;\n layerPrefix?: string;\n}\n\nexport interface HealthResult {\n /** 全部管段评分 */\n scores: Array<{ pipeId: string; score: PipeHealthScore }>;\n /** 热力图聚合格 */\n heatmap: HeatmapCell[];\n /** 优先维护建议 */\n maintenance: Array<{ id: string; healthScore: number; lng: number; lat: number; label?: string }>;\n /** 计算耗时 */\n durationMs: number;\n}\n\ntype Listener = (r: HealthResult) => void;\n\n/**\n * 管线健康评估组件\n */\nexport class PipelineHealth {\n private map: CaoguoMap;\n private dataset: PipelineTopologyDataset;\n private cellSize: number;\n private layerPrefix: string;\n private listeners = new Set<Listener>();\n private lastResult: HealthResult | null = null;\n private layerIds: string[] = [];\n\n constructor(options: PipelineHealthOptions) {\n this.map = options.map;\n this.dataset = options.dataset;\n this.cellSize = options.cellSize ?? 500;\n this.layerPrefix = options.layerPrefix ?? 'cg-health';\n }\n\n /** 评估全网管线健康度 */\n evaluate(weights = DEFAULT_WEIGHTS): HealthResult {\n const t0 = (typeof performance !== 'undefined' ? performance.now() : Date.now());\n const nodeById = new Map(this.dataset.nodes.map((n) => [n.id, n] as const));\n\n const scores = this.dataset.pipes.map((p) => {\n const input: PipeHealthInput = {\n installDate: p.properties?.installDate,\n material: p.properties?.material,\n failureCount: undefined,\n pressure: p.properties?.pressure,\n ratedPressure: p.properties?.ratedPressure,\n hasCathodicProtection: undefined,\n status: p.properties?.status,\n };\n return { pipeId: p.id, score: scorePipeHealth(input, weights) };\n });\n\n const points = scores.flatMap((s, i) => {\n const pipe = this.dataset.pipes[i];\n const from = nodeById.get(pipe.fromNode);\n const to = nodeById.get(pipe.toNode);\n if (!from || !to) return [];\n return [\n {\n lng: (from.lng + to.lng) / 2,\n lat: (from.lat + to.lat) / 2,\n healthScore: s.score.score,\n },\n ];\n });\n\n const heatmap = aggregateHeatmap(points, { cellSize: this.cellSize });\n const maintenance = prioritizeMaintenance(\n scores.flatMap((s, i) => {\n const pipe = this.dataset.pipes[i];\n const from = nodeById.get(pipe.fromNode);\n const to = nodeById.get(pipe.toNode);\n if (!from || !to) return [];\n return [\n {\n id: pipe.id,\n healthScore: s.score.score,\n lng: (from.lng + to.lng) / 2,\n lat: (from.lat + to.lat) / 2,\n label: pipe.id,\n },\n ];\n })\n );\n\n const durationMs =\n (typeof performance !== 'undefined' ? performance.now() : Date.now()) - t0;\n\n const result: HealthResult = { scores, heatmap, maintenance, durationMs };\n this.lastResult = result;\n this.renderHeatmap(result);\n for (const l of this.listeners) l(result);\n return result;\n }\n\n /** 清空图层 */\n clear(): void {\n for (const id of this.layerIds) {\n this.map.removeLayer(id);\n }\n this.layerIds = [];\n }\n\n /** 销毁 */\n destroy(): void {\n this.clear();\n this.listeners.clear();\n this.lastResult = null;\n }\n\n /** 订阅结果 */\n onResult(fn: Listener): () => void {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n\n /** 取最后一次结果 */\n getLastResult(): HealthResult | null {\n return this.lastResult;\n }\n\n private renderHeatmap(result: HealthResult): void {\n this.clear();\n const mlMap = (this.map as unknown as {\n instance: {\n addSource: (id: string, source: unknown) => void;\n addLayer: (layer: unknown) => void;\n getSource: (id: string) => unknown;\n };\n }).instance;\n const data = heatmapToGeoJSON(result.heatmap);\n const sourceId = `${this.layerPrefix}-heat-src`;\n const layerId = `${this.layerPrefix}-heat-point`;\n if (!mlMap.getSource(sourceId)) mlMap.addSource(sourceId, data);\n try {\n mlMap.addLayer({\n id: layerId,\n type: 'heatmap',\n source: sourceId,\n paint: {\n 'heatmap-weight': [\n 'interpolate',\n ['linear'],\n ['get', 'healthScore'],\n 0, 1,\n 50, 0.5,\n 100, 0,\n ] as unknown,\n 'heatmap-intensity': 1,\n 'heatmap-color': [\n 'interpolate',\n ['linear'],\n ['heatmap-density'],\n 0, 'rgba(34,197,94,0)',\n 0.2, 'rgba(34,197,94,0.5)',\n 0.5, 'rgba(245,158,11,0.7)',\n 0.8, 'rgba(239,68,68,0.8)',\n 1, 'rgba(127,29,29,0.9)',\n ] as unknown,\n 'heatmap-radius': 25,\n 'heatmap-opacity': 0.7,\n },\n });\n this.layerIds.push(layerId);\n } catch {\n // ignore\n }\n }\n}\n"]}
@@ -0,0 +1,210 @@
1
+ import { PipeMaterial, PipeStatus, PipelineTopologyDataset } from '../types/index.cjs';
2
+ import { Map } from '@caoguo/maplibre';
3
+
4
+ /**
5
+ * 管线健康度评分(healthScorer)
6
+ *
7
+ * 6 维加权评分(PRD §4.4.2):
8
+ * health_score = age (0.25) + material (0.20) + soil (0.15) +
9
+ * history (0.20) + pressure (0.10) + protection (0.10)
10
+ *
11
+ * 每维 0-100,最终加权求和。
12
+ * 评分模型可解释:每个维度的评分依据清晰可见。
13
+ */
14
+
15
+ interface PipeHealthInput {
16
+ /** 安装日期 ISO */
17
+ installDate?: string;
18
+ /** 材质 */
19
+ material?: PipeMaterial;
20
+ /** 当前故障次数 */
21
+ failureCount?: number;
22
+ /** 当前压力(MPa) */
23
+ pressure?: number;
24
+ /** 最高允许压力(MPa) */
25
+ ratedPressure?: number;
26
+ /** 是否阴极保护 */
27
+ hasCathodicProtection?: boolean;
28
+ /** 土壤腐蚀指数 0-1(无数据时 0.5) */
29
+ soilCorrosion?: number;
30
+ /** 状态(damaged / under_repair 直接影响评分) */
31
+ status?: PipeStatus;
32
+ }
33
+ interface PipeHealthScore {
34
+ /** 总分 0-100 */
35
+ score: number;
36
+ /** 等级 */
37
+ level: 'excellent' | 'good' | 'fair' | 'poor' | 'critical';
38
+ /** 6 维细分 */
39
+ dimensions: {
40
+ age: {
41
+ score: number;
42
+ weight: number;
43
+ reason: string;
44
+ };
45
+ material: {
46
+ score: number;
47
+ weight: number;
48
+ reason: string;
49
+ };
50
+ soil: {
51
+ score: number;
52
+ weight: number;
53
+ reason: string;
54
+ };
55
+ history: {
56
+ score: number;
57
+ weight: number;
58
+ reason: string;
59
+ };
60
+ pressure: {
61
+ score: number;
62
+ weight: number;
63
+ reason: string;
64
+ };
65
+ protection: {
66
+ score: number;
67
+ weight: number;
68
+ reason: string;
69
+ };
70
+ };
71
+ }
72
+ /** 默认权重 */
73
+ declare const DEFAULT_WEIGHTS: {
74
+ age: number;
75
+ material: number;
76
+ soil: number;
77
+ history: number;
78
+ pressure: number;
79
+ protection: number;
80
+ };
81
+ /**
82
+ * 计算单根管线的健康度
83
+ */
84
+ declare function scorePipeHealth(input: PipeHealthInput, weights?: {
85
+ age: number;
86
+ material: number;
87
+ soil: number;
88
+ history: number;
89
+ pressure: number;
90
+ protection: number;
91
+ }): PipeHealthScore;
92
+ /**
93
+ * 批量评分(按需遍历)
94
+ */
95
+ declare function scorePipes(inputs: PipeHealthInput[], weights?: {
96
+ age: number;
97
+ material: number;
98
+ soil: number;
99
+ history: number;
100
+ pressure: number;
101
+ protection: number;
102
+ }): PipeHealthScore[];
103
+
104
+ /**
105
+ * 风险热力图(riskHeatmap)
106
+ *
107
+ * 把 scorePipeHealth 输出按地理网格聚合,输出每个网格的平均分/最高风险,
108
+ * 用于地图热力图(heat-map layer)。
109
+ *
110
+ * 输入:管线数组 [{ lng, lat, healthScore }]
111
+ * 输出:GeoJSON FeatureCollection<Point>(含 healthScore 属性)
112
+ */
113
+ interface HeatmapCell {
114
+ lng: number;
115
+ lat: number;
116
+ healthScore: number;
117
+ /** 网格内管段数 */
118
+ pipeCount: number;
119
+ }
120
+ interface PipeHealthPoint {
121
+ lng: number;
122
+ lat: number;
123
+ healthScore: number;
124
+ }
125
+ interface RiskHeatmapOptions {
126
+ /** 网格尺寸(m),默认 500 */
127
+ cellSize?: number;
128
+ /** 聚合方式 */
129
+ aggregation?: 'average' | 'min' | 'max';
130
+ }
131
+ declare function aggregateHeatmap(points: PipeHealthPoint[], options?: RiskHeatmapOptions): HeatmapCell[];
132
+ declare function heatmapToGeoJSON(cells: HeatmapCell[]): GeoJSON.FeatureCollection<GeoJSON.Point>;
133
+ /** 优先维护建议列表(风险最高的 Top N 管线) */
134
+ declare function prioritizeMaintenance(pipes: Array<{
135
+ id: string;
136
+ healthScore: number;
137
+ lng: number;
138
+ lat: number;
139
+ label?: string;
140
+ }>, topN?: number): {
141
+ id: string;
142
+ healthScore: number;
143
+ lng: number;
144
+ lat: number;
145
+ label?: string;
146
+ }[];
147
+
148
+ /**
149
+ * PipelineHealth 组件类(地图集成层)
150
+ */
151
+
152
+ interface PipelineHealthOptions {
153
+ map: Map;
154
+ dataset: PipelineTopologyDataset;
155
+ cellSize?: number;
156
+ layerPrefix?: string;
157
+ }
158
+ interface HealthResult {
159
+ /** 全部管段评分 */
160
+ scores: Array<{
161
+ pipeId: string;
162
+ score: PipeHealthScore;
163
+ }>;
164
+ /** 热力图聚合格 */
165
+ heatmap: HeatmapCell[];
166
+ /** 优先维护建议 */
167
+ maintenance: Array<{
168
+ id: string;
169
+ healthScore: number;
170
+ lng: number;
171
+ lat: number;
172
+ label?: string;
173
+ }>;
174
+ /** 计算耗时 */
175
+ durationMs: number;
176
+ }
177
+ type Listener = (r: HealthResult) => void;
178
+ /**
179
+ * 管线健康评估组件
180
+ */
181
+ declare class PipelineHealth {
182
+ private map;
183
+ private dataset;
184
+ private cellSize;
185
+ private layerPrefix;
186
+ private listeners;
187
+ private lastResult;
188
+ private layerIds;
189
+ constructor(options: PipelineHealthOptions);
190
+ /** 评估全网管线健康度 */
191
+ evaluate(weights?: {
192
+ age: number;
193
+ material: number;
194
+ soil: number;
195
+ history: number;
196
+ pressure: number;
197
+ protection: number;
198
+ }): HealthResult;
199
+ /** 清空图层 */
200
+ clear(): void;
201
+ /** 销毁 */
202
+ destroy(): void;
203
+ /** 订阅结果 */
204
+ onResult(fn: Listener): () => void;
205
+ /** 取最后一次结果 */
206
+ getLastResult(): HealthResult | null;
207
+ private renderHeatmap;
208
+ }
209
+
210
+ export { DEFAULT_WEIGHTS, type HealthResult, type HeatmapCell, type PipeHealthInput, type PipeHealthPoint, type PipeHealthScore, PipelineHealth, type PipelineHealthOptions, type RiskHeatmapOptions, aggregateHeatmap, heatmapToGeoJSON, prioritizeMaintenance, scorePipeHealth, scorePipes };