@caoguo/maplibre-pipeline 0.0.5 → 0.0.7
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.
- package/README.md +46 -18
- package/dist/burst/index.cjs.map +1 -1
- package/dist/burst/index.js +2 -2
- package/dist/{chunk-HCT6NSNS.js → chunk-2O4IXAXO.js} +3 -3
- package/dist/{chunk-HCT6NSNS.js.map → chunk-2O4IXAXO.js.map} +1 -1
- package/dist/{chunk-3656CGXE.js → chunk-33TITD2I.js} +31 -3
- package/dist/chunk-33TITD2I.js.map +1 -0
- package/dist/{chunk-QVY4WJLM.js → chunk-4HP7Q7OL.js} +6 -3
- package/dist/chunk-4HP7Q7OL.js.map +1 -0
- package/dist/{chunk-YBLESEN4.js → chunk-7LPD52KL.js} +34 -5
- package/dist/chunk-7LPD52KL.js.map +1 -0
- package/dist/{chunk-BWQKY35F.js → chunk-ASITLG37.js} +3 -3
- package/dist/{chunk-BWQKY35F.js.map → chunk-ASITLG37.js.map} +1 -1
- package/dist/{chunk-GCDA7KJM.js → chunk-XCP7XVNO.js} +5 -8
- package/dist/chunk-XCP7XVNO.js.map +1 -0
- package/dist/{chunk-YS2ICFVK.js → chunk-YB2PMLA6.js} +3 -3
- package/dist/{chunk-YS2ICFVK.js.map → chunk-YB2PMLA6.js.map} +1 -1
- package/dist/graph/index.cjs +3 -6
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +4 -0
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.js +1 -1
- package/dist/health/index.cjs +30 -0
- package/dist/health/index.cjs.map +1 -1
- package/dist/health/index.d.cts +29 -1
- package/dist/health/index.d.ts +29 -1
- package/dist/health/index.js +1 -1
- package/dist/index.cjs +68 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -7
- package/dist/nlpg/index.cjs +32 -3
- package/dist/nlpg/index.cjs.map +1 -1
- package/dist/nlpg/index.d.cts +20 -6
- package/dist/nlpg/index.d.ts +20 -6
- package/dist/nlpg/index.js +1 -1
- package/dist/style/index.cjs +4 -0
- package/dist/style/index.cjs.map +1 -1
- package/dist/style/index.d.cts +3 -1
- package/dist/style/index.d.ts +3 -1
- package/dist/style/index.js +2 -2
- package/dist/topology/index.cjs +2 -2
- package/dist/topology/index.cjs.map +1 -1
- package/dist/topology/index.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-3656CGXE.js.map +0 -1
- package/dist/chunk-GCDA7KJM.js.map +0 -1
- package/dist/chunk-QVY4WJLM.js.map +0 -1
- package/dist/chunk-YBLESEN4.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/burst/burstCore.ts","../src/burst/valvePlanner.ts","../src/burst/impactArea.ts","../src/burst/burstClass.ts"],"names":[],"mappings":"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","file":"chunk-HCT6NSNS.js","sourcesContent":["/**\n * BurstSimulator 核心算法(纯函数)\n *\n * 模拟\"故障管段\"后:\n * 1. 找所有隔离候选阀门(沿故障 pipe 任意一端 BFS,候选上、下游最近阀门)\n * 2. 至少保留:上游最近阀门 + 下游最近阀门,确保\"故障段完全与气源/水源分离\"\n * 3. 下游 BFS(同时绕过被关闭阀门)找受影响节点\n * 4. 关联受影响用户(居民/商业/工业)\n * 5. 重要用户识别(医院/学校/工厂)\n * 6. 备选供气/供水路径(Dijkstra)\n *\n * 全部为纯函数,接收数据集返回结果,可在 Node/浏览器两侧运行。\n */\n\nimport type {\n PipelineTopologyDataset,\n PipelineNode,\n PipelinePipe,\n PipelineUser,\n UserKind,\n} from '../types';\nimport {\n buildAdjacency,\n type AdjacencyList,\n haversine,\n} from '../graph/adjacency';\nimport { bfs } from '../graph/bfs';\nimport { dijkstra } from '../graph/shortestPath';\nimport { findPaths } from '../graph/connectivity';\n\n/** 阀门隔离方案 */\nexport interface ValvePlan {\n /** 需关闭的阀门(隔离故障段) */\n closeValves: PipelineNode[];\n /** 需打开的阀门(泄压/排水) */\n openValves: PipelineNode[];\n /** 备选供气/供水路径(多源时才有) */\n alternativePaths: string[][];\n /** 预计停气/停水时间字符串(如 \"2h\"、\"45min\") */\n estimatedShutdownTime: string;\n /** 隔离方案的可读摘要 */\n summary: string;\n}\n\n/** 影响区域(受影响管段的几何范围) */\nexport interface ImpactArea {\n type: 'FeatureCollection';\n features: Array<\n | { type: 'Feature'; geometry: { type: 'Point'; coordinates: [number, number] }; properties: { kind: 'node' } }\n | { type: 'Feature'; geometry: { type: 'LineString'; coordinates: [number, number][] }; properties: { kind: 'pipe' } }\n >;\n /** 凸包多边形(受影响区域外轮廓) */\n hull: [number, number][];\n}\n\nexport interface BurstSimulateOptions {\n /** 风机等扩展参数:默认按气体泄漏 */\n scenario?: 'gas' | 'water' | 'drainage' | 'heating';\n /** 是否同时禁用\"已关闭阀门\"作为隔离点(推荐 true) */\n skipClosedValves?: boolean;\n /** 最大 alternative path 数 */\n maxAlternatives?: number;\n}\n\nexport interface BurstSimulateResult {\n /** 故障管段 */\n pipe: PipelinePipe;\n /** 受影响节点列表(含故障管段两端) */\n affectedNodes: PipelineNode[];\n /** 受影响管段列表 */\n affectedPipes: PipelinePipe[];\n /** 受影响用户列表 */\n affectedUsers: PipelineUser[];\n /** 受影响用户总数 */\n affectedUserCount: number;\n /** 重要用户(医院/学校/政府) */\n importantUsers: PipelineUser[];\n /** 影响区域几何(GeoJSON FeatureCollection + 凸包) */\n impactArea: ImpactArea;\n /** 阀门隔离方案 */\n valvePlan: ValvePlan;\n /** 计算耗时(ms) */\n durationMs: number;\n}\n\n/**\n * 主入口:执行爆管推演\n */\nexport function simulateBurst(\n dataset: PipelineTopologyDataset,\n pipeId: string,\n opts: BurstSimulateOptions = {}\n): BurstSimulateResult {\n const t0 = (typeof performance !== 'undefined' ? performance.now() : Date.now());\n const scenario = opts.scenario ?? 'gas';\n const skipClosed = opts.skipClosedValves ?? true;\n const maxAlt = opts.maxAlternatives ?? 2;\n\n const pipe = dataset.pipes.find((p) => p.id === pipeId);\n if (!pipe) {\n throw new Error(`BurstSimulator: pipe '${pipeId}' not found in dataset`);\n }\n const nodeById = new Map(dataset.nodes.map((n) => [n.id, n] as const));\n const adj = buildAdjacency(dataset);\n\n // 1) 沿故障 pipe 两端都搜索最近阀门(上下游)\n const upstreamValves = findValvesFromEndpoint(adj, pipe, dataset, pipe.fromNode, skipClosed);\n const downstreamValves = findValvesFromEndpoint(adj, pipe, dataset, pipe.toNode, skipClosed);\n // 合并(按距离排序去重)\n const candidateClose = mergeCandidateValves(upstreamValves, downstreamValves);\n\n // 2) 下游 BFS(PRD step 2):跳过关闭的阀门\n const closedSet = new Set(candidateClose.map((v) => v.id));\n const downstream = bfs(adj, pipe.toNode, {\n allowEdge: (_e, _f, to) => {\n if (closedSet.has(to)) return false;\n return true;\n },\n maxDepth: 1_000,\n });\n\n const affectedSet = new Set(downstream.visited);\n // 故障 pipe from/to 节点也要纳入受影响范围(事件源)\n affectedSet.add(pipe.fromNode);\n\n const affectedNodes: PipelineNode[] = [];\n for (const id of affectedSet) {\n const n = nodeById.get(id);\n if (n) affectedNodes.push(n);\n }\n\n // 受影响管段:所有至少一端在 affectedNodes 的管段\n const affectedPipes: PipelinePipe[] = dataset.pipes.filter(\n (p) => affectedSet.has(p.fromNode) || affectedSet.has(p.toNode)\n );\n\n // 3) 查询受影响用户\n const users = dataset.users ?? [];\n const affectedUsers = users.filter((u) => {\n if (!u.nodeId) return false;\n return affectedSet.has(u.nodeId);\n });\n const importantUsers = affectedUsers.filter((u) => u.kind === 'important');\n\n // 4) 影响区域几何\n const impactArea = computeImpactArea(affectedNodes, affectedPipes);\n\n // 5) 阀门隔离方案\n const valvePlan = buildValvePlan(\n adj,\n dataset,\n pipe,\n candidateClose,\n affectedNodes,\n maxAlt,\n scenario\n );\n\n const durationMs = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - t0;\n return {\n pipe,\n affectedNodes,\n affectedPipes,\n affectedUsers,\n affectedUserCount: affectedUsers.length,\n importantUsers,\n impactArea,\n valvePlan,\n durationMs,\n };\n}\n\n// ============================================================\n// 内部辅助\n// ============================================================\n\ninterface ValveCandidate {\n node: PipelineNode;\n /** 距起点跳数 */\n hops: number;\n /** 距起点物理距离 */\n distance: number;\n /** 来源端 fromNode/toNode */\n endpoint: 'from' | 'to';\n}\n\n/** 从指定端点出发 BFS,沿拓扑找最近的阀门\n *\n * 关键规则:\n * - 端点本身如果是阀门 → 直接作为最近阀门返回,不再扩展\n * - 否则 BFS 找最近的阀门(找到立即停止)\n */\nfunction findValvesFromEndpoint(\n adj: AdjacencyList,\n pipe: PipelinePipe,\n dataset: PipelineTopologyDataset,\n startId: string,\n skipClosed: boolean\n): ValveCandidate[] {\n const faultPipeId = pipe.id;\n const nodeById = new Map(dataset.nodes.map((n) => [n.id, n] as const));\n const out: ValveCandidate[] = [];\n const endpoint = startId === pipe.fromNode ? 'from' : 'to';\n\n const startNode = nodeById.get(startId);\n if (!startNode) return [];\n\n // 0) 端点本身就是阀门 → 立即返回\n if (startNode.kind === 'valve') {\n if (!skipClosed || startNode.properties?.valveStatus !== 'closed') {\n out.push({ node: startNode, hops: 0, distance: 0, endpoint });\n }\n return out;\n }\n\n // 1) 否则 BFS 找最近的阀门\n const visited = new Set<string>();\n const queue: Array<{ id: string; hops: number; dist: number }> = [\n { id: startId, hops: 0, dist: 0 },\n ];\n\n while (queue.length > 0) {\n const cur = queue.shift()!;\n if (visited.has(cur.id)) continue;\n visited.add(cur.id);\n\n const n = nodeById.get(cur.id);\n if (!n) continue;\n\n if (n.kind === 'valve' && (!skipClosed || n.properties?.valveStatus !== 'closed')) {\n out.push({ node: n, hops: cur.hops, distance: cur.dist, endpoint });\n return out; // 找最近的,返回\n }\n\n const edges = adj.get(cur.id) ?? [];\n for (const e of edges) {\n if (e.pipeId === faultPipeId) continue;\n if (visited.has(e.to)) continue;\n queue.push({\n id: e.to,\n hops: cur.hops + 1,\n dist: cur.dist + (e.length || 0),\n });\n }\n }\n\n return out;\n}\n\n/** 合并上下游阀门候选(按距离排重) */\nfunction mergeCandidateValves(\n upstream: ValveCandidate[],\n downstream: ValveCandidate[]\n): PipelineNode[] {\n const seen = new Set<string>();\n const all = [...upstream, ...downstream].sort((a, b) => a.distance - b.distance);\n const out: PipelineNode[] = [];\n for (const c of all) {\n if (seen.has(c.node.id)) continue;\n seen.add(c.node.id);\n out.push(c.node);\n }\n return out;\n}\n\n/**\n * 构造影响区域\n * - features: 受影响节点(Point) + 受影响管段(LineString)\n * - hull: 节点集的凸包(用于地图高亮\"受影响地理范围\")\n */\nfunction computeImpactArea(\n nodes: PipelineNode[],\n pipes: PipelinePipe[]\n): ImpactArea {\n const features: ImpactArea['features'] = [];\n const nodeById = new Map(nodes.map((n) => [n.id, n] as const));\n\n for (const n of nodes) {\n features.push({\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [n.lng, n.lat] },\n properties: { kind: 'node' },\n });\n }\n for (const p of pipes) {\n let coords: [number, number][] = [];\n if (p.geometry && p.geometry.length >= 2) {\n coords = p.geometry as [number, number][];\n } else {\n const from = nodeById.get(p.fromNode);\n const to = nodeById.get(p.toNode);\n if (from && to) coords = [[from.lng, from.lat], [to.lng, to.lat]];\n }\n if (coords.length >= 2) {\n features.push({\n type: 'Feature',\n geometry: { type: 'LineString', coordinates: coords },\n properties: { kind: 'pipe' },\n });\n }\n }\n\n const hull = convexHull(nodes.map((n) => [n.lng, n.lat] as [number, number]));\n\n return { type: 'FeatureCollection', features, hull };\n}\n\n/**\n * 构造阀门隔离方案\n */\nfunction buildValvePlan(\n adj: AdjacencyList,\n dataset: PipelineTopologyDataset,\n pipe: PipelinePipe,\n closeValves: PipelineNode[],\n _affectedNodes: PipelineNode[],\n maxAlt: number,\n scenario: string\n): ValvePlan {\n const closeSet = new Set(closeValves.map((v) => v.id));\n\n // 找泄压点:受影响区域内\"开放\"且\"不在关闭列表\"的阀门\n const openValves: PipelineNode[] = [];\n for (const n of _affectedNodes) {\n if (n.kind !== 'valve') continue;\n if (closeSet.has(n.id)) continue;\n if (n.properties?.valveStatus !== 'open') continue;\n const from = dataset.nodes.find((m) => m.id === pipe.fromNode);\n const to = dataset.nodes.find((m) => m.id === pipe.toNode);\n if (!from || !to) continue;\n const d1 = haversine(n.lng, n.lat, from.lng, from.lat);\n const d2 = haversine(n.lng, n.lat, to.lng, to.lat);\n if (Math.min(d1, d2) < 1000) openValves.push(n);\n }\n\n // 备选路径:从关闭阀门出发 → 其它 source(隔离后备用气源/水源)\n const alternativePaths: string[][] = [];\n if (closeValves.length) {\n const sources = dataset.nodes.filter((n) => n.kind === 'source');\n for (const s of sources) {\n // 选最接近关闭阀门的 source 寻路(确保目标非 closed 阀门)\n const r = dijkstra(adj, closeValves[0].id, s.id, {\n weight: (e) => (closeSet.has(e.to) ? Infinity : e.length || 1),\n });\n if (r.found) {\n const paths = findPaths(adj, closeValves[0].id, s.id, {\n maxPaths: maxAlt,\n maxDepth: 20,\n });\n for (const p of paths) alternativePaths.push(p);\n break;\n }\n }\n }\n\n // 估算停气/停水时间(基于受影响用户数和场景)\n const userCount = (dataset.users ?? []).filter((u) =>\n _affectedNodes.some((n) => n.id === u.nodeId)\n ).length;\n const baseHours = userCount / 200;\n const scenarioFactor = scenario === 'water' ? 1.5 : scenario === 'heating' ? 2 : 1;\n const hours = Math.max(0.5, Math.min(8, baseHours * scenarioFactor));\n const estimatedShutdownTime = hours >= 1 ? `${hours.toFixed(1)}h` : `${Math.round(hours * 60)}min`;\n\n const summary = buildSummary(closeValves, openValves, userCount, scenario);\n\n return {\n closeValves,\n openValves,\n alternativePaths,\n estimatedShutdownTime,\n summary,\n };\n}\n\nfunction buildSummary(\n closeValves: PipelineNode[],\n openValves: PipelineNode[],\n userCount: number,\n scenario: string\n): string {\n const labels: Record<string, string> = {\n gas: '停气',\n water: '停水',\n drainage: '排水中断',\n heating: '停热',\n };\n const label = labels[scenario] ?? '受影响';\n const parts: string[] = [];\n parts.push(`预计${label}${userCount}户`);\n if (closeValves.length) {\n parts.push(`关闭阀门 ${closeValves.map((v) => v.properties?.code ?? v.id).join(', ')}`);\n } else {\n parts.push('未找到上游隔离阀门(建议人工指定)');\n }\n if (openValves.length) {\n parts.push(`打开阀门 ${openValves.map((v) => v.properties?.code ?? v.id).join(', ')}(泄压)`);\n }\n return parts.join(';');\n}\n\n// ============================================================\n// 凸包(Andrew's monotone chain,O(n log n))\n// ============================================================\n\n/** Andrew's monotone chain,返回逆时针凸包顶点(首尾不重复) */\nexport function convexHull(points: [number, number][]): [number, number][] {\n if (points.length < 3) return [...points];\n const pts = [...points];\n pts.sort((a, b) => (a[0] - b[0]) || (a[1] - b[1]));\n\n const cross = (\n o: [number, number],\n a: [number, number],\n b: [number, number]\n ): number => (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);\n\n const lower: [number, number][] = [];\n for (const p of pts) {\n while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], p) <= 0) {\n lower.pop();\n }\n lower.push(p);\n }\n const upper: [number, number][] = [];\n for (let i = pts.length - 1; i >= 0; i--) {\n const p = pts[i];\n while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], p) <= 0) {\n upper.pop();\n }\n upper.push(p);\n }\n upper.pop();\n lower.pop();\n return lower.concat(upper);\n}\n\n/** 用户严重程度打分(用于\"优先通告\"列表) */\nexport function userSeverity(kind: UserKind, scale = 1): number {\n const base: Record<UserKind, number> = {\n important: 100,\n industrial: 50,\n commercial: 20,\n residential: 1,\n };\n return (base[kind] ?? 1) * (scale ?? 1);\n}\n","/**\n * 阀门规划(valve planner)\n *\n * 在已知故障管段的前提下,候选出最优的\"关闭+打开\"组合。\n * 评估指标:\n * - 隔离完整性:关闭阀门后故障段必须与气源/水源完全分离\n * - 影响最小:关闭数量最小,受影响用户最少\n * - 操作便利:按操作顺序列出阀门编号\n */\n\nimport type { PipelineNode, PipelineTopologyDataset, PipelinePipe } from '../types';\nimport { buildAdjacency, type AdjacencyList } from '../graph/adjacency';\nimport { bfs } from '../graph/bfs';\nimport { dijkstra } from '../graph/shortestPath';\n\nexport interface CandidateValveSet {\n valves: PipelineNode[];\n /** 完整性:关闭后故障段到最近 source 的最短距离(Infinity = 完全隔离) */\n isolationCompleteness: number;\n /** 受影响用户数(关闭阀门后的下游覆盖) */\n impactUserCount: number;\n /** 阀门操作顺序(按节点编号字典序,仅辅助) */\n operationOrder: string[];\n}\n\nexport interface PlannerOptions {\n /** 最大候选组合数(指数爆炸时截断) */\n maxCombinations?: number;\n /** 阀门过滤:仅考虑状态/类型匹配的 */\n filter?: (valve: PipelineNode) => boolean;\n}\n\n/**\n * 列出上游候选阀门(沿故障 pipe 两端 BFS 找到的所有阀门,按距离排序)\n */\nexport function listCandidateValves(\n dataset: PipelineTopologyDataset,\n pipeId: string,\n filter?: (valve: PipelineNode) => boolean\n): PipelineNode[] {\n const pipe = dataset.pipes.find((p) => p.id === pipeId);\n if (!pipe) return [];\n const nodeById = new Map(dataset.nodes.map((n) => [n.id, n] as const));\n const adj = buildAdjacency(dataset);\n\n const visited = new Set<string>();\n const valveCandidates: Array<{ n: PipelineNode; dist: number }> = [];\n\n for (const startId of [pipe.fromNode, pipe.toNode]) {\n const queue: Array<{ id: string; d: number }> = [{ id: startId, d: 0 }];\n while (queue.length > 0) {\n const { id, d } = queue.shift()!;\n if (visited.has(id)) continue;\n visited.add(id);\n\n const n = nodeById.get(id);\n if (!n) continue;\n // 端点本身如果是阀门, 也算候选\n if (n.kind === 'valve' && (!filter || filter(n))) {\n valveCandidates.push({ n, dist: d });\n // 第一个阀门已找到, 不必继续扩展 (但允许从端点继续找其它)\n if (d > 0) continue;\n }\n\n const edges = adj.get(id) ?? [];\n for (const e of edges) {\n if (e.pipeId === pipeId) continue; // 不穿过故障 pipe\n if (visited.has(e.to)) continue;\n queue.push({ id: e.to, d: d + 1 });\n }\n }\n }\n\n valveCandidates.sort((a, b) => a.dist - b.dist);\n return valveCandidates.map((v) => v.n);\n}\n\n/**\n * 评估某组阀门关闭后的隔离完整性与受影响用户数\n */\nexport function evaluateValvePlan(\n dataset: PipelineTopologyDataset,\n pipeId: string,\n valvesToClose: PipelineNode[]\n): CandidateValveSet {\n const pipe = dataset.pipes.find((p) => p.id === pipeId);\n if (!pipe) {\n return {\n valves: valvesToClose,\n isolationCompleteness: Infinity,\n impactUserCount: 0,\n operationOrder: [],\n };\n }\n\n // 模拟\"关闭阀门 = 在邻接表中标记为不可通过\",重新计算下游覆盖\n const adj = buildAdjacency(dataset);\n const closedSet = new Set(valvesToClose.map((v) => v.id));\n const pipeById = new Map(dataset.pipes.map((p) => [p.id, p] as const));\n\n const affectedNodes = bfs(adj, pipe.toNode, {\n allowEdge: (_e, _f, to) => !closedSet.has(to),\n maxDepth: 1000,\n }).visited;\n\n // 受影响用户数\n const users = (dataset.users ?? []).filter((u) => {\n if (!u.nodeId) return false;\n return affectedNodes.includes(u.nodeId);\n });\n\n // 隔离完整性:source → 故障段 任一端 的可达性\n// 语义:所有 source 都不能绕过 closedSet 抵达 fromNode/toNode → Infinity(完全隔离)\n// 否则:completeness = source 到故障段最近的可达距离(米)\n const sources = dataset.nodes.filter((n) => n.kind === 'source');\n let completeness = Infinity;\n for (const s of sources) {\n const rTo = dijkstra(adj, s.id, pipe.toNode, {\n weight: (e) => (closedSet.has(e.to) ? Infinity : e.length || 1),\n });\n const rFrom = dijkstra(adj, s.id, pipe.fromNode, {\n weight: (e) => (closedSet.has(e.to) ? Infinity : e.length || 1),\n });\n const reachable =\n rTo.found ? rTo.distance : Infinity;\n const reachableFrom =\n rFrom.found ? rFrom.distance : Infinity;\n const nearest = Math.min(reachable, reachableFrom);\n if (nearest < completeness) completeness = nearest;\n }\n\n const order = valvesToClose\n .map((v) => v.properties?.code ?? v.id)\n .sort();\n\n return {\n valves: valvesToClose,\n isolationCompleteness: completeness,\n impactUserCount: users.length,\n operationOrder: order,\n };\n}\n","/**\n * 影响区域 helpers\n *\n * 把 BurstSimulator 输出的受影响节点+管段渲染成 MapLibre 图层用的 GeoJSON。\n */\n\nimport type { BurstSimulateResult } from './burstCore';\nimport type { PipelineNode, PipelinePipe } from '../types';\n\nexport interface MapLayerData {\n /** 受影响区域凸包多边形(用于高亮) */\n hullPolygon: GeoJSON.Feature<\n GeoJSON.Polygon,\n { score: number; affected: number }\n > | null;\n /** 受影响管段 LineString 集合(用于粗化红色线) */\n affectedPipes: GeoJSON.FeatureCollection<\n GeoJSON.LineString,\n { pipeId: string; scenario: string }\n >;\n /** 受影响节点 Point 集合 */\n affectedNodes: GeoJSON.FeatureCollection<\n GeoJSON.Point,\n { nodeId: string; kind: string }\n >;\n}\n\n/**\n * 把 BurstSimulateResult 映射为地图图层数据\n */\nexport function toMapLayerData(result: BurstSimulateResult): MapLayerData {\n const hull = result.impactArea.hull;\n const hullPolygon: MapLayerData['hullPolygon'] = hull.length >= 3\n ? {\n type: 'Feature',\n geometry: { type: 'Polygon', coordinates: [hull] },\n properties: { score: 1, affected: result.affectedUserCount },\n }\n : null;\n\n // 构造 node 坐标索引以便退化几何\n const nodeCoords = new Map<string, { lng: number; lat: number }>();\n for (const n of result.affectedNodes) nodeCoords.set(n.id, n);\n\n const affectedPipes: GeoJSON.FeatureCollection<GeoJSON.LineString, { pipeId: string; scenario: string }> = {\n type: 'FeatureCollection',\n features: result.affectedPipes\n .map((p) => ({\n type: 'Feature' as const,\n geometry: pipeToLineString(p, nodeCoords),\n properties: { pipeId: p.id, scenario: 'affected' },\n }))\n .filter((f) => f.geometry.coordinates.length >= 2),\n };\n\n const affectedNodes: GeoJSON.FeatureCollection<GeoJSON.Point, { nodeId: string; kind: string }> = {\n type: 'FeatureCollection',\n features: result.affectedNodes.map((n) => ({\n type: 'Feature' as const,\n geometry: { type: 'Point', coordinates: [n.lng, n.lat] },\n properties: { nodeId: n.id, kind: n.kind },\n })),\n };\n\n return { hullPolygon, affectedPipes, affectedNodes };\n}\n\nfunction pipeToLineString(p: PipelinePipe, nodes: Map<string, { lng: number; lat: number }>): GeoJSON.LineString {\n if (p.geometry && p.geometry.length >= 2) {\n return { type: 'LineString', coordinates: p.geometry as [number, number][] };\n }\n // 退化:从端点拉直线\n const from = nodes.get(p.fromNode);\n const to = nodes.get(p.toNode);\n if (from && to) {\n return {\n type: 'LineString',\n coordinates: [\n [from.lng, from.lat],\n [to.lng, to.lat],\n ],\n };\n }\n return { type: 'LineString', coordinates: [] };\n}\n\n/** 计算受影响区域总面积(使用 shoelace 公式) */\nexport function impactAreaSquareMeters(hull: [number, number][]): number {\n if (hull.length < 3) return 0;\n // 把经纬度局部转米(以第一个点为原点,使用等距近似)\n const refLat = hull[0][1];\n const mPerDegLat = 110_540;\n const mPerDegLng = 111_320 * Math.cos((refLat * Math.PI) / 180);\n\n const pts = hull.map(([lng, lat]) => [\n (lng - hull[0][0]) * mPerDegLng,\n (lat - hull[0][1]) * mPerDegLat,\n ]);\n\n let sum = 0;\n for (let i = 0; i < pts.length; i++) {\n const [x1, y1] = pts[i];\n const [x2, y2] = pts[(i + 1) % pts.length];\n sum += x1 * y2 - x2 * y1;\n }\n return Math.abs(sum) / 2;\n}\n\n/** 估算受影响节点的\"中心点\"(用于地图 flyTo) */\nexport function impactCenter(nodes: PipelineNode[]): [number, number] | null {\n if (!nodes.length) return null;\n let lng = 0;\n let lat = 0;\n for (const n of nodes) {\n lng += n.lng;\n lat += n.lat;\n }\n return [lng / nodes.length, lat / nodes.length];\n}\n\n/** 从管段上取最近的节点(用于点击管线后弹出该节点信息卡) */\nexport function nearestNodeOnPipe(\n pipe: PipelinePipe,\n nodes: PipelineNode[],\n lng: number,\n lat: number\n): PipelineNode | null {\n const a = nodes.find((n) => n.id === pipe.fromNode);\n const b = nodes.find((n) => n.id === pipe.toNode);\n if (!a || !b) return null;\n const da = haversineApprox(a.lng, a.lat, lng, lat);\n const db = haversineApprox(b.lng, b.lat, lng, lat);\n return da < db ? a : b;\n}\n\nfunction haversineApprox(lng1: number, lat1: number, lng2: number, lat2: number): number {\n const dx = (lng2 - lng1) * 111_320 * Math.cos((lat1 * Math.PI) / 180);\n const dy = (lat2 - lat1) * 110_540;\n return Math.sqrt(dx * dx + dy * dy);\n}\n","/**\n * BurstSimulator 组件类(地图集成层)\n *\n * 包装 simulateBurst 纯函数 + 维护 MapLibre 图层状态。\n * 组件层职责:\n * - 接收地图实例,添加受影响区域/管段/阀门、方案侧栏\n * - 暴露 simulate()、clear() 等命令式 API\n * - 可订阅结果事件(affectedNodes/valvePlan/impactArea)\n *\n * 注意:此组件不直接依赖 Vue/React(业务方可在任意框架中实例化)\n */\n\nimport type { Map as CaoguoMap } from '@caoguo/maplibre';\nimport {\n simulateBurst,\n type BurstSimulateOptions,\n type BurstSimulateResult,\n} from './burstCore';\nimport { toMapLayerData } from './impactArea';\nimport type { PipelineTopologyDataset, PipelineType } from '../types';\n\nexport interface BurstSimulatorOptions {\n map: CaoguoMap;\n dataset: PipelineTopologyDataset;\n /** 受影响管段样式(maplibre paint props) */\n affectedPipePaint?: Record<string, unknown>;\n /** 阀门隔离方案样式 */\n valvePaint?: Record<string, unknown>;\n /** 影响区域凸包样式 */\n hullPaint?: Record<string, unknown>;\n /** 受影响节点图标样式 */\n affectedNodePaint?: Record<string, unknown>;\n /** 推演情景 */\n scenario?: BurstSimulateOptions['scenario'];\n /** 该实例只处理指定管线类型(用于多管类地图) */\n pipelineType?: PipelineType;\n /** 层 ID 前缀(避免多实例冲突) */\n layerPrefix?: string;\n}\n\nexport type BurstResult = BurstSimulateResult;\n\ntype Listener = (r: BurstSimulateResult) => void;\n\n/**\n * 爆管推演组件(前端类)\n *\n * 用法:\n * const sim = new BurstSimulator({ map, dataset });\n * const result = sim.simulate('pipe-A12');\n * // 受影响区域已添加到 map\n * sim.clear();\n * sim.destroy();\n */\nexport class BurstSimulator {\n private map: CaoguoMap;\n private dataset: PipelineTopologyDataset;\n private scenario: 'gas' | 'water' | 'drainage' | 'heating';\n private affectedPipePaint: Record<string, unknown>;\n private affectedNodePaint: Record<string, unknown>;\n private valvePaint: Record<string, unknown>;\n private hullPaint: Record<string, unknown>;\n private layerPrefix: string;\n private listeners = new Set<Listener>();\n private lastResult: BurstSimulateResult | null = null;\n private layerIds: string[] = [];\n\n constructor(options: BurstSimulatorOptions) {\n this.map = options.map;\n this.dataset = options.dataset;\n this.scenario = options.scenario ?? 'gas';\n this.affectedPipePaint = options.affectedPipePaint ?? {\n 'line-color': '#ef4444',\n 'line-width': 4,\n 'line-opacity': 0.85,\n 'line-blur': 1.5,\n };\n this.affectedNodePaint = options.affectedNodePaint ?? {\n 'circle-radius': 6,\n 'circle-color': '#ef4444',\n 'circle-stroke-width': 2,\n 'circle-stroke-color': '#ffffff',\n };\n this.valvePaint = options.valvePaint ?? {\n 'circle-radius': 8,\n 'circle-color': '#fbbf24',\n 'circle-stroke-width': 2,\n 'circle-stroke-color': '#000000',\n };\n this.hullPaint = options.hullPaint ?? {\n 'fill-color': '#ef4444',\n 'fill-opacity': 0.15,\n 'fill-outline-color': '#ef4444',\n };\n this.layerPrefix = options.layerPrefix ?? 'cg-burst';\n }\n\n /** 触发爆管推演 */\n simulate(pipeId: string, overrideOpts?: BurstSimulateOptions): BurstSimulateResult {\n const result = simulateBurst(this.dataset, pipeId, {\n scenario: overrideOpts?.scenario ?? this.scenario,\n skipClosedValves: overrideOpts?.skipClosedValves ?? true,\n maxAlternatives: overrideOpts?.maxAlternatives ?? 2,\n });\n this.lastResult = result;\n this.render(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(): BurstSimulateResult | null {\n return this.lastResult;\n }\n\n // ------------------------------------------------------\n // 内部:把结果渲染为 MapLibre 图层\n // ------------------------------------------------------\n private render(result: BurstSimulateResult): void {\n this.clear();\n const layerData = toMapLayerData(result);\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\n const prefix = this.layerPrefix;\n const sourcesToAdd: Array<{ id: string; data: unknown }> = [];\n const layersToAdd: Array<Record<string, unknown>> = [];\n\n if (layerData.hullPolygon) {\n sourcesToAdd.push({ id: `${prefix}-hull-src`, data: layerData.hullPolygon });\n layersToAdd.push({\n id: `${prefix}-hull-fill`,\n type: 'fill',\n source: `${prefix}-hull-src`,\n paint: this.hullPaint,\n });\n }\n\n sourcesToAdd.push({ id: `${prefix}-pipes-src`, data: layerData.affectedPipes });\n layersToAdd.push({\n id: `${prefix}-pipes-line`,\n type: 'line',\n source: `${prefix}-pipes-src`,\n paint: this.affectedPipePaint,\n });\n\n sourcesToAdd.push({ id: `${prefix}-nodes-src`, data: layerData.affectedNodes });\n layersToAdd.push({\n id: `${prefix}-nodes-pt`,\n type: 'circle',\n source: `${prefix}-nodes-src`,\n paint: this.affectedNodePaint,\n });\n\n for (const src of sourcesToAdd) {\n if (!mlMap.getSource(src.id)) mlMap.addSource(src.id, src.data as never);\n }\n for (const layer of layersToAdd) {\n try {\n mlMap.addLayer(layer);\n this.layerIds.push(layer.id as string);\n } catch {\n // ignore duplicate\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/burst/burstCore.ts","../src/burst/valvePlanner.ts","../src/burst/impactArea.ts","../src/burst/burstClass.ts"],"names":[],"mappings":"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","file":"chunk-2O4IXAXO.js","sourcesContent":["/**\n * BurstSimulator 核心算法(纯函数)\n *\n * 模拟\"故障管段\"后:\n * 1. 找所有隔离候选阀门(沿故障 pipe 任意一端 BFS,候选上、下游最近阀门)\n * 2. 至少保留:上游最近阀门 + 下游最近阀门,确保\"故障段完全与气源/水源分离\"\n * 3. 下游 BFS(同时绕过被关闭阀门)找受影响节点\n * 4. 关联受影响用户(居民/商业/工业)\n * 5. 重要用户识别(医院/学校/工厂)\n * 6. 备选供气/供水路径(Dijkstra)\n *\n * 全部为纯函数,接收数据集返回结果,可在 Node/浏览器两侧运行。\n */\n\nimport type {\n PipelineTopologyDataset,\n PipelineNode,\n PipelinePipe,\n PipelineUser,\n UserKind,\n} from '../types';\nimport {\n buildAdjacency,\n type AdjacencyList,\n haversine,\n} from '../graph/adjacency';\nimport { bfs } from '../graph/bfs';\nimport { dijkstra } from '../graph/shortestPath';\nimport { findPaths } from '../graph/connectivity';\n\n/** 阀门隔离方案 */\nexport interface ValvePlan {\n /** 需关闭的阀门(隔离故障段) */\n closeValves: PipelineNode[];\n /** 需打开的阀门(泄压/排水) */\n openValves: PipelineNode[];\n /** 备选供气/供水路径(多源时才有) */\n alternativePaths: string[][];\n /** 预计停气/停水时间字符串(如 \"2h\"、\"45min\") */\n estimatedShutdownTime: string;\n /** 隔离方案的可读摘要 */\n summary: string;\n}\n\n/** 影响区域(受影响管段的几何范围) */\nexport interface ImpactArea {\n type: 'FeatureCollection';\n features: Array<\n | { type: 'Feature'; geometry: { type: 'Point'; coordinates: [number, number] }; properties: { kind: 'node' } }\n | { type: 'Feature'; geometry: { type: 'LineString'; coordinates: [number, number][] }; properties: { kind: 'pipe' } }\n >;\n /** 凸包多边形(受影响区域外轮廓) */\n hull: [number, number][];\n}\n\nexport interface BurstSimulateOptions {\n /** 风机等扩展参数:默认按气体泄漏 */\n scenario?: 'gas' | 'water' | 'drainage' | 'heating';\n /** 是否同时禁用\"已关闭阀门\"作为隔离点(推荐 true) */\n skipClosedValves?: boolean;\n /** 最大 alternative path 数 */\n maxAlternatives?: number;\n}\n\nexport interface BurstSimulateResult {\n /** 故障管段 */\n pipe: PipelinePipe;\n /** 受影响节点列表(含故障管段两端) */\n affectedNodes: PipelineNode[];\n /** 受影响管段列表 */\n affectedPipes: PipelinePipe[];\n /** 受影响用户列表 */\n affectedUsers: PipelineUser[];\n /** 受影响用户总数 */\n affectedUserCount: number;\n /** 重要用户(医院/学校/政府) */\n importantUsers: PipelineUser[];\n /** 影响区域几何(GeoJSON FeatureCollection + 凸包) */\n impactArea: ImpactArea;\n /** 阀门隔离方案 */\n valvePlan: ValvePlan;\n /** 计算耗时(ms) */\n durationMs: number;\n}\n\n/**\n * 主入口:执行爆管推演\n */\nexport function simulateBurst(\n dataset: PipelineTopologyDataset,\n pipeId: string,\n opts: BurstSimulateOptions = {}\n): BurstSimulateResult {\n const t0 = (typeof performance !== 'undefined' ? performance.now() : Date.now());\n const scenario = opts.scenario ?? 'gas';\n const skipClosed = opts.skipClosedValves ?? true;\n const maxAlt = opts.maxAlternatives ?? 2;\n\n const pipe = dataset.pipes.find((p) => p.id === pipeId);\n if (!pipe) {\n throw new Error(`BurstSimulator: pipe '${pipeId}' not found in dataset`);\n }\n const nodeById = new Map(dataset.nodes.map((n) => [n.id, n] as const));\n const adj = buildAdjacency(dataset);\n\n // 1) 沿故障 pipe 两端都搜索最近阀门(上下游)\n const upstreamValves = findValvesFromEndpoint(adj, pipe, dataset, pipe.fromNode, skipClosed);\n const downstreamValves = findValvesFromEndpoint(adj, pipe, dataset, pipe.toNode, skipClosed);\n // 合并(按距离排序去重)\n const candidateClose = mergeCandidateValves(upstreamValves, downstreamValves);\n\n // 2) 下游 BFS(PRD step 2):跳过关闭的阀门\n const closedSet = new Set(candidateClose.map((v) => v.id));\n const downstream = bfs(adj, pipe.toNode, {\n allowEdge: (_e, _f, to) => {\n if (closedSet.has(to)) return false;\n return true;\n },\n maxDepth: 1_000,\n });\n\n const affectedSet = new Set(downstream.visited);\n // 故障 pipe from/to 节点也要纳入受影响范围(事件源)\n affectedSet.add(pipe.fromNode);\n\n const affectedNodes: PipelineNode[] = [];\n for (const id of affectedSet) {\n const n = nodeById.get(id);\n if (n) affectedNodes.push(n);\n }\n\n // 受影响管段:所有至少一端在 affectedNodes 的管段\n const affectedPipes: PipelinePipe[] = dataset.pipes.filter(\n (p) => affectedSet.has(p.fromNode) || affectedSet.has(p.toNode)\n );\n\n // 3) 查询受影响用户\n const users = dataset.users ?? [];\n const affectedUsers = users.filter((u) => {\n if (!u.nodeId) return false;\n return affectedSet.has(u.nodeId);\n });\n const importantUsers = affectedUsers.filter((u) => u.kind === 'important');\n\n // 4) 影响区域几何\n const impactArea = computeImpactArea(affectedNodes, affectedPipes);\n\n // 5) 阀门隔离方案\n const valvePlan = buildValvePlan(\n adj,\n dataset,\n pipe,\n candidateClose,\n affectedNodes,\n maxAlt,\n scenario\n );\n\n const durationMs = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - t0;\n return {\n pipe,\n affectedNodes,\n affectedPipes,\n affectedUsers,\n affectedUserCount: affectedUsers.length,\n importantUsers,\n impactArea,\n valvePlan,\n durationMs,\n };\n}\n\n// ============================================================\n// 内部辅助\n// ============================================================\n\ninterface ValveCandidate {\n node: PipelineNode;\n /** 距起点跳数 */\n hops: number;\n /** 距起点物理距离 */\n distance: number;\n /** 来源端 fromNode/toNode */\n endpoint: 'from' | 'to';\n}\n\n/** 从指定端点出发 BFS,沿拓扑找最近的阀门\n *\n * 关键规则:\n * - 端点本身如果是阀门 → 直接作为最近阀门返回,不再扩展\n * - 否则 BFS 找最近的阀门(找到立即停止)\n */\nfunction findValvesFromEndpoint(\n adj: AdjacencyList,\n pipe: PipelinePipe,\n dataset: PipelineTopologyDataset,\n startId: string,\n skipClosed: boolean\n): ValveCandidate[] {\n const faultPipeId = pipe.id;\n const nodeById = new Map(dataset.nodes.map((n) => [n.id, n] as const));\n const out: ValveCandidate[] = [];\n const endpoint = startId === pipe.fromNode ? 'from' : 'to';\n\n const startNode = nodeById.get(startId);\n if (!startNode) return [];\n\n // 0) 端点本身就是阀门 → 立即返回\n if (startNode.kind === 'valve') {\n if (!skipClosed || startNode.properties?.valveStatus !== 'closed') {\n out.push({ node: startNode, hops: 0, distance: 0, endpoint });\n }\n return out;\n }\n\n // 1) 否则 BFS 找最近的阀门\n const visited = new Set<string>();\n const queue: Array<{ id: string; hops: number; dist: number }> = [\n { id: startId, hops: 0, dist: 0 },\n ];\n\n while (queue.length > 0) {\n const cur = queue.shift()!;\n if (visited.has(cur.id)) continue;\n visited.add(cur.id);\n\n const n = nodeById.get(cur.id);\n if (!n) continue;\n\n if (n.kind === 'valve' && (!skipClosed || n.properties?.valveStatus !== 'closed')) {\n out.push({ node: n, hops: cur.hops, distance: cur.dist, endpoint });\n return out; // 找最近的,返回\n }\n\n const edges = adj.get(cur.id) ?? [];\n for (const e of edges) {\n if (e.pipeId === faultPipeId) continue;\n if (visited.has(e.to)) continue;\n queue.push({\n id: e.to,\n hops: cur.hops + 1,\n dist: cur.dist + (e.length || 0),\n });\n }\n }\n\n return out;\n}\n\n/** 合并上下游阀门候选(按距离排重) */\nfunction mergeCandidateValves(\n upstream: ValveCandidate[],\n downstream: ValveCandidate[]\n): PipelineNode[] {\n const seen = new Set<string>();\n const all = [...upstream, ...downstream].sort((a, b) => a.distance - b.distance);\n const out: PipelineNode[] = [];\n for (const c of all) {\n if (seen.has(c.node.id)) continue;\n seen.add(c.node.id);\n out.push(c.node);\n }\n return out;\n}\n\n/**\n * 构造影响区域\n * - features: 受影响节点(Point) + 受影响管段(LineString)\n * - hull: 节点集的凸包(用于地图高亮\"受影响地理范围\")\n */\nfunction computeImpactArea(\n nodes: PipelineNode[],\n pipes: PipelinePipe[]\n): ImpactArea {\n const features: ImpactArea['features'] = [];\n const nodeById = new Map(nodes.map((n) => [n.id, n] as const));\n\n for (const n of nodes) {\n features.push({\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [n.lng, n.lat] },\n properties: { kind: 'node' },\n });\n }\n for (const p of pipes) {\n let coords: [number, number][] = [];\n if (p.geometry && p.geometry.length >= 2) {\n coords = p.geometry as [number, number][];\n } else {\n const from = nodeById.get(p.fromNode);\n const to = nodeById.get(p.toNode);\n if (from && to) coords = [[from.lng, from.lat], [to.lng, to.lat]];\n }\n if (coords.length >= 2) {\n features.push({\n type: 'Feature',\n geometry: { type: 'LineString', coordinates: coords },\n properties: { kind: 'pipe' },\n });\n }\n }\n\n const hull = convexHull(nodes.map((n) => [n.lng, n.lat] as [number, number]));\n\n return { type: 'FeatureCollection', features, hull };\n}\n\n/**\n * 构造阀门隔离方案\n */\nfunction buildValvePlan(\n adj: AdjacencyList,\n dataset: PipelineTopologyDataset,\n pipe: PipelinePipe,\n closeValves: PipelineNode[],\n _affectedNodes: PipelineNode[],\n maxAlt: number,\n scenario: string\n): ValvePlan {\n const closeSet = new Set(closeValves.map((v) => v.id));\n\n // 找泄压点:受影响区域内\"开放\"且\"不在关闭列表\"的阀门\n const openValves: PipelineNode[] = [];\n for (const n of _affectedNodes) {\n if (n.kind !== 'valve') continue;\n if (closeSet.has(n.id)) continue;\n if (n.properties?.valveStatus !== 'open') continue;\n const from = dataset.nodes.find((m) => m.id === pipe.fromNode);\n const to = dataset.nodes.find((m) => m.id === pipe.toNode);\n if (!from || !to) continue;\n const d1 = haversine(n.lng, n.lat, from.lng, from.lat);\n const d2 = haversine(n.lng, n.lat, to.lng, to.lat);\n if (Math.min(d1, d2) < 1000) openValves.push(n);\n }\n\n // 备选路径:从关闭阀门出发 → 其它 source(隔离后备用气源/水源)\n const alternativePaths: string[][] = [];\n if (closeValves.length) {\n const sources = dataset.nodes.filter((n) => n.kind === 'source');\n for (const s of sources) {\n // 选最接近关闭阀门的 source 寻路(确保目标非 closed 阀门)\n const r = dijkstra(adj, closeValves[0].id, s.id, {\n weight: (e) => (closeSet.has(e.to) ? Infinity : e.length || 1),\n });\n if (r.found) {\n const paths = findPaths(adj, closeValves[0].id, s.id, {\n maxPaths: maxAlt,\n maxDepth: 20,\n });\n for (const p of paths) alternativePaths.push(p);\n break;\n }\n }\n }\n\n // 估算停气/停水时间(基于受影响用户数和场景)\n const userCount = (dataset.users ?? []).filter((u) =>\n _affectedNodes.some((n) => n.id === u.nodeId)\n ).length;\n const baseHours = userCount / 200;\n const scenarioFactor = scenario === 'water' ? 1.5 : scenario === 'heating' ? 2 : 1;\n const hours = Math.max(0.5, Math.min(8, baseHours * scenarioFactor));\n const estimatedShutdownTime = hours >= 1 ? `${hours.toFixed(1)}h` : `${Math.round(hours * 60)}min`;\n\n const summary = buildSummary(closeValves, openValves, userCount, scenario);\n\n return {\n closeValves,\n openValves,\n alternativePaths,\n estimatedShutdownTime,\n summary,\n };\n}\n\nfunction buildSummary(\n closeValves: PipelineNode[],\n openValves: PipelineNode[],\n userCount: number,\n scenario: string\n): string {\n const labels: Record<string, string> = {\n gas: '停气',\n water: '停水',\n drainage: '排水中断',\n heating: '停热',\n };\n const label = labels[scenario] ?? '受影响';\n const parts: string[] = [];\n parts.push(`预计${label}${userCount}户`);\n if (closeValves.length) {\n parts.push(`关闭阀门 ${closeValves.map((v) => v.properties?.code ?? v.id).join(', ')}`);\n } else {\n parts.push('未找到上游隔离阀门(建议人工指定)');\n }\n if (openValves.length) {\n parts.push(`打开阀门 ${openValves.map((v) => v.properties?.code ?? v.id).join(', ')}(泄压)`);\n }\n return parts.join(';');\n}\n\n// ============================================================\n// 凸包(Andrew's monotone chain,O(n log n))\n// ============================================================\n\n/** Andrew's monotone chain,返回逆时针凸包顶点(首尾不重复) */\nexport function convexHull(points: [number, number][]): [number, number][] {\n if (points.length < 3) return [...points];\n const pts = [...points];\n pts.sort((a, b) => (a[0] - b[0]) || (a[1] - b[1]));\n\n const cross = (\n o: [number, number],\n a: [number, number],\n b: [number, number]\n ): number => (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);\n\n const lower: [number, number][] = [];\n for (const p of pts) {\n while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], p) <= 0) {\n lower.pop();\n }\n lower.push(p);\n }\n const upper: [number, number][] = [];\n for (let i = pts.length - 1; i >= 0; i--) {\n const p = pts[i];\n while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], p) <= 0) {\n upper.pop();\n }\n upper.push(p);\n }\n upper.pop();\n lower.pop();\n return lower.concat(upper);\n}\n\n/** 用户严重程度打分(用于\"优先通告\"列表) */\nexport function userSeverity(kind: UserKind, scale = 1): number {\n const base: Record<UserKind, number> = {\n important: 100,\n industrial: 50,\n commercial: 20,\n residential: 1,\n };\n return (base[kind] ?? 1) * (scale ?? 1);\n}\n","/**\n * 阀门规划(valve planner)\n *\n * 在已知故障管段的前提下,候选出最优的\"关闭+打开\"组合。\n * 评估指标:\n * - 隔离完整性:关闭阀门后故障段必须与气源/水源完全分离\n * - 影响最小:关闭数量最小,受影响用户最少\n * - 操作便利:按操作顺序列出阀门编号\n */\n\nimport type { PipelineNode, PipelineTopologyDataset, PipelinePipe } from '../types';\nimport { buildAdjacency, type AdjacencyList } from '../graph/adjacency';\nimport { bfs } from '../graph/bfs';\nimport { dijkstra } from '../graph/shortestPath';\n\nexport interface CandidateValveSet {\n valves: PipelineNode[];\n /** 完整性:关闭后故障段到最近 source 的最短距离(Infinity = 完全隔离) */\n isolationCompleteness: number;\n /** 受影响用户数(关闭阀门后的下游覆盖) */\n impactUserCount: number;\n /** 阀门操作顺序(按节点编号字典序,仅辅助) */\n operationOrder: string[];\n}\n\nexport interface PlannerOptions {\n /** 最大候选组合数(指数爆炸时截断) */\n maxCombinations?: number;\n /** 阀门过滤:仅考虑状态/类型匹配的 */\n filter?: (valve: PipelineNode) => boolean;\n}\n\n/**\n * 列出上游候选阀门(沿故障 pipe 两端 BFS 找到的所有阀门,按距离排序)\n */\nexport function listCandidateValves(\n dataset: PipelineTopologyDataset,\n pipeId: string,\n filter?: (valve: PipelineNode) => boolean\n): PipelineNode[] {\n const pipe = dataset.pipes.find((p) => p.id === pipeId);\n if (!pipe) return [];\n const nodeById = new Map(dataset.nodes.map((n) => [n.id, n] as const));\n const adj = buildAdjacency(dataset);\n\n const visited = new Set<string>();\n const valveCandidates: Array<{ n: PipelineNode; dist: number }> = [];\n\n for (const startId of [pipe.fromNode, pipe.toNode]) {\n const queue: Array<{ id: string; d: number }> = [{ id: startId, d: 0 }];\n while (queue.length > 0) {\n const { id, d } = queue.shift()!;\n if (visited.has(id)) continue;\n visited.add(id);\n\n const n = nodeById.get(id);\n if (!n) continue;\n // 端点本身如果是阀门, 也算候选\n if (n.kind === 'valve' && (!filter || filter(n))) {\n valveCandidates.push({ n, dist: d });\n // 第一个阀门已找到, 不必继续扩展 (但允许从端点继续找其它)\n if (d > 0) continue;\n }\n\n const edges = adj.get(id) ?? [];\n for (const e of edges) {\n if (e.pipeId === pipeId) continue; // 不穿过故障 pipe\n if (visited.has(e.to)) continue;\n queue.push({ id: e.to, d: d + 1 });\n }\n }\n }\n\n valveCandidates.sort((a, b) => a.dist - b.dist);\n return valveCandidates.map((v) => v.n);\n}\n\n/**\n * 评估某组阀门关闭后的隔离完整性与受影响用户数\n */\nexport function evaluateValvePlan(\n dataset: PipelineTopologyDataset,\n pipeId: string,\n valvesToClose: PipelineNode[]\n): CandidateValveSet {\n const pipe = dataset.pipes.find((p) => p.id === pipeId);\n if (!pipe) {\n return {\n valves: valvesToClose,\n isolationCompleteness: Infinity,\n impactUserCount: 0,\n operationOrder: [],\n };\n }\n\n // 模拟\"关闭阀门 = 在邻接表中标记为不可通过\",重新计算下游覆盖\n const adj = buildAdjacency(dataset);\n const closedSet = new Set(valvesToClose.map((v) => v.id));\n const pipeById = new Map(dataset.pipes.map((p) => [p.id, p] as const));\n\n const affectedNodes = bfs(adj, pipe.toNode, {\n allowEdge: (_e, _f, to) => !closedSet.has(to),\n maxDepth: 1000,\n }).visited;\n\n // 受影响用户数\n const users = (dataset.users ?? []).filter((u) => {\n if (!u.nodeId) return false;\n return affectedNodes.includes(u.nodeId);\n });\n\n // 隔离完整性:source → 故障段 任一端 的可达性\n// 语义:所有 source 都不能绕过 closedSet 抵达 fromNode/toNode → Infinity(完全隔离)\n// 否则:completeness = source 到故障段最近的可达距离(米)\n const sources = dataset.nodes.filter((n) => n.kind === 'source');\n let completeness = Infinity;\n for (const s of sources) {\n const rTo = dijkstra(adj, s.id, pipe.toNode, {\n weight: (e) => (closedSet.has(e.to) ? Infinity : e.length || 1),\n });\n const rFrom = dijkstra(adj, s.id, pipe.fromNode, {\n weight: (e) => (closedSet.has(e.to) ? Infinity : e.length || 1),\n });\n const reachable =\n rTo.found ? rTo.distance : Infinity;\n const reachableFrom =\n rFrom.found ? rFrom.distance : Infinity;\n const nearest = Math.min(reachable, reachableFrom);\n if (nearest < completeness) completeness = nearest;\n }\n\n const order = valvesToClose\n .map((v) => v.properties?.code ?? v.id)\n .sort();\n\n return {\n valves: valvesToClose,\n isolationCompleteness: completeness,\n impactUserCount: users.length,\n operationOrder: order,\n };\n}\n","/**\n * 影响区域 helpers\n *\n * 把 BurstSimulator 输出的受影响节点+管段渲染成 MapLibre 图层用的 GeoJSON。\n */\n\nimport type { BurstSimulateResult } from './burstCore';\nimport type { PipelineNode, PipelinePipe } from '../types';\n\nexport interface MapLayerData {\n /** 受影响区域凸包多边形(用于高亮) */\n hullPolygon: GeoJSON.Feature<\n GeoJSON.Polygon,\n { score: number; affected: number }\n > | null;\n /** 受影响管段 LineString 集合(用于粗化红色线) */\n affectedPipes: GeoJSON.FeatureCollection<\n GeoJSON.LineString,\n { pipeId: string; scenario: string }\n >;\n /** 受影响节点 Point 集合 */\n affectedNodes: GeoJSON.FeatureCollection<\n GeoJSON.Point,\n { nodeId: string; kind: string }\n >;\n}\n\n/**\n * 把 BurstSimulateResult 映射为地图图层数据\n */\nexport function toMapLayerData(result: BurstSimulateResult): MapLayerData {\n const hull = result.impactArea.hull;\n const hullPolygon: MapLayerData['hullPolygon'] = hull.length >= 3\n ? {\n type: 'Feature',\n geometry: { type: 'Polygon', coordinates: [hull] },\n properties: { score: 1, affected: result.affectedUserCount },\n }\n : null;\n\n // 构造 node 坐标索引以便退化几何\n const nodeCoords = new Map<string, { lng: number; lat: number }>();\n for (const n of result.affectedNodes) nodeCoords.set(n.id, n);\n\n const affectedPipes: GeoJSON.FeatureCollection<GeoJSON.LineString, { pipeId: string; scenario: string }> = {\n type: 'FeatureCollection',\n features: result.affectedPipes\n .map((p) => ({\n type: 'Feature' as const,\n geometry: pipeToLineString(p, nodeCoords),\n properties: { pipeId: p.id, scenario: 'affected' },\n }))\n .filter((f) => f.geometry.coordinates.length >= 2),\n };\n\n const affectedNodes: GeoJSON.FeatureCollection<GeoJSON.Point, { nodeId: string; kind: string }> = {\n type: 'FeatureCollection',\n features: result.affectedNodes.map((n) => ({\n type: 'Feature' as const,\n geometry: { type: 'Point', coordinates: [n.lng, n.lat] },\n properties: { nodeId: n.id, kind: n.kind },\n })),\n };\n\n return { hullPolygon, affectedPipes, affectedNodes };\n}\n\nfunction pipeToLineString(p: PipelinePipe, nodes: Map<string, { lng: number; lat: number }>): GeoJSON.LineString {\n if (p.geometry && p.geometry.length >= 2) {\n return { type: 'LineString', coordinates: p.geometry as [number, number][] };\n }\n // 退化:从端点拉直线\n const from = nodes.get(p.fromNode);\n const to = nodes.get(p.toNode);\n if (from && to) {\n return {\n type: 'LineString',\n coordinates: [\n [from.lng, from.lat],\n [to.lng, to.lat],\n ],\n };\n }\n return { type: 'LineString', coordinates: [] };\n}\n\n/** 计算受影响区域总面积(使用 shoelace 公式) */\nexport function impactAreaSquareMeters(hull: [number, number][]): number {\n if (hull.length < 3) return 0;\n // 把经纬度局部转米(以第一个点为原点,使用等距近似)\n const refLat = hull[0][1];\n const mPerDegLat = 110_540;\n const mPerDegLng = 111_320 * Math.cos((refLat * Math.PI) / 180);\n\n const pts = hull.map(([lng, lat]) => [\n (lng - hull[0][0]) * mPerDegLng,\n (lat - hull[0][1]) * mPerDegLat,\n ]);\n\n let sum = 0;\n for (let i = 0; i < pts.length; i++) {\n const [x1, y1] = pts[i];\n const [x2, y2] = pts[(i + 1) % pts.length];\n sum += x1 * y2 - x2 * y1;\n }\n return Math.abs(sum) / 2;\n}\n\n/** 估算受影响节点的\"中心点\"(用于地图 flyTo) */\nexport function impactCenter(nodes: PipelineNode[]): [number, number] | null {\n if (!nodes.length) return null;\n let lng = 0;\n let lat = 0;\n for (const n of nodes) {\n lng += n.lng;\n lat += n.lat;\n }\n return [lng / nodes.length, lat / nodes.length];\n}\n\n/** 从管段上取最近的节点(用于点击管线后弹出该节点信息卡) */\nexport function nearestNodeOnPipe(\n pipe: PipelinePipe,\n nodes: PipelineNode[],\n lng: number,\n lat: number\n): PipelineNode | null {\n const a = nodes.find((n) => n.id === pipe.fromNode);\n const b = nodes.find((n) => n.id === pipe.toNode);\n if (!a || !b) return null;\n const da = haversineApprox(a.lng, a.lat, lng, lat);\n const db = haversineApprox(b.lng, b.lat, lng, lat);\n return da < db ? a : b;\n}\n\nfunction haversineApprox(lng1: number, lat1: number, lng2: number, lat2: number): number {\n const dx = (lng2 - lng1) * 111_320 * Math.cos((lat1 * Math.PI) / 180);\n const dy = (lat2 - lat1) * 110_540;\n return Math.sqrt(dx * dx + dy * dy);\n}\n","/**\n * BurstSimulator 组件类(地图集成层)\n *\n * 包装 simulateBurst 纯函数 + 维护 MapLibre 图层状态。\n * 组件层职责:\n * - 接收地图实例,添加受影响区域/管段/阀门、方案侧栏\n * - 暴露 simulate()、clear() 等命令式 API\n * - 可订阅结果事件(affectedNodes/valvePlan/impactArea)\n *\n * 注意:此组件不直接依赖 Vue/React(业务方可在任意框架中实例化)\n */\n\nimport type { Map as CaoguoMap } from '@caoguo/maplibre';\nimport {\n simulateBurst,\n type BurstSimulateOptions,\n type BurstSimulateResult,\n} from './burstCore';\nimport { toMapLayerData } from './impactArea';\nimport type { PipelineTopologyDataset, PipelineType } from '../types';\n\nexport interface BurstSimulatorOptions {\n map: CaoguoMap;\n dataset: PipelineTopologyDataset;\n /** 受影响管段样式(maplibre paint props) */\n affectedPipePaint?: Record<string, unknown>;\n /** 阀门隔离方案样式 */\n valvePaint?: Record<string, unknown>;\n /** 影响区域凸包样式 */\n hullPaint?: Record<string, unknown>;\n /** 受影响节点图标样式 */\n affectedNodePaint?: Record<string, unknown>;\n /** 推演情景 */\n scenario?: BurstSimulateOptions['scenario'];\n /** 该实例只处理指定管线类型(用于多管类地图) */\n pipelineType?: PipelineType;\n /** 层 ID 前缀(避免多实例冲突) */\n layerPrefix?: string;\n}\n\nexport type BurstResult = BurstSimulateResult;\n\ntype Listener = (r: BurstSimulateResult) => void;\n\n/**\n * 爆管推演组件(前端类)\n *\n * 用法:\n * const sim = new BurstSimulator({ map, dataset });\n * const result = sim.simulate('pipe-A12');\n * // 受影响区域已添加到 map\n * sim.clear();\n * sim.destroy();\n */\nexport class BurstSimulator {\n private map: CaoguoMap;\n private dataset: PipelineTopologyDataset;\n private scenario: 'gas' | 'water' | 'drainage' | 'heating';\n private affectedPipePaint: Record<string, unknown>;\n private affectedNodePaint: Record<string, unknown>;\n private valvePaint: Record<string, unknown>;\n private hullPaint: Record<string, unknown>;\n private layerPrefix: string;\n private listeners = new Set<Listener>();\n private lastResult: BurstSimulateResult | null = null;\n private layerIds: string[] = [];\n\n constructor(options: BurstSimulatorOptions) {\n this.map = options.map;\n this.dataset = options.dataset;\n this.scenario = options.scenario ?? 'gas';\n this.affectedPipePaint = options.affectedPipePaint ?? {\n 'line-color': '#ef4444',\n 'line-width': 4,\n 'line-opacity': 0.85,\n 'line-blur': 1.5,\n };\n this.affectedNodePaint = options.affectedNodePaint ?? {\n 'circle-radius': 6,\n 'circle-color': '#ef4444',\n 'circle-stroke-width': 2,\n 'circle-stroke-color': '#ffffff',\n };\n this.valvePaint = options.valvePaint ?? {\n 'circle-radius': 8,\n 'circle-color': '#fbbf24',\n 'circle-stroke-width': 2,\n 'circle-stroke-color': '#000000',\n };\n this.hullPaint = options.hullPaint ?? {\n 'fill-color': '#ef4444',\n 'fill-opacity': 0.15,\n 'fill-outline-color': '#ef4444',\n };\n this.layerPrefix = options.layerPrefix ?? 'cg-burst';\n }\n\n /** 触发爆管推演 */\n simulate(pipeId: string, overrideOpts?: BurstSimulateOptions): BurstSimulateResult {\n const result = simulateBurst(this.dataset, pipeId, {\n scenario: overrideOpts?.scenario ?? this.scenario,\n skipClosedValves: overrideOpts?.skipClosedValves ?? true,\n maxAlternatives: overrideOpts?.maxAlternatives ?? 2,\n });\n this.lastResult = result;\n this.render(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(): BurstSimulateResult | null {\n return this.lastResult;\n }\n\n // ------------------------------------------------------\n // 内部:把结果渲染为 MapLibre 图层\n // ------------------------------------------------------\n private render(result: BurstSimulateResult): void {\n this.clear();\n const layerData = toMapLayerData(result);\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\n const prefix = this.layerPrefix;\n const sourcesToAdd: Array<{ id: string; data: unknown }> = [];\n const layersToAdd: Array<Record<string, unknown>> = [];\n\n if (layerData.hullPolygon) {\n sourcesToAdd.push({ id: `${prefix}-hull-src`, data: layerData.hullPolygon });\n layersToAdd.push({\n id: `${prefix}-hull-fill`,\n type: 'fill',\n source: `${prefix}-hull-src`,\n paint: this.hullPaint,\n });\n }\n\n sourcesToAdd.push({ id: `${prefix}-pipes-src`, data: layerData.affectedPipes });\n layersToAdd.push({\n id: `${prefix}-pipes-line`,\n type: 'line',\n source: `${prefix}-pipes-src`,\n paint: this.affectedPipePaint,\n });\n\n sourcesToAdd.push({ id: `${prefix}-nodes-src`, data: layerData.affectedNodes });\n layersToAdd.push({\n id: `${prefix}-nodes-pt`,\n type: 'circle',\n source: `${prefix}-nodes-src`,\n paint: this.affectedNodePaint,\n });\n\n for (const src of sourcesToAdd) {\n if (!mlMap.getSource(src.id)) mlMap.addSource(src.id, src.data as never);\n }\n for (const layer of layersToAdd) {\n try {\n mlMap.addLayer(layer);\n this.layerIds.push(layer.id as string);\n } catch {\n // ignore duplicate\n }\n }\n }\n}\n"]}
|
|
@@ -194,6 +194,34 @@ function prioritizeMaintenance(pipes, topN = 10) {
|
|
|
194
194
|
return [...pipes].sort((a, b) => a.healthScore - b.healthScore).slice(0, topN);
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// src/health/uiData.ts
|
|
198
|
+
function gradeOf(score) {
|
|
199
|
+
if (score >= 85) return "\u4F18";
|
|
200
|
+
if (score >= 70) return "\u826F";
|
|
201
|
+
if (score >= 60) return "\u4E2D";
|
|
202
|
+
return "\u5DEE";
|
|
203
|
+
}
|
|
204
|
+
function buildHealthCard(report) {
|
|
205
|
+
const scores = report.scores.map((s) => s.score.score);
|
|
206
|
+
const avg = scores.length ? scores.reduce((a, b) => a + b, 0) / scores.length : 0;
|
|
207
|
+
const worstCount = report.scores.filter((s) => s.score.score < 60).length;
|
|
208
|
+
return {
|
|
209
|
+
title: "\u7BA1\u7F51\u5065\u5EB7\u8BC4\u4F30",
|
|
210
|
+
avgScore: Math.round(avg * 10) / 10,
|
|
211
|
+
grade: gradeOf(avg),
|
|
212
|
+
worstCount,
|
|
213
|
+
maintenanceCount: report.maintenance.length,
|
|
214
|
+
durationMs: Math.round(report.durationMs * 100) / 100
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function buildHealthScoreSeries(report) {
|
|
218
|
+
const sorted = [...report.scores].sort((a, b) => a.score.score - b.score.score);
|
|
219
|
+
return {
|
|
220
|
+
labels: sorted.map((s) => s.pipeId),
|
|
221
|
+
values: sorted.map((s) => Math.round(s.score.score * 10) / 10)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
197
225
|
// src/health/PipelineHealth.ts
|
|
198
226
|
var PipelineHealth = class {
|
|
199
227
|
map;
|
|
@@ -335,6 +363,6 @@ var PipelineHealth = class {
|
|
|
335
363
|
}
|
|
336
364
|
};
|
|
337
365
|
|
|
338
|
-
export { DEFAULT_WEIGHTS, PipelineHealth, aggregateHeatmap, heatmapToGeoJSON, prioritizeMaintenance, scorePipeHealth, scorePipes };
|
|
339
|
-
//# sourceMappingURL=chunk-
|
|
340
|
-
//# sourceMappingURL=chunk-
|
|
366
|
+
export { DEFAULT_WEIGHTS, PipelineHealth, aggregateHeatmap, buildHealthCard, buildHealthScoreSeries, heatmapToGeoJSON, prioritizeMaintenance, scorePipeHealth, scorePipes };
|
|
367
|
+
//# sourceMappingURL=chunk-33TITD2I.js.map
|
|
368
|
+
//# sourceMappingURL=chunk-33TITD2I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/health/healthScorer.ts","../src/health/riskHeatmap.ts","../src/health/uiData.ts","../src/health/PipelineHealth.ts"],"names":[],"mappings":";AAiDO,IAAM,eAAA,GAAkB;AAAA,EAC7B,GAAA,EAAK,IAAA;AAAA,EACL,QAAA,EAAU,GAAA;AAAA,EACV,IAAA,EAAM,IAAA;AAAA,EACN,OAAA,EAAS,GAAA;AAAA,EACT,QAAA,EAAU,GAAA;AAAA,EACV,UAAA,EAAY;AACd;AAEA,IAAM,aAAA,GAA8C;AAAA,EAClD,SAAA,EAAW,IAAA;AAAA;AAAA,EACX,YAAA,EAAc,GAAA;AAAA;AAAA,EACd,KAAA,EAAO,GAAA;AAAA,EACP,EAAA,EAAI,GAAA;AAAA,EACJ,GAAA,EAAK,IAAA;AAAA,EACL,QAAA,EAAU,GAAA;AAAA,EACV,IAAA,EAAM,IAAA;AAAA,EACN,MAAA,EAAQ,GAAA;AAAA,EACR,OAAA,EAAS;AACX,CAAA;AAKO,SAAS,eAAA,CAAgB,KAAA,EAAwB,OAAA,GAAU,eAAA,EAAkC;AAClG,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,GAAA,EAAK,QAAA,CAAS,KAAA,EAAO,OAAA,CAAQ,GAAG,CAAA;AAAA,IAChC,QAAA,EAAU,aAAA,CAAc,KAAA,EAAO,OAAA,CAAQ,QAAQ,CAAA;AAAA,IAC/C,IAAA,EAAM,SAAA,CAAU,KAAA,EAAO,OAAA,CAAQ,IAAI,CAAA;AAAA,IACnC,OAAA,EAAS,YAAA,CAAa,KAAA,EAAO,OAAA,CAAQ,OAAO,CAAA;AAAA,IAC5C,QAAA,EAAU,aAAA,CAAc,KAAA,EAAO,OAAA,CAAQ,QAAQ,CAAA;AAAA,IAC/C,UAAA,EAAY,eAAA,CAAgB,KAAA,EAAO,OAAA,CAAQ,UAAU;AAAA,GACvD;AAEA,EAAA,MAAM,KAAA,GACJ,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,KAAK,GAAA,CAAI,MAAA,GAC1B,IAAA,CAAK,QAAA,CAAS,QAAQ,IAAA,CAAK,QAAA,CAAS,MAAA,GACpC,IAAA,CAAK,KAAK,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,MAAA,GAC5B,KAAK,OAAA,CAAQ,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,SAClC,IAAA,CAAK,QAAA,CAAS,KAAA,GAAQ,IAAA,CAAK,SAAS,MAAA,GACpC,IAAA,CAAK,UAAA,CAAW,KAAA,GAAQ,KAAK,UAAA,CAAW,MAAA;AAG1C,EAAA,IAAI,KAAA,GAAQ,KAAA;AACZ,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,SAAA,EAAW,KAAA,IAAS,GAAA;AAAA,OAAA,IAChC,KAAA,CAAM,MAAA,KAAW,cAAA,EAAgB,KAAA,IAAS,GAAA;AAAA,OAAA,IAC1C,KAAA,CAAM,MAAA,KAAW,WAAA,EAAa,KAAA,GAAQ,CAAA;AAE/C,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAAA,IACvB,KAAA,EAAO,QAAQ,KAAK,CAAA;AAAA,IACpB,UAAA,EAAY;AAAA,GACd;AACF;AAEA,SAAS,QAAQ,KAAA,EAAyC;AACxD,EAAA,IAAI,KAAA,IAAS,IAAI,OAAO,WAAA;AACxB,EAAA,IAAI,KAAA,IAAS,IAAI,OAAO,MAAA;AACxB,EAAA,IAAI,KAAA,IAAS,IAAI,OAAO,MAAA;AACxB,EAAA,IAAI,KAAA,IAAS,IAAI,OAAO,MAAA;AACxB,EAAA,OAAO,UAAA;AACT;AAEA,SAAS,QAAA,CAAS,OAAwB,MAAA,EAAsD;AAC9F,EAAA,IAAI,CAAC,MAAM,WAAA,EAAa;AACtB,IAAA,OAAO,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,oEAAA,EAAc;AAAA,EACpD;AACA,EAAA,MAAM,QAAA,GAAA,CAAY,IAAA,CAAK,GAAA,EAAI,GAAI,IAAI,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA,CAAE,OAAA,EAAQ,KAAM,MAAA,GAAS,KAAK,IAAA,GAAO,GAAA,CAAA;AAC9F,EAAA,IAAI,QAAA,GAAW,GAAG,OAAO,EAAE,OAAO,GAAA,EAAK,MAAA,EAAQ,QAAQ,wDAAA,EAAY;AACnE,EAAA,IAAI,QAAA,GAAW,GAAG,OAAO,EAAE,OAAO,GAAA,EAAK,MAAA,EAAQ,QAAQ,qCAAA,EAAa;AACpE,EAAA,IAAI,QAAA,GAAW,IAAI,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,2BAAA,EAAa;AACpE,EAAA,IAAI,QAAA,GAAW,IAAI,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,4BAAA,EAAc;AACrE,EAAA,IAAI,QAAA,GAAW,IAAI,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,4BAAA,EAAc;AACrE,EAAA,IAAI,QAAA,GAAW,IAAI,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,0BAAA,EAAY;AACnE,EAAA,OAAO,EAAE,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,QAAQ,0BAAA,EAAY;AACjD;AAEA,SAAS,aAAA,CAAc,OAAwB,MAAA,EAA2D;AACxG,EAAA,IAAI,CAAC,MAAM,QAAA,EAAU;AACnB,IAAA,OAAO,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,wDAAA,EAAY;AAAA,EAClD;AACA,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAA,IAAK,GAAA;AAC9C,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAA,CAAO,CAAA,GAAI,QAAQ,GAAG,CAAA;AACzC,EAAA,MAAM,MAAA,GAAiC;AAAA,IACrC,SAAA,EAAW,4CAAA;AAAA,IACX,YAAA,EAAc,0BAAA;AAAA,IACd,KAAA,EAAO,QAAA;AAAA,IACP,EAAA,EAAI,kCAAA;AAAA,IACJ,GAAA,EAAK,KAAA;AAAA,IACL,QAAA,EAAU,oBAAA;AAAA,IACV,IAAA,EAAM,8BAAA;AAAA,IACN,MAAA,EAAQ,QAAA;AAAA,IACR,OAAA,EAAS;AAAA,GACX;AACA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA,EAAQ,MAAA,CAAO,KAAA,CAAM,QAAQ,KAAK,KAAA,CAAM;AAAA,GAC1C;AACF;AAEA,SAAS,SAAA,CAAU,OAAwB,MAAA,EAAuD;AAChG,EAAA,MAAM,CAAA,GAAI,MAAM,aAAA,IAAiB,GAAA;AACjC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAA,CAAO,CAAA,GAAI,KAAK,GAAG,CAAA;AACtC,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA,EAAQ,CAAA,KAAM,GAAA,IAAO,CAAC,KAAA,CAAM,aAAA,GAAgB,8DAAA,GAAe,CAAA,qCAAA,EAAU,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,GACnF;AACF;AAEA,SAAS,YAAA,CAAa,OAAwB,MAAA,EAA0D;AACtG,EAAA,MAAM,IAAA,GAAO,MAAM,YAAA,IAAgB,CAAA;AACnC,EAAA,IAAI,IAAA,KAAS,GAAG,OAAO,EAAE,OAAO,GAAA,EAAK,MAAA,EAAQ,QAAQ,gCAAA,EAAQ;AAC7D,EAAA,IAAI,IAAA,KAAS,GAAG,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,mCAAA,EAAW;AAC/D,EAAA,IAAI,IAAA,KAAS,GAAG,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,mCAAA,EAAW;AAC/D,EAAA,IAAI,IAAA,KAAS,GAAG,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,mCAAA,EAAW;AAC/D,EAAA,OAAO,EAAE,KAAA,EAAO,CAAA,EAAG,QAAQ,MAAA,EAAQ,CAAA,mBAAA,EAAO,IAAI,CAAA,mBAAA,CAAA,EAAO;AACvD;AAEA,SAAS,aAAA,CAAc,OAAwB,MAAA,EAA2D;AACxG,EAAA,IAAI,CAAC,MAAM,QAAA,EAAU;AACnB,IAAA,OAAO,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,0EAAA,EAAe;AAAA,EACrD;AACA,EAAA,IAAI,CAAC,MAAM,aAAA,EAAe;AACxB,IAAA,OAAO,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,sCAAA,EAAS;AAAA,EAC/C;AACA,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,QAAA,GAAW,KAAA,CAAM,aAAA;AACrC,EAAA,IAAI,KAAA,GAAQ,KAAK,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,oDAAA,EAAkB;AACvE,EAAA,IAAI,KAAA,GAAQ,KAAK,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,sDAAA,EAAoB;AACzE,EAAA,IAAI,KAAA,GAAQ,GAAK,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,uDAAA,EAAqB;AAC1E,EAAA,IAAI,KAAA,GAAQ,KAAK,OAAO,EAAE,OAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,qCAAA,EAAkB;AACvE,EAAA,OAAO,EAAE,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,QAAQ,8CAAA,EAAiB;AACtD;AAEA,SAAS,eAAA,CAAgB,OAAwB,MAAA,EAA6D;AAC5G,EAAA,IAAI,KAAA,CAAM,0BAA0B,IAAA,EAAM;AACxC,IAAA,OAAO,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,gCAAA,EAAQ;AAAA,EAC9C;AACA,EAAA,IAAI,KAAA,CAAM,0BAA0B,KAAA,EAAO;AACzC,IAAA,OAAO,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,gCAAA,EAAQ;AAAA,EAC9C;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,QAAQ,sCAAA,EAAS;AAC/C;AAKO,SAAS,UAAA,CAAW,MAAA,EAA2B,OAAA,GAAU,eAAA,EAAoC;AAClG,EAAA,OAAO,OAAO,GAAA,CAAI,CAAC,MAAM,eAAA,CAAgB,CAAA,EAAG,OAAO,CAAC,CAAA;AACtD;;;ACxKO,SAAS,gBAAA,CACd,MAAA,EACA,OAAA,GAA8B,EAAC,EAChB;AACf,EAAA,MAAM,IAAA,GAAO,QAAQ,QAAA,IAAY,GAAA;AACjC,EAAA,MAAM,GAAA,GAAM,QAAQ,WAAA,IAAe,SAAA;AAGnC,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAEjC,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAC,CAAA,CAAE,GAAA;AACzB,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAC,CAAA,CAAE,GAAA;AACzB,EAAA,MAAM,UAAA,GAAa,MAAA;AACnB,EAAA,MAAM,aAAa,MAAA,GAAU,IAAA,CAAK,IAAK,MAAA,GAAS,IAAA,CAAK,KAAM,GAAG,CAAA;AAE9D,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAkG;AACnH,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,MAAM,CAAA,GAAA,CAAK,CAAA,CAAE,GAAA,GAAM,MAAA,IAAU,UAAA;AAC7B,IAAA,MAAM,CAAA,GAAA,CAAK,CAAA,CAAE,GAAA,GAAM,MAAA,IAAU,UAAA;AAC7B,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,IAAI,CAAA;AAC9B,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,IAAI,CAAA;AAC9B,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA;AACvB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACxB,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,IAAA,CAAK,IAAI,GAAA,EAAK;AAAA,QACZ,KAAK,CAAA,CAAE,WAAA;AAAA,QACP,KAAA,EAAO,CAAA;AAAA,QACP,MAAM,CAAA,CAAE,WAAA;AAAA,QACR,MAAM,CAAA,CAAE,WAAA;AAAA,QACR,KAAK,CAAA,CAAE,GAAA;AAAA,QACP,KAAK,CAAA,CAAE;AAAA,OACR,CAAA;AAAA,IACH,CAAA,MAAO;AACL,MAAA,GAAA,CAAI,OAAO,CAAA,CAAE,WAAA;AACb,MAAA,GAAA,CAAI,KAAA,IAAS,CAAA;AACb,MAAA,IAAI,EAAE,WAAA,GAAc,GAAA,CAAI,IAAA,EAAM,GAAA,CAAI,OAAO,CAAA,CAAE,WAAA;AAC3C,MAAA,IAAI,EAAE,WAAA,GAAc,GAAA,CAAI,IAAA,EAAM,GAAA,CAAI,OAAO,CAAA,CAAE,WAAA;AAC3C,MAAA,GAAA,CAAI,GAAA,GAAA,CAAO,IAAI,GAAA,IAAO,GAAA,CAAI,QAAQ,CAAA,CAAA,GAAK,CAAA,CAAE,OAAO,GAAA,CAAI,KAAA;AACpD,MAAA,GAAA,CAAI,GAAA,GAAA,CAAO,IAAI,GAAA,IAAO,GAAA,CAAI,QAAQ,CAAA,CAAA,GAAK,CAAA,CAAE,OAAO,GAAA,CAAI,KAAA;AAAA,IACtD;AAAA,EACF;AAEA,EAAA,MAAM,QAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,MAAA,EAAO,EAAG;AAC7B,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI,GAAA,KAAQ,KAAA,EAAO,KAAA,GAAQ,CAAA,CAAE,IAAA;AAAA,SAAA,IACpB,GAAA,KAAQ,KAAA,EAAO,KAAA,GAAQ,CAAA,CAAE,IAAA;AAAA,SAC7B,KAAA,GAAQ,CAAA,CAAE,GAAA,GAAM,CAAA,CAAE,KAAA;AACvB,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,KAAK,CAAA,CAAE,GAAA;AAAA,MACP,KAAK,CAAA,CAAE,GAAA;AAAA,MACP,WAAA,EAAa,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAAA,MAC7B,WAAW,CAAA,CAAE;AAAA,KACd,CAAA;AAAA,EACH;AACA,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,iBAAiB,KAAA,EAAgE;AAC/F,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,mBAAA;AAAA,IACN,QAAA,EAAU,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MAC1B,IAAA,EAAM,SAAA;AAAA,MACN,QAAA,EAAU,EAAE,IAAA,EAAM,OAAA,EAAS,WAAA,EAAa,CAAC,CAAA,CAAE,GAAA,EAAK,CAAA,CAAE,GAAG,CAAA,EAAE;AAAA,MACvD,UAAA,EAAY;AAAA,QACV,aAAa,CAAA,CAAE,WAAA;AAAA,QACf,WAAW,CAAA,CAAE;AAAA;AACf,KACF,CAAE;AAAA,GACJ;AACF;AAGO,SAAS,qBAAA,CACd,KAAA,EACA,IAAA,GAAO,EAAA,EACP;AACA,EAAA,OAAO,CAAC,GAAG,KAAK,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,cAAc,CAAA,CAAE,WAAW,CAAA,CAAE,KAAA,CAAM,GAAG,IAAI,CAAA;AAC/E;;;ACtFA,SAAS,QAAQ,KAAA,EAAoC;AACnD,EAAA,IAAI,KAAA,IAAS,IAAI,OAAO,QAAA;AACxB,EAAA,IAAI,KAAA,IAAS,IAAI,OAAO,QAAA;AACxB,EAAA,IAAI,KAAA,IAAS,IAAI,OAAO,QAAA;AACxB,EAAA,OAAO,QAAA;AACT;AAGO,SAAS,gBAAgB,MAAA,EAAkC;AAChE,EAAA,MAAM,MAAA,GAAS,OAAO,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,MAAM,KAAK,CAAA;AACrD,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,OAAO,MAAA,GAAS,CAAA;AAChF,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,KAAA,CAAM,KAAA,GAAQ,EAAE,CAAA,CAAE,MAAA;AACnE,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,sCAAA;AAAA,IACP,QAAA,EAAU,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,EAAE,CAAA,GAAI,EAAA;AAAA,IACjC,KAAA,EAAO,QAAQ,GAAG,CAAA;AAAA,IAClB,UAAA;AAAA,IACA,gBAAA,EAAkB,OAAO,WAAA,CAAY,MAAA;AAAA,IACrC,YAAY,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,UAAA,GAAa,GAAG,CAAA,GAAI;AAAA,GACpD;AACF;AAGO,SAAS,uBAAuB,MAAA,EAA8D;AACnG,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,MAAA,CAAO,MAAM,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,CAAM,KAAA,GAAQ,CAAA,CAAE,MAAM,KAAK,CAAA;AAC9E,EAAA,OAAO;AAAA,IACL,QAAQ,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,MAAM,CAAA;AAAA,IAClC,MAAA,EAAQ,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,KAAA,CAAM,KAAA,GAAQ,EAAE,CAAA,GAAI,EAAE;AAAA,GAC/D;AACF;;;ACpBO,IAAM,iBAAN,MAAqB;AAAA,EAClB,GAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA,uBAAgB,GAAA,EAAc;AAAA,EAC9B,UAAA,GAAkC,IAAA;AAAA,EAClC,WAAqB,EAAC;AAAA,EAE9B,YAAY,OAAA,EAAgC;AAC1C,IAAA,IAAA,CAAK,MAAM,OAAA,CAAQ,GAAA;AACnB,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,OAAA;AACvB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAQ,QAAA,IAAY,GAAA;AACpC,IAAA,IAAA,CAAK,WAAA,GAAc,QAAQ,WAAA,IAAe,WAAA;AAAA,EAC5C;AAAA;AAAA,EAGA,QAAA,CAAS,UAAU,eAAA,EAA+B;AAChD,IAAA,MAAM,EAAA,GAAM,OAAO,WAAA,KAAgB,WAAA,GAAc,YAAY,GAAA,EAAI,GAAI,KAAK,GAAA,EAAI;AAC9E,IAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,IAAA,CAAK,QAAQ,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,EAAA,EAAI,CAAC,CAAU,CAAC,CAAA;AAE1E,IAAA,MAAM,SAAS,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM;AAC3C,MAAA,MAAM,KAAA,GAAyB;AAAA,QAC7B,WAAA,EAAa,EAAE,UAAA,EAAY,WAAA;AAAA,QAC3B,QAAA,EAAU,EAAE,UAAA,EAAY,QAAA;AAAA,QACxB,YAAA,EAAc,CAAA,CAAE,UAAA,EAAY,YAAA,IAAgB,CAAA;AAAA,QAC5C,QAAA,EAAU,EAAE,UAAA,EAAY,QAAA;AAAA,QACxB,aAAA,EAAe,EAAE,UAAA,EAAY,aAAA;AAAA,QAC7B,qBAAA,EAAuB,CAAA,CAAE,UAAA,EAAY,qBAAA,IAAyB,KAAA;AAAA,QAC9D,MAAA,EAAQ,EAAE,UAAA,EAAY;AAAA,OACxB;AACA,MAAA,OAAO,EAAE,QAAQ,CAAA,CAAE,EAAA,EAAI,OAAO,eAAA,CAAgB,KAAA,EAAO,OAAO,CAAA,EAAE;AAAA,IAChE,CAAC,CAAA;AAED,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,CAAC,GAAG,CAAA,KAAM;AACtC,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA;AACjC,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA;AACvC,MAAA,MAAM,EAAA,GAAK,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACnC,MAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,EAAA,SAAW,EAAC;AAC1B,MAAA,OAAO;AAAA,QACL;AAAA,UACE,GAAA,EAAA,CAAM,IAAA,CAAK,GAAA,GAAM,EAAA,CAAG,GAAA,IAAO,CAAA;AAAA,UAC3B,GAAA,EAAA,CAAM,IAAA,CAAK,GAAA,GAAM,EAAA,CAAG,GAAA,IAAO,CAAA;AAAA,UAC3B,WAAA,EAAa,EAAE,KAAA,CAAM;AAAA;AACvB,OACF;AAAA,IACF,CAAC,CAAA;AAED,IAAA,MAAM,UAAU,gBAAA,CAAiB,MAAA,EAAQ,EAAE,QAAA,EAAU,IAAA,CAAK,UAAU,CAAA;AACpE,IAAA,MAAM,WAAA,GAAc,qBAAA;AAAA,MAClB,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACvB,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA;AACjC,QAAA,MAAM,IAAA,GAAO,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA;AACvC,QAAA,MAAM,EAAA,GAAK,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACnC,QAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,EAAA,SAAW,EAAC;AAC1B,QAAA,OAAO;AAAA,UACL;AAAA,YACE,IAAI,IAAA,CAAK,EAAA;AAAA,YACT,WAAA,EAAa,EAAE,KAAA,CAAM,KAAA;AAAA,YACrB,GAAA,EAAA,CAAM,IAAA,CAAK,GAAA,GAAM,EAAA,CAAG,GAAA,IAAO,CAAA;AAAA,YAC3B,GAAA,EAAA,CAAM,IAAA,CAAK,GAAA,GAAM,EAAA,CAAG,GAAA,IAAO,CAAA;AAAA,YAC3B,OAAO,IAAA,CAAK;AAAA;AACd,SACF;AAAA,MACF,CAAC;AAAA,KACH;AAEA,IAAA,MAAM,UAAA,GAAA,CACH,OAAO,WAAA,KAAgB,WAAA,GAAc,YAAY,GAAA,EAAI,GAAI,IAAA,CAAK,GAAA,EAAI,IAAK,EAAA;AAE1E,IAAA,MAAM,MAAA,GAAuB,EAAE,MAAA,EAAQ,OAAA,EAAS,aAAa,UAAA,EAAW;AACxE,IAAA,IAAA,CAAK,UAAA,GAAa,MAAA;AAClB,IAAA,IAAA,CAAK,cAAc,MAAM,CAAA;AACzB,IAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,SAAA,EAAW,CAAA,CAAE,MAAM,CAAA;AACxC,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA,EAGA,KAAA,GAAc;AACZ,IAAA,KAAA,MAAW,EAAA,IAAM,KAAK,QAAA,EAAU;AAC9B,MAAA,IAAA,CAAK,GAAA,CAAI,YAAY,EAAE,CAAA;AAAA,IACzB;AACA,IAAA,IAAA,CAAK,WAAW,EAAC;AAAA,EACnB;AAAA;AAAA,EAGA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,KAAA,EAAM;AACX,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AACrB,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAAA,EACpB;AAAA;AAAA,EAGA,SAAS,EAAA,EAA0B;AACjC,IAAA,IAAA,CAAK,SAAA,CAAU,IAAI,EAAE,CAAA;AACrB,IAAA,OAAO,MAAM,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,EAAE,CAAA;AAAA,EACvC;AAAA;AAAA,EAGA,aAAA,GAAqC;AACnC,IAAA,OAAO,IAAA,CAAK,UAAA;AAAA,EACd;AAAA,EAEQ,cAAc,MAAA,EAA4B;AAChD,IAAA,IAAA,CAAK,KAAA,EAAM;AACX,IAAA,MAAM,KAAA,GAAS,KAAK,GAAA,CAMjB,QAAA;AACH,IAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,MAAA,CAAO,OAAO,CAAA;AAC5C,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,IAAA,CAAK,WAAW,CAAA,SAAA,CAAA;AACpC,IAAA,MAAM,OAAA,GAAU,CAAA,EAAG,IAAA,CAAK,WAAW,CAAA,WAAA,CAAA;AACnC,IAAA,IAAI,CAAC,MAAM,SAAA,CAAU,QAAQ,GAAG,KAAA,CAAM,SAAA,CAAU,UAAU,IAAI,CAAA;AAC9D,IAAA,IAAI;AACF,MAAA,KAAA,CAAM,QAAA,CAAS;AAAA,QACb,EAAA,EAAI,OAAA;AAAA,QACJ,IAAA,EAAM,SAAA;AAAA,QACN,MAAA,EAAQ,QAAA;AAAA,QACR,KAAA,EAAO;AAAA,UACL,gBAAA,EAAkB;AAAA,YAChB,aAAA;AAAA,YACA,CAAC,QAAQ,CAAA;AAAA,YACT,CAAC,OAAO,aAAa,CAAA;AAAA,YACrB,CAAA;AAAA,YAAG,CAAA;AAAA,YACH,EAAA;AAAA,YAAI,GAAA;AAAA,YACJ,GAAA;AAAA,YAAK;AAAA,WACP;AAAA,UACA,mBAAA,EAAqB,CAAA;AAAA,UACrB,eAAA,EAAiB;AAAA,YACf,aAAA;AAAA,YACA,CAAC,QAAQ,CAAA;AAAA,YACT,CAAC,iBAAiB,CAAA;AAAA,YAClB,CAAA;AAAA,YAAG,mBAAA;AAAA,YACH,GAAA;AAAA,YAAK,qBAAA;AAAA,YACL,GAAA;AAAA,YAAK,sBAAA;AAAA,YACL,GAAA;AAAA,YAAK,qBAAA;AAAA,YACL,CAAA;AAAA,YAAG;AAAA,WACL;AAAA,UACA,gBAAA,EAAkB,EAAA;AAAA,UAClB,iBAAA,EAAmB;AAAA;AACrB,OACD,CAAA;AACD,MAAA,IAAA,CAAK,QAAA,CAAS,KAAK,OAAO,CAAA;AAAA,IAC5B,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACF","file":"chunk-33TITD2I.js","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 * 管线健康卡片 / 折线数据层(P2-c UI 数据层,纯函数)\n *\n * 由 {@link HealthResult} 生成卡片展示结构与折线序列,供业务层直接渲染。\n */\n\nimport type { HealthResult } from './PipelineHealth';\n\n/** 健康卡片数据 */\nexport interface HealthCard {\n title: string;\n /** 全网平均健康分(0-100) */\n avgScore: number;\n /** 健康等级文字 */\n grade: '优' | '良' | '中' | '差';\n /** 最差管段数(<60 分) */\n worstCount: number;\n /** 优先维护条数 */\n maintenanceCount: number;\n /** 计算耗时(ms) */\n durationMs: number;\n}\n\nfunction gradeOf(score: number): HealthCard['grade'] {\n if (score >= 85) return '优';\n if (score >= 70) return '良';\n if (score >= 60) return '中';\n return '差';\n}\n\n/** 由评估结果生成健康卡片 */\nexport function buildHealthCard(report: HealthResult): HealthCard {\n const scores = report.scores.map((s) => s.score.score);\n const avg = scores.length ? scores.reduce((a, b) => a + b, 0) / scores.length : 0;\n const worstCount = report.scores.filter((s) => s.score.score < 60).length;\n return {\n title: '管网健康评估',\n avgScore: Math.round(avg * 10) / 10,\n grade: gradeOf(avg),\n worstCount,\n maintenanceCount: report.maintenance.length,\n durationMs: Math.round(report.durationMs * 100) / 100,\n };\n}\n\n/** 折线序列:各管段健康分(按分数升序,便于看最差段) */\nexport function buildHealthScoreSeries(report: HealthResult): { labels: string[]; values: number[] } {\n const sorted = [...report.scores].sort((a, b) => a.score.score - b.score.score);\n return {\n labels: sorted.map((s) => s.pipeId),\n values: sorted.map((s) => Math.round(s.score.score * 10) / 10),\n };\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: p.properties?.failureCount ?? 0,\n pressure: p.properties?.pressure,\n ratedPressure: p.properties?.ratedPressure,\n hasCathodicProtection: p.properties?.hasCathodicProtection ?? false,\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"]}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { INDUSTRY_META } from '@caoguo/theme';
|
|
2
|
+
|
|
1
3
|
// src/style/pipelineTheme.ts
|
|
4
|
+
var INDUSTRY_PRIMARY = INDUSTRY_META.pipeline.primary;
|
|
2
5
|
var PIPELINE_TYPE_COLORS = {
|
|
3
6
|
gas: "#f59e0b",
|
|
4
7
|
// 琥珀(燃气)
|
|
@@ -251,6 +254,6 @@ function paintPipeWidthByDiameter(minWidth = 1.5, maxWidth = 6) {
|
|
|
251
254
|
];
|
|
252
255
|
}
|
|
253
256
|
|
|
254
|
-
export { HEALTH_LEVEL_COLORS, HEALTH_LEVEL_LABELS, NODE_KIND_COLORS, NODE_KIND_ICONS, PIPELINE_TYPE_COLORS, PIPELINE_TYPE_ICONS, PIPELINE_TYPE_LABELS, PIPE_MATERIAL_COLORS, PIPE_STATUS_COLORS, PIPE_STATUS_META, healthLevel, paintNodeByKind, paintPipeBy, paintPipeByDiameter, paintPipeByHealth, paintPipeByMaterial, paintPipeByStatus, paintPipeByType, paintPipeWidthByDiameter, pipelineTypeColor };
|
|
255
|
-
//# sourceMappingURL=chunk-
|
|
256
|
-
//# sourceMappingURL=chunk-
|
|
257
|
+
export { HEALTH_LEVEL_COLORS, HEALTH_LEVEL_LABELS, INDUSTRY_PRIMARY, NODE_KIND_COLORS, NODE_KIND_ICONS, PIPELINE_TYPE_COLORS, PIPELINE_TYPE_ICONS, PIPELINE_TYPE_LABELS, PIPE_MATERIAL_COLORS, PIPE_STATUS_COLORS, PIPE_STATUS_META, healthLevel, paintNodeByKind, paintPipeBy, paintPipeByDiameter, paintPipeByHealth, paintPipeByMaterial, paintPipeByStatus, paintPipeByType, paintPipeWidthByDiameter, pipelineTypeColor };
|
|
258
|
+
//# sourceMappingURL=chunk-4HP7Q7OL.js.map
|
|
259
|
+
//# sourceMappingURL=chunk-4HP7Q7OL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/style/pipelineTheme.ts","../src/style/paintRules.ts"],"names":[],"mappings":"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","file":"chunk-4HP7Q7OL.js","sourcesContent":["/**\n * 草果地图管网专用样式 - `caoguo-pipeline`\n *\n * 设计目标:\n * - 行业辨识度高:燃气=琥珀、供水=蓝、供热=红、电力=紫、通信=绿、排水=灰\n * - 状态语义强:正常/老化/损坏/维修中 各有专属色 + 动画\n * - 与 caoguo-dark/light 主题协调:在亮/暗模式下都可读\n *\n * 颜色规范依据 PRD §4.5。\n */\n\nimport type { PipelineType, PipeMaterial, PipeStatus, NodeKind } from '../types';\nimport { INDUSTRY_META } from '@caoguo/theme';\n\n/** 管网行业主色(六张网统一标识色,单一来源 @caoguo/theme) */\nexport const INDUSTRY_PRIMARY = INDUSTRY_META.pipeline.primary;\n\n/** 管线大类配色(caoguo-pipeline) */\nexport const PIPELINE_TYPE_COLORS: Record<PipelineType, string> = {\n gas: '#f59e0b', // 琥珀(燃气)\n water: '#3b82f6', // 蓝(供水)\n drainage: '#6b7280', // 灰(排水)\n heating: '#ef4444', // 红(供热)\n power: '#8b5cf6', // 紫(电力管沟)\n telecom: '#10b981', // 绿(通信管沟)\n};\n\n/** 管线大类的中文标签(地图图例/卡片显示) */\nexport const PIPELINE_TYPE_LABELS: Record<PipelineType, string> = {\n gas: '燃气管',\n water: '供水管',\n drainage: '排水管',\n heating: '供热管',\n power: '电力管沟',\n telecom: '通信管沟',\n};\n\n/** 管线大类的 Emoji 图标(轻量可视化标识,用于卡片/Tag) */\nexport const PIPELINE_TYPE_ICONS: Record<PipelineType, string> = {\n gas: '🔥',\n water: '💧',\n drainage: '🚰',\n heating: '🔴',\n power: '⚡',\n telecom: '📡',\n};\n\n/** 管段状态配色 */\nexport const PIPE_STATUS_COLORS: Record<PipeStatus, string> = {\n normal: '#4ade80', // 绿\n aging: '#fbbf24', // 黄\n damaged: '#ef4444', // 红\n under_repair: '#8b5cf6', // 紫\n abandoned: '#4b5563', // 深灰\n unknown: '#6b7280', // 灰\n};\n\n/** 状态的语义 + 动画 */\nexport const PIPE_STATUS_META: Record<\n PipeStatus,\n { label: string; animation?: 'pulse' | 'dashed' | 'none' }\n> = {\n normal: { label: '正常', animation: 'none' },\n aging: { label: '老化', animation: 'none' },\n damaged: { label: '损坏', animation: 'pulse' },\n under_repair: { label: '维修中', animation: 'dashed' },\n abandoned: { label: '废弃', animation: 'none' },\n unknown: { label: '未知', animation: 'none' },\n};\n\n/** 管材配色(maplibre style 用) */\nexport const PIPE_MATERIAL_COLORS: Record<PipeMaterial, string> = {\n cast_iron: '#94a3b8', // 蓝灰(旧铸铁)\n ductile_iron: '#0ea5e9', // 天蓝(球墨铸铁)\n steel: '#64748b', // 钢蓝\n pe: '#22c55e', // 绿(PE 现代管材)\n pvc: '#a78bfa', // 紫(PVC)\n concrete: '#a8a29e', // 米灰(混凝土)\n hdpe: '#16a34a', // 深绿(HDPE)\n copper: '#d97706', // 橙(铜)\n unknown: '#6b7280',\n};\n\n/** 节点图标(用 SVG path 描点,地图渲染层用) */\nexport const NODE_KIND_ICONS: Record<NodeKind, string> = {\n junction: 'M -6 0 L 6 0 M 0 -6 L 0 6', // 十字\n valve: 'M -8 -4 L 8 4 M 0 -4 L 0 4', // X\n pump: 'M -6 0 A 6 6 0 1 0 6 0 A 6 6 0 1 0 -6 0', // 圆\n meter: 'M -6 -6 L 6 -6 L 6 6 L -6 6 Z', // 方\n source: 'M 0 -10 L 6 6 L -6 6 Z', // 三角\n tank: 'M -8 -6 Q 0 -10 8 -6 L 8 6 L -8 6 Z', // 圆角\n junction_box: 'M -7 -4 L 7 -4 L 7 4 L -7 4 Z',// 小方\n};\n\n/** 节点配色(默认按 type 衍生) */\nexport const NODE_KIND_COLORS: Record<NodeKind, string> = {\n junction: '#94a3b8',\n valve: '#ef4444', // 阀门=红(控制关键)\n pump: '#f59e0b',\n meter: '#3b82f6',\n source: '#22c55e',\n tank: '#06b6d4',\n junction_box: '#8b5cf6',\n};\n\n/** 健康度等级配色(PipelineHealth 用) */\nexport const HEALTH_LEVEL_COLORS: Record<string, string> = {\n excellent: '#22c55e', // 绿 80-100\n good: '#3b82f6', // 蓝 60-80\n fair: '#eab308', // 黄 40-60\n poor: '#f97316', // 橙 20-40\n critical: '#ef4444', // 红 0-20\n};\n\n/** 健康等级 label */\nexport const HEALTH_LEVEL_LABELS: Record<string, string> = {\n excellent: '优',\n good: '良',\n fair: '中',\n poor: '差',\n critical: '危',\n};\n\n/**\n * 健康度 → 等级(保留闭区间,遵守 PRD §4.4.2)\n * @param score 0-100 健康分\n */\nexport function healthLevel(score: number): 'excellent' | 'good' | 'fair' | 'poor' | 'critical' {\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\n/** 按管线类型取默认色(兜底用) */\nexport function pipelineTypeColor(type: PipelineType | undefined): string {\n if (!type) return '#94a3b8';\n return PIPELINE_TYPE_COLORS[type];\n}\n","/**\n * 管网 MapLibre paint 规则(caoguo-pipeline)\n *\n * 把\"管线/节点如何着色\"的业务规则翻译成 MapLibre style spec,\n * 业务方可直接 addLayer / setPaintProperty 使用。\n *\n * 规则集:\n * - 管线按管线大类着色(type)\n * - 管线按管径着色(diameter,PRD §4.1.4)\n * - 管线按状态着色(status)\n * - 管线按材质着色(material)\n * - 管线按健康度着色(health,PipelineHealth 集成)\n *\n * 节点按节点类型着色 + 图标。\n */\n\nimport type {\n PipelineType,\n PipeMaterial,\n PipeStatus,\n ColorByMode,\n} from '../types';\nimport { PIPELINE_TYPE_COLORS, PIPE_STATUS_COLORS, HEALTH_LEVEL_COLORS, PIPE_MATERIAL_COLORS } from './pipelineTheme';\n\n/**\n * MapLibre style spec 的 color function DSL(typed),\n * 业务方可直接 `map.addLayer({type:'line', paint: {'line-color': rule} })`\n *\n * MapLibre 表达式其实接受 string | number | 嵌套数组,所以我们用 unknown 让 TS 放行\n */\nexport type PaintRule = unknown;\n\n/** 管线按\"管线大类\"着色 */\nexport function paintPipeByType(types?: PipelineType[]): PaintRule {\n if (!types || types.length === 0) {\n // 全部类型都涂色\n return [\n 'match',\n ['get', 'pipelineType'],\n ...Object.entries(PIPELINE_TYPE_COLORS).flatMap(([k, v]) => [k, v]),\n '#94a3b8',\n ];\n }\n return [\n 'match',\n ['get', 'pipelineType'],\n ...types.flatMap((t) => [t, PIPELINE_TYPE_COLORS[t]]),\n '#94a3b8',\n ];\n}\n\n/** 管线按\"管径\"渐变着色(PRD §4.1.4) */\nexport function paintPipeByDiameter(): PaintRule {\n return [\n 'interpolate',\n ['linear'],\n ['coalesce', ['get', 'diameter'], 0],\n 0, '#4ade80', // 极细管 绿\n 50, '#4ade80', // DN50 以下 绿(支管)\n 150, '#60a5fa', // DN150 蓝(配水管)\n 300, '#f59e0b', // DN300 黄(干管)\n 600, '#ef4444', // DN600+ 红(主管)\n 1500, '#7f1d1d', // 极大管 深红\n ];\n}\n\n/** 管线按\"状态\"着色 */\nexport function paintPipeByStatus(): PaintRule {\n return [\n 'match',\n ['coalesce', ['get', 'status'], 'unknown'],\n ...Object.entries(PIPE_STATUS_COLORS).flatMap(([k, v]) => [k, v]),\n '#6b7280',\n ];\n}\n\n/** 管线按\"材质\"着色 */\nexport function paintPipeByMaterial(): PaintRule {\n return [\n 'match',\n ['coalesce', ['get', 'material'], 'unknown'],\n ...Object.entries(PIPE_MATERIAL_COLORS).flatMap(([k, v]) => [k, v]),\n '#6b7280',\n ];\n}\n\n/** 管线按\"健康度\"着色(健康分 0-100,规则按 healthLevel 离散) */\nexport function paintPipeByHealth(): PaintRule {\n return [\n 'step',\n ['coalesce', ['get', 'healthScore'], 100],\n HEALTH_LEVEL_COLORS.critical, // <20\n 20, HEALTH_LEVEL_COLORS.poor,\n 40, HEALTH_LEVEL_COLORS.fair,\n 60, HEALTH_LEVEL_COLORS.good,\n 80, HEALTH_LEVEL_COLORS.excellent,\n ];\n}\n\n/** 根据模式返回 paint rule 工厂 */\nexport function paintPipeBy(mode: ColorByMode, opts?: { types?: PipelineType[] }): PaintRule {\n switch (mode) {\n case 'type':\n return paintPipeByType(opts?.types);\n case 'diameter':\n return paintPipeByDiameter();\n case 'status':\n return paintPipeByStatus();\n case 'material':\n return paintPipeByMaterial();\n case 'health':\n return paintPipeByHealth();\n case 'uniform':\n default:\n return '#60a5fa';\n }\n}\n\n/** 节点按 kind 着色(maplibre style circle-color 用) */\nexport function paintNodeByKind(): PaintRule {\n return [\n 'match',\n ['get', 'kind'],\n 'junction', '#94a3b8',\n 'valve', '#ef4444',\n 'pump', '#f59e0b',\n 'meter', '#3b82f6',\n 'source', '#22c55e',\n 'tank', '#06b6d4',\n 'junction_box', '#8b5cf6',\n '#cbd5e1',\n ];\n}\n\n/** 默认管段宽度(按管径递推) */\nexport function paintPipeWidthByDiameter(minWidth = 1.5, maxWidth = 6): PaintRule {\n return [\n 'interpolate',\n ['linear'],\n ['coalesce', ['get', 'diameter'], 100],\n 0, minWidth,\n 1500, maxWidth,\n ];\n}\n"]}
|
|
@@ -107,27 +107,56 @@ function buildDescription(intent, f) {
|
|
|
107
107
|
// src/nlpg/pipelineNlpClass.ts
|
|
108
108
|
var PipelineNlp = class {
|
|
109
109
|
burstSimulator;
|
|
110
|
+
dataset;
|
|
110
111
|
onIntent;
|
|
112
|
+
onBurst;
|
|
113
|
+
lastResult = null;
|
|
114
|
+
lastBurst = null;
|
|
111
115
|
constructor(options = {}) {
|
|
112
116
|
this.burstSimulator = options.burstSimulator;
|
|
117
|
+
this.dataset = options.dataset;
|
|
113
118
|
this.onIntent = options.onIntent;
|
|
119
|
+
this.onBurst = options.onBurst;
|
|
114
120
|
}
|
|
115
|
-
/**
|
|
121
|
+
/** 解析并按意图触发动作(爆管意图自动联动推演) */
|
|
116
122
|
query(text) {
|
|
117
123
|
const result = parsePipelineQuery(text);
|
|
124
|
+
this.lastResult = result;
|
|
118
125
|
if (this.onIntent) this.onIntent(result.intent, result);
|
|
126
|
+
if (result.intent === "burst" && this.burstSimulator) {
|
|
127
|
+
const pipeId = this.resolveBurstPipeId(text);
|
|
128
|
+
if (pipeId) {
|
|
129
|
+
this.lastBurst = this.burstSimulator.simulate(pipeId);
|
|
130
|
+
if (this.onBurst) this.onBurst(this.lastBurst);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
119
133
|
return result;
|
|
120
134
|
}
|
|
121
135
|
/** 仅解析不触发动作 */
|
|
122
136
|
parse(text) {
|
|
123
137
|
return parsePipelineQuery(text);
|
|
124
138
|
}
|
|
125
|
-
/** 关联 BurstSimulator */
|
|
126
|
-
setBurstSimulator(sim) {
|
|
139
|
+
/** 关联 BurstSimulator 与数据集(联动推演用) */
|
|
140
|
+
setBurstSimulator(sim, dataset) {
|
|
127
141
|
this.burstSimulator = sim;
|
|
142
|
+
if (dataset) this.dataset = dataset;
|
|
143
|
+
}
|
|
144
|
+
/** 取最近一次联动推演结果 */
|
|
145
|
+
getLastBurst() {
|
|
146
|
+
return this.lastBurst;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* 从查询文本解析爆管管段 id。
|
|
150
|
+
* 优先匹配「pipe-xxx / 管段xxx」显式编号;否则回退到数据集首条管段。
|
|
151
|
+
*/
|
|
152
|
+
resolveBurstPipeId(text) {
|
|
153
|
+
const m = text.match(/管段\s*([A-Za-z0-9_\-]+)|pipe[-\s]*([A-Za-z0-9_\-]+)/i);
|
|
154
|
+
if (m) return (m[1] ?? m[2]) || null;
|
|
155
|
+
if (this.dataset?.pipes?.length) return this.dataset.pipes[0].id;
|
|
156
|
+
return null;
|
|
128
157
|
}
|
|
129
158
|
};
|
|
130
159
|
|
|
131
160
|
export { PipelineNlp, parsePipelineQuery };
|
|
132
|
-
//# sourceMappingURL=chunk-
|
|
133
|
-
//# sourceMappingURL=chunk-
|
|
161
|
+
//# sourceMappingURL=chunk-7LPD52KL.js.map
|
|
162
|
+
//# sourceMappingURL=chunk-7LPD52KL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/nlpg/pipelineNlp.ts","../src/nlpg/pipelineNlpClass.ts"],"names":[],"mappings":"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","file":"chunk-7LPD52KL.js","sourcesContent":["/**\n * NLPG 管网场景扩展(Phase 1)\n */\nimport type { PipelineType } from '../types';\n\nexport type PipelineNlpIntent =\n | 'burst'\n | 'valve'\n | 'material_age'\n | 'pressure'\n | 'nearby'\n | 'alarm_cluster'\n | 'unknown';\n\nexport interface PipelineNlpFilters {\n pipelineType?: PipelineType;\n material?: string;\n minAgeYears?: number;\n maxAgeYears?: number;\n minPressure?: number;\n maxPressure?: number;\n radius?: number;\n timeWindow?: '1h' | '1d' | '7d' | '30d';\n region?: string;\n}\n\nexport interface PipelineNlpResult {\n intent: PipelineNlpIntent;\n filters: PipelineNlpFilters;\n description: string;\n confidence: number;\n}\n\nconst PATTERNS: Array<{ intent: PipelineNlpIntent; re: RegExp; confidence: number }> = [\n { intent: 'burst', re: /(爆管|破裂|泄漏|故障|事故|爆裂)/, confidence: 0.95 },\n { intent: 'valve', re: /(阀门|闸).*?(关闭|关|合)|(?:关闭|关|合).*?(阀门|闸)/, confidence: 0.9 },\n { intent: 'material_age', re: /(\\d+)\\s*年.*?(铸铁|钢|PE|PVC|铜)/, confidence: 0.85 },\n { intent: 'material_age', re: /(铸铁|钢|PE|PVC|铜).*?(\\d+)\\s*年/, confidence: 0.85 },\n { intent: 'pressure', re: /压力.*?(低于|高于|小于|大于|<|>|>=|<=|低|高)\\s*(\\d+\\.?\\d*)/, confidence: 0.85 },\n { intent: 'nearby', re: /(\\d+)\\s*(米|m|公里|km).*?(学校|医院|工厂|消防|政府|小区)/, confidence: 0.85 },\n { intent: 'alarm_cluster', re: /报警|告警/, confidence: 0.8 },\n];\n\nconst TYPE_REGEX: Array<{ type: PipelineType; re: RegExp }> = [\n { type: 'gas', re: /燃气|煤气|天然气/ },\n { type: 'water', re: /供水|自来水|水管/ },\n { type: 'drainage', re: /排水|污水|雨水/ },\n { type: 'heating', re: /供热|暖气|热力/ },\n { type: 'power', re: /电力|电缆|高压/ },\n { type: 'telecom', re: /通信|光纤|光缆/ },\n];\n\nconst MATERIAL_REGEX: Array<{ key: string; re: RegExp; cname: string }> = [\n { key: 'cast_iron', cname: '铸铁', re: /铸铁/ },\n { key: 'ductile_iron', cname: '球墨铸铁', re: /球墨/ },\n { key: 'steel', cname: '钢', re: /钢/ },\n { key: 'pe', cname: 'PE', re: /PE/ },\n { key: 'pvc', cname: 'PVC', re: /PVC/ },\n { key: 'concrete', cname: '混凝土', re: /混凝土/ },\n { key: 'hdpe', cname: 'HDPE', re: /HDPE/ },\n { key: 'copper', cname: '铜', re: /铜/ },\n];\n\nconst REGION_REGEX = /(朝阳区|海淀区|江岸区|江汉区|硚口区|汉阳区|武昌区|青山区|洪山区|东西湖区|黄陂区|新洲区|江夏区|蔡甸区|汉南区)/;\n\nexport function parsePipelineQuery(query: string): PipelineNlpResult {\n let best: { intent: PipelineNlpIntent; confidence: number } = { intent: 'unknown', confidence: 0 };\n for (const p of PATTERNS) {\n const m = query.match(p.re);\n if (m) {\n const c = p.confidence * (1 + 0.05 * (m[0].length / query.length));\n if (c > best.confidence) best = { intent: p.intent, confidence: Math.min(c, 1) };\n }\n }\n\n const filters: PipelineNlpFilters = {};\n for (const t of TYPE_REGEX) {\n if (t.re.test(query)) {\n filters.pipelineType = t.type;\n break;\n }\n }\n for (const m of MATERIAL_REGEX) {\n if (m.re.test(query)) {\n filters.material = m.key;\n break;\n }\n }\n const ageMatch = query.match(/(\\d+)\\s*年/);\n if (ageMatch) {\n const years = parseInt(ageMatch[1]);\n if (best.intent === 'material_age') {\n if (/超[过于]/.test(query) || /[以]?上/.test(query)) filters.minAgeYears = years;\n else if (/内|以下|不超/.test(query)) filters.maxAgeYears = years;\n else filters.minAgeYears = years;\n } else {\n filters.minAgeYears = years;\n }\n }\n const pressureMatch = query.match(/(\\d+\\.?\\d*)\\s*(MPa|mpa)/);\n if (pressureMatch) {\n const v = parseFloat(pressureMatch[1]);\n if (/低|小于|小于等于|</.test(query)) filters.maxPressure = v;\n else if (/高|大于|大于等于|>/.test(query)) filters.minPressure = v;\n else filters.maxPressure = v;\n } else if (/压力/.test(query)) {\n filters.maxPressure = 0.2; // 默认低压阈值\n }\n const distMatch = query.match(/(\\d+)\\s*(公里|km|千米|米|m)/);\n if (distMatch) {\n let d = parseInt(distMatch[1]);\n const unit = distMatch[2];\n if (/公里|km|千米/.test(unit)) d *= 1000;\n filters.radius = d;\n }\n if (/昨天/.test(query)) filters.timeWindow = '1d';\n else if (/今天/.test(query)) filters.timeWindow = '1d';\n else if (/最近一周|过去一周|7\\s*天/.test(query)) filters.timeWindow = '7d';\n else if (/最近一个月/.test(query)) filters.timeWindow = '30d';\n const regionMatch = query.match(REGION_REGEX);\n if (regionMatch) filters.region = regionMatch[1];\n\n return {\n intent: best.intent,\n filters,\n description: buildDescription(best.intent, filters),\n confidence: best.confidence,\n };\n}\n\nfunction buildDescription(intent: PipelineNlpIntent, f: PipelineNlpFilters): string {\n const desc: string[] = [];\n if (intent === 'burst') desc.push('触发爆管推演');\n else if (intent === 'valve') desc.push('查询阀门关闭影响');\n else if (intent === 'material_age') {\n const matName = MATERIAL_REGEX.find((m) => m.key === f.material)?.cname ?? f.material ?? '';\n desc.push(`筛选${matName}管${f.minAgeYears ?? '?'}年以上`);\n } else if (intent === 'pressure') desc.push(`筛选压力${f.maxPressure ?? ''}MPa以下`);\n else if (intent === 'nearby') desc.push(`${f.radius}m内查找POI`);\n else if (intent === 'alarm_cluster') desc.push(`查询${f.timeWindow ?? '1d'}内报警聚集`);\n if (f.pipelineType) desc.push(`[${f.pipelineType}]`);\n if (f.region) desc.push(`区域:${f.region}`);\n return desc.join(' ');\n}\n","/**\n * PipelineNlp 组件类\n *\n * 包装 parsePipelineQuery + 与 BurstSimulator 联动推演。\n * 当识别为爆管意图且已关联 BurstSimulator 时,自动触发空间推演。\n */\n\nimport { parsePipelineQuery, type PipelineNlpResult, type PipelineNlpIntent } from './pipelineNlp';\nimport type { BurstSimulator } from '../burst/burstClass';\nimport type { PipelineTopologyDataset } from '../types';\n\nexport interface PipelineNlpOptions {\n burstSimulator?: BurstSimulator;\n dataset?: PipelineTopologyDataset;\n onIntent?: (intent: PipelineNlpIntent, result: PipelineNlpResult) => void;\n onBurst?: (result: ReturnType<BurstSimulator['simulate']>) => void;\n}\n\nexport class PipelineNlp {\n private burstSimulator?: BurstSimulator;\n private dataset?: PipelineTopologyDataset;\n private onIntent?: PipelineNlpOptions['onIntent'];\n private onBurst?: PipelineNlpOptions['onBurst'];\n private lastResult: PipelineNlpResult | null = null;\n private lastBurst: ReturnType<BurstSimulator['simulate']> | null = null;\n\n constructor(options: PipelineNlpOptions = {}) {\n this.burstSimulator = options.burstSimulator;\n this.dataset = options.dataset;\n this.onIntent = options.onIntent;\n this.onBurst = options.onBurst;\n }\n\n /** 解析并按意图触发动作(爆管意图自动联动推演) */\n query(text: string): PipelineNlpResult {\n const result = parsePipelineQuery(text);\n this.lastResult = result;\n if (this.onIntent) this.onIntent(result.intent, result);\n\n if (result.intent === 'burst' && this.burstSimulator) {\n const pipeId = this.resolveBurstPipeId(text);\n if (pipeId) {\n this.lastBurst = this.burstSimulator.simulate(pipeId);\n if (this.onBurst) this.onBurst(this.lastBurst);\n }\n }\n return result;\n }\n\n /** 仅解析不触发动作 */\n parse(text: string): PipelineNlpResult {\n return parsePipelineQuery(text);\n }\n\n /** 关联 BurstSimulator 与数据集(联动推演用) */\n setBurstSimulator(sim: BurstSimulator, dataset?: PipelineTopologyDataset): void {\n this.burstSimulator = sim;\n if (dataset) this.dataset = dataset;\n }\n\n /** 取最近一次联动推演结果 */\n getLastBurst(): ReturnType<BurstSimulator['simulate']> | null {\n return this.lastBurst;\n }\n\n /**\n * 从查询文本解析爆管管段 id。\n * 优先匹配「pipe-xxx / 管段xxx」显式编号;否则回退到数据集首条管段。\n */\n private resolveBurstPipeId(text: string): string | null {\n const m = text.match(/管段\\s*([A-Za-z0-9_\\-]+)|pipe[-\\s]*([A-Za-z0-9_\\-]+)/i);\n if (m) return (m[1] ?? m[2]) || null;\n if (this.dataset?.pipes?.length) return this.dataset.pipes[0].id;\n return null;\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { paintPipeBy } from './chunk-
|
|
1
|
+
import { paintPipeBy } from './chunk-4HP7Q7OL.js';
|
|
2
2
|
import { upsertSource } from '@caoguo/maplibre';
|
|
3
3
|
|
|
4
4
|
var PipelineTopology = class {
|
|
@@ -255,5 +255,5 @@ var PipelineTopology = class {
|
|
|
255
255
|
};
|
|
256
256
|
|
|
257
257
|
export { PipelineTopology };
|
|
258
|
-
//# sourceMappingURL=chunk-
|
|
259
|
-
//# sourceMappingURL=chunk-
|
|
258
|
+
//# sourceMappingURL=chunk-ASITLG37.js.map
|
|
259
|
+
//# sourceMappingURL=chunk-ASITLG37.js.map
|