topo-engine 0.1.8 → 0.1.9

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 CHANGED
@@ -12,7 +12,7 @@
12
12
  - 🔍 **拓扑查询 API** — 节点 / 边 / 邻居 / 子树 / 主干链 / 路径 / 坐标 查询
13
13
  - 🎨 **样式控制** — 节点、边样式覆盖与批量重置
14
14
  - 🎨 **节点 / 电表染色** — 按 **psrId(设备编码)** 染普通节点、按 **assetNo(资产编号)** 染计量箱内电表户(状态色、告警色场景)
15
- - ✨ **动画与高亮** — 节点脉动、边流动、路径高亮、其余变暗、异常标注
15
+ - ✨ **动画与高亮** — 节点脉动、节点光晕(发光环,颜色可设)、边流动、路径高亮、其余变暗、异常标注
16
16
  - 📝 **文字标注** — 附加文字、用户名 full / short / hidden 切换
17
17
  - 🃏 **卡片盒** — 节点信息卡片(字段 + 按钮),适配"运行曲线/工单跳转"类场景
18
18
  - 🔗 **连接线 / 拓扑线** — 任意两节点动态连接线、路径拓扑高亮线
@@ -257,6 +257,25 @@ const dataUrl = ref('/data/topology.json');
257
257
 
258
258
  > 也可自行 `import { TopoApi }`,按 `new TopoApi(graph, model, layout, nodeByIdMap)` 构造后调用同一套方法;事件与查询见下。使用组件时无需关心内部构造。
259
259
 
260
+ > 📌 **引用统一(id / psrId / assetNo)**:所有目标入参(查询/定位/样式/高亮/动画/文字/卡片/连线…)都可传
261
+ > **节点内部 id**、**psrId(设备编码)** 或 **客户 assetNo(资产编号,兼容 consNo/consId)**:
262
+ > - 命中普通节点 → 作用在该节点;
263
+ > - 命中**箱内电表户** → 视觉/定位/动画**精确作用在该户表位**(光环/高亮环/脉动/文字/染色/卡片),
264
+ > 查询/拓扑按所在计量箱参与(`getNode(assetNo)` 返回箱节点并附 `customer` 信息),
265
+ > 定位聚焦表位中心(`locateNode(assetNo)`、`getNodePosition(assetNo)`)。
266
+ >
267
+ > ```js
268
+ > topo.locateNode(assetNo); // 定位到某户表位中心
269
+ > topo.highlightNode(assetNo, { color: '#FF0000' }); // 该户表位高亮环
270
+ > topo.setNodeGlow(assetNo, { color: '#FF6600' }); // 该户表位光晕
271
+ > topo.setNodePulse(assetNo); // 该户电表格脉动
272
+ > topo.setText(assetNo, '异常'); // 表位上方标注
273
+ > topo.showCard(assetNo); // 客户档案卡片(定位在表位旁)
274
+ > topo.selectNode(assetNo); // 编程选中该户(联动 customer-select)
275
+ > topo.getNode(assetNo); // → 所在箱节点副本 { …, customer, customerIndex, targetKind:'customer' }
276
+ > topo.resolveRef(assetNo); // → { kind:'customer', boxId, index, customer, … } | null
277
+ > ```
278
+
260
279
  ### 查询
261
280
 
262
281
  | 方法 | 说明 |
@@ -318,6 +337,8 @@ topo.unhighlightAll();
318
337
 
319
338
  ```javascript
320
339
  topo.setNodePulse('2', { color: '#00C8FF', duration: 1500 }); // 节点脉动
340
+ topo.setNodeGlow('2', { color: '#FF0000', spread: 18 }); // 节点光晕(发光环,颜色可设;ref 支持 psrId)
341
+ topo.removeNodeGlow('2');
321
342
  topo.setEdgeFlow('1', '2', { color: '#00C8FF', duration: 2000 }); // 边流动
322
343
  topo.removeAnimation('2');
323
344
  topo.removeAllAnimations();
package/dist/index.d.ts CHANGED
@@ -8,40 +8,46 @@
8
8
  /// <reference lib="es2015.promise" />
9
9
 
10
10
  // 核心 API
11
+ // ref:全库统一引用 —— 节点内部 id / psrId(设备编码)命中普通节点;
12
+ // 客户 assetNo(资产编号,兼容 consNo/consId)命中「计量箱内电表户」。
11
13
  export class TopoApi {
12
14
  constructor(graph: any, model: any, layout: any, nodeByIdMap: Map<string, any>);
13
-
14
- // 查询 API
15
- getNode(nodeId: string): any;
15
+
16
+ // 统一引用解析
17
+ resolveRef(ref: string): any; // { kind:'node', id, node } | { kind:'customer', boxId, boxNode, index, customer, key, assetNo, name } | null
18
+ getCustomer(ref: string): { node: any, customer: any, index: number, count: number, boxId: string } | null;
19
+
20
+ // 查询 API(目标参数均支持 id/psrId/assetNo;assetNo 命中后按确认语义返回)
21
+ getNode(ref: string): any; // 电表户 → 所在计量箱节点副本(附 customer/customerIndex/customerCount/targetKind)
16
22
  getAllNodes(): any[];
17
23
  findNodes(filter: object): any[];
18
24
  getSelectedId(): string | null;
19
- getNeighbors(nodeId: string): { upstream: any[], downstream: any[] };
20
- getStreamNodes(nodeId: string, direction: 'upstream' | 'downstream'): any[];
25
+ getNeighbors(ref: string): { upstream: any[], downstream: any[] };
26
+ getStreamNodes(ref: string, direction: 'upstream' | 'downstream'): any[];
21
27
  getTrunkNodes(): any[];
22
- getSubtreeNodes(nodeId: string): any[];
23
- getPath(fromId: string, toId: string): any[] | null;
24
- getEdge(srcId: string, tgtId: string): any;
28
+ getSubtreeNodes(ref: string): any[];
29
+ getPath(fromRef: string, toRef: string): any[] | null;
30
+ getEdge(srcRef: string, tgtRef: string): any;
25
31
  getEdges(): any[];
26
- getStreamEdges(nodeId: string, direction: 'upstream' | 'downstream'): any[];
32
+ getStreamEdges(ref: string, direction: 'upstream' | 'downstream'): any[];
27
33
  getMainEdge(): any[];
28
- getNodePosition(nodeId: string): { x: number, y: number } | null;
29
- getEdgePath(srcId: string, tgtId: string): number[][] | null;
34
+ getNodePosition(ref: string): { x: number, y: number } | null; // assetNo → 表位中心
35
+ getEdgePath(srcRef: string, tgtRef: string): number[][] | null;
30
36
  getGraphBounds(): { minX: number, minY: number, maxX: number, maxY: number };
31
37
  getStats(): any;
32
-
38
+
33
39
  // 视图控制
34
40
  fitView(padding?: number): void;
35
41
  zoomTo(ratio: number, center?: { x: number, y: number }): void;
36
42
  zoomIn(step?: number): void;
37
43
  zoomOut(step?: number): void;
38
- locateNode(nodeId: string, zoom?: number): void;
44
+ locateNode(ref: string, zoom?: number): void; // assetNo → 聚焦表位
39
45
  getViewport(): { zoom: number, center: { x: number, y: number } };
40
-
41
- // 节点样式
42
- setNodeStyle(nodeId: string, style: object): void;
43
- batchSetNodeStyle(nodeIds: string[], style: object): void;
44
- resetNodeStyle(nodeId: string): void;
46
+
47
+ // 节点样式(assetNo → 作用于所在计量箱节点)
48
+ setNodeStyle(ref: string, style: object): void;
49
+ batchSetNodeStyle(refs: string[], style: object): void;
50
+ resetNodeStyle(ref: string): void;
45
51
  resetAllNodeStyles(): void;
46
52
 
47
53
  // 节点 / 箱内电表户染色(ref:节点 id 或 psrId;电表户用客户 assetNo/consNo/consId)
@@ -50,43 +56,48 @@ export class TopoApi {
50
56
  resetNodeColor(ref: string): boolean;
51
57
  resetAllNodeColors(): void;
52
58
  getNodeColor(ref: string): { kind: 'node' | 'customer', id: string, index?: number, color: string | null } | null;
53
-
54
- // 边样式
55
- setEdgeStyle(srcId: string, tgtId: string, style: object): void;
56
- batchSetEdgeStyle(edgeIds: [string, string][], style: object): void;
57
- resetEdgeStyle(srcId: string, tgtId: string): void;
58
-
59
- // 高亮与标注
60
- highlightNode(nodeId: string, opts?: object): void;
61
- unhighlightNode(nodeId: string): void;
62
- highlightPath(nodeIds: string[], opts?: object): void;
59
+
60
+ // 边样式(端点均可传节点 id / psrId / assetNo)
61
+ setEdgeStyle(srcRef: string, tgtRef: string, style: object): void;
62
+ batchSetEdgeStyle(edgeRefs: [string, string][], style: object): void;
63
+ resetEdgeStyle(srcRef: string, tgtRef: string): void;
64
+
65
+ // 高亮与标注(assetNo → 该户表位高亮环 + 可选文字)
66
+ highlightNode(ref: string, opts?: object): void;
67
+ unhighlightNode(ref: string): void;
68
+ highlightPath(refs: string[], opts?: object): void;
63
69
  unhighlightAll(): void;
64
- dimOthers(keepIds: string[], opacity?: number): void;
65
-
66
- // 动画
67
- setNodePulse(nodeId: string, opts?: object): void;
68
- setEdgeFlow(srcId: string, tgtId: string, opts?: object): void;
69
- removeAnimation(targetId: string): void;
70
+ dimOthers(keepRefs: string[], opacity?: number): void;
71
+
72
+ // 动画(ref 支持节点 id/psrId;assetNo → 该户电表格)
73
+ setNodePulse(ref: string, opts?: { duration?: number; min?: number; max?: number }): void;
74
+ setEdgeFlow(srcRef: string, tgtRef: string, opts?: object): void;
75
+ removeAnimation(ref: string): void;
70
76
  removeAllAnimations(): void;
71
-
72
- // 文字标注
73
- setText(nodeId: string, text: string, opts?: object): void;
74
- removeText(nodeId: string): void;
77
+
78
+ // 节点光晕动画(ref 支持节点 id / psrId / assetNo)
79
+ setNodeGlow(ref: string, opts?: { color?: string; spread?: number; radius?: number; duration?: number; opacity?: number }): boolean;
80
+ removeNodeGlow(ref: string): boolean;
81
+ removeAllNodeGlows(): void;
82
+
83
+ // 文字标注(assetNo → 该户表位旁小标注)
84
+ setText(ref: string, text: string, opts?: object): void;
85
+ removeText(ref: string): void;
75
86
  removeAllTexts(): void;
76
87
  setDeviceText(cat: string, fontSize: number): void;
77
88
  changeUserName(mode: 'full' | 'short' | 'hidden'): void;
78
-
79
- // 卡片盒
80
- showCard(nodeId: string, content: object): void;
81
- hideCard(nodeId: string): void;
89
+
90
+ // 卡片盒(content 可省略:自动按设备/客户档案生成;assetNo 卡片定位在该户表位旁)
91
+ showCard(ref: string, content?: object): void;
92
+ hideCard(ref: string): void;
82
93
  hideAllCards(): void;
83
94
 
84
- // 连接线与拓扑线(端点支持节点 id 或箱内用户的客户档案编号 consNo/consId
95
+ // 连接线与拓扑线(端点/路径点支持节点 id、psrId 或箱内用户的客户编号 assetNo
85
96
  resolveUserRef(ref: string): string | null;
86
97
  addConnection(fromId: string, toId: string, opts?: object): string | false;
87
98
  removeConnection(fromId: string, toId: string): void;
88
99
  removeAllConnections(): void;
89
- addTopoLine(nodeIds: string[], opts?: object): string;
100
+ addTopoLine(refs: string[], opts?: object): string;
90
101
  removeTopoLine(lineId: string): void;
91
102
  removeAllTopoLines(): void;
92
103
 
package/dist/style.css CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  /* —— 主题变量:dark 为默认值,light 由 [data-theme='light'] 覆盖 —— */
3
- .topo-wrap[data-v-c2cd8b2c] {
3
+ .topo-wrap[data-v-d3774ed5] {
4
4
  --tp-bg: #050505;
5
5
  --tp-toolbar-bg: rgba(20, 20, 20, 0.88);
6
6
  --tp-toolbar-border: #333;
@@ -19,7 +19,7 @@
19
19
  overflow: hidden;
20
20
  background: var(--tp-bg);
21
21
  }
22
- .topo-wrap[data-theme='light'][data-v-c2cd8b2c] {
22
+ .topo-wrap[data-theme='light'][data-v-d3774ed5] {
23
23
  --tp-bg: #ffffff;
24
24
  --tp-toolbar-bg: rgba(255, 255, 255, 0.92);
25
25
  --tp-toolbar-border: #d9d9d9;
@@ -33,11 +33,11 @@
33
33
  --tp-text: #555;
34
34
  --tp-error: #d32f2f;
35
35
  }
36
- .topo-container[data-v-c2cd8b2c] {
36
+ .topo-container[data-v-d3774ed5] {
37
37
  width: 100%;
38
38
  height: 100%;
39
39
  }
40
- .topo-toolbar[data-v-c2cd8b2c] {
40
+ .topo-toolbar[data-v-d3774ed5] {
41
41
  position: absolute;
42
42
  top: 10px;
43
43
  left: 12px;
@@ -52,14 +52,14 @@
52
52
  color: var(--tp-text);
53
53
  z-index: 10;
54
54
  }
55
- .topo-title[data-v-c2cd8b2c] {
55
+ .topo-title[data-v-d3774ed5] {
56
56
  color: var(--tp-title);
57
57
  font-weight: 600;
58
58
  }
59
- .topo-meta[data-v-c2cd8b2c] {
59
+ .topo-meta[data-v-d3774ed5] {
60
60
  color: var(--tp-meta);
61
61
  }
62
- .btn[data-v-c2cd8b2c] {
62
+ .btn[data-v-d3774ed5] {
63
63
  margin-left: 4px;
64
64
  padding: 3px 10px;
65
65
  border: 1px solid var(--tp-btn-border);
@@ -69,12 +69,12 @@
69
69
  cursor: pointer;
70
70
  font-size: 12px;
71
71
  }
72
- .btn[data-v-c2cd8b2c]:hover {
72
+ .btn[data-v-d3774ed5]:hover {
73
73
  border-color: var(--tp-accent);
74
74
  color: var(--tp-accent);
75
75
  }
76
- .topo-loading[data-v-c2cd8b2c],
77
- .topo-error[data-v-c2cd8b2c] {
76
+ .topo-loading[data-v-d3774ed5],
77
+ .topo-error[data-v-d3774ed5] {
78
78
  position: absolute;
79
79
  inset: 0;
80
80
  display: flex;
@@ -85,7 +85,7 @@
85
85
  z-index: 5;
86
86
  background: var(--tp-overlay-bg);
87
87
  }
88
- .topo-error[data-v-c2cd8b2c] {
88
+ .topo-error[data-v-d3774ed5] {
89
89
  color: var(--tp-error);
90
90
  }
91
91