model-action 2.1.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,71 @@
1
1
  /**
2
- * 点POI打开外部弹窗
3
- * 用来让UE抛出POI位置
2
+ * 弹框:三维内置弹框或外部弹框(返回屏幕坐标比例供前端自绘,可随锚点移动)。
3
+ * 内置样式需按项目单独开发,本包只负责协议与发送。
4
4
  */
5
5
  import { Action } from "./Action";
6
+ /** create / remove / update / move */
7
+ export type WindowCrudAction = "create" | "remove" | "update" | "move";
8
+ export type WindowActionType = WindowCrudAction | "getWindowDetails";
9
+ /** buildIn:三维内弹框;buildOut:前端弹框(接收屏幕坐标比例) */
10
+ export type WindowPopType = "buildIn" | "buildOut";
11
+ /** 弹框详情行:属性 / 事件 / 服务 */
12
+ export type WindowDetailRowType = "attr" | "event" | "service";
13
+ /** windowInfo.params 单项 */
14
+ export interface WindowDetailParam {
15
+ /** 默认 attr;为空时三维会按 attr 处理 */
16
+ type?: WindowDetailRowType;
17
+ id?: string;
18
+ value?: string;
19
+ name?: string;
20
+ unit?: string;
21
+ textColor?: string;
22
+ textSize?: number;
23
+ /** 文本是否有背景(协议字段名如此) */
24
+ hasBlackground?: boolean;
25
+ alertIs?: boolean;
26
+ alertTime?: string;
27
+ }
28
+ /** 弹框主体配置 */
29
+ export interface WindowInfo {
30
+ /** 设备所在场景编码,按项目约定,非必须 */
31
+ sceneCode?: string;
32
+ /** 弹框唯一 id,不传由三维生成 */
33
+ id?: string;
34
+ /** 绑定的三维资产模型 id */
35
+ linkAssetId?: string;
36
+ /** 标题 */
37
+ name?: string;
38
+ /** 设备/弹框类型 */
39
+ type?: string;
40
+ /** 世界坐标;不传则可用 linkAssetId 对应资产坐标 */
41
+ position?: string;
42
+ /** 相对锚点偏移,用于微调 */
43
+ localPosition?: string;
44
+ /** 详情内容;列表时每项一行 */
45
+ params?: WindowDetailParam[];
46
+ }
47
+ export type WindowPayload = {
48
+ action: WindowCrudAction;
49
+ popType: WindowPopType;
50
+ windowInfo: WindowInfo;
51
+ } | {
52
+ action: "getWindowDetails";
53
+ /** 如机柜、机柜设备 */
54
+ type: string;
55
+ id: string;
56
+ /** 注意:与 windowInfo.sceneCode 不同,此处协议字段名为 senceCode */
57
+ senceCode: string;
58
+ };
6
59
  export declare class WindowAction extends Action {
60
+ private static crud;
61
+ static createWindow(popType: WindowPopType, windowInfo: WindowInfo): Promise<any>;
62
+ static removeWindow(popType: WindowPopType, windowInfo: WindowInfo): Promise<any>;
63
+ static updateWindow(popType: WindowPopType, windowInfo: WindowInfo): Promise<any>;
64
+ static moveWindow(popType: WindowPopType, windowInfo: WindowInfo): Promise<any>;
7
65
  /**
8
- * 打开外部弹窗
9
- * @param {*} attendId (必须)弹框的三维物体的唯一ID)
10
- */
11
- static openOut(attendId: string): void;
12
- /**
13
- * 关闭外部弹窗
14
- * @param {*} attendId (必须)弹框的三维物体的唯一ID)
66
+ * 查询弹框详情(按设备类型、设备 id、场景)
67
+ * @param senceCode 协议字段名与 sceneCode 拼写不一致,与三维约定保持一致
15
68
  */
16
- static closeOut(attendId: string): void;
69
+ static getWindowDetails(type: string, id: string, senceCode: string): Promise<any>;
17
70
  }
18
71
  //# sourceMappingURL=Window.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Window.d.ts","sourceRoot":"","sources":["../../src/modules/Window.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAG,MAAM,UAAU,CAAC;AAEnC,qBAAa,YAAa,SAAQ,MAAM;IACpC;;;QAGI;IACJ,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM;IAY/B;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM;CAWnC"}
1
+ {"version":3,"file":"Window.d.ts","sourceRoot":"","sources":["../../src/modules/Window.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAa,MAAM,UAAU,CAAC;AAE7C,sCAAsC;AACtC,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEvE,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAErE,4CAA4C;AAC5C,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAEnD,yBAAyB;AACzB,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAE/D,2BAA2B;AAC3B,MAAM,WAAW,iBAAiB;IAC9B,8BAA8B;IAC9B,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,aAAa;AACb,MAAM,WAAW,UAAU;IACvB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS;IACT,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB;IACnB,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED,MAAM,MAAM,aAAa,GACnB;IACI,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;CAC1B,GACD;IACI,MAAM,EAAE,kBAAkB,CAAC;IAC3B,eAAe;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;CACrB,CAAC;AAOR,qBAAa,YAAa,SAAQ,MAAM;IACpC,OAAO,CAAC,MAAM,CAAC,IAAI;IAiBnB,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU;IAIlE,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU;IAIlE,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU;IAIlE,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU;IAIhE;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CACnB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM;CAaxB"}
@@ -1,38 +1,41 @@
1
1
  /**
2
- * 点POI打开外部弹窗
3
- * 用来让UE抛出POI位置
2
+ * 弹框:三维内置弹框或外部弹框(返回屏幕坐标比例供前端自绘,可随锚点移动)。
3
+ * 内置样式需按项目单独开发,本包只负责协议与发送。
4
4
  */
5
- import { Action, } from "./Action";
5
+ import { Action } from "./Action";
6
6
  export class WindowAction extends Action {
7
- /**
8
- * 打开外部弹窗
9
- * @param {*} attendId (必须)弹框的三维物体的唯一ID)
10
- */
11
- static openOut(attendId) {
12
- const param = {
13
- cmd: "window",
14
- data: {
15
- action: 'pop',
16
- type: 'builtOut',
17
- attendId,
18
- }
7
+ static crud(action, popType, windowInfo, log) {
8
+ const data = {
9
+ action,
10
+ popType,
11
+ windowInfo
19
12
  };
20
- this.sendParam(param, '打开外部弹窗');
13
+ return this.sendParam({ cmd: "window", data }, log);
14
+ }
15
+ static createWindow(popType, windowInfo) {
16
+ return this.crud("create", popType, windowInfo, `弹框创建 - ${popType}`);
17
+ }
18
+ static removeWindow(popType, windowInfo) {
19
+ return this.crud("remove", popType, windowInfo, `弹框移除 - ${popType}`);
20
+ }
21
+ static updateWindow(popType, windowInfo) {
22
+ return this.crud("update", popType, windowInfo, `弹框更新 - ${popType}`);
23
+ }
24
+ static moveWindow(popType, windowInfo) {
25
+ return this.crud("move", popType, windowInfo, `弹框移动 - ${popType}`);
21
26
  }
22
27
  /**
23
- * 关闭外部弹窗
24
- * @param {*} attendId (必须)弹框的三维物体的唯一ID)
28
+ * 查询弹框详情(按设备类型、设备 id、场景)
29
+ * @param senceCode 协议字段名与 sceneCode 拼写不一致,与三维约定保持一致
25
30
  */
26
- static closeOut(attendId) {
27
- const param = {
28
- cmd: "window",
29
- data: {
30
- action: 'remove',
31
- type: 'builtOut',
32
- attendId,
33
- }
31
+ static getWindowDetails(type, id, senceCode) {
32
+ const data = {
33
+ action: "getWindowDetails",
34
+ type,
35
+ id,
36
+ senceCode
34
37
  };
35
- this.sendParam(param, '关闭外部弹窗');
38
+ return this.sendParam({ cmd: "window", data }, `获取弹框详情 - type: ${type} id: ${id}`);
36
39
  }
37
40
  }
38
41
  //# sourceMappingURL=Window.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Window.js","sourceRoot":"","sources":["../../src/modules/Window.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,OAAO,EAAE,MAAM,GAAG,MAAM,UAAU,CAAC;AAEnC,MAAM,OAAO,YAAa,SAAQ,MAAM;IACpC;;;QAGI;IACJ,MAAM,CAAC,OAAO,CAAC,QAAgB;QAC3B,MAAM,KAAK,GAAQ;YACf,GAAG,EAAE,QAAQ;YACb,IAAI,EAAE;gBACF,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,UAAU;gBAChB,QAAQ;aACX;SACJ,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IACnC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAgB;QAC5B,MAAM,KAAK,GAAQ;YACf,GAAG,EAAE,QAAQ;YACb,IAAI,EAAE;gBACF,MAAM,EAAE,QAAQ;gBAChB,IAAI,EAAE,UAAU;gBAChB,QAAQ;aACX;SACJ,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IACnC,CAAC;CACJ"}
1
+ {"version":3,"file":"Window.js","sourceRoot":"","sources":["../../src/modules/Window.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAa,MAAM,UAAU,CAAC;AAqE7C,MAAM,OAAO,YAAa,SAAQ,MAAM;IAC5B,MAAM,CAAC,IAAI,CACf,MAAwB,EACxB,OAAsB,EACtB,UAAsB,EACtB,GAAW;QAEX,MAAM,IAAI,GAAyD;YAC/D,MAAM;YACN,OAAO;YACP,UAAU;SACb,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CACjB,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAqB,EAC1C,GAAG,CACN,CAAC;IACN,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,OAAsB,EAAE,UAAsB;QAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,OAAsB,EAAE,UAAsB;QAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,OAAsB,EAAE,UAAsB;QAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,OAAsB,EAAE,UAAsB;QAC5D,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,OAAO,EAAE,CAAC,CAAC;IACvE,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CACnB,IAAY,EACZ,EAAU,EACV,SAAiB;QAEjB,MAAM,IAAI,GAA2D;YACjE,MAAM,EAAE,kBAAkB;YAC1B,IAAI;YACJ,EAAE;YACF,SAAS;SACZ,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CACjB,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAqB,EAC1C,kBAAkB,IAAI,QAAQ,EAAE,EAAE,CACrC,CAAC;IACN,CAAC;CACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "model-action",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "description": "与三维交互api",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -8,9 +8,42 @@ export { StatusAction } from './modules/Status'
8
8
  export { CameraViewAction } from './modules/CameraView'
9
9
  export { FocusAction } from './modules/Focus'
10
10
  export { SceneAction } from './modules/Scene'
11
+ export { SceneAssetAction } from './modules/SceneAsset'
11
12
  export { GameModeAction } from './modules/GameMode'
12
13
  export { AnimationAction } from './modules/Animation'
13
14
  export { EffectAction } from './modules/Effect'
14
15
  export { InitAction } from './modules/Init'
15
16
  export { VideoFusionAction } from './modules/VideoFusion'
17
+ export { WindowAction } from './modules/Window'
18
+ export { SingleMeshAction } from './modules/SingleMesh'
19
+ export type {
20
+ SceneAssetActionType,
21
+ SceneAssetType,
22
+ RoomMapLocationParam,
23
+ PoiMapLocationParam,
24
+ SceneAssetMapLocationPayload,
25
+ SceneAssetPayload,
26
+ SceneAssetOnAssetSelectedData,
27
+ SceneAssetOnEditAssetData,
28
+ SceneAssetPushData,
29
+ SceneAssetPushMessage
30
+ } from './modules/SceneAsset'
31
+ export type {
32
+ WindowActionType,
33
+ WindowCrudAction,
34
+ WindowPopType,
35
+ WindowDetailRowType,
36
+ WindowDetailParam,
37
+ WindowInfo,
38
+ WindowPayload
39
+ } from './modules/Window'
40
+ export type {
41
+ SingleMeshOp,
42
+ SingleMeshSceneType,
43
+ SingleMeshDeviceModelType,
44
+ SingleMeshDeviceCategory,
45
+ SingleMeshDevice,
46
+ SingleMeshScene,
47
+ SingleMeshPayload
48
+ } from './modules/SingleMesh'
16
49
  export type { InitVideoOptions } from './modules/Init'
@@ -15,12 +15,21 @@ interface PendingRequest {
15
15
  timeout: ReturnType<typeof setTimeout>;
16
16
  }
17
17
 
18
+ /** 三维大包分包:首包 -S、中间 -I、末包 -E,拼接后为完整 JSON 字符串(与未分包时一致) */
19
+ interface ChunkAssembly {
20
+ buffer: string;
21
+ requestId: string | null;
22
+ }
23
+
18
24
  export class Action {
19
25
  // 存储待处理的请求,key 为 requestId
20
26
  private static pendingRequests = new Map<string, PendingRequest>();
21
-
27
+
28
+ /** 正在组装的分包(同一时间仅处理一条分包流;并行多条需三维在每段携带 requestId,见 tryExtractRequestId) */
29
+ private static chunkAssembly: ChunkAssembly | null = null;
30
+
22
31
  // 默认超时时间(毫秒)
23
- private static defaultTimeout = 30000;
32
+ private static defaultTimeout = 10000;
24
33
 
25
34
  /**
26
35
  * 生成唯一请求ID
@@ -34,6 +43,85 @@ export class Action {
34
43
  * 注意:三维系统保证在响应中返回 requestId,因此通过 requestId 精确匹配请求
35
44
  * @param responseData 响应数据,必须包含 requestId 字段
36
45
  */
46
+ /**
47
+ * 从 JSON 片段中尽早解析 requestId(用于日志;分包并行时需首段或中段出现该字段)
48
+ */
49
+ private static tryExtractRequestId(jsonPrefix: string): string | null {
50
+ const m = jsonPrefix.match(/"requestId"\s*:\s*"([^"]+)"/);
51
+ return m ? m[1] : null;
52
+ }
53
+
54
+ /**
55
+ * 处理 peer-stream 收到的一条原始消息(支持未分包 JSON 与 -S/-I/-E 分包)
56
+ * @param raw 字符串:整段 JSON,或以 -S / -I / -E 开头的分包片段
57
+ * @param onMessage 与 Init 中一致的业务回调(收到完整一条 JSON 后调用一次)
58
+ */
59
+ static handleIncomingRawMessage(raw: string | object, onMessage?: (data: any) => void) {
60
+ if (typeof raw !== 'string') {
61
+ const data = raw as any;
62
+ this.handleResponse(data);
63
+ onMessage?.(data);
64
+ return;
65
+ }
66
+
67
+ const isChunk = raw.startsWith('-S') || raw.startsWith('-I') || raw.startsWith('-E');
68
+ if (!isChunk) {
69
+ let data: any;
70
+ try {
71
+ data = JSON.parse(raw);
72
+ } catch (e) {
73
+ console.error('解析消息失败:', e);
74
+ return;
75
+ }
76
+ this.handleResponse(data);
77
+ onMessage?.(data);
78
+ return;
79
+ }
80
+
81
+ const tag = raw.slice(0, 2);
82
+ const body = raw.slice(2);
83
+
84
+ if (tag === '-S') {
85
+ if (this.chunkAssembly) {
86
+ console.warn('分包消息: 收到新的 -S,丢弃未拼完的上一包');
87
+ }
88
+ this.chunkAssembly = { buffer: body, requestId: this.tryExtractRequestId(body) };
89
+ return;
90
+ }
91
+
92
+ if (tag === '-I') {
93
+ if (!this.chunkAssembly) {
94
+ console.error('分包消息: 收到 -I 但缺少前置 -S');
95
+ return;
96
+ }
97
+ this.chunkAssembly.buffer += body;
98
+ if (!this.chunkAssembly.requestId) {
99
+ this.chunkAssembly.requestId = this.tryExtractRequestId(this.chunkAssembly.buffer);
100
+ }
101
+ return;
102
+ }
103
+
104
+ if (tag === '-E') {
105
+ if (!this.chunkAssembly) {
106
+ console.error('分包消息: 收到 -E 但缺少前置 -S');
107
+ return;
108
+ }
109
+ this.chunkAssembly.buffer += body;
110
+ const fullJson = this.chunkAssembly.buffer;
111
+ this.chunkAssembly = null;
112
+
113
+ let data: any;
114
+ try {
115
+ data = JSON.parse(fullJson);
116
+ } catch (e) {
117
+ console.error('分包消息 JSON 解析失败:', e);
118
+ return;
119
+ }
120
+ this.handleResponse(data);
121
+ onMessage?.(data);
122
+ }
123
+ }
124
+
37
125
  static handleResponse(responseData: any) {
38
126
  // 通过 requestId 精确匹配请求(三维系统保证返回 requestId)
39
127
  if (responseData.requestId && this.pendingRequests.has(responseData.requestId)) {
@@ -52,20 +140,20 @@ export class Action {
52
140
 
53
141
  /**
54
142
  * 发送到model
55
- * @param {SendParam} param 发送的参数
56
- * @param {string} msg 打印的信息
57
- * @param {number} timeout 超时时间(毫秒),默认 30
58
- * @returns {Promise<any>} 返回 Promise,在收到响应时 resolve
143
+ * @param param 发送的参数
144
+ * @param msg 打印的信息
145
+ * @param timeout 超时时间(毫秒),默认 10
146
+ * @returns 收到响应时 resolve 为三维数据;超时时 resolve `{ timedOut: true, requestId }`(不 reject)
59
147
  */
60
148
  static sendParam<T extends SendParam>(
61
- param: T,
149
+ param: T,
62
150
  msg: string = '',
63
151
  timeout: number = this.defaultTimeout
64
152
  ): Promise<any> {
65
153
  return new Promise((resolve, reject) => {
66
154
  // 生成唯一请求ID
67
155
  const requestId = this.generateRequestId();
68
-
156
+
69
157
  // 在请求参数中添加 requestId
70
158
  const paramWithId = {
71
159
  ...param,
@@ -73,11 +161,11 @@ export class Action {
73
161
  };
74
162
 
75
163
  console.log(`发送给三维|${msg}`, JSON.stringify(paramWithId));
76
-
77
- // 创建超时定时器
164
+
78
165
  const timeoutHandle = setTimeout(() => {
79
166
  this.pendingRequests.delete(requestId);
80
- reject(new Error(`请求超时: ${msg}`));
167
+ console.warn(`请求等待超时(三维可能不返回): ${msg}`);
168
+ resolve({ timedOut: true, requestId });
81
169
  }, timeout);
82
170
 
83
171
  // 存储待处理的请求(通过 requestId 匹配)
@@ -4,8 +4,6 @@
4
4
  import { Action } from "./Action";
5
5
  // 导入 peer-stream.js 以确保自定义元素在使用前被注册
6
6
  import "../peer-stream.js";
7
- import { VideoFusionAction } from "./VideoFusion";
8
-
9
7
  // 初始化配置选项
10
8
  export interface InitVideoOptions {
11
9
  /** 视频容器元素(DOM元素或ref) */
@@ -56,26 +54,14 @@ export class InitAction extends Action {
56
54
  ps.registerMouseHoverEvents();
57
55
  }
58
56
 
59
- // 监听消息事件
60
- if (options.onMessage) {
61
- ps.addEventListener("message", (e: any) => {
62
- try {
63
- const data = JSON.parse(e.detail);
64
- // 先处理 Promise 响应
65
- Action.handleResponse(data);
66
- // 然后调用用户自定义的回调
67
- options.onMessage!(data);
68
- //视频融合初始化的返回。我这里先自动处理一波,外面可以不处理了
69
- // if (data.code === '0' && data.cmd === 'videoFusion' && data.message.includes("初始化")) {
70
- // //获取当前所有融合点位ID
71
-
72
- // VideoFusionAction.get();
73
- // }
74
- } catch (error) {
75
- console.error("解析消息失败:", error);
76
- }
77
- });
78
- }
57
+ // 监听消息事件(含三维大包 -S/-I/-E 分包拼包后,再 handleResponse + onMessage)
58
+ ps.addEventListener("message", (e: any) => {
59
+ try {
60
+ Action.handleIncomingRawMessage(e.detail, options.onMessage);
61
+ } catch (error) {
62
+ console.error("解析消息失败:", error);
63
+ }
64
+ });
79
65
 
80
66
  // 监听元数据加载完成
81
67
  ps.addEventListener("loadedmetadata", () => {
@@ -0,0 +1,242 @@
1
+ /**
2
+ * 场景资产操作方法(上图、房间/资产与三维场景绑定等)
3
+ */
4
+ import { Action, SendParam } from "./Action";
5
+
6
+ /** 前端发往三维的 action */
7
+ export type SceneAssetActionType =
8
+ | "mapLocation"
9
+ | "editSave"
10
+ | "editCancel"
11
+ | "disableSceneEdit";
12
+
13
+ /** 资产大类:房间、POI 等 */
14
+ export type SceneAssetType = "Room" | "POI" | string;
15
+
16
+ /** 地图定位 — 房间在单层下的条目 */
17
+ export interface RoomMapLocationParam {
18
+ /** 房间等业务唯一标识,必须 */
19
+ id: string;
20
+ /** 三维场景内唯一 id,初始可空,上图后由三维回写 */
21
+ sceneId?: string;
22
+ /** 展示名称,必须 */
23
+ name: string;
24
+ /** 如 `X=0.0,Y=0.0,Z=0.0`;空或省略则使用楼层分层默认定位 */
25
+ location?: string;
26
+ description?: string;
27
+ /** 是否已上图;也可由后台根据坐标是否为空推断 */
28
+ alreadyMap?: boolean;
29
+ }
30
+
31
+ /** POI 打点 — 单条参数(与 Room 的 params 结构不同) */
32
+ export interface PoiMapLocationParam {
33
+ /** POI 子类型,用于区分展示样式,如 Camera */
34
+ type: string;
35
+ /** 非必须;前端有唯一值可传给三维,否则由三维生成并回传 */
36
+ sceneId?: string;
37
+ /** 业务关联 ID,必须 */
38
+ linkId: string;
39
+ /** 有则建议传入 */
40
+ name?: string;
41
+ /** 非必须;不传时三维可取当前鼠标在场景中的坐标 */
42
+ location?: string;
43
+ }
44
+
45
+ export type SceneAssetMapLocationPayload =
46
+ | {
47
+ action: "mapLocation";
48
+ type: "Room";
49
+ buildingId: string;
50
+ floor: string;
51
+ params: RoomMapLocationParam[];
52
+ }
53
+ | {
54
+ action: "mapLocation";
55
+ type: "POI";
56
+ /** 不传或空:室外打点;传入时三维会与当前分层校验 */
57
+ buildingId?: string;
58
+ floor?: string;
59
+ params: PoiMapLocationParam[];
60
+ };
61
+
62
+ export type SceneAssetPayload =
63
+ | SceneAssetMapLocationPayload
64
+ | {
65
+ action: "editSave";
66
+ type: SceneAssetType;
67
+ /** 三维返回的 sceneId */
68
+ id: string;
69
+ }
70
+ | {
71
+ action: "editCancel";
72
+ type: SceneAssetType;
73
+ id: string;
74
+ }
75
+ | {
76
+ action: "disableSceneEdit";
77
+ };
78
+
79
+ /** 三维推送:编辑模式下选中资产,前端可据此弹出编辑框 */
80
+ export interface SceneAssetOnAssetSelectedData {
81
+ action: "OnAssetSelected";
82
+ type: SceneAssetType;
83
+ /** POI 场景下为前端下发的 linkId */
84
+ id: string;
85
+ /** 三维生成的唯一 id,需入库 */
86
+ sceneId: string;
87
+ /** POI 所在位置描述,需入库与三维一致 */
88
+ place?: string;
89
+ location: string;
90
+ }
91
+
92
+ /** 三维推送:单个资产修改后的结果 */
93
+ export interface SceneAssetOnEditAssetData {
94
+ action: "OnEditAsset";
95
+ type: SceneAssetType;
96
+ id: string;
97
+ sceneId: string;
98
+ location: string;
99
+ }
100
+
101
+ export type SceneAssetPushData =
102
+ | SceneAssetOnAssetSelectedData
103
+ | SceneAssetOnEditAssetData;
104
+
105
+ /** 三维经 sceneAsset 推送的通用消息壳(无 requestId) */
106
+ export interface SceneAssetPushMessage<
107
+ T extends SceneAssetPushData = SceneAssetPushData
108
+ > {
109
+ code: string;
110
+ message: string;
111
+ cmd: "sceneAsset";
112
+ data: T;
113
+ }
114
+
115
+ type SceneAssetParamType = SendParam & {
116
+ cmd: "sceneAsset";
117
+ data: SceneAssetPayload;
118
+ };
119
+
120
+ function appendPoiBuildingFloor(
121
+ data: Extract<SceneAssetMapLocationPayload, { type: "POI" }>,
122
+ buildingId?: string,
123
+ floor?: string
124
+ ) {
125
+ const b = buildingId?.trim();
126
+ const f = floor?.trim();
127
+ if (b) data.buildingId = b;
128
+ if (f) data.floor = f;
129
+ }
130
+
131
+ export class SceneAssetAction extends Action {
132
+ /**
133
+ * 房间等在指定建筑、楼层上地图定位(上图)
134
+ * @param buildingId 建筑唯一 ID
135
+ * @param floor 楼层,如 1F、B1
136
+ */
137
+ static mapRoomLocation(
138
+ buildingId: string,
139
+ floor: string,
140
+ params: RoomMapLocationParam[]
141
+ ) {
142
+ const data: Extract<SceneAssetMapLocationPayload, { type: "Room" }> = {
143
+ action: "mapLocation",
144
+ type: "Room",
145
+ buildingId,
146
+ floor,
147
+ params
148
+ };
149
+
150
+ const sendParam: SceneAssetParamType = {
151
+ cmd: "sceneAsset",
152
+ data
153
+ };
154
+ return this.sendParam(
155
+ sendParam,
156
+ `场景资产房间上图 - buildingId: ${buildingId} floor: ${floor}`
157
+ );
158
+ }
159
+
160
+ /**
161
+ * POI 打点上图。不传 `buildingId`、`floor`(或仅空白)视为室外;
162
+ * 传入时三维会与当前分层匹配,不匹配则打点失败,前端需提示先分层到目标楼层。
163
+ */
164
+ static mapPoiLocation(
165
+ params: PoiMapLocationParam[],
166
+ buildingId?: string,
167
+ floor?: string
168
+ ) {
169
+ const data: Extract<SceneAssetMapLocationPayload, { type: "POI" }> = {
170
+ action: "mapLocation",
171
+ type: "POI",
172
+ params
173
+ };
174
+ appendPoiBuildingFloor(data, buildingId, floor);
175
+
176
+ const sendParam: SceneAssetParamType = {
177
+ cmd: "sceneAsset",
178
+ data
179
+ };
180
+ const scope =
181
+ buildingId?.trim() && floor?.trim()
182
+ ? `buildingId: ${buildingId} floor: ${floor}`
183
+ : "室外";
184
+ return this.sendParam(sendParam, `场景资产 POI 上图 - ${scope}`);
185
+ }
186
+
187
+ /**
188
+ * 前端编辑框「保存」后通知三维
189
+ * @param id 三维返回的 sceneId
190
+ */
191
+ static editSave(id: string, type: SceneAssetType = "Room") {
192
+ const data: Extract<SceneAssetPayload, { action: "editSave" }> = {
193
+ action: "editSave",
194
+ type,
195
+ id
196
+ };
197
+
198
+ const sendParam: SceneAssetParamType = {
199
+ cmd: "sceneAsset",
200
+ data
201
+ };
202
+ return this.sendParam(
203
+ sendParam,
204
+ `场景资产编辑保存 - ${type} sceneId: ${id}`
205
+ );
206
+ }
207
+
208
+ /**
209
+ * 前端编辑框「取消」后通知三维
210
+ * @param id 三维返回的 sceneId
211
+ */
212
+ static editCancel(id: string, type: SceneAssetType = "Room") {
213
+ const data: Extract<SceneAssetPayload, { action: "editCancel" }> = {
214
+ action: "editCancel",
215
+ type,
216
+ id
217
+ };
218
+
219
+ const sendParam: SceneAssetParamType = {
220
+ cmd: "sceneAsset",
221
+ data
222
+ };
223
+ return this.sendParam(
224
+ sendParam,
225
+ `场景资产编辑取消 - ${type} sceneId: ${id}`
226
+ );
227
+ }
228
+
229
+ /** 退出整个资产管理编辑模块 */
230
+ static disableSceneEdit() {
231
+ const data: Extract<SceneAssetPayload, { action: "disableSceneEdit" }> =
232
+ {
233
+ action: "disableSceneEdit"
234
+ };
235
+
236
+ const sendParam: SceneAssetParamType = {
237
+ cmd: "sceneAsset",
238
+ data
239
+ };
240
+ return this.sendParam(sendParam, "退出场景资产编辑模块");
241
+ }
242
+ }