@ray-js/robot-data-stream 0.0.15-beta.9 → 0.0.16-beta.2

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.
Files changed (34) hide show
  1. package/lib/constant.d.ts +1 -0
  2. package/lib/constant.js +11 -0
  3. package/lib/mqtt/hooks/useStructuredMessage.d.ts +0 -3
  4. package/lib/mqtt/hooks/useStructuredMessage.js +148 -116
  5. package/lib/mqtt/type/fun.d.ts +24 -9
  6. package/lib/mqtt/type/fun.js +2 -1
  7. package/lib/mqtt/type/index.d.ts +4 -1
  8. package/lib/mqtt/type/protocols/base.d.ts +4 -1
  9. package/lib/mqtt/type/protocols/base.js +9 -3
  10. package/lib/mqtt/type/protocols/carpetCleanProtocol.d.ts +2 -2
  11. package/lib/mqtt/type/protocols/carpetCleanProtocol.js +2 -2
  12. package/lib/mqtt/type/protocols/carpetProtocol.d.ts +5 -5
  13. package/lib/mqtt/type/protocols/carpetProtocol.js +7 -7
  14. package/lib/mqtt/type/protocols/roomPropertyProtocol.d.ts +8 -2
  15. package/lib/mqtt/type/protocols/roomPropertyProtocol.js +26 -5
  16. package/lib/mqtt/type/protocols/scheduleProtocol.d.ts +12 -3
  17. package/lib/mqtt/type/protocols/scheduleProtocol.js +17 -0
  18. package/lib/mqtt/type/protocols/selectRoomCleanProtocol.d.ts +6 -2
  19. package/lib/mqtt/type/protocols/selectRoomCleanProtocol.js +12 -4
  20. package/lib/mqtt/type/protocols/spotCleanProtocol.d.ts +8 -2
  21. package/lib/mqtt/type/protocols/spotCleanProtocol.js +24 -2
  22. package/lib/mqtt/type/protocols/wifiMapProtocol.d.ts +1 -0
  23. package/lib/mqtt/type/protocols/wifiMapProtocol.js +2 -1
  24. package/lib/mqtt/type/protocols/zoneCleanProtocol.d.ts +7 -2
  25. package/lib/mqtt/type/protocols/zoneCleanProtocol.js +31 -4
  26. package/lib/mqtt/useRoomProperty.js +8 -4
  27. package/lib/mqtt/useSchedule.js +25 -7
  28. package/lib/mqtt/useSelectRoomClean.js +36 -13
  29. package/lib/mqtt/useSpotClean.js +22 -10
  30. package/lib/mqtt/useWifiMap.js +4 -2
  31. package/lib/mqtt/useZoneClean.js +39 -45
  32. package/lib/mqtt/waterPreference.d.ts +20 -0
  33. package/lib/mqtt/waterPreference.js +70 -0
  34. package/package.json +7 -4
@@ -1,5 +1,7 @@
1
1
  import * as z from '../../../myLib/zod/mini';
2
+ import { MqttError } from '../../promise';
2
3
  import { BaseResponseSchema, Point } from './base';
4
+ const VALIDATION_ERROR_CODE = -2;
3
5
  const zoneSchema = z.object({
4
6
  // 区域点集
5
7
  points: z.array(Point),
@@ -20,10 +22,12 @@ export const setZoneCleanSchema = z.object({
20
22
  zones: z.array(zoneSchema),
21
23
  origin: Point,
22
24
  suctions: z.optional(z.array(z.string())),
23
- cisterns: z.optional(z.array(z.string())),
25
+ cisterns: z.optional(z.array(z.union([z.string(), z.number()]))),
26
+ waterValues: z.optional(z.array(z.union([z.string(), z.number()]))),
24
27
  cleanCounts: z.optional(z.array(z.int())),
25
28
  yMops: z.optional(z.array(z.int())),
26
- sweepMopModes: z.optional(z.array(z.string()))
29
+ sweepMopModes: z.optional(z.array(z.string())),
30
+ routePreferences: z.optional(z.array(z.string()))
27
31
  });
28
32
 
29
33
  // 划区清扫响应 Schema
@@ -35,15 +39,38 @@ const setZoneCleanResponseSchema = z.extend(BaseResponseSchema, {
35
39
  // 吸力, closed - 关闭 gentle - 安静 normal - 正常 strong - 强劲 max - 超强 ,默认值为''
36
40
  suctions: z.optional(z.array(z.string())),
37
41
  // 拖地水量 "closed"- 关闭,"low"-低,"middle"-中,"high"-高,默认值为''
38
- cisterns: z.optional(z.array(z.string())),
42
+ cisterns: z.optional(z.array(z.union([z.string(), z.number()]))),
43
+ // 自定义拖地水量
44
+ waterValues: z.optional(z.array(z.union([z.string(), z.number()]))),
39
45
  // 清扫次数 默认值1
40
46
  cleanCounts: z.optional(z.array(z.int())),
41
47
  // 拖地模式 1:开启Y型拖地 0:关闭Y型拖地 -1 未设置 默认值-1
42
48
  yMops: z.optional(z.array(z.int())),
43
49
  // 扫拖模式 "only_sweep":仅扫,"only_mop":仅拖,"both_work":扫拖同时,"clean_before_mop":先扫后拖,默认值为'only_sweep'
44
- sweepMopModes: z.optional(z.array(z.string()))
50
+ sweepMopModes: z.optional(z.array(z.string())),
51
+ // 路线偏好
52
+ routePreferences: z.optional(z.array(z.string()))
45
53
  });
46
54
 
47
55
  // 类型导出
48
56
 
57
+ export function validateSetZoneClean(data) {
58
+ const num = data.zones.length;
59
+ const validateLength = (name, value) => {
60
+ if (value && value.length !== num) {
61
+ throw new MqttError(`${name} length must be ${num}, actual is ${value.length}`, {
62
+ errCode: VALIDATION_ERROR_CODE,
63
+ reqType: 'set_zone_clean'
64
+ });
65
+ }
66
+ };
67
+ validateLength('suctions', data.suctions);
68
+ validateLength('cisterns', data.cisterns);
69
+ validateLength('waterValues', data.waterValues);
70
+ validateLength('cleanCounts', data.cleanCounts);
71
+ validateLength('yMops', data.yMops);
72
+ validateLength('sweepMopModes', data.sweepMopModes);
73
+ validateLength('routePreferences', data.routePreferences);
74
+ }
75
+
49
76
  // 函数类型定义
@@ -1,8 +1,10 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import { useContext } from 'react';
2
3
  import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMessage';
3
4
  import { SingletonContext } from './mqttProvider';
4
5
  import { RoomPropertyEnum } from './type';
5
6
  import { validator } from './type/fun';
7
+ import { normalizeWaterPreferencePayload } from './waterPreference';
6
8
  /**
7
9
  * 自定义 Hook,用于房间属性管理
8
10
  * @param devId 设备ID(可选,如果不提供则从 MqttProvider Context 获取)
@@ -45,7 +47,7 @@ export const useRoomProperty = () => {
45
47
  setRoomProperty: data => {
46
48
  return new Promise((resolve, reject) => {
47
49
  try {
48
- var _data$num, _data$suctions, _data$cisterns, _data$cleanCounts, _data$yMops, _data$sweepMopModes, _data$names;
50
+ var _data$num, _data$suctions, _data$cleanCounts, _data$yMops, _data$sweepMopModes, _data$names;
49
51
  if (!useMqtt) {
50
52
  reject(new Error('useMqtt is not used'));
51
53
  return;
@@ -56,18 +58,20 @@ export const useRoomProperty = () => {
56
58
  ids
57
59
  } = data;
58
60
  const len = ids.length;
59
- const sendData = {
61
+ const sendData = _objectSpread(_objectSpread({
60
62
  num: (_data$num = data.num) !== null && _data$num !== void 0 ? _data$num : len,
61
63
  ids,
62
64
  suctions: (_data$suctions = data.suctions) !== null && _data$suctions !== void 0 ? _data$suctions : new Array(len).fill('closed'),
63
- cisterns: (_data$cisterns = data.cisterns) !== null && _data$cisterns !== void 0 ? _data$cisterns : new Array(len).fill('closed'),
64
65
  cleanCounts: (_data$cleanCounts = data.cleanCounts) !== null && _data$cleanCounts !== void 0 ? _data$cleanCounts : new Array(len).fill(1),
65
66
  yMops: (_data$yMops = data.yMops) !== null && _data$yMops !== void 0 ? _data$yMops : new Array(len).fill(-1),
66
67
  sweepMopModes: (_data$sweepMopModes = data.sweepMopModes) !== null && _data$sweepMopModes !== void 0 ? _data$sweepMopModes : new Array(len).fill('only_sweep'),
67
68
  names: (_data$names = data.names) !== null && _data$names !== void 0 ? _data$names : new Array(len).fill(''),
69
+ nameLabels: data.nameLabels,
68
70
  floorTypes: data.floorTypes,
69
71
  orders: data.orders
70
- };
72
+ }, data.routePreferences && {
73
+ routePreferences: data.routePreferences
74
+ }), normalizeWaterPreferencePayload(data.cisterns, data.waterValues));
71
75
 
72
76
  // 使用 TypeBox Schema 进行参数验证(包含自定义验证逻辑)
73
77
  const validatedData = validator.validate('set_room_property', sendData);
@@ -1,8 +1,12 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
3
+ const _excluded = ["routePreferences"];
1
4
  import "core-js/modules/esnext.iterator.map.js";
2
5
  // 定时
3
6
  import { encodeDeviceTimer0x30 } from '@ray-js/robot-protocol';
4
7
  import { useContext } from 'react';
5
- import { CISTERN_MAP, CLEAN_MODE_MAP, SUCTION_MAP } from '../constant';
8
+ import { CLEAN_MODE_MAP, SUCTION_MAP, ROUTE_PREFERENCE_MAP } from '../constant';
9
+ import { normalizeWaterPreferencePayload, resolveWaterLevel } from './waterPreference';
6
10
  import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMessage';
7
11
  import { SingletonContext } from './mqttProvider';
8
12
  import { ScheduleEnum } from './type';
@@ -53,8 +57,19 @@ export const useSchedule = () => {
53
57
  try {
54
58
  // 使用 TypeBox Schema 进行参数验证
55
59
  const validatedData = validator.validate('set_schedule', message);
60
+ const list = validatedData.list.map(item => {
61
+ const {
62
+ routePreferences
63
+ } = item,
64
+ rest = _objectWithoutProperties(item, _excluded);
65
+ return _objectSpread(_objectSpread(_objectSpread({}, rest), normalizeWaterPreferencePayload(item.cisterns, item.waterValues)), routePreferences && {
66
+ routePreferences
67
+ });
68
+ });
56
69
  if (useMqtt) {
57
- sendStructuredMessage(ScheduleEnum.set, validatedData, resolve, error => reject(handleMqttError(error, 'Failed to set schedule')), ScheduleEnum.query // 响应类型是 query,不是 set
70
+ sendStructuredMessage(ScheduleEnum.set, _objectSpread(_objectSpread({}, validatedData), {}, {
71
+ list
72
+ }), resolve, error => reject(handleMqttError(error, 'Failed to set schedule')), ScheduleEnum.query // 响应类型是 query,不是 set
58
73
  );
59
74
  return;
60
75
  }
@@ -63,7 +78,7 @@ export const useSchedule = () => {
63
78
  const command = encodeDeviceTimer0x30({
64
79
  version: commandVersion,
65
80
  number: validatedData.num,
66
- list: validatedData.list.map(_ref => {
81
+ list: list.map(_ref => {
67
82
  let {
68
83
  active,
69
84
  suctions,
@@ -72,13 +87,15 @@ export const useSchedule = () => {
72
87
  cleanCounts,
73
88
  cycle,
74
89
  cisterns,
75
- time
90
+ waterValues,
91
+ time,
92
+ routePreferences
76
93
  } = _ref;
77
94
  return {
78
95
  effectiveness: active,
79
96
  cleanMode: CLEAN_MODE_MAP[(sweepMopModes === null || sweepMopModes === void 0 ? void 0 : sweepMopModes[0]) || ''],
80
97
  fanLevel: SUCTION_MAP[(suctions === null || suctions === void 0 ? void 0 : suctions[0]) || ''],
81
- waterLevel: CISTERN_MAP[(cisterns === null || cisterns === void 0 ? void 0 : cisterns[0]) || ''],
98
+ waterLevel: resolveWaterLevel(waterValues === null || waterValues === void 0 ? void 0 : waterValues[0], cisterns === null || cisterns === void 0 ? void 0 : cisterns[0]),
82
99
  time: {
83
100
  hour: time[0],
84
101
  minute: time[1]
@@ -86,7 +103,8 @@ export const useSchedule = () => {
86
103
  week: cycle,
87
104
  sweepCount: (cleanCounts === null || cleanCounts === void 0 ? void 0 : cleanCounts[0]) || 1,
88
105
  roomIds: ids || [],
89
- roomNum: (ids === null || ids === void 0 ? void 0 : ids.length) || 0
106
+ roomNum: (ids === null || ids === void 0 ? void 0 : ids.length) || 0,
107
+ routePreference: ROUTE_PREFERENCE_MAP[(routePreferences === null || routePreferences === void 0 ? void 0 : routePreferences[0]) || 'standard']
90
108
  };
91
109
  })
92
110
  });
@@ -97,7 +115,7 @@ export const useSchedule = () => {
97
115
  reqType: ScheduleEnum.query,
98
116
  version: commandVersion,
99
117
  taskId: `${Date.now()}`,
100
- list: validatedData.list,
118
+ list,
101
119
  num: validatedData.num
102
120
  });
103
121
  } catch (error) {
@@ -1,6 +1,8 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import "core-js/modules/esnext.iterator.constructor.js";
2
3
  import "core-js/modules/esnext.iterator.for-each.js";
3
4
  import "core-js/modules/esnext.iterator.map.js";
5
+ import "core-js/modules/esnext.iterator.some.js";
4
6
  // 选区清扫
5
7
  import { encodeRoomClean0x14, requestRoomClean0x15 } from '@ray-js/robot-protocol';
6
8
  import { useContext } from 'react';
@@ -8,6 +10,7 @@ import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMess
8
10
  import { SingletonContext } from './mqttProvider';
9
11
  import { RoomCleanSetEnum } from './type';
10
12
  import { validator } from './type/fun';
13
+ import { normalizeWaterPreferencePayload } from './waterPreference';
11
14
  /**
12
15
  * 自定义 Hook,用于选区清扫
13
16
  * @returns 包含 requestSelectRoomClean 和 setRoomClean 函数的对象
@@ -59,9 +62,11 @@ export const useSelectRoomClean = () => {
59
62
  ids: [],
60
63
  suctions: [],
61
64
  cisterns: [],
65
+ waterValues: [],
62
66
  cleanCounts: [],
63
67
  yMops: [],
64
- sweepMopModes: []
68
+ sweepMopModes: [],
69
+ routePreferences: []
65
70
  });
66
71
  } catch (error) {
67
72
  reject(handleMqttError(error, 'Failed to request select room clean'));
@@ -77,28 +82,37 @@ export const useSelectRoomClean = () => {
77
82
  if (useMqtt) {
78
83
  const ids = [];
79
84
  const suctions = [];
80
- const cisterns = [];
81
85
  const cleanCounts = [];
82
86
  const yMops = [];
83
87
  const sweepMopModes = [];
88
+ const prefs = rooms.map(room => room.routePreference);
84
89
  rooms.forEach(room => {
85
90
  var _room$suction, _room$cleanTimes, _room$yMop, _room$sweepMopMode;
86
91
  ids.push(room.roomId);
87
92
  suctions.push((_room$suction = room.suction) !== null && _room$suction !== void 0 ? _room$suction : '');
88
- cisterns.push(room.cistern);
89
93
  cleanCounts.push((_room$cleanTimes = room.cleanTimes) !== null && _room$cleanTimes !== void 0 ? _room$cleanTimes : 1);
90
94
  yMops.push((_room$yMop = room.yMop) !== null && _room$yMop !== void 0 ? _room$yMop : -1);
91
95
  sweepMopModes.push((_room$sweepMopMode = room.sweepMopMode) !== null && _room$sweepMopMode !== void 0 ? _room$sweepMopMode : 'only_sweep');
92
96
  });
93
- sendStructuredMessage(RoomCleanSetEnum.set, {
97
+ const waterPayload = normalizeWaterPreferencePayload(rooms.map(room => {
98
+ var _room$cistern;
99
+ return (_room$cistern = room.cistern) !== null && _room$cistern !== void 0 ? _room$cistern : '';
100
+ }), rooms.map(room => {
101
+ var _room$waterValue;
102
+ return (_room$waterValue = room.waterValue) !== null && _room$waterValue !== void 0 ? _room$waterValue : '';
103
+ }));
104
+ sendStructuredMessage(RoomCleanSetEnum.set, _objectSpread(_objectSpread(_objectSpread({
94
105
  ids,
95
- suctions,
96
- cisterns,
106
+ suctions
107
+ }, waterPayload), {}, {
97
108
  cleanCounts,
98
109
  yMops,
99
- sweepMopModes,
110
+ sweepMopModes
111
+ }, prefs.some(Boolean) && {
112
+ routePreferences: prefs.map(p => p !== null && p !== void 0 ? p : 'standard')
113
+ }), {}, {
100
114
  num: rooms.length
101
- }, resolve, error => reject(handleMqttError(error, 'Failed to set room clean')), RoomCleanSetEnum.query // 响应类型是 query,不是 set
115
+ }), resolve, error => reject(handleMqttError(error, 'Failed to set room clean')), RoomCleanSetEnum.query // 响应类型是 query,不是 set
102
116
  );
103
117
  return;
104
118
  }
@@ -115,7 +129,13 @@ export const useSelectRoomClean = () => {
115
129
  var _room$suction2;
116
130
  return (_room$suction2 = room.suction) !== null && _room$suction2 !== void 0 ? _room$suction2 : '';
117
131
  });
118
- const cisterns = rooms.map(room => room.cistern);
132
+ const waterPayload = normalizeWaterPreferencePayload(rooms.map(room => {
133
+ var _room$cistern2;
134
+ return (_room$cistern2 = room.cistern) !== null && _room$cistern2 !== void 0 ? _room$cistern2 : '';
135
+ }), rooms.map(room => {
136
+ var _room$waterValue2;
137
+ return (_room$waterValue2 = room.waterValue) !== null && _room$waterValue2 !== void 0 ? _room$waterValue2 : '';
138
+ }));
119
139
  const cleanCounts = rooms.map(room => {
120
140
  var _room$cleanTimes2;
121
141
  return (_room$cleanTimes2 = room.cleanTimes) !== null && _room$cleanTimes2 !== void 0 ? _room$cleanTimes2 : 1;
@@ -128,19 +148,22 @@ export const useSelectRoomClean = () => {
128
148
  var _room$sweepMopMode2;
129
149
  return (_room$sweepMopMode2 = room.sweepMopMode) !== null && _room$sweepMopMode2 !== void 0 ? _room$sweepMopMode2 : 'only_sweep';
130
150
  });
131
- resolve({
151
+ const prefs = rooms.map(room => room.routePreference);
152
+ resolve(_objectSpread(_objectSpread({
132
153
  success: true,
133
154
  errCode: 0,
134
155
  reqType: RoomCleanSetEnum.query,
135
156
  version: commandVersion,
136
157
  taskId: `${Date.now()}`,
137
158
  ids,
138
- suctions,
139
- cisterns,
159
+ suctions
160
+ }, waterPayload), {}, {
140
161
  cleanCounts,
141
162
  yMops,
142
163
  sweepMopModes
143
- });
164
+ }, prefs.some(Boolean) && {
165
+ routePreferences: prefs.map(p => p !== null && p !== void 0 ? p : 'standard')
166
+ }));
144
167
  } catch (error) {
145
168
  reject(handleMqttError(error, 'Failed to set room clean'));
146
169
  }
@@ -1,3 +1,4 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import "core-js/modules/esnext.iterator.map.js";
2
3
  // 定点清扫
3
4
 
@@ -8,6 +9,7 @@ import { encodeSpotClean0x16 } from '@ray-js/robot-protocol';
8
9
  import { pointsToString } from '../utils';
9
10
  import { useStructuredMessage, handleMqttError } from './hooks/useStructuredMessage';
10
11
  import { validator } from './type/fun';
12
+ import { normalizeWaterPreferencePayload } from './waterPreference';
11
13
  /**
12
14
  * 自定义 Hook,用于定点清扫
13
15
  * @returns 包含 requestSpotClean 和 setSpotClean 函数的对象
@@ -57,25 +59,31 @@ export const useSpotClean = () => {
57
59
  origin
58
60
  } = validatedData;
59
61
  const num = spots.length;
62
+ const waterPayload = normalizeWaterPreferencePayload(validatedData.cisterns, validatedData.waterValues);
60
63
 
61
64
  // 为可选字段设置默认值
62
65
  const {
63
66
  suctions = new Array(num).fill(''),
64
- cisterns = new Array(num).fill(''),
65
67
  cleanCounts = new Array(num).fill(1),
66
68
  yMops = new Array(num).fill(-1),
67
- sweepMopModes = new Array(num).fill('only_sweep')
69
+ sweepMopModes = new Array(num).fill('only_sweep'),
70
+ routePreferences,
71
+ names
68
72
  } = validatedData;
69
73
  if (useMqtt) {
70
- sendStructuredMessage(SpotCleanEnum.set, {
74
+ sendStructuredMessage(SpotCleanEnum.set, _objectSpread(_objectSpread(_objectSpread({
71
75
  num,
72
76
  polygons: spots.map(spot => pointsToString([spot], origin)),
73
- suctions,
74
- cisterns,
77
+ suctions
78
+ }, waterPayload), {}, {
75
79
  cleanCounts,
76
80
  yMops,
77
81
  sweepMopModes
78
- }, resolve, error => reject(handleMqttError(error, 'Failed to set spot clean')), SpotCleanEnum.query // 响应类型是 query,不是 set
82
+ }, routePreferences && {
83
+ routePreferences
84
+ }), names && {
85
+ names
86
+ }), resolve, error => reject(handleMqttError(error, 'Failed to set spot clean')), SpotCleanEnum.query // 响应类型是 query,不是 set
79
87
  );
80
88
  return;
81
89
  }
@@ -87,19 +95,23 @@ export const useSpotClean = () => {
87
95
  point: spots[0]
88
96
  });
89
97
  devices.common.model.actions.command_trans.set(command);
90
- resolve({
98
+ resolve(_objectSpread(_objectSpread(_objectSpread({
91
99
  success: true,
92
100
  errCode: 0,
93
101
  reqType: SpotCleanEnum.query,
94
102
  version: commandVersion,
95
103
  taskId: `${Date.now()}`,
96
104
  polygons: spots.map(spot => pointsToString([spot], origin)),
97
- suctions,
98
- cisterns,
105
+ suctions
106
+ }, waterPayload), {}, {
99
107
  cleanCounts,
100
108
  yMops,
101
109
  sweepMopModes
102
- });
110
+ }, routePreferences && {
111
+ routePreferences
112
+ }), names && {
113
+ names
114
+ }));
103
115
  } catch (error) {
104
116
  reject(handleMqttError(error, 'Failed to set spot clean'));
105
117
  }
@@ -18,7 +18,7 @@ export const useWifiMap = () => {
18
18
 
19
19
  /**
20
20
  * 设置 WiFi 地图
21
- * @param data 包含 taskId 的参数对象(taskId 可选,不提供时自动生成)
21
+ * @param data 包含 taskId 的参数对象(taskId 可选,不提供时自动生成,switch 可选,默认)
22
22
  * @returns Promise<WifiMapResponse> 响应结果
23
23
  */
24
24
 
@@ -36,9 +36,11 @@ export const useWifiMap = () => {
36
36
  let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
37
37
  return new Promise((resolve, reject) => {
38
38
  try {
39
+ var _data$switch;
39
40
  // 如果没有提供 taskId,自动生成
40
41
  const wifiMapData = {
41
- taskId: data.taskId || String(Date.now())
42
+ taskId: data.taskId || String(Date.now()),
43
+ switch: (_data$switch = data.switch) !== null && _data$switch !== void 0 ? _data$switch : true
42
44
  };
43
45
 
44
46
  // 使用 TypeBox Schema 进行参数验证
@@ -1,3 +1,4 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import "core-js/modules/esnext.iterator.map.js";
2
3
  // 划区清扫
3
4
  import { encodeZoneClean0x3a, requestZoneClean0x3b } from '@ray-js/robot-protocol';
@@ -7,6 +8,7 @@ import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMess
7
8
  import { SingletonContext } from './mqttProvider';
8
9
  import { ZoneCleanEnum } from './type';
9
10
  import { validator } from './type/fun';
11
+ import { normalizeWaterPreferencePayload } from './waterPreference';
10
12
  /**
11
13
  * 自定义 Hook,用于划区清扫
12
14
  * @returns 包含 requestZoneClean 和 setZoneClean 函数的对象
@@ -73,16 +75,15 @@ export const useZoneClean = () => {
73
75
 
74
76
  // 将业务参数转换为协议数据格式
75
77
  const num = zones.length;
78
+ const waterPayload = normalizeWaterPreferencePayload(params.cisterns, params.waterValues);
76
79
  const {
77
80
  suctions = new Array(num).fill(''),
78
- cisterns = new Array(num).fill(''),
79
81
  cleanCounts = new Array(num).fill(1),
80
82
  yMops = new Array(num).fill(-1),
81
- sweepMopModes = new Array(num).fill('only_sweep')
83
+ sweepMopModes = new Array(num).fill('only_sweep'),
84
+ routePreferences
82
85
  } = params;
83
-
84
- // 构建符合 SetZoneCleanData 格式的数据
85
- const zoneCleanData = {
86
+ const zoneCleanData = _objectSpread(_objectSpread({
86
87
  zones: zones.map(_ref => {
87
88
  let {
88
89
  points,
@@ -96,41 +97,46 @@ export const useZoneClean = () => {
96
97
  };
97
98
  }),
98
99
  origin,
99
- suctions,
100
- cisterns,
100
+ suctions
101
+ }, waterPayload), {}, {
101
102
  cleanCounts,
102
103
  yMops,
103
104
  sweepMopModes
104
- };
105
+ }, routePreferences && {
106
+ routePreferences
107
+ });
105
108
 
106
109
  // 使用 TypeBox Schema 进行参数验证
107
110
  const validatedData = validator.validate('set_zone_clean', zoneCleanData);
111
+ const polygons = zones.map(_ref2 => {
112
+ let {
113
+ points
114
+ } = _ref2;
115
+ return pointsToString(points, origin);
116
+ });
117
+ const names = zones.map(_ref3 => {
118
+ let {
119
+ name
120
+ } = _ref3;
121
+ return name || '';
122
+ });
123
+ const commonFields = _objectSpread(_objectSpread({
124
+ suctions: validatedData.suctions
125
+ }, waterPayload), {}, {
126
+ cleanCounts: validatedData.cleanCounts,
127
+ yMops: validatedData.yMops,
128
+ sweepMopModes: validatedData.sweepMopModes
129
+ }, validatedData.routePreferences && {
130
+ routePreferences: validatedData.routePreferences
131
+ });
108
132
  if (useMqtt) {
109
- // 将 zones 转换为 polygons 字符串格式(用于 MQTT 消息)
110
- const polygons = zones.map(_ref2 => {
111
- let {
112
- points
113
- } = _ref2;
114
- return pointsToString(points, origin);
115
- });
116
- const names = zones.map(_ref3 => {
117
- let {
118
- name
119
- } = _ref3;
120
- return name || '';
121
- });
122
- sendStructuredMessage(ZoneCleanEnum.set, {
123
- num: zones.length,
133
+ sendStructuredMessage(ZoneCleanEnum.set, _objectSpread(_objectSpread({
134
+ num,
124
135
  switchGo: true,
125
- polygons,
126
- suctions: validatedData.suctions,
127
- cisterns: validatedData.cisterns,
128
- cleanCounts: validatedData.cleanCounts,
129
- yMops: validatedData.yMops,
130
- sweepMopModes: validatedData.sweepMopModes,
136
+ polygons
137
+ }, commonFields), {}, {
131
138
  names
132
- }, resolve, error => reject(handleMqttError(error, 'Failed to set zone clean')), ZoneCleanEnum.query // 响应类型是 query,不是 set
133
- );
139
+ }), resolve, error => reject(handleMqttError(error, 'Failed to set zone clean')), ZoneCleanEnum.query);
134
140
  return;
135
141
  }
136
142
 
@@ -146,19 +152,7 @@ export const useZoneClean = () => {
146
152
  }))
147
153
  });
148
154
  devices.common.model.actions.command_trans.set(command);
149
- const polygons = zones.map(_ref4 => {
150
- let {
151
- points
152
- } = _ref4;
153
- return pointsToString(points, origin);
154
- });
155
- const names = zones.map(_ref5 => {
156
- let {
157
- name
158
- } = _ref5;
159
- return name || '';
160
- });
161
- resolve({
155
+ resolve(_objectSpread({
162
156
  success: true,
163
157
  errCode: 0,
164
158
  reqType: ZoneCleanEnum.query,
@@ -166,7 +160,7 @@ export const useZoneClean = () => {
166
160
  taskId: `${Date.now()}`,
167
161
  polygons,
168
162
  names
169
- });
163
+ }, commonFields));
170
164
  } catch (error) {
171
165
  reject(handleMqttError(error, 'Failed to set zone clean'));
172
166
  }
@@ -0,0 +1,20 @@
1
+ export type WaterPreferenceValue = string | number;
2
+ /**
3
+ * 将自定义水量 / 标准水量统一归一化为设备命令需要的数值。
4
+ * 优先使用 waterValue,其次回退到 cistern。
5
+ */
6
+ export declare const resolveWaterLevel: (waterValue?: WaterPreferenceValue, cistern?: WaterPreferenceValue, fallback?: number) => number;
7
+ export declare const hasPreferenceValue: (value?: WaterPreferenceValue | null) => boolean;
8
+ /**
9
+ * MQTT 水量相关字段是可选的。
10
+ * 当数组里全是空字符串时,认为该字段未设置,避免把空 cisterns/waterValues 发给设备。
11
+ */
12
+ export declare const normalizeOptionalPreferenceArray: <T extends WaterPreferenceValue>(values?: T[] | undefined) => T[] | undefined;
13
+ /**
14
+ * 自定义水量优先于旧 cistern 水量。
15
+ * 当某一项存在自定义水量时,同位置的 cistern 会被清空;最终空数组字段会被省略。
16
+ */
17
+ export declare const normalizeWaterPreferencePayload: (cisterns?: WaterPreferenceValue[], waterValues?: WaterPreferenceValue[]) => {
18
+ cisterns?: WaterPreferenceValue[] | undefined;
19
+ waterValues?: WaterPreferenceValue[] | undefined;
20
+ };
@@ -0,0 +1,70 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import "core-js/modules/esnext.iterator.constructor.js";
3
+ import "core-js/modules/esnext.iterator.some.js";
4
+ import { CISTERN_MAP } from '../constant';
5
+ /**
6
+ * 将自定义水量 / 标准水量统一归一化为设备命令需要的数值。
7
+ * 优先使用 waterValue,其次回退到 cistern。
8
+ */
9
+ export const resolveWaterLevel = function (waterValue, cistern) {
10
+ var _ref, _resolveValue;
11
+ let fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : CISTERN_MAP.closed;
12
+ const resolveValue = value => {
13
+ if (typeof value === 'number' && Number.isFinite(value)) {
14
+ return value;
15
+ }
16
+ if (typeof value !== 'string') {
17
+ return undefined;
18
+ }
19
+ if (value in CISTERN_MAP) {
20
+ return CISTERN_MAP[value];
21
+ }
22
+ const parsed = Number(value);
23
+ return Number.isFinite(parsed) ? parsed : undefined;
24
+ };
25
+ return (_ref = (_resolveValue = resolveValue(waterValue)) !== null && _resolveValue !== void 0 ? _resolveValue : resolveValue(cistern)) !== null && _ref !== void 0 ? _ref : fallback;
26
+ };
27
+ export const hasPreferenceValue = value => value !== '' && value !== null && value !== undefined;
28
+
29
+ /**
30
+ * MQTT 水量相关字段是可选的。
31
+ * 当数组里全是空字符串时,认为该字段未设置,避免把空 cisterns/waterValues 发给设备。
32
+ */
33
+ export const normalizeOptionalPreferenceArray = values => {
34
+ if (!values) {
35
+ return undefined;
36
+ }
37
+ return values.some(hasPreferenceValue) ? values : undefined;
38
+ };
39
+
40
+ /**
41
+ * 自定义水量优先于旧 cistern 水量。
42
+ * 当某一项存在自定义水量时,同位置的 cistern 会被清空;最终空数组字段会被省略。
43
+ */
44
+ export const normalizeWaterPreferencePayload = (cisterns, waterValues) => {
45
+ var _cisterns$length, _waterValues$length;
46
+ const maxLength = Math.max((_cisterns$length = cisterns === null || cisterns === void 0 ? void 0 : cisterns.length) !== null && _cisterns$length !== void 0 ? _cisterns$length : 0, (_waterValues$length = waterValues === null || waterValues === void 0 ? void 0 : waterValues.length) !== null && _waterValues$length !== void 0 ? _waterValues$length : 0);
47
+ if (maxLength === 0) {
48
+ return {};
49
+ }
50
+ const normalizedCisterns = normalizeOptionalPreferenceArray(Array.from({
51
+ length: maxLength
52
+ }, (_, index) => {
53
+ var _cisterns$index;
54
+ if (hasPreferenceValue(waterValues === null || waterValues === void 0 ? void 0 : waterValues[index])) {
55
+ return '';
56
+ }
57
+ return (_cisterns$index = cisterns === null || cisterns === void 0 ? void 0 : cisterns[index]) !== null && _cisterns$index !== void 0 ? _cisterns$index : '';
58
+ }));
59
+ const normalizedWaterValues = normalizeOptionalPreferenceArray(Array.from({
60
+ length: maxLength
61
+ }, (_, index) => {
62
+ var _waterValues$index;
63
+ return (_waterValues$index = waterValues === null || waterValues === void 0 ? void 0 : waterValues[index]) !== null && _waterValues$index !== void 0 ? _waterValues$index : '';
64
+ }));
65
+ return _objectSpread(_objectSpread({}, normalizedCisterns ? {
66
+ cisterns: normalizedCisterns
67
+ } : {}), normalizedWaterValues ? {
68
+ waterValues: normalizedWaterValues
69
+ } : {});
70
+ };