@cpzxrobot/sdk 1.2.85 → 1.2.86

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/device_gateway.ts CHANGED
@@ -208,6 +208,14 @@ export class DeviceGateway extends Object {
208
208
  this.context.showInDeviceManager(id,type);
209
209
  }
210
210
 
211
+ async watch(
212
+ id: number,
213
+ fn: any,
214
+ ) {
215
+ var axios = await this.context.ready;
216
+ return axios.getAsSse(`/api/v2/device/watch/${id}`, fn)
217
+ }
218
+
211
219
  private getFilter<T extends { id: number }>(
212
220
  type: string,
213
221
  cls: new (context: Cpzxrobot) => DeviceFilter<T>
@@ -159,6 +159,10 @@ class DeviceGateway extends Object {
159
159
  show(id, type = "datapoint") {
160
160
  this.context.showInDeviceManager(id, type);
161
161
  }
162
+ async watch(id, fn) {
163
+ var axios = await this.context.ready;
164
+ return axios.getAsSse(`/api/v2/device/watch/${id}`, fn);
165
+ }
162
166
  getFilter(type, cls) {
163
167
  // 如果filters中已经有对应type的过滤器,则直接返回该过滤器
164
168
  if (this.filters.has(type)) {
package/dist/index.js CHANGED
@@ -108,6 +108,49 @@ class Cpzxrobot {
108
108
  }
109
109
  return response;
110
110
  };
111
+ const streamWithAuth = async (input, init, fn) => {
112
+ const headers = new Headers(init === null || init === void 0 ? void 0 : init.headers);
113
+ headers.set('Authorization', this.token);
114
+ const response = await fetch(baseURL + input.toString(), Object.assign(Object.assign({}, init), { headers }));
115
+ var reader = response.body.getReader();
116
+ const decoder = new TextDecoder("utf-8");
117
+ let done = false;
118
+ var buf = "";
119
+ while (!done) {
120
+ const { value, done } = await reader.read();
121
+ if (done) {
122
+ break;
123
+ }
124
+ const chunkValue = decoder.decode(value);
125
+ //split value to lines
126
+ // 将值拆分为行
127
+ buf = buf + chunkValue;
128
+ var i = buf.indexOf("\n");
129
+ while (i > -1) {
130
+ //find first \n
131
+ var line = buf.substring(0, i);
132
+ try {
133
+ if (line === "[DONE]") {
134
+ break;
135
+ }
136
+ else {
137
+ // remove prefix 'data: '
138
+ // 移除前缀 'data: '
139
+ var data = JSON.parse(line.split(": ")[1]);
140
+ //{"choices":[{"delta":{"content":" </"},"index":0}],"created":1741749068,"id":"chatcmpl-67ccb889154043f5874cbf3a64ec163e","model":"DeepSeek-R1","object":"chat.completion.chunk"}
141
+ fn === null || fn === void 0 ? void 0 : fn.call(data);
142
+ }
143
+ }
144
+ catch (e) {
145
+ console.error("解析失败", e);
146
+ }
147
+ buf = buf.substring(i + 1);
148
+ i = buf.indexOf("\n");
149
+ }
150
+ }
151
+ ;
152
+ return true;
153
+ };
111
154
  const processQueryParams = (url, config) => {
112
155
  if (config && config.params) {
113
156
  const flattenParams = (params, prefix = '') => {
@@ -155,7 +198,27 @@ class Cpzxrobot {
155
198
  headers: config === null || config === void 0 ? void 0 : config.headers
156
199
  });
157
200
  const blob = await response.blob();
158
- await this.saveBlob(blob, (_a = config === null || config === void 0 ? void 0 : config.fileName) !== null && _a !== void 0 ? _a : "file");
201
+ // 文件名解析逻辑
202
+ const contentDisposition = response.headers.get('Content-Disposition');
203
+ let filename = (_a = config === null || config === void 0 ? void 0 : config.fileName) !== null && _a !== void 0 ? _a : ""; // 默认文件名
204
+ // 1. 优先使用响应头中的文件名
205
+ if (filename == "") {
206
+ if (contentDisposition) {
207
+ const utf8FilenameMatch = contentDisposition.match(/filename\*=UTF-8''(.+)/i);
208
+ if (utf8FilenameMatch) {
209
+ filename = decodeURIComponent(utf8FilenameMatch[1]);
210
+ }
211
+ else {
212
+ const filenameMatch = contentDisposition.match(/filename="?(.+?)"?(;|$)/i);
213
+ if (filenameMatch)
214
+ filename = filenameMatch[1];
215
+ }
216
+ }
217
+ else {
218
+ filename = "file";
219
+ }
220
+ }
221
+ await this.saveBlob(blob, filename);
159
222
  return { data: blob };
160
223
  },
161
224
  getAndPreview: async (url, config) => {
@@ -198,6 +261,13 @@ class Cpzxrobot {
198
261
  }
199
262
  };
200
263
  });
264
+ },
265
+ getAsSse: (url, fn, config) => {
266
+ return new Promise((resolve, reject) => {
267
+ streamWithAuth(url, {
268
+ method: 'GET',
269
+ }, fn);
270
+ });
201
271
  }
202
272
  };
203
273
  // @ts-ignore
@@ -266,6 +336,7 @@ class Cpzxrobot {
266
336
  const platform =
267
337
  // @ts-ignore
268
338
  window.flutter_inappwebview;
339
+ var that = this;
269
340
  this._getSelectedFarmFromMiniApp = function () {
270
341
  return platform.callHandler("getSelectedFarmFromMiniApp");
271
342
  };
@@ -338,6 +409,12 @@ class Cpzxrobot {
338
409
  upload: function (url, option) {
339
410
  return platform.callHandler("axios_upload", url, option);
340
411
  },
412
+ getAsSse: async function (url, fn, config) {
413
+ var randomId = Math.random().toString(36).substring(2);
414
+ that.sseCallbacks[randomId] = fn;
415
+ await platform.callHandler("axios_getAsSse", url, config, randomId);
416
+ delete that.sseCallbacks[randomId];
417
+ },
341
418
  };
342
419
  if (
343
420
  // @ts-ignore
@@ -358,6 +435,19 @@ class Cpzxrobot {
358
435
  }, 1500);
359
436
  });
360
437
  }
438
+ window.addEventListener('message', (event) => {
439
+ if (event.data == 'capturePort') {
440
+ if (event.ports[0] != null) {
441
+ this.messagePort = event.ports[0];
442
+ this.messagePort.onmessage = (event) => {
443
+ if (event.data.id != undefined) {
444
+ var callback = this.sseCallbacks[event.data.id];
445
+ callback(event.data);
446
+ }
447
+ };
448
+ }
449
+ }
450
+ }, false);
361
451
  }
362
452
  else {
363
453
  if (this.isLocalDomain(domain)) {
package/index.ts CHANGED
@@ -43,6 +43,7 @@ export class Cpzxrobot {
43
43
  rejectReady!: (reason?: any) => void;
44
44
  transport: TransportGateway;
45
45
  platformReady!: Promise<boolean>;
46
+ messagePort!: MessagePort;
46
47
  _getSelectedFarmFromMiniApp!: () => any;
47
48
  _getSelectedUnitFromMiniApp!: () => any;
48
49
  _jumpToMiniApp!: (url: string) => any;
@@ -78,6 +79,7 @@ export class Cpzxrobot {
78
79
  ai: AiGateway = new AiGateway(this);
79
80
  construction: ConstructionGateway = new ConstructionGateway(this);
80
81
  system: SystemGateway = new SystemGateway(this);
82
+ sseCallbacks: any;
81
83
 
82
84
 
83
85
  constructor(appCode: string) {
@@ -127,6 +129,53 @@ export class Cpzxrobot {
127
129
  return response;
128
130
  };
129
131
 
132
+ const streamWithAuth = async (input: RequestInfo, init?: RequestInit, fn?: Function) => {
133
+ const headers = new Headers(init?.headers);
134
+ headers.set('Authorization', this.token);
135
+ const response = await fetch(baseURL + input.toString(), {
136
+ ...init,
137
+ headers
138
+ });
139
+
140
+ var reader = response.body!.getReader();
141
+ const decoder = new TextDecoder("utf-8");
142
+ let done = false;
143
+ var buf: string = "";
144
+ while (!done) {
145
+ const { value, done } = await reader.read();
146
+ if (done) {
147
+ break;
148
+ }
149
+ const chunkValue = decoder.decode(value);
150
+
151
+ //split value to lines
152
+ // 将值拆分为行
153
+ buf = buf + chunkValue;
154
+ var i = buf.indexOf("\n");
155
+ while (i > -1) {
156
+ //find first \n
157
+ var line = buf.substring(0, i);
158
+ try {
159
+ if (line === "[DONE]") {
160
+ break;
161
+ } else {
162
+ // remove prefix 'data: '
163
+ // 移除前缀 'data: '
164
+ var data = JSON.parse(line.split(": ")[1]);
165
+ //{"choices":[{"delta":{"content":" </"},"index":0}],"created":1741749068,"id":"chatcmpl-67ccb889154043f5874cbf3a64ec163e","model":"DeepSeek-R1","object":"chat.completion.chunk"}
166
+ fn?.call(data);
167
+ }
168
+ } catch (e) {
169
+ console.error("解析失败", e);
170
+ }
171
+ buf = buf.substring(i + 1);
172
+ i = buf.indexOf("\n");
173
+ }
174
+ };
175
+ return true;
176
+ };
177
+
178
+
130
179
  const processQueryParams = (url: string, config?: any) => {
131
180
  if (config && config.params) {
132
181
  const flattenParams = (params: any, prefix = '') => {
@@ -177,7 +226,27 @@ export class Cpzxrobot {
177
226
  headers: config?.headers
178
227
  });
179
228
  const blob = await response.blob();
180
- await this.saveBlob(blob, config?.fileName ?? "file");
229
+
230
+ // 文件名解析逻辑
231
+ const contentDisposition = response.headers.get('Content-Disposition');
232
+ let filename = config?.fileName ?? ""; // 默认文件名
233
+
234
+ // 1. 优先使用响应头中的文件名
235
+ if (filename == "") {
236
+ if (contentDisposition) {
237
+ const utf8FilenameMatch = contentDisposition.match(/filename\*=UTF-8''(.+)/i);
238
+ if (utf8FilenameMatch) {
239
+ filename = decodeURIComponent(utf8FilenameMatch[1]);
240
+ } else {
241
+ const filenameMatch = contentDisposition.match(/filename="?(.+?)"?(;|$)/i);
242
+ if (filenameMatch) filename = filenameMatch[1];
243
+ }
244
+ } else {
245
+ filename = "file"
246
+ }
247
+ }
248
+
249
+ await this.saveBlob(blob, filename);
181
250
  return { data: blob };
182
251
  },
183
252
  getAndPreview: async (url: string, config?: {
@@ -222,6 +291,17 @@ export class Cpzxrobot {
222
291
  }
223
292
  };
224
293
  });
294
+ },
295
+ getAsSse: (url: string, fn: any, config?: {
296
+ fileName?: string;
297
+ params?: any;
298
+ preview?: boolean;
299
+ }) => {
300
+ return new Promise<any>((resolve, reject) => {
301
+ streamWithAuth(url, {
302
+ method: 'GET',
303
+ }, fn);
304
+ });
225
305
  }
226
306
  };
227
307
  // @ts-ignore
@@ -295,6 +375,7 @@ export class Cpzxrobot {
295
375
  } =
296
376
  // @ts-ignore
297
377
  window.flutter_inappwebview;
378
+ var that = this;
298
379
  this._getSelectedFarmFromMiniApp = function () {
299
380
  return platform.callHandler("getSelectedFarmFromMiniApp");
300
381
  };
@@ -356,10 +437,10 @@ export class Cpzxrobot {
356
437
  return platform.callHandler("axios_getAndSave", url, config);
357
438
  },
358
439
  getAndPreview: function (url, config) {
359
- if (config== undefined){
440
+ if (config == undefined) {
360
441
  config = {};
361
442
  }
362
- if (config.preview == undefined){
443
+ if (config.preview == undefined) {
363
444
  config.preview = true;
364
445
  }
365
446
  return platform.callHandler("axios_getAndSave", url, config);
@@ -367,6 +448,12 @@ export class Cpzxrobot {
367
448
  upload: function (url, option) {
368
449
  return platform.callHandler("axios_upload", url, option);
369
450
  },
451
+ getAsSse: async function (url, fn, config?) {
452
+ var randomId = Math.random().toString(36).substring(2);
453
+ that.sseCallbacks[randomId] = fn;
454
+ await platform.callHandler("axios_getAsSse", url, config, randomId);
455
+ delete that.sseCallbacks[randomId];
456
+ },
370
457
  };
371
458
  if (
372
459
  // @ts-ignore
@@ -390,6 +477,19 @@ export class Cpzxrobot {
390
477
  }, 1500);
391
478
  });
392
479
  }
480
+ window.addEventListener('message', (event) => {
481
+ if (event.data == 'capturePort') {
482
+ if (event.ports[0] != null) {
483
+ this.messagePort = event.ports[0];
484
+ this.messagePort.onmessage = (event) => {
485
+ if (event.data.id != undefined) {
486
+ var callback = this.sseCallbacks[event.data.id];
487
+ callback(event.data);
488
+ }
489
+ };
490
+ }
491
+ }
492
+ }, false);
393
493
  } else {
394
494
  if (this.isLocalDomain(domain)) {
395
495
  this.mode = "dev";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cpzxrobot/sdk",
3
- "version": "1.2.85",
3
+ "version": "1.2.86",
4
4
  "description": "提供给上海正芯数智APP第三方H5应用使用的SDK",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/types.d.ts CHANGED
@@ -300,6 +300,7 @@ interface MyAxiosInstance {
300
300
  //option.fileField:上传的文件字段名,默认为file
301
301
  //option.data:上传的数据,例如{id:123,name:"xxx"},文件会被附加到data中,作为文件字段上传
302
302
  upload: (url: string, option?: {}) => Promise<any>;
303
+ getAsSse: (url: string, fn: any, config?: any) => Promise<any>;
303
304
  }
304
305
 
305
306
  interface Assistant {