@miot-rn/common-component 1.0.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.
- package/README.md +9 -0
- package/dist/index.d.ts +0 -0
- package/dist/index.js +0 -0
- package/dist/resources/i18n.d.ts +55 -0
- package/dist/resources/i18n.js +212 -0
- package/dist/service/specs/error-code.d.ts +19 -0
- package/dist/service/specs/error-code.js +41 -0
- package/dist/service/specs/index.d.ts +95 -0
- package/dist/service/specs/index.js +412 -0
- package/dist/service/specs/spec.d.ts +10 -0
- package/dist/service/specs/spec.js +109 -0
- package/dist/service/specs/specCache.d.ts +85 -0
- package/dist/service/specs/specCache.js +421 -0
- package/dist/service/specs/std-spec.d.ts +5 -0
- package/dist/service/specs/std-spec.js +228 -0
- package/dist/service/specs/subject.d.ts +20 -0
- package/dist/service/specs/subject.js +145 -0
- package/dist/service/specs/utils.d.ts +28 -0
- package/dist/service/specs/utils.js +46 -0
- package/dist/specs/i18n-parser.d.ts +10 -0
- package/dist/specs/i18n-parser.js +300 -0
- package/dist/specs/instance-parser.d.ts +26 -0
- package/dist/specs/instance-parser.js +706 -0
- package/dist/store/useGlobalSpecManager.d.ts +320 -0
- package/dist/store/useGlobalSpecManager.js +867 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/fns.d.ts +12 -0
- package/dist/utils/fns.js +308 -0
- package/dist/utils/get-value-or-default.d.ts +1 -0
- package/dist/utils/get-value-or-default.js +4 -0
- package/dist/utils/i18n.d.ts +1 -0
- package/dist/utils/i18n.js +141 -0
- package/dist/utils/objects.d.ts +2 -0
- package/dist/utils/objects.js +222 -0
- package/dist/utils/spec.d.ts +8 -0
- package/dist/utils/spec.js +171 -0
- package/dist/utils/types.d.ts +3 -0
- package/dist/utils/types.js +25 -0
- package/package.json +27 -0
|
@@ -0,0 +1,867 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
/*
|
|
4
|
+
https://github.com/pmndrs/zustand
|
|
5
|
+
*/
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
import { create } from 'zustand';
|
|
8
|
+
import { useEffect, useRef } from 'react';
|
|
9
|
+
import { getProps, setProps, doAction as _doAction, subscribe } from "../service/specs/index.js";
|
|
10
|
+
import { encodeProp } from "../utils/spec.js";
|
|
11
|
+
import { deepEqual } from "../utils/objects.js";
|
|
12
|
+
|
|
13
|
+
/* eslint-disable no-console */
|
|
14
|
+
|
|
15
|
+
const toKey = encodeProp;
|
|
16
|
+
export { toKey };
|
|
17
|
+
const TAG = 'GlobalSpecManager';
|
|
18
|
+
const GlobalSpecManagerErrorCode = {
|
|
19
|
+
SUCCESS: 0,
|
|
20
|
+
// 全局公共错误
|
|
21
|
+
INVALID_PARAM: -101000,
|
|
22
|
+
// 参数无效(通用)
|
|
23
|
+
// fetchSpecs 方法错误
|
|
24
|
+
FETCH_INVALID_SPEC: -101101,
|
|
25
|
+
// fetchSpecs: 无效的 spec 对象
|
|
26
|
+
FETCH_REQUEST_FAILED: -101102,
|
|
27
|
+
// fetchSpecs: 请求失败
|
|
28
|
+
// setSpecs 方法错误
|
|
29
|
+
SET_INVALID_SPEC: -101201,
|
|
30
|
+
// setSpecs: 无效的属性设置对象
|
|
31
|
+
SET_REQUEST_FAILED: -101202,
|
|
32
|
+
// setSpecs: 请求失败
|
|
33
|
+
// ACTION 方法错误
|
|
34
|
+
ACTION_INVALID_PARAM: -101301,
|
|
35
|
+
// action: 无效的参数
|
|
36
|
+
ACTION_EXECUTION_FAILED: -101302,
|
|
37
|
+
// action: 执行失败
|
|
38
|
+
// subscribeSpecs 方法错误
|
|
39
|
+
SUBSCRIBE_INVALID_SPEC: -101401,
|
|
40
|
+
// subscribeSpecs: 无效的 spec 对象
|
|
41
|
+
SUBSCRIBE_NO_PIID_OR_EIID: -101402,
|
|
42
|
+
// subscribeSpecs: 缺少 piid/eiid
|
|
43
|
+
// onEvent 方法错误
|
|
44
|
+
ON_EVENT_INVALID_EVENT_SPEC: -101501,
|
|
45
|
+
// onEvent: 无效的事件 spec
|
|
46
|
+
ON_EVENT_INVALID_LISTENER: -101502 // onEvent: 无效的监听器
|
|
47
|
+
};
|
|
48
|
+
const LogFilter = (key, value) => {
|
|
49
|
+
return ['service', 'prop', 'event', 'arguments'].includes(key) ? undefined : value;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// setSpec 节流:以 siid:piid 为 key,500ms 内第一次立即执行,冷却期内丢弃
|
|
53
|
+
const _setSpecLastExecTime = {};
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
负责管理设备Spec的全局Manager
|
|
57
|
+
PS.
|
|
58
|
+
1、无法感知数据是来源于蓝牙直连或服务端
|
|
59
|
+
2、不负责维护设备Spec的历史数据
|
|
60
|
+
*/
|
|
61
|
+
const useGlobalSpecManager = create((set, get) => ({
|
|
62
|
+
/*
|
|
63
|
+
储存每个 spec 的元信息,
|
|
64
|
+
{
|
|
65
|
+
[specKey]: {
|
|
66
|
+
updateTime: number
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
*/
|
|
70
|
+
specsMetaInfo: {},
|
|
71
|
+
/*
|
|
72
|
+
储存每个 spec 的state
|
|
73
|
+
*/
|
|
74
|
+
specsState: {},
|
|
75
|
+
/*
|
|
76
|
+
储存每个spec event 监听器
|
|
77
|
+
*/
|
|
78
|
+
eventListeners: {},
|
|
79
|
+
/*
|
|
80
|
+
订阅的spec列表,内部使用
|
|
81
|
+
*/
|
|
82
|
+
subscribedSpecs: new Set(),
|
|
83
|
+
/*
|
|
84
|
+
注入的二方监听器,value或metaInfo更新时触发
|
|
85
|
+
*/
|
|
86
|
+
specUpdateListeners: [],
|
|
87
|
+
/**
|
|
88
|
+
* 注册Spec更新监听器
|
|
89
|
+
* @function addSpecUpdateListener
|
|
90
|
+
* @memberof useGlobalSpecManager
|
|
91
|
+
* @param {Function} listener - 监听器函数
|
|
92
|
+
* @returns {Function} 返回移除监听器的函数
|
|
93
|
+
*/
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
addSpecUpdateListener: listener => {
|
|
96
|
+
if (typeof listener !== 'function') {
|
|
97
|
+
console.log(`[STD-LOCK][${TAG}][addSpecUpdateListener] 监听器必须为函数类型`);
|
|
98
|
+
return () => {};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// @ts-ignore
|
|
102
|
+
set(state => ({
|
|
103
|
+
specUpdateListeners: [...state.specUpdateListeners, listener]
|
|
104
|
+
}));
|
|
105
|
+
return () => {
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
set(state => ({
|
|
108
|
+
specUpdateListeners: state.specUpdateListeners.filter(l => l !== listener)
|
|
109
|
+
}));
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
/**
|
|
113
|
+
* 主动读取设备Spec属性
|
|
114
|
+
* @async
|
|
115
|
+
* @function fetchSpecs
|
|
116
|
+
* @memberof useGlobalSpecManager
|
|
117
|
+
* @param {Array<object>} specs - Spec对象数组,每个对象必须包含 siid 属性
|
|
118
|
+
* @param {boolean} [fromSource=true] - 是否强制从源获取数据
|
|
119
|
+
* @param {boolean} [batchUpdate=false] - 是否批量更新状态
|
|
120
|
+
* @returns {Promise<Array<object>>} 返回包含每个Spec读取结果的数组
|
|
121
|
+
* @throws {Error} 当入参无效或读取过程中发生异常时抛出错误
|
|
122
|
+
*/
|
|
123
|
+
fetchSpecs: async (specs, fromSource = true, batchUpdate = false) => {
|
|
124
|
+
// 边界验证:specs 必须是数组且非空
|
|
125
|
+
if (!Array.isArray(specs) || specs.length === 0) {
|
|
126
|
+
console.log(`[STD-LOCK][${TAG}][fetchSpecs][${new Date().toISOString()}] 入参 specs 必须为非空数组`);
|
|
127
|
+
return [{
|
|
128
|
+
code: GlobalSpecManagerErrorCode.INVALID_PARAM,
|
|
129
|
+
message: '入参 specs 必须为非空数组'
|
|
130
|
+
}];
|
|
131
|
+
}
|
|
132
|
+
const promises = specs.map(async spec => {
|
|
133
|
+
if (!spec || typeof spec !== 'object' || !spec.siid || !spec.piid) {
|
|
134
|
+
console.log(`[STD-LOCK][${TAG}][fetchSpecs][${new Date().toISOString()}] 无效的 spec 对象: ${JSON.stringify(spec, LogFilter, 2)}`);
|
|
135
|
+
return {
|
|
136
|
+
code: GlobalSpecManagerErrorCode.FETCH_INVALID_SPEC,
|
|
137
|
+
message: '无效的 spec 对象',
|
|
138
|
+
spec
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const key = toKey(spec);
|
|
143
|
+
const results = await getProps([{
|
|
144
|
+
...spec,
|
|
145
|
+
fromSource
|
|
146
|
+
}], {
|
|
147
|
+
fromSourceIfNeed: fromSource
|
|
148
|
+
});
|
|
149
|
+
// data manager返回的结果code是0,但value是null,需要两者都判断
|
|
150
|
+
if (results[0]?.code === 0 && results[0]?.value != null) {
|
|
151
|
+
const updateTime = Math.floor(Date.now() / 1000);
|
|
152
|
+
|
|
153
|
+
// 非批量模式:立即更新 state
|
|
154
|
+
const specDataSource = results[0]?.specDataSource;
|
|
155
|
+
if (!batchUpdate) {
|
|
156
|
+
set(state => ({
|
|
157
|
+
specsState: {
|
|
158
|
+
...state.specsState,
|
|
159
|
+
[key]: results[0].value
|
|
160
|
+
},
|
|
161
|
+
specsMetaInfo: {
|
|
162
|
+
...state.specsMetaInfo,
|
|
163
|
+
[key]: {
|
|
164
|
+
...(state.specsMetaInfo[key] || {}),
|
|
165
|
+
updateTime,
|
|
166
|
+
specDataSource
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}));
|
|
170
|
+
|
|
171
|
+
// 触发监听器
|
|
172
|
+
get().specUpdateListeners.forEach(listener => {
|
|
173
|
+
listener({
|
|
174
|
+
type: 'prop',
|
|
175
|
+
key,
|
|
176
|
+
data: {
|
|
177
|
+
value: results[0].value,
|
|
178
|
+
updateTime,
|
|
179
|
+
specDataSource
|
|
180
|
+
},
|
|
181
|
+
triggerType: 'fetch'
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
return {
|
|
185
|
+
code: GlobalSpecManagerErrorCode.SUCCESS,
|
|
186
|
+
message: '读取成功',
|
|
187
|
+
data: {
|
|
188
|
+
value: results[0].value,
|
|
189
|
+
updateTime,
|
|
190
|
+
specDataSource
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// 批量模式:仅收集结果不更新 state
|
|
196
|
+
return {
|
|
197
|
+
code: GlobalSpecManagerErrorCode.SUCCESS,
|
|
198
|
+
key,
|
|
199
|
+
value: results[0].value,
|
|
200
|
+
updateTime,
|
|
201
|
+
specDataSource,
|
|
202
|
+
message: '读取成功'
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
console.log(`[STD-LOCK][${TAG}][fetchSpecs][${new Date().toISOString()}] 读取 spec 失败: ${JSON.stringify(results[0], LogFilter, 2)}`);
|
|
206
|
+
return {
|
|
207
|
+
code: GlobalSpecManagerErrorCode.FETCH_REQUEST_FAILED,
|
|
208
|
+
message: '无返回结果',
|
|
209
|
+
key: toKey(spec)
|
|
210
|
+
};
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error(`[STD-LOCK][${TAG}][fetchSpecs][${new Date().toISOString()}] 读取 spec 异常: ${JSON.stringify(error, LogFilter, 2)}`);
|
|
213
|
+
return {
|
|
214
|
+
code: GlobalSpecManagerErrorCode.FETCH_REQUEST_FAILED,
|
|
215
|
+
message: 'getProps出现异常',
|
|
216
|
+
rawErrorCode: error?.code,
|
|
217
|
+
rawErrorMessage: error?.message
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
const results = await Promise.all(promises);
|
|
222
|
+
|
|
223
|
+
// 批量模式:统一更新 state
|
|
224
|
+
if (batchUpdate) {
|
|
225
|
+
const successResults = results.filter(r => r.code === 0);
|
|
226
|
+
if (successResults.length > 0) {
|
|
227
|
+
set(state => ({
|
|
228
|
+
specsState: successResults.reduce((acc, res) => {
|
|
229
|
+
acc[res.key] = res.value;
|
|
230
|
+
return acc;
|
|
231
|
+
}, {
|
|
232
|
+
...state.specsState
|
|
233
|
+
}),
|
|
234
|
+
specsMetaInfo: successResults.reduce((acc, res) => {
|
|
235
|
+
acc[res.key] = {
|
|
236
|
+
...(state.specsMetaInfo[res.key] || {}),
|
|
237
|
+
updateTime: res.updateTime,
|
|
238
|
+
specDataSource: res.specDataSource
|
|
239
|
+
};
|
|
240
|
+
return acc;
|
|
241
|
+
}, {
|
|
242
|
+
...state.specsMetaInfo
|
|
243
|
+
})
|
|
244
|
+
}));
|
|
245
|
+
|
|
246
|
+
// 批量触发监听器
|
|
247
|
+
successResults.forEach(res => {
|
|
248
|
+
get().specUpdateListeners.forEach(listener => {
|
|
249
|
+
listener({
|
|
250
|
+
type: 'prop',
|
|
251
|
+
key: res.key,
|
|
252
|
+
data: {
|
|
253
|
+
value: res.value,
|
|
254
|
+
updateTime: res.updateTime,
|
|
255
|
+
specDataSource: res.specDataSource
|
|
256
|
+
},
|
|
257
|
+
triggerType: 'fetch'
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return results;
|
|
264
|
+
},
|
|
265
|
+
/**
|
|
266
|
+
* 主动设置设备Spec属性
|
|
267
|
+
* @async
|
|
268
|
+
* @function setSpecs
|
|
269
|
+
* @memberof useGlobalSpecManager
|
|
270
|
+
* @param {Array<object>} specsToSet - 要设置的Spec对象数组,每个对象必须包含 siid、piid 和 value
|
|
271
|
+
* @param {boolean} [batchUpdate=false] - 是否批量更新状态
|
|
272
|
+
* @returns {Promise<Array<object>>} 返回包含每个Spec设置结果的数组
|
|
273
|
+
*/
|
|
274
|
+
setSpecs: async (specsToSet, batchUpdate = false) => {
|
|
275
|
+
if (!Array.isArray(specsToSet) || specsToSet.length === 0) {
|
|
276
|
+
console.log(`[STD-LOCK][${TAG}][setSpecs][${new Date().toISOString()}] 入参 specsToSet 必须为非空数组`);
|
|
277
|
+
return [{
|
|
278
|
+
code: GlobalSpecManagerErrorCode.INVALID_PARAM,
|
|
279
|
+
message: '入参 specsToSet 必须为非空数组'
|
|
280
|
+
}];
|
|
281
|
+
}
|
|
282
|
+
const promises = specsToSet.map(async spec => {
|
|
283
|
+
if (!spec || typeof spec !== 'object' || !spec.siid || !spec.piid || spec.value == null) {
|
|
284
|
+
console.log(`[STD-LOCK][${TAG}][setSpecs][${new Date().toISOString()}] 无效的属性设置对象,需包含 siid、piid 和 value: ${JSON.stringify(spec, LogFilter, 2)}`);
|
|
285
|
+
return {
|
|
286
|
+
code: GlobalSpecManagerErrorCode.SET_INVALID_SPEC,
|
|
287
|
+
message: '无效的属性设置对象'
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
const key = toKey(spec);
|
|
292
|
+
const value = spec.value;
|
|
293
|
+
const results = await setProps([spec]);
|
|
294
|
+
if (results[0]?.code === 0) {
|
|
295
|
+
const updateTime = Math.floor(Date.now() / 1000);
|
|
296
|
+
const specDataSource = results[0]?.specDataSource;
|
|
297
|
+
|
|
298
|
+
// 非批量模式:立即更新 state
|
|
299
|
+
if (!batchUpdate) {
|
|
300
|
+
set(state => ({
|
|
301
|
+
specsState: {
|
|
302
|
+
...state.specsState,
|
|
303
|
+
[key]: value
|
|
304
|
+
},
|
|
305
|
+
specsMetaInfo: {
|
|
306
|
+
...state.specsMetaInfo,
|
|
307
|
+
[key]: {
|
|
308
|
+
...(state.specsMetaInfo[key] || {}),
|
|
309
|
+
updateTime,
|
|
310
|
+
specDataSource
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}));
|
|
314
|
+
|
|
315
|
+
// 触发监听器
|
|
316
|
+
get().specUpdateListeners.forEach(listener => {
|
|
317
|
+
listener({
|
|
318
|
+
type: 'prop',
|
|
319
|
+
key,
|
|
320
|
+
data: {
|
|
321
|
+
value,
|
|
322
|
+
updateTime,
|
|
323
|
+
specDataSource
|
|
324
|
+
},
|
|
325
|
+
triggerType: 'set'
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
return {
|
|
329
|
+
code: GlobalSpecManagerErrorCode.SUCCESS,
|
|
330
|
+
message: '设置成功',
|
|
331
|
+
data: {
|
|
332
|
+
value,
|
|
333
|
+
updateTime,
|
|
334
|
+
specDataSource
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// 批量模式:仅收集结果不更新 state
|
|
340
|
+
return {
|
|
341
|
+
code: GlobalSpecManagerErrorCode.SUCCESS,
|
|
342
|
+
key,
|
|
343
|
+
value,
|
|
344
|
+
updateTime,
|
|
345
|
+
specDataSource,
|
|
346
|
+
message: '设置成功'
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
console.log(`[STD-LOCK][${TAG}][setSpecs][${new Date().toISOString()}] 设置 spec 失败: ${JSON.stringify(results[0], LogFilter, 2)}`);
|
|
350
|
+
return {
|
|
351
|
+
code: GlobalSpecManagerErrorCode.SET_REQUEST_FAILED,
|
|
352
|
+
message: 'setProps失败',
|
|
353
|
+
rawErrorCode: results[0]?.code,
|
|
354
|
+
rawErrorMessage: ''
|
|
355
|
+
};
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error(`[STD-LOCK][${TAG}][setSpecs][${new Date().toISOString()}] 设置 spec 异常: ${JSON.stringify(error, LogFilter, 2)}`);
|
|
358
|
+
return {
|
|
359
|
+
code: GlobalSpecManagerErrorCode.SET_REQUEST_FAILED,
|
|
360
|
+
message: 'setProps出现异常',
|
|
361
|
+
rawErrorCode: error?.code,
|
|
362
|
+
rawErrorMessage: error?.message
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
const results = await Promise.all(promises);
|
|
367
|
+
|
|
368
|
+
// 批量模式:统一更新 state
|
|
369
|
+
if (batchUpdate) {
|
|
370
|
+
const successResults = results.filter(r => r.code === 0);
|
|
371
|
+
if (successResults.length > 0) {
|
|
372
|
+
set(state => ({
|
|
373
|
+
specsState: successResults.reduce((acc, res) => {
|
|
374
|
+
acc[res.key] = res.value;
|
|
375
|
+
return acc;
|
|
376
|
+
}, {
|
|
377
|
+
...state.specsState
|
|
378
|
+
}),
|
|
379
|
+
specsMetaInfo: successResults.reduce((acc, res) => {
|
|
380
|
+
acc[res.key] = {
|
|
381
|
+
...(state.specsMetaInfo[res.key] || {}),
|
|
382
|
+
updateTime: res.updateTime
|
|
383
|
+
};
|
|
384
|
+
return acc;
|
|
385
|
+
}, {
|
|
386
|
+
...state.specsMetaInfo
|
|
387
|
+
})
|
|
388
|
+
}));
|
|
389
|
+
|
|
390
|
+
// 批量触发监听器
|
|
391
|
+
successResults.forEach(res => {
|
|
392
|
+
get().specUpdateListeners.forEach(listener => {
|
|
393
|
+
listener({
|
|
394
|
+
type: 'prop',
|
|
395
|
+
key: res.key,
|
|
396
|
+
data: {
|
|
397
|
+
value: res.value,
|
|
398
|
+
updateTime: res.updateTime
|
|
399
|
+
},
|
|
400
|
+
triggerType: 'set'
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return results;
|
|
407
|
+
},
|
|
408
|
+
/**
|
|
409
|
+
* 主动设置单个设备Spec属性
|
|
410
|
+
* @async
|
|
411
|
+
* @function setSpec
|
|
412
|
+
* @memberof useGlobalSpecManager
|
|
413
|
+
* @param {object} specToSet - 要设置的单个Spec对象,必须包含 siid、piid 和 value
|
|
414
|
+
* @param {boolean} [batchUpdate=false] - 是否批量更新状态
|
|
415
|
+
* @returns {Promise<object>} 返回Spec设置结果
|
|
416
|
+
*/
|
|
417
|
+
setSpec: async specToSet => {
|
|
418
|
+
if (!specToSet || typeof specToSet !== 'object' || !specToSet.siid || !specToSet.piid || specToSet.value == null) {
|
|
419
|
+
console.log(`[STD-LOCK][${TAG}][setSpec][${new Date().toISOString()}] 入参必须为有效的spec对象,需包含 siid、piid 和 value: ${JSON.stringify(specToSet, LogFilter, 2)}`);
|
|
420
|
+
return {
|
|
421
|
+
code: GlobalSpecManagerErrorCode.INVALID_PARAM,
|
|
422
|
+
message: '入参必须为有效的spec对象'
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
const throttleKey = `${specToSet.miid}:${specToSet.siid}:${specToSet.piid}`;
|
|
426
|
+
const now = Date.now();
|
|
427
|
+
const lastExec = _setSpecLastExecTime[throttleKey] || 0;
|
|
428
|
+
const elapsed = now - lastExec;
|
|
429
|
+
if (elapsed >= 500) {
|
|
430
|
+
// 冷却期已过,立即执行
|
|
431
|
+
console.log(`[STD-LOCK====][${TAG}][setSpec][throttle][${new Date().toISOString()}] 立即执行 key=${throttleKey}, value=${JSON.stringify(specToSet.value)}, elapsed=${elapsed}ms`);
|
|
432
|
+
_setSpecLastExecTime[throttleKey] = now;
|
|
433
|
+
const results = await get().setSpecs([specToSet], false);
|
|
434
|
+
return results[0];
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// 冷却期内,直接丢弃
|
|
438
|
+
console.log(`[STD-LOCK====][${TAG}][setSpec][throttle][${new Date().toISOString()}] 被节流丢弃 key=${throttleKey}, value=${JSON.stringify(specToSet.value)}, elapsed=${elapsed}ms, remaining=${500 - elapsed}ms`);
|
|
439
|
+
return {
|
|
440
|
+
code: 0,
|
|
441
|
+
message: 'throttled: dropped'
|
|
442
|
+
};
|
|
443
|
+
},
|
|
444
|
+
/**
|
|
445
|
+
* 执行设备操作
|
|
446
|
+
* @async
|
|
447
|
+
* @function doAction
|
|
448
|
+
* @memberof useGlobalSpecManager
|
|
449
|
+
* @param {object} spec - 操作对象,必须包含 siid、aiid 和 in
|
|
450
|
+
* @returns {Promise<object>} 返回操作结果
|
|
451
|
+
*/
|
|
452
|
+
doAction: async spec => {
|
|
453
|
+
if (!spec || typeof spec !== 'object' || !spec.siid || !spec.aiid || spec.in == null) {
|
|
454
|
+
console.log(`[STD-LOCK][${TAG}][doAction][${new Date().toISOString()}] 无效的action对象,需包含 siid、aiid 和 in: ${JSON.stringify(spec, LogFilter, 2)}`);
|
|
455
|
+
return {
|
|
456
|
+
code: GlobalSpecManagerErrorCode.ACTION_INVALID_PARAM,
|
|
457
|
+
message: '无效的action对象'
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
try {
|
|
461
|
+
const res = await _doAction(spec);
|
|
462
|
+
if ([0, 1].includes(res?.code)) {
|
|
463
|
+
return {
|
|
464
|
+
code: GlobalSpecManagerErrorCode.SUCCESS,
|
|
465
|
+
message: '执行成功',
|
|
466
|
+
data: res?.out ?? []
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
console.log(`[STD-LOCK][${TAG}][doAction][${new Date().toISOString()}] 执行action失败: ${JSON.stringify(res, LogFilter, 2)}`);
|
|
470
|
+
return {
|
|
471
|
+
code: GlobalSpecManagerErrorCode.ACTION_EXECUTION_FAILED,
|
|
472
|
+
message: '执行action失败',
|
|
473
|
+
rawErrorCode: res?.code,
|
|
474
|
+
rawErrorMessage: res?.message,
|
|
475
|
+
data: res
|
|
476
|
+
};
|
|
477
|
+
} catch (error) {
|
|
478
|
+
if (__DEV__ && console.warn) {
|
|
479
|
+
console.warn(`[STD-LOCK][${TAG}][doAction][${new Date().toISOString()}] 执行action异常: ${JSON.stringify(error, LogFilter, 2)}`);
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
code: GlobalSpecManagerErrorCode.ACTION_EXECUTION_FAILED,
|
|
483
|
+
message: '执行action异常',
|
|
484
|
+
rawErrorCode: error?.code,
|
|
485
|
+
rawErrorMessage: error?.message
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
/**
|
|
490
|
+
* 订阅Spec属性或事件
|
|
491
|
+
* @async
|
|
492
|
+
* @function subscribeSpecs
|
|
493
|
+
* @memberof useGlobalSpecManager
|
|
494
|
+
* @param {Array<object>} specs - 要订阅的Spec对象数组
|
|
495
|
+
* @returns {Function} 成功时返回取消订阅的函数,失败/错误时返回空函数
|
|
496
|
+
*/
|
|
497
|
+
subscribeSpecs: async specs => {
|
|
498
|
+
if (!Array.isArray(specs) || specs.length === 0) {
|
|
499
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 入参 specs 必须为非空数组`);
|
|
500
|
+
return () => {};
|
|
501
|
+
}
|
|
502
|
+
try {
|
|
503
|
+
const currentState = get();
|
|
504
|
+
const newSpecs = specs.filter(spec => {
|
|
505
|
+
if (!spec || typeof spec !== 'object' || !spec.siid) {
|
|
506
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 无效的 spec 对象: ${JSON.stringify(spec, LogFilter, 2)}`);
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
509
|
+
if (spec.eiid == null && spec.piid == null) {
|
|
510
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] spec 需包含 piid(属性)或 eiid(事件): ${JSON.stringify(spec, LogFilter, 2)}`);
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
const key = toKey(spec);
|
|
514
|
+
return !currentState.subscribedSpecs.has(key);
|
|
515
|
+
});
|
|
516
|
+
if (newSpecs.length === 0) {
|
|
517
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 无新订阅 spec 对象: ${JSON.stringify(specs, LogFilter, 2)}`);
|
|
518
|
+
return () => {}; // 无新订阅,返回空取消函数
|
|
519
|
+
}
|
|
520
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 新订阅 spec 对象: ${JSON.stringify(newSpecs, LogFilter, 2)}`);
|
|
521
|
+
const subscription = await subscribe(newSpecs, updatedSpec => {
|
|
522
|
+
if (!updatedSpec) {
|
|
523
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 订阅到的 spec 消息推送为空`);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const updateTime = updatedSpec.updateTime ?? Math.floor(Date.now() / 1000);
|
|
527
|
+
const key = toKey(updatedSpec);
|
|
528
|
+
const {
|
|
529
|
+
eiid
|
|
530
|
+
} = updatedSpec;
|
|
531
|
+
const latestState = get();
|
|
532
|
+
if (eiid) {
|
|
533
|
+
// 事件:触发所有注册的监听器(使用最新状态)
|
|
534
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 订阅到的 spec 事件推送: ${JSON.stringify(updatedSpec, LogFilter, 2)}`);
|
|
535
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 触发事件监听器: key=${key}, eventListeners=${JSON.stringify(latestState.eventListeners, null, 2)}, listener=${JSON.stringify(latestState.eventListeners[key], null, 2)}`);
|
|
536
|
+
const listeners = latestState.eventListeners[key] || [];
|
|
537
|
+
listeners.forEach(listener => {
|
|
538
|
+
try {
|
|
539
|
+
listener({
|
|
540
|
+
...updatedSpec,
|
|
541
|
+
triggerType: 'event'
|
|
542
|
+
});
|
|
543
|
+
} catch (error) {
|
|
544
|
+
console.error(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 事件监听器执行失败: ${JSON.stringify(error, null, 2)}`);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
get().specUpdateListeners.forEach(listener => {
|
|
548
|
+
listener({
|
|
549
|
+
type: 'event',
|
|
550
|
+
// 明确类型为事件
|
|
551
|
+
key,
|
|
552
|
+
data: {
|
|
553
|
+
value: updatedSpec,
|
|
554
|
+
// 事件参数(完整的事件 spec)
|
|
555
|
+
updateTime
|
|
556
|
+
},
|
|
557
|
+
triggerType: 'event'
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
} else {
|
|
561
|
+
// 属性:根据更新时间和值变化决定是否更新状态
|
|
562
|
+
const localUpdateTime = latestState.specsMetaInfo[key]?.updateTime || 0; // 初始状态默认旧时间为0
|
|
563
|
+
// 这里对于updateTime相等的情况,需要处理,因为设备时间戳是秒级
|
|
564
|
+
const isNewerUpdateTime = updatedSpec.updateTime == null ? true : updatedSpec.updateTime >= localUpdateTime;
|
|
565
|
+
const isValueChanged = !deepEqual(latestState.specsState[key], updatedSpec.value);
|
|
566
|
+
|
|
567
|
+
// 仅在updateTime比本地记录时间更晚时处理
|
|
568
|
+
if (isNewerUpdateTime) {
|
|
569
|
+
// 传入值为空,非法,不处理
|
|
570
|
+
if (updatedSpec.value == null) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
const specDataSource = updatedSpec.specDataSource;
|
|
574
|
+
if (isValueChanged) {
|
|
575
|
+
// 值变化:更新值和时间
|
|
576
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 订阅到的 spec 推送::属性变更 ${JSON.stringify(updatedSpec, LogFilter, 2)}`);
|
|
577
|
+
set(state => ({
|
|
578
|
+
specsState: {
|
|
579
|
+
...state.specsState,
|
|
580
|
+
[key]: updatedSpec.value
|
|
581
|
+
},
|
|
582
|
+
specsMetaInfo: {
|
|
583
|
+
...state.specsMetaInfo,
|
|
584
|
+
[key]: {
|
|
585
|
+
...(state.specsMetaInfo[key] || {}),
|
|
586
|
+
updateTime,
|
|
587
|
+
specDataSource
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}));
|
|
591
|
+
get().specUpdateListeners.forEach(listener => {
|
|
592
|
+
listener({
|
|
593
|
+
type: 'prop',
|
|
594
|
+
// 明确类型为属性
|
|
595
|
+
key,
|
|
596
|
+
data: {
|
|
597
|
+
value: updatedSpec.value,
|
|
598
|
+
updateTime,
|
|
599
|
+
specDataSource
|
|
600
|
+
},
|
|
601
|
+
triggerType: 'prop_changed'
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
} else {
|
|
605
|
+
// 值未变化:仅更新时间
|
|
606
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 订阅到的 spec 推送::仅更新时间 ${JSON.stringify(updatedSpec, LogFilter, 2)}`);
|
|
607
|
+
set(state => ({
|
|
608
|
+
specsMetaInfo: {
|
|
609
|
+
...state.specsMetaInfo,
|
|
610
|
+
[key]: {
|
|
611
|
+
...(state.specsMetaInfo[key] || {}),
|
|
612
|
+
updateTime,
|
|
613
|
+
specDataSource
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}));
|
|
617
|
+
get().specUpdateListeners.forEach(listener => {
|
|
618
|
+
listener({
|
|
619
|
+
type: 'prop',
|
|
620
|
+
// 明确类型为属性
|
|
621
|
+
key,
|
|
622
|
+
data: {
|
|
623
|
+
value: updatedSpec.value,
|
|
624
|
+
updateTime,
|
|
625
|
+
specDataSource
|
|
626
|
+
},
|
|
627
|
+
triggerType: 'prop_changed_time_only'
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
} else {
|
|
632
|
+
console.log(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 订阅到的 spec 推送::旧数据\nlocalUpdateTime: ${localUpdateTime} isValueChanged: ${isValueChanged} \n${JSON.stringify(updatedSpec, LogFilter, 2)}`);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}, {
|
|
636
|
+
publishImmediately: true
|
|
637
|
+
});
|
|
638
|
+
// 记录新订阅的 spec key
|
|
639
|
+
newSpecs.forEach(spec => {
|
|
640
|
+
const key = toKey(spec);
|
|
641
|
+
set(state => {
|
|
642
|
+
const newSubscribed = new Set(state.subscribedSpecs);
|
|
643
|
+
newSubscribed.add(key);
|
|
644
|
+
return {
|
|
645
|
+
subscribedSpecs: newSubscribed
|
|
646
|
+
};
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
// 返回取消订阅函数(清除订阅记录)
|
|
651
|
+
return () => {
|
|
652
|
+
subscription.unsubscribe();
|
|
653
|
+
newSpecs.forEach(spec => {
|
|
654
|
+
const key = toKey(spec);
|
|
655
|
+
set(state => {
|
|
656
|
+
const newSubscribed = new Set(state.subscribedSpecs);
|
|
657
|
+
newSubscribed.delete(key);
|
|
658
|
+
return {
|
|
659
|
+
subscribedSpecs: newSubscribed
|
|
660
|
+
};
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
};
|
|
664
|
+
} catch (error) {
|
|
665
|
+
console.error(`[STD-LOCK][${TAG}][subscribeSpecs][${new Date().toISOString()}] 订阅异常: ${JSON.stringify(error, null, 2)}`);
|
|
666
|
+
return () => {};
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
/**
|
|
670
|
+
* 注册事件监听器
|
|
671
|
+
* @function onEvent
|
|
672
|
+
* @memberof useGlobalSpecManager
|
|
673
|
+
* @param {object} eventSpec - 事件Spec对象,必须包含 siid 和 eiid
|
|
674
|
+
* @param {Function} listener - 事件监听器函数
|
|
675
|
+
* @returns {Function|object} 成功时返回移除监听器的函数,失败/错误时返回空函数
|
|
676
|
+
*/
|
|
677
|
+
onEvent: (eventSpec, listener) => {
|
|
678
|
+
if (!eventSpec || typeof eventSpec !== 'object' || !eventSpec.siid || !eventSpec.eiid) {
|
|
679
|
+
console.log(`[STD-LOCK][${TAG}][onEvent][${new Date().toISOString()}] 无效的事件 spec,需包含 siid 和 eiid: ${JSON.stringify(eventSpec, LogFilter, 2)}`);
|
|
680
|
+
// return { code: GlobalSpecManagerErrorCode.ON_EVENT_INVALID_EVENT_SPEC, message: '无效的事件 spec' };
|
|
681
|
+
return () => {};
|
|
682
|
+
}
|
|
683
|
+
if (typeof listener !== 'function') {
|
|
684
|
+
console.log(`[STD-LOCK][${TAG}][onEvent][${new Date().toISOString()}] 监听器必须是函数类型: ${typeof listener}`);
|
|
685
|
+
// return { code: GlobalSpecManagerErrorCode.ON_EVENT_INVALID_LISTENER, message: '监听器必须是函数类型' };
|
|
686
|
+
return () => {};
|
|
687
|
+
}
|
|
688
|
+
const eventKey = toKey(eventSpec);
|
|
689
|
+
console.log(`[STD-LOCK][${TAG}][onEvent][${new Date().toISOString()}] 注册事件监听器: eventKey=${eventKey}`);
|
|
690
|
+
set(state => ({
|
|
691
|
+
eventListeners: {
|
|
692
|
+
...state.eventListeners,
|
|
693
|
+
[eventKey]: [...(state.eventListeners[eventKey] || []), listener]
|
|
694
|
+
}
|
|
695
|
+
}));
|
|
696
|
+
return () => {
|
|
697
|
+
set(state => ({
|
|
698
|
+
eventListeners: {
|
|
699
|
+
...state.eventListeners,
|
|
700
|
+
[eventKey]: (state.eventListeners[eventKey] || []).filter(l => l !== listener)
|
|
701
|
+
}
|
|
702
|
+
}));
|
|
703
|
+
};
|
|
704
|
+
},
|
|
705
|
+
/**
|
|
706
|
+
* 获取Spec状态
|
|
707
|
+
* @function getSpecState
|
|
708
|
+
* @memberof useGlobalSpecManager
|
|
709
|
+
* @param {object|string} spec - Spec对象或Spec键
|
|
710
|
+
* @returns {*} 返回Spec的值
|
|
711
|
+
*/
|
|
712
|
+
getSpecState: spec => {
|
|
713
|
+
const key = typeof spec === 'string' ? spec : toKey(spec);
|
|
714
|
+
return get().specsState[key];
|
|
715
|
+
},
|
|
716
|
+
/**
|
|
717
|
+
* 获取Spec元信息
|
|
718
|
+
* @function getSpecMetaInfo
|
|
719
|
+
* @memberof useGlobalSpecManager
|
|
720
|
+
* @param {object|string} spec - Spec对象或Spec键
|
|
721
|
+
* @returns {object|null} 返回Spec的元信息对象或 null
|
|
722
|
+
*/
|
|
723
|
+
getSpecMetaInfo: spec => {
|
|
724
|
+
const key = typeof spec === 'string' ? spec : toKey(spec);
|
|
725
|
+
return get().specsMetaInfo[key];
|
|
726
|
+
}
|
|
727
|
+
}));
|
|
728
|
+
export default useGlobalSpecManager;
|
|
729
|
+
export { useGlobalSpecManager };
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* 用于获取Spec状态的 React Hook
|
|
733
|
+
* @function useSpecState
|
|
734
|
+
* @param {object|string} spec - Spec对象或Spec键
|
|
735
|
+
* @returns {*} 返回Spec的当前值
|
|
736
|
+
*/
|
|
737
|
+
export const useSpecState = spec => {
|
|
738
|
+
return useGlobalSpecManager(state => state.getSpecState(spec));
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* 用于获取Spec元信息的 React Hook
|
|
743
|
+
* @function useSpecMetaInfo
|
|
744
|
+
* @param {object|string} spec - Spec对象或Spec键
|
|
745
|
+
* @returns {object|null} 返回Spec的元信息对象或 null
|
|
746
|
+
*/
|
|
747
|
+
export const useSpecMetaInfo = spec => {
|
|
748
|
+
return useGlobalSpecManager(state => state.getSpecMetaInfo(spec));
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
// 注册 Spec 更新监听器
|
|
752
|
+
export const useSpecUpdateListener = listener => {
|
|
753
|
+
const listenerRef = useRef(listener);
|
|
754
|
+
|
|
755
|
+
// 始终保持最新的 listener 内容
|
|
756
|
+
useEffect(() => {
|
|
757
|
+
listenerRef.current = listener;
|
|
758
|
+
}, [listener]);
|
|
759
|
+
useEffect(() => {
|
|
760
|
+
// 注册一个稳定引用的 wrapper 函数
|
|
761
|
+
const wrappedListener = (...args) => {
|
|
762
|
+
if (listenerRef.current) {
|
|
763
|
+
listenerRef.current(...args);
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
// 只在挂载时添加一次
|
|
768
|
+
const removeListener = useGlobalSpecManager.getState().addSpecUpdateListener(wrappedListener);
|
|
769
|
+
return () => removeListener();
|
|
770
|
+
}, []);
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
// 注册事件监听器
|
|
774
|
+
export const useEventListener = (eventSpec, listener) => {
|
|
775
|
+
useEffect(() => {
|
|
776
|
+
const removeListener = useGlobalSpecManager.getState().onEvent(eventSpec, listener);
|
|
777
|
+
return () => typeof removeListener === 'function' && removeListener();
|
|
778
|
+
}, [eventSpec, listener]);
|
|
779
|
+
|
|
780
|
+
// 可选返回 removeListener 函数
|
|
781
|
+
return () => {
|
|
782
|
+
const state = useGlobalSpecManager.getState();
|
|
783
|
+
const fn = state.onEvent(eventSpec, listener);
|
|
784
|
+
if (typeof fn === 'function') fn();
|
|
785
|
+
};
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
// ----------------- normal function
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* 添加全局 Spec 更新监听器
|
|
792
|
+
* @param listener 更新回调函数
|
|
793
|
+
* @returns 取消监听函数
|
|
794
|
+
*/
|
|
795
|
+
export const addSpecUpdateListener = listener => {
|
|
796
|
+
return useGlobalSpecManager.getState().addSpecUpdateListener(listener);
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* 读取设备 spec
|
|
801
|
+
* @param specs Spec 对象数组
|
|
802
|
+
* @param fromSource 是否强制从设备/服务端获取
|
|
803
|
+
* @param batchUpdate 是否批量更新状态
|
|
804
|
+
*/
|
|
805
|
+
export const fetchSpecs = async (specs, fromSource = true, batchUpdate = false) => {
|
|
806
|
+
return useGlobalSpecManager.getState().fetchSpecs(specs, fromSource, batchUpdate);
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* 设置设备 specs
|
|
811
|
+
* @param specsToSet Spec 对象数组,每个对象必须包含 siid, piid, value
|
|
812
|
+
* @param batchUpdate 是否批量更新状态
|
|
813
|
+
*/
|
|
814
|
+
export const setSpecs = async (specsToSet, batchUpdate = false) => {
|
|
815
|
+
return useGlobalSpecManager.getState().setSpecs(specsToSet, batchUpdate);
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* 设置设备 spec
|
|
820
|
+
* @param specToSet Spec 对象,必须包含 siid, piid, value
|
|
821
|
+
*/
|
|
822
|
+
export const setSpec = async specToSet => {
|
|
823
|
+
return useGlobalSpecManager.getState().setSpec(specToSet);
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* 执行设备操作
|
|
828
|
+
* @param spec 操作对象,必须包含 siid, aiid 和 in
|
|
829
|
+
*/
|
|
830
|
+
export const doAction = async spec => {
|
|
831
|
+
return useGlobalSpecManager.getState().doAction(spec);
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* 订阅 Spec 并返回取消订阅函数
|
|
836
|
+
* @param specs Spec 对象数组
|
|
837
|
+
* @returns 取消订阅函数
|
|
838
|
+
*/
|
|
839
|
+
export const subscribeSpecs = async specs => {
|
|
840
|
+
return useGlobalSpecManager.getState().subscribeSpecs(specs);
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* 注册事件监听器
|
|
845
|
+
* @param eventSpec 事件对象,必须包含 siid 和 eiid
|
|
846
|
+
* @param listener 事件回调
|
|
847
|
+
* @returns 取消监听函数
|
|
848
|
+
*/
|
|
849
|
+
export const onEvent = (eventSpec, listener) => {
|
|
850
|
+
return useGlobalSpecManager.getState().onEvent(eventSpec, listener);
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* 获取 Spec 当前值
|
|
855
|
+
* @param spec Spec 对象或 Spec key
|
|
856
|
+
*/
|
|
857
|
+
export const getSpecState = spec => {
|
|
858
|
+
return useGlobalSpecManager.getState().getSpecState(spec);
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* 获取 Spec 元信息
|
|
863
|
+
* @param spec Spec 对象或 Spec key
|
|
864
|
+
*/
|
|
865
|
+
export const getSpecMetaInfo = spec => {
|
|
866
|
+
return useGlobalSpecManager.getState().getSpecMetaInfo(spec);
|
|
867
|
+
};
|