@cpzxrobot/sdk 1.2.92 → 1.2.94

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.
@@ -0,0 +1,179 @@
1
+ import { PlatformInterface } from "./platform_interface";
2
+ import { Factory, MyAxiosInstance, Unit } from "./types";
3
+
4
+ export class MobilePlatform implements PlatformInterface {
5
+ private platform: {
6
+ callHandler: Function;
7
+ };
8
+ private sseCallbacks: { [key: string]: (data: any) => void } = {};
9
+ token: string = "";
10
+ appCode: string = "";
11
+ baseURL: string = "";
12
+
13
+ constructor() {
14
+ // @ts-ignore
15
+ this.platform = window.flutter_inappwebview;
16
+
17
+ window.addEventListener('message', (event) => {
18
+ if (event.data == 'capturePort') {
19
+ const port = event.ports[0];
20
+ if (port != null) {
21
+ port.onmessage = (event: MessageEvent) => {
22
+ if (event.data.id != undefined) {
23
+ const callback = this.sseCallbacks[event.data.id];
24
+ callback?.(event.data.data);
25
+ }
26
+ };
27
+ }
28
+ }
29
+ }, false);
30
+ }
31
+ setSelectedFarm(farm: Factory): void {
32
+ throw new Error("Method not implemented.");
33
+ }
34
+ setSelectedUnit(unit: Unit): void {
35
+ this.platform.callHandler("selectUnit", unit).then((_res:any) => {
36
+ // @ts-ignore
37
+ window._notifyUnitChanged?.(unit);
38
+ })
39
+ }
40
+
41
+
42
+ ready() {
43
+ if (
44
+ // @ts-ignore
45
+ window.flutter_inappwebview != null &&
46
+ // @ts-ignore
47
+ window.flutter_inappwebview.callHandler != null
48
+ ) {
49
+ return Promise.resolve(true);
50
+ } else {
51
+ return new Promise<boolean>((resolve, reject) => {
52
+ window.addEventListener(
53
+ "flutterInAppWebViewPlatformReady",
54
+ function () {
55
+ console.log("flutter android/ios platform is ready");
56
+ resolve(true);
57
+ }
58
+ );
59
+ setTimeout(() => {
60
+ console.log("flutter android/ios platform is timeout");
61
+ reject("timeout");
62
+ }, 1500);
63
+ });
64
+ }
65
+ }
66
+
67
+
68
+ getAxiosFromMiniApp(): MyAxiosInstance {
69
+ const that = this;
70
+ return {
71
+ get: function (url, data) {
72
+ return that.platform.callHandler("axios_get", url, data);
73
+ },
74
+ post: function (url, data) {
75
+ return that.platform.callHandler("axios_post", url, data);
76
+ },
77
+ getAndSave: function (url, config) {
78
+ return that.platform.callHandler("axios_getAndSave", url, config);
79
+ },
80
+ getAndPreview: function (url, config) {
81
+ if (config == undefined) {
82
+ config = {};
83
+ }
84
+ if (config.preview == undefined) {
85
+ config.preview = true;
86
+ }
87
+ return that.platform.callHandler("axios_getAndSave", url, config);
88
+ },
89
+ upload: function (url, option) {
90
+ return that.platform.callHandler("axios_upload", url, option);
91
+ },
92
+ getAsSse: async function (url, fn, config?) {
93
+ var randomId = Math.random().toString(36).substring(2);
94
+ that.sseCallbacks[randomId] = fn;
95
+ console.log("getAsSse", url, fn, randomId);
96
+ await that.platform.callHandler("axios_getAsSse", url, config, randomId);
97
+ delete that.sseCallbacks[randomId];
98
+ },
99
+ };
100
+ }
101
+
102
+ async getSelectedFarmFromMiniApp(): Promise<any> {
103
+ return this.platform.callHandler("getSelectedFarmFromMiniApp");
104
+ }
105
+
106
+ async getSelectedUnitFromMiniApp(): Promise<any> {
107
+ return this.platform.callHandler("getSelectedUnitFromMiniApp");
108
+ }
109
+
110
+ async jumpToMiniApp(url: string): Promise<void> {
111
+ return this.platform.callHandler("app.openMiniapp", url);
112
+ }
113
+
114
+ async scanQrcode(): Promise<string> {
115
+ return this.platform.callHandler("app.scanQrcode");
116
+ }
117
+
118
+ setTitle(title: string): void {
119
+ this.platform.callHandler("app.setTitle", title);
120
+ }
121
+
122
+ async saveBase64(base64: string, filename: string): Promise<void> {
123
+ return this.platform.callHandler("app.saveBase64", base64, filename);
124
+ }
125
+
126
+ async saveBlob(blob: Blob, filename: string): Promise<void> {
127
+ const reader = new FileReader();
128
+ return new Promise<void>((resolve, reject) => {
129
+ reader.readAsDataURL(blob);
130
+ reader.onloadend = async () => {
131
+ const base64 = reader.result as string;
132
+ await this.saveBase64(base64, filename);
133
+ resolve();
134
+ };
135
+ reader.onerror = (err) => {
136
+ reject(err);
137
+ };
138
+ });
139
+ }
140
+
141
+ vibrate(time?: number): void {
142
+ this.platform.callHandler("app.vibrate", time);
143
+ }
144
+
145
+ async showInDeviceManager(deviceId: any, type: string): Promise<void> {
146
+ return this.platform.callHandler("app.showInDeviceManager", deviceId, type);
147
+ }
148
+
149
+ reloadGroup(group: string): void {
150
+ this.platform.callHandler("app.reloadGroup", group);
151
+ }
152
+
153
+ async getGeo(): Promise<{ lat: number; lng: number }> {
154
+ const result = await this.platform.callHandler("app.getGeo");
155
+ if (result.error) {
156
+ throw result.error;
157
+ }
158
+ return {
159
+ lat: result.lat,
160
+ lng: result.lng
161
+ };
162
+ }
163
+
164
+ setResult(name: string, value: any): void {
165
+ this.platform.callHandler("app.setResult", name, value);
166
+ }
167
+
168
+ setResultAs(name: string, value: any, type: string): void {
169
+ this.platform.callHandler("app.setResultAs", name, value, type);
170
+ }
171
+
172
+ setError(message: string): void {
173
+ this.platform.callHandler("app.setError", message);
174
+ }
175
+
176
+ setProgress(precentage: number): void {
177
+ this.platform.callHandler("app.setProgress", precentage);
178
+ }
179
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cpzxrobot/sdk",
3
- "version": "1.2.92",
3
+ "version": "1.2.94",
4
4
  "description": "提供给上海正芯数智APP第三方H5应用使用的SDK",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -0,0 +1,35 @@
1
+ import { Factory, MyAxiosInstance, Unit } from "./types";
2
+
3
+ export abstract class PlatformInterface {
4
+
5
+ token: string;
6
+ appCode: string;
7
+ baseURL: string;
8
+
9
+ //define constructor(token: string, appCode: string) {
10
+ constructor(token: string, appCode: string, baseURL: string) {
11
+ this.token = token;
12
+ this.appCode = appCode;
13
+ this.baseURL = baseURL;
14
+ }
15
+
16
+ abstract getSelectedFarmFromMiniApp(): Promise<any>;
17
+ abstract getSelectedUnitFromMiniApp(): Promise<any>;
18
+ abstract jumpToMiniApp(url: string): Promise<void>;
19
+ abstract scanQrcode(): Promise<string>;
20
+ abstract setTitle(title: string): void;
21
+ abstract saveBase64(base64: string, filename: string): Promise<void>;
22
+ abstract saveBlob(blob: Blob, filename: string): Promise<void>;
23
+ abstract vibrate(time?: number): void;
24
+ abstract showInDeviceManager(deviceId: any, type: string): Promise<void>;
25
+ abstract reloadGroup(key: string): void;
26
+ abstract getGeo(): Promise<{ lat: number; lng: number }>;
27
+ abstract setResult(name: string, value: any): void;
28
+ abstract setResultAs(name: string, value: any, type: string): void;
29
+ abstract setError(message: string): void;
30
+ abstract setProgress(precentage: number): void;
31
+ abstract getAxiosFromMiniApp(): MyAxiosInstance;
32
+ abstract ready(): Promise<boolean>;
33
+ abstract setSelectedUnit(unit: Unit|String|Number): void;
34
+ abstract setSelectedFarm(farm: Factory|String|Number): void;
35
+ }
package/types.d.ts CHANGED
@@ -21,6 +21,7 @@ import { EnergyGateway } from "./energy_gateway";
21
21
  import { type ElectricMeterRate } from "./energy_types/electric_meter_gateway";
22
22
  import { ConstructionGateway } from "./construction_gateway";
23
23
  import { SystemGateway } from "./system_gateway";
24
+ import { PlatformInterface } from "./platform_interface";
24
25
 
25
26
  type Device = {
26
27
  id: number;
@@ -360,18 +361,19 @@ class Cpzxrobot {
360
361
  construction: ConstructionGateway;
361
362
  system: SystemGateway;
362
363
  dict: (key: string) => any;
363
- _getSelectedFarmFromMiniApp: () => Promise<Factory>;
364
- _getSelectedUnitFromMiniApp: () => Promise<Unit>;
364
+ platform: PlatformInterface;
365
+ // _getSelectedFarmFromMiniApp: () => Promise<Factory>;
366
+ // _getSelectedUnitFromMiniApp: () => Promise<Unit>;
365
367
  openMiniApp: (url: string) => void;
366
368
  on: (event: string, callback: (data: any) => void) => void;
367
- setTitle: (title: string) => void;
368
- saveBase64: (base64: string, filename: string) => void;
369
- saveBlob: (blob: Blob, filename: string) => void;
370
- scanQrcode: () => Promise<string>;
371
- vibrate: (time?: number) => void;
372
- reloadGroup: (key: string) => void;
373
- getGeo: () => Promise<{ lat: number; lng: number }>;
374
- showInDeviceManager: (deviceId: number, type: string) => Promise<void>;
369
+ // setTitle: (title: string) => void;
370
+ // saveBase64: (base64: string, filename: string) => void;
371
+ // saveBlob: (blob: Blob, filename: string) => void;
372
+ // scanQrcode: () => Promise<string>;
373
+ // vibrate: (time?: number) => void;
374
+ // reloadGroup: (key: string) => void;
375
+ // getGeo: () => Promise<{ lat: number; lng: number }>;
376
+ // showInDeviceManager: (deviceId: number, type: string) => Promise<void>;
375
377
  }
376
378
 
377
379
  declare global {
package/user_gateway.ts CHANGED
@@ -27,7 +27,7 @@ export class UserGateway extends Object {
27
27
  resolve(this._selectedFarm);
28
28
  break;
29
29
  case "miniapp_in_app":
30
- this.context._getSelectedFarmFromMiniApp().then((farm: any) => {
30
+ this.context.platform.getSelectedFarmFromMiniApp().then((farm: any) => {
31
31
  this._selectedFarm = farm;
32
32
  resolve(farm);
33
33
  });
@@ -42,6 +42,15 @@ export class UserGateway extends Object {
42
42
  });
43
43
  }
44
44
 
45
+ public async selectUnit(unit: Unit|String|Number) {
46
+ if ((typeof unit === "string") || (typeof unit === "number")) {
47
+ var axios = await this.context.ready;
48
+ this.context.platform.setSelectedUnit(unit);
49
+ } else {
50
+ this.context.platform.setSelectedUnit(unit);
51
+ }
52
+ }
53
+
45
54
  //获得当前用户选择的单元
46
55
  getSelectedUnit() {
47
56
  return this.context.ready.then(() => {
@@ -51,7 +60,7 @@ export class UserGateway extends Object {
51
60
  resolve(this._selectedUnit);
52
61
  break;
53
62
  case "miniapp_in_app":
54
- this.context._getSelectedUnitFromMiniApp().then((unit: any) => {
63
+ this.context.platform.getSelectedUnitFromMiniApp().then((unit: any) => {
55
64
  this._selectedUnit = unit;
56
65
  resolve(unit);
57
66
  });
@@ -68,38 +77,11 @@ export class UserGateway extends Object {
68
77
  }
69
78
 
70
79
  set selectedFarm(farm: Factory) {
71
- switch (this.context.mode) {
72
- case "dev":
73
- this._selectedFarm = farm;
74
- break;
75
- case "miniapp_in_app":
76
- console.log("miniapp_in_app mode, ignore");
77
- break;
78
- case "miniapp_in_web":
79
- this._selectedFarm = farm;
80
- break;
81
- default:
82
- console.log("dev mode, ignore");
83
- break;
84
- }
80
+ this.context.platform.setSelectedFarm(farm);
85
81
  }
86
82
 
87
- set selectedUnit(farm: Unit) {
88
- switch (this.context.mode) {
89
- case "dev":
90
- this._selectedUnit = farm;
91
- break;
92
- case "miniapp_in_app":
93
- console.log("miniapp_in_app mode, ignore");
94
- break;
95
- case "miniapp_in_web":
96
- this._selectedUnit = farm;
97
- console.log("miniapp_in_web mode, ignore");
98
- break;
99
- default:
100
- console.log("dev mode, ignore");
101
- break;
102
- }
83
+ set selectedUnit(unit: Unit) {
84
+ this.context.platform.setSelectedUnit(unit);
103
85
  }
104
86
 
105
87
  async add(user: any) {
@@ -0,0 +1,322 @@
1
+ import { PlatformInterface } from "./platform_interface";
2
+ import { Factory, MyAxiosInstance, Unit } from "./types";
3
+
4
+ export class WebPlatform implements PlatformInterface {
5
+ token: string = "";
6
+ appCode: string = "";
7
+ baseURL: string = "";
8
+ _selectedFarm: Factory | undefined;
9
+ _selectedUnit: Unit | undefined;
10
+
11
+ constructor(token: string, appCode: string, baseURL: string, selectedFarm: Factory | undefined, selectedUnit: Unit | undefined) {
12
+ this.token = token;
13
+ this.appCode = appCode;
14
+ this.baseURL = baseURL;
15
+ this._selectedFarm = selectedFarm;
16
+ this._selectedUnit = selectedUnit;
17
+ }
18
+ setSelectedFarm(farm: Factory): void {
19
+ this._selectedFarm = farm;
20
+ }
21
+ setSelectedUnit(unit: Unit): void {
22
+ this._selectedUnit = unit;
23
+ }
24
+
25
+ async fetchWithAuth(input: RequestInfo, init?: RequestInit) {
26
+ const headers = new Headers(init?.headers);
27
+ headers.set('Authorization', this.token);
28
+ headers.set('Miniapp-Code', this.appCode);
29
+ const response = await fetch(this.baseURL + input.toString(), {
30
+ ...init,
31
+ headers
32
+ });
33
+
34
+ if (!response.ok) {
35
+ throw new Error(`HTTP error! status: ${response.status}`);
36
+ }
37
+ return response;
38
+ };
39
+
40
+ async streamWithAuth(input: RequestInfo, init?: RequestInit, fn?: Function) {
41
+ const headers = new Headers(init?.headers);
42
+ headers.set('Authorization', this.token);
43
+ headers.set('Miniapp-Code', this.appCode);
44
+ const response = await fetch(this.baseURL + input.toString(), {
45
+ ...init,
46
+ headers
47
+ });
48
+
49
+ var reader = response.body!.getReader();
50
+ const decoder = new TextDecoder("utf-8");
51
+ let done = false;
52
+ var buf: string = "";
53
+ while (!done) {
54
+ const { value, done } = await reader.read();
55
+ if (done) {
56
+ break;
57
+ }
58
+ const chunkValue = decoder.decode(value);
59
+
60
+ //split value to lines
61
+ // 将值拆分为行
62
+ buf = buf + chunkValue;
63
+ var i = buf.indexOf("\n");
64
+ while (i > -1) {
65
+ //find first \n
66
+ var line = buf.substring(0, i);
67
+ try {
68
+ if (line === "[DONE]") {
69
+ break;
70
+ } else {
71
+ // remove prefix 'data: '
72
+ // 移除前缀 'data: '
73
+ var data = JSON.parse(line.split(": ")[1]);
74
+ //{"choices":[{"delta":{"content":" </"},"index":0}],"created":1741749068,"id":"chatcmpl-67ccb889154043f5874cbf3a64ec163e","model":"DeepSeek-R1","object":"chat.completion.chunk"}
75
+ fn?.call(data);
76
+ }
77
+ } catch (e) {
78
+ console.error("解析失败", e);
79
+ }
80
+ buf = buf.substring(i + 1);
81
+ i = buf.indexOf("\n");
82
+ }
83
+ };
84
+ return true;
85
+ };
86
+
87
+ processQueryParams(url: string, config?: any) {
88
+ if (config && config.params) {
89
+ const flattenParams = (params: any, prefix = '') => {
90
+ const result: Record<string, string> = {};
91
+ Object.keys(params).forEach(key => {
92
+ const value = params[key];
93
+ const fullKey = prefix ? `${prefix}[${key}]` : key;
94
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
95
+ Object.assign(result, flattenParams(value, fullKey));
96
+ } else if (value) {
97
+ result[fullKey] = value.toString();
98
+ }
99
+ });
100
+ return result;
101
+ };
102
+ const flattened = flattenParams(config.params);
103
+ url += "?" + new URLSearchParams(flattened).toString();
104
+ delete config.params;
105
+ }
106
+ return url;
107
+ }
108
+
109
+ getAxiosFromMiniApp(): MyAxiosInstance {
110
+ var instance = this;
111
+ return {
112
+ get: async (url: string, config?: any) => {
113
+ url = instance.processQueryParams(url, config);
114
+ const response = await this.fetchWithAuth(url, {
115
+ method: 'GET',
116
+ headers: config?.headers
117
+ });
118
+ return { data: await response.json() };
119
+ },
120
+ post: async (url: string, data?: any, config?: any) => {
121
+ const response = await this.fetchWithAuth(url, {
122
+ method: 'POST',
123
+ headers: {
124
+ 'Content-Type': 'application/json',
125
+ ...config?.headers
126
+ },
127
+ body: JSON.stringify(data)
128
+ });
129
+ return { data: await response.json() };
130
+ },
131
+ getAndSave: async function(url: string, config?: any) {
132
+ url = instance.processQueryParams(url, config);
133
+ const response = await instance.fetchWithAuth(url, {
134
+ method: 'GET',
135
+ headers: config?.headers
136
+ });
137
+ const blob = await response.blob();
138
+
139
+ // 文件名解析逻辑
140
+ const contentDisposition = response.headers.get('Content-Disposition');
141
+ let filename = config?.fileName ?? ""; // 默认文件名
142
+
143
+ // 1. 优先使用响应头中的文件名
144
+ if (filename == "") {
145
+ if (contentDisposition) {
146
+ const utf8FilenameMatch = contentDisposition.match(/filename\*=UTF-8''(.+)/i);
147
+ if (utf8FilenameMatch) {
148
+ filename = decodeURIComponent(utf8FilenameMatch[1]);
149
+ } else {
150
+ const filenameMatch = contentDisposition.match(/filename="?(.+?)"?(;|$)/i);
151
+ if (filenameMatch) filename = filenameMatch[1];
152
+ }
153
+ } else {
154
+ filename = "file"
155
+ }
156
+ }
157
+ await instance.saveBlob(blob, filename);
158
+ return { data: blob };
159
+ },
160
+ getAndPreview: async function(url: string, config?: {
161
+ fileName?: string;
162
+ params?: any;
163
+ preview?: boolean;
164
+ }){
165
+ url = instance.processQueryParams(url, config);
166
+ return this.getAndSave(url, config);
167
+ },
168
+ upload: async (url: string, option?: any) => {
169
+ return new Promise<any>((resolve, reject) => {
170
+ const button = document.createElement("input");
171
+ button.type = "file";
172
+ button.style.display = "none";
173
+ button.multiple = option?.multiple || false;
174
+ document.body.appendChild(button);
175
+ button.click(); // 手动触发点击
176
+ button.onchange = async (e: Event) => {
177
+ const files = (e.target as HTMLInputElement).files;
178
+ if (files && files.length > 0) {
179
+ const formData = new FormData();
180
+ if (option?.multiple) {
181
+ for (let i = 0; i < files.length; i++) {
182
+ formData.append("files[]", files[i]);
183
+ }
184
+ } else {
185
+ formData.append(option?.["fileField"] || "file", files[0]);
186
+ }
187
+ for (let key in option?.["data"]) {
188
+ formData.append(key, option!["data"][key]);
189
+ }
190
+ const response = await instance.fetchWithAuth(url, {
191
+ method: 'POST',
192
+ body: formData
193
+ });
194
+ button.remove();
195
+ resolve({ data: await response.json() });
196
+ } else {
197
+ button.remove();
198
+ resolve({ data: { Error: "没有选择文件" } });
199
+ }
200
+ };
201
+ });
202
+ },
203
+ getAsSse: (url: string, fn: any, config?: {
204
+ fileName?: string;
205
+ params?: any;
206
+ preview?: boolean;
207
+ }) => {
208
+ return new Promise<any>((resolve, reject) => {
209
+ instance.streamWithAuth(url, {
210
+ method: 'GET',
211
+ }, fn);
212
+ });
213
+ }
214
+ };
215
+ }
216
+ ready(): Promise<boolean> {
217
+ return Promise.resolve(true);
218
+ }
219
+ getSelectedFarmFromMiniApp(): Promise<any> {
220
+ return Promise.resolve(this._selectedFarm);
221
+ }
222
+
223
+ getSelectedUnitFromMiniApp(): Promise<any> {
224
+ return Promise.resolve(this._selectedUnit);
225
+ }
226
+
227
+ jumpToMiniApp(url: string): Promise<void> {
228
+ window.location.href = url;
229
+ return Promise.resolve();
230
+ }
231
+
232
+ scanQrcode(): Promise<string> {
233
+ throw new Error("Method not available in web platform");
234
+ }
235
+
236
+ setTitle(title: string): void {
237
+ document.title = title;
238
+ }
239
+
240
+ async saveBase64(base64: string, filename: string): Promise<void> {
241
+ const byteCharacters = atob(base64);
242
+ const byteNumbers = new Array(byteCharacters.length);
243
+ for (let i = 0; i < byteCharacters.length; i++) {
244
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
245
+ }
246
+ const byteArray = new Uint8Array(byteNumbers);
247
+ const blob = new Blob([byteArray], {
248
+ type: "application/octet-stream",
249
+ });
250
+ return this.saveBlob(blob, filename);
251
+ }
252
+
253
+ saveBlob(blob: Blob, filename: string): Promise<void> {
254
+ return new Promise((resolve, reject) => {
255
+ try {
256
+ const url = URL.createObjectURL(blob);
257
+ const a = document.createElement("a");
258
+ a.href = url;
259
+ a.download = filename;
260
+ document.body.appendChild(a);
261
+ a.click();
262
+ setTimeout(() => {
263
+ URL.revokeObjectURL(url);
264
+ document.body.removeChild(a);
265
+ resolve();
266
+ }, 0);
267
+ } catch (error) {
268
+ reject(error);
269
+ }
270
+ });
271
+ }
272
+
273
+ vibrate(time?: number): void {
274
+ if (navigator.vibrate) {
275
+ navigator.vibrate(time || 200);
276
+ }
277
+ }
278
+
279
+ showInDeviceManager(deviceId: any, type: string): Promise<void> {
280
+ return Promise.resolve();
281
+ }
282
+
283
+ reloadGroup(key: string): void {
284
+ // No implementation in web platform
285
+ }
286
+
287
+ getGeo(): Promise<{ lat: number; lng: number }> {
288
+ return new Promise((resolve, reject) => {
289
+ if (navigator.geolocation) {
290
+ navigator.geolocation.getCurrentPosition(
291
+ (position) => {
292
+ resolve({
293
+ lat: position.coords.latitude,
294
+ lng: position.coords.longitude
295
+ });
296
+ },
297
+ (error) => {
298
+ reject(error);
299
+ }
300
+ );
301
+ } else {
302
+ reject(new Error("浏览器不支持获取位置信息"));
303
+ }
304
+ });
305
+ }
306
+
307
+ setResult(name: string, value: any): void {
308
+ // No implementation in web platform
309
+ }
310
+
311
+ setResultAs(name: string, value: any, type: string): void {
312
+ // No implementation in web platform
313
+ }
314
+
315
+ setError(message: string): void {
316
+ console.error(message);
317
+ }
318
+
319
+ setProgress(precentage: number): void {
320
+ // No implementation in web platform
321
+ }
322
+ }