nayota-show-sdk 1.3.103 → 1.3.105
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/api/attendanceRecord.js +15 -7
- package/api/controlRoom.js +225 -0
- package/api/controlRoom.test.js +98 -0
- package/api/workSchedule.js +107 -19
- package/api/workSchedule.test.js +104 -0
- package/index.js +2 -0
- package/package.json +1 -1
package/api/attendanceRecord.js
CHANGED
|
@@ -15,11 +15,13 @@ import { requestShow } from '../utils'
|
|
|
15
15
|
* @property {string} _id - 考勤记录id
|
|
16
16
|
* @property {string|Object} user - 关联用户
|
|
17
17
|
* @property {Date} date - 考勤日期
|
|
18
|
-
* @property {
|
|
18
|
+
* @property {string} [shiftType] - 班次类型,如:早班、中班、晚班
|
|
19
19
|
* @property {Date} [clockInTime] - 上班打卡时间
|
|
20
20
|
* @property {Date} [clockOutTime] - 下班打卡时间
|
|
21
21
|
* @property {string} [clockInPhoto] - 上班打卡照片
|
|
22
|
+
* @property {number} [clockInDistance] - 上班打卡距离
|
|
22
23
|
* @property {string} [clockOutPhoto] - 下班打卡照片
|
|
24
|
+
* @property {number} [clockOutDistance] - 下班打卡距离
|
|
23
25
|
* @property {number} [clockInStatus] - 上班状态,1 上班打卡,2 上班迟到,3 上班未打卡
|
|
24
26
|
* @property {number} [clockOutStatus] - 下班状态,4 下班打卡,5 下班早退,6 下班未打卡
|
|
25
27
|
* @property {number} status - 汇总考勤状态,优先保留上班异常,其次下班异常;1 上班打卡,2 上班迟到,3 上班未打卡,4 下班打卡,5 下班早退,6 下班未打卡,7 缺勤
|
|
@@ -35,11 +37,13 @@ import { requestShow } from '../utils'
|
|
|
35
37
|
* "_id": "67f8f0000000000000000001",
|
|
36
38
|
* "user": "67f8f0000000000000000002",
|
|
37
39
|
* "date": "2026-03-31T00:00:00.000Z",
|
|
38
|
-
* "shiftType":
|
|
40
|
+
* "shiftType": "早班",
|
|
39
41
|
* "clockInTime": "2026-03-31T00:03:00.000Z",
|
|
40
42
|
* "clockOutTime": "2026-03-31T08:02:00.000Z",
|
|
41
43
|
* "clockInPhoto": "https://example.com/clock-in.jpg",
|
|
44
|
+
* "clockInDistance": 12.5,
|
|
42
45
|
* "clockOutPhoto": "https://example.com/clock-out.jpg",
|
|
46
|
+
* "clockOutDistance": 10,
|
|
43
47
|
* "clockInStatus": 2,
|
|
44
48
|
* "clockOutStatus": 4,
|
|
45
49
|
* "status": 2,
|
|
@@ -59,7 +63,7 @@ import { requestShow } from '../utils'
|
|
|
59
63
|
* @property {string|Date} endTime - 结束时间
|
|
60
64
|
* @property {'week'|'month'|'year'} [dimension] - 查询维度,不传时由服务端按时间跨度自动推断
|
|
61
65
|
* @property {string} [user] - 用户id
|
|
62
|
-
* @property {
|
|
66
|
+
* @property {string} [shiftType] - 班次类型,如:早班、中班、晚班
|
|
63
67
|
* @property {string} [creator] - 创建者 UUID
|
|
64
68
|
*/
|
|
65
69
|
|
|
@@ -149,7 +153,7 @@ export function violationStatistics(query) {
|
|
|
149
153
|
* @param {number} [query.month] - 统计月份,1-12;不传表示查询整年
|
|
150
154
|
* @param {string} [query.creator] - 创建者 UUID
|
|
151
155
|
* @param {string} [query.user] - 用户id
|
|
152
|
-
* @param {
|
|
156
|
+
* @param {string} [query.shiftType] - 班次类型,如:早班、中班、晚班
|
|
153
157
|
* @returns {number} code - 返回码,0 表示成功
|
|
154
158
|
* @returns {Object} data - 统计结果
|
|
155
159
|
* @returns {'year'|'month'} data.dimension - 明细维度
|
|
@@ -215,7 +219,7 @@ export function dutyStatistics(query) {
|
|
|
215
219
|
* @param {string} [query.search] - 模糊查询值
|
|
216
220
|
* @param {string} [query.user] - 用户id
|
|
217
221
|
* @param {string|Date} [query.date] - 考勤日期
|
|
218
|
-
* @param {
|
|
222
|
+
* @param {string} [query.shiftType] - 班次类型,如:早班、中班、晚班
|
|
219
223
|
* @param {number} [query.status] - 考勤状态
|
|
220
224
|
* @param {string} [query.sort] - 排序字段
|
|
221
225
|
* @returns {number} code - 返回码,0表示成功
|
|
@@ -235,11 +239,13 @@ export function list(query) {
|
|
|
235
239
|
* @param {Object} data - 请求体
|
|
236
240
|
* @param {string} data.user - 用户id
|
|
237
241
|
* @param {string|Date} data.date - 考勤日期
|
|
238
|
-
* @param {
|
|
242
|
+
* @param {string} [data.shiftType] - 班次类型,如:早班、中班、晚班
|
|
239
243
|
* @param {string|Date|null} [data.clockInTime] - 上班打卡时间
|
|
240
244
|
* @param {string|Date|null} [data.clockOutTime] - 下班打卡时间
|
|
241
245
|
* @param {string|null} [data.clockInPhoto] - 上班打卡照片
|
|
246
|
+
* @param {number|null} [data.clockInDistance] - 上班打卡距离
|
|
242
247
|
* @param {string|null} [data.clockOutPhoto] - 下班打卡照片
|
|
248
|
+
* @param {number|null} [data.clockOutDistance] - 下班打卡距离
|
|
243
249
|
* @param {number} [data.clockInStatus] - 上班状态,通常由服务端自动计算
|
|
244
250
|
* @param {number} [data.clockOutStatus] - 下班状态,通常由服务端自动计算
|
|
245
251
|
* @param {number} [data.status] - 考勤状态,服务端会按班次和打卡时间自动修正
|
|
@@ -277,11 +283,13 @@ export function getOne(id) {
|
|
|
277
283
|
* @param {string} data._id - 考勤记录id
|
|
278
284
|
* @param {string} [data.user] - 用户id
|
|
279
285
|
* @param {string|Date} [data.date] - 考勤日期
|
|
280
|
-
* @param {
|
|
286
|
+
* @param {string} [data.shiftType] - 班次类型,如:早班、中班、晚班
|
|
281
287
|
* @param {string|Date|null} [data.clockInTime] - 上班打卡时间
|
|
282
288
|
* @param {string|Date|null} [data.clockOutTime] - 下班打卡时间
|
|
283
289
|
* @param {string|null} [data.clockInPhoto] - 上班打卡照片
|
|
290
|
+
* @param {number|null} [data.clockInDistance] - 上班打卡距离
|
|
284
291
|
* @param {string|null} [data.clockOutPhoto] - 下班打卡照片
|
|
292
|
+
* @param {number|null} [data.clockOutDistance] - 下班打卡距离
|
|
285
293
|
* @param {number} [data.clockInStatus] - 上班状态,通常由服务端自动计算
|
|
286
294
|
* @param {number} [data.clockOutStatus] - 下班状态,通常由服务端自动计算
|
|
287
295
|
* @param {number} [data.status] - 考勤状态,服务端会按班次和打卡时间自动修正
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import urlcfg from '../config/urlcfg'
|
|
2
|
+
import { requestShow } from '../utils'
|
|
3
|
+
|
|
4
|
+
const baseUrl = '/control-rooms'
|
|
5
|
+
|
|
6
|
+
function isPlainObject(value) {
|
|
7
|
+
return Object.prototype.toString.call(value) === '[object Object]'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function mapAreaFieldToSpace(value) {
|
|
11
|
+
if (!isPlainObject(value)) {
|
|
12
|
+
return value
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const next = { ...value }
|
|
16
|
+
if (next.space === undefined && Object.prototype.hasOwnProperty.call(next, 'area')) {
|
|
17
|
+
next.space = next.area
|
|
18
|
+
}
|
|
19
|
+
delete next.area
|
|
20
|
+
return next
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function mapControlRoomRequestFields(value) {
|
|
24
|
+
if (!urlcfg.isV2() || !isPlainObject(value)) {
|
|
25
|
+
return value
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const next = mapAreaFieldToSpace(value)
|
|
29
|
+
if (isPlainObject(next.query)) {
|
|
30
|
+
next.query = mapAreaFieldToSpace(next.query)
|
|
31
|
+
} else if (typeof next.query === 'string') {
|
|
32
|
+
try {
|
|
33
|
+
const queryObject = JSON.parse(next.query)
|
|
34
|
+
if (isPlainObject(queryObject)) {
|
|
35
|
+
next.query = JSON.stringify(mapAreaFieldToSpace(queryObject))
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
// 保留原始 query 字符串,交给服务端按原行为处理。
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return next
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function mapControlRoomEntity(entity) {
|
|
45
|
+
if (!urlcfg.isV2() || !isPlainObject(entity)) {
|
|
46
|
+
return entity
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
...entity,
|
|
51
|
+
area: entity.area !== undefined ? entity.area : entity.space
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function mapControlRoomResponse(response) {
|
|
56
|
+
if (!urlcfg.isV2() || !isPlainObject(response)) {
|
|
57
|
+
return response
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (Array.isArray(response.rows)) {
|
|
61
|
+
return {
|
|
62
|
+
...response,
|
|
63
|
+
rows: response.rows.map(mapControlRoomEntity)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (response.data !== undefined) {
|
|
68
|
+
return {
|
|
69
|
+
...response,
|
|
70
|
+
data: Array.isArray(response.data)
|
|
71
|
+
? response.data.map(mapControlRoomEntity)
|
|
72
|
+
: mapControlRoomEntity(response.data)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return mapControlRoomEntity(response)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function requestControlRoom(config) {
|
|
80
|
+
const response = await requestShow(config)
|
|
81
|
+
return mapControlRoomResponse(response)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @file 消控室api
|
|
86
|
+
* @module 消控室接口
|
|
87
|
+
* @category 人员管理
|
|
88
|
+
* @import
|
|
89
|
+
* import { controlRoom } from 'nayota-show-sdk'
|
|
90
|
+
* const { list, create, getOne, updateOne, deleteOne, deleteMany } = controlRoom
|
|
91
|
+
* list({ page: 1, limit: 10 })
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @typedef {Object} ControlRoomContact - 消控室联系人
|
|
96
|
+
* @property {string|null} [name] - 姓名
|
|
97
|
+
* @property {string|null} [phone] - 电话
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @typedef {Object} ControlRoomLocation - 消控室定位
|
|
102
|
+
* @property {number|null} [longitude] - 经度
|
|
103
|
+
* @property {number|null} [latitude] - 纬度
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @typedef {Object} ControlRoomShift - 消控室班次
|
|
108
|
+
* @property {string} name - 班次名称,例如早班、中班、晚班
|
|
109
|
+
* @property {string} startTime - 开始时间,格式 HH:mm,支持 24:00
|
|
110
|
+
* @property {string} endTime - 结束时间,格式 HH:mm,支持 24:00
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @typedef {Object} ControlRoom - 消控室
|
|
115
|
+
* @property {string} _id - 消控室 UUID
|
|
116
|
+
* @property {string|null} [name] - 消控室名称
|
|
117
|
+
* @property {Date|null} [commissionedDate] - 投用日期
|
|
118
|
+
* @property {string|null} [managementUnit] - 管理(使用)单位
|
|
119
|
+
* @property {ControlRoomContact} [fireSafetyResponsiblePerson] - 消防安全责任人及电话
|
|
120
|
+
* @property {ControlRoomContact} [controlRoomManager] - 消控室负责人/管理人及电话
|
|
121
|
+
* @property {string|null} [space] - 关联空间 UUID
|
|
122
|
+
* @property {string|null} [area] - v2 SDK 兼容字段,映射自 space
|
|
123
|
+
* @property {ControlRoomLocation} [location] - 经纬度定位
|
|
124
|
+
* @property {Array<string|Object>} [users] - 关联人员 UUID 数组
|
|
125
|
+
* @property {Array<ControlRoomShift>} [shifts] - 班次配置
|
|
126
|
+
* @property {string|null} [creator] - 创建者 UUID
|
|
127
|
+
* @property {Date} createdAt - 创建时间
|
|
128
|
+
* @property {Date} updatedAt - 更新时间
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 获取消控室列表
|
|
133
|
+
* @param {Object} query - 请求对象
|
|
134
|
+
* @param {number} [query.page] - 页码
|
|
135
|
+
* @param {number} [query.limit] - 每页数量
|
|
136
|
+
* @param {string} [query.name] - 消控室名称
|
|
137
|
+
* @param {string} [query.space] - 空间 UUID
|
|
138
|
+
* @param {string} [query.area] - v2 兼容别名,发送时映射为 space
|
|
139
|
+
* @param {string} [query.sort] - 排序字段
|
|
140
|
+
*/
|
|
141
|
+
export function list(query) {
|
|
142
|
+
return requestControlRoom({
|
|
143
|
+
url: baseUrl,
|
|
144
|
+
method: 'get',
|
|
145
|
+
params: mapControlRoomRequestFields(query)
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 新增消控室
|
|
151
|
+
* @param {Object} data - 请求体
|
|
152
|
+
* @param {string|null} [data.name] - 消控室名称
|
|
153
|
+
* @param {Date|null} [data.commissionedDate] - 投用日期
|
|
154
|
+
* @param {string|null} [data.managementUnit] - 管理(使用)单位
|
|
155
|
+
* @param {ControlRoomContact|null} [data.fireSafetyResponsiblePerson] - 消防安全责任人及电话
|
|
156
|
+
* @param {ControlRoomContact|null} [data.controlRoomManager] - 消控室负责人/管理人及电话
|
|
157
|
+
* @param {string|Object|null} [data.space] - 空间 UUID,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
158
|
+
* @param {string|Object|null} [data.area] - v2 兼容别名,发送时映射为 space
|
|
159
|
+
* @param {ControlRoomLocation|null} [data.location] - 经纬度定位
|
|
160
|
+
* @param {Array<string|Object>} [data.users] - 关联人员 UUID 数组,支持传入 UUID 字符串或包含 id/_id 的对象数组
|
|
161
|
+
* @param {Array<ControlRoomShift>} [data.shifts] - 班次配置
|
|
162
|
+
*/
|
|
163
|
+
export function create(data) {
|
|
164
|
+
return requestControlRoom({
|
|
165
|
+
url: baseUrl,
|
|
166
|
+
method: 'post',
|
|
167
|
+
data: mapControlRoomRequestFields(data)
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 获取消控室详情
|
|
173
|
+
* @param {string} id - 消控室 ID
|
|
174
|
+
*/
|
|
175
|
+
export function getOne(id) {
|
|
176
|
+
return requestControlRoom({
|
|
177
|
+
url: `${baseUrl}/${id}`,
|
|
178
|
+
method: 'get'
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 编辑消控室
|
|
184
|
+
* @param {Object} data - 修改数据对象
|
|
185
|
+
* @param {string} data._id - 消控室 UUID
|
|
186
|
+
*/
|
|
187
|
+
export function updateOne(data) {
|
|
188
|
+
return requestControlRoom({
|
|
189
|
+
url: `${baseUrl}/${data._id || data.id}`,
|
|
190
|
+
method: 'put',
|
|
191
|
+
data: mapControlRoomRequestFields(data)
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 删除消控室
|
|
197
|
+
* @param {string} id - 消控室 ID
|
|
198
|
+
*/
|
|
199
|
+
export function deleteOne(id) {
|
|
200
|
+
return requestControlRoom({
|
|
201
|
+
url: `${baseUrl}/${id}`,
|
|
202
|
+
method: 'delete'
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 批量删除消控室
|
|
208
|
+
* @param {Array<string>} ids - 消控室 ID 数组
|
|
209
|
+
*/
|
|
210
|
+
export function deleteMany(ids) {
|
|
211
|
+
return requestControlRoom({
|
|
212
|
+
url: baseUrl,
|
|
213
|
+
method: 'delete',
|
|
214
|
+
data: ids
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export default {
|
|
219
|
+
list,
|
|
220
|
+
create,
|
|
221
|
+
getOne,
|
|
222
|
+
updateOne,
|
|
223
|
+
deleteOne,
|
|
224
|
+
deleteMany
|
|
225
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
jest.mock('../utils', () => ({
|
|
2
|
+
requestShow: jest.fn()
|
|
3
|
+
}))
|
|
4
|
+
|
|
5
|
+
const urlcfg = require('../config/urlcfg').default
|
|
6
|
+
const { requestShow } = require('../utils')
|
|
7
|
+
const controlRoom = require('./controlRoom').default
|
|
8
|
+
|
|
9
|
+
describe('controlRoom api v2 field compatibility', () => {
|
|
10
|
+
const originalVersion = urlcfg.version
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
urlcfg.version = originalVersion
|
|
14
|
+
jest.clearAllMocks()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('keeps legacy area payload in v1', async () => {
|
|
18
|
+
const query = {
|
|
19
|
+
area: 'space-legacy'
|
|
20
|
+
}
|
|
21
|
+
requestShow.mockResolvedValue({ code: 0, rows: [] })
|
|
22
|
+
|
|
23
|
+
await controlRoom.list(query)
|
|
24
|
+
|
|
25
|
+
expect(requestShow).toHaveBeenCalledWith({
|
|
26
|
+
url: '/control-rooms',
|
|
27
|
+
method: 'get',
|
|
28
|
+
params: query
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('maps legacy area request field to space in v2', async () => {
|
|
33
|
+
urlcfg.version = 'v2'
|
|
34
|
+
const data = {
|
|
35
|
+
_id: 'control-room-1',
|
|
36
|
+
name: '一号消控室',
|
|
37
|
+
area: '22222222-2222-4222-8222-222222222222',
|
|
38
|
+
shifts: [{ name: '早班', startTime: '08:00', endTime: '16:00' }]
|
|
39
|
+
}
|
|
40
|
+
requestShow.mockResolvedValue({ code: 0, data: {} })
|
|
41
|
+
|
|
42
|
+
await controlRoom.updateOne(data)
|
|
43
|
+
|
|
44
|
+
expect(requestShow).toHaveBeenCalledWith({
|
|
45
|
+
url: '/control-rooms/control-room-1',
|
|
46
|
+
method: 'put',
|
|
47
|
+
data: {
|
|
48
|
+
_id: 'control-room-1',
|
|
49
|
+
name: '一号消控室',
|
|
50
|
+
space: '22222222-2222-4222-8222-222222222222',
|
|
51
|
+
shifts: [{ name: '早班', startTime: '08:00', endTime: '16:00' }]
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('maps legacy area inside query filter to space in v2', async () => {
|
|
57
|
+
urlcfg.version = 'v2'
|
|
58
|
+
requestShow.mockResolvedValue({ code: 0, rows: [] })
|
|
59
|
+
|
|
60
|
+
await controlRoom.list({
|
|
61
|
+
query: {
|
|
62
|
+
area: '22222222-2222-4222-8222-222222222222',
|
|
63
|
+
name: '一号消控室'
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
expect(requestShow).toHaveBeenCalledWith({
|
|
68
|
+
url: '/control-rooms',
|
|
69
|
+
method: 'get',
|
|
70
|
+
params: {
|
|
71
|
+
query: {
|
|
72
|
+
name: '一号消控室',
|
|
73
|
+
space: '22222222-2222-4222-8222-222222222222'
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test('maps v2 response space back to legacy area alias', async () => {
|
|
80
|
+
urlcfg.version = 'v2'
|
|
81
|
+
requestShow.mockResolvedValue({
|
|
82
|
+
code: 0,
|
|
83
|
+
data: {
|
|
84
|
+
id: 'control-room-1',
|
|
85
|
+
name: '一号消控室',
|
|
86
|
+
space: '22222222-2222-4222-8222-222222222222'
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const response = await controlRoom.getOne('control-room-1')
|
|
91
|
+
|
|
92
|
+
expect(response.data).toEqual(expect.objectContaining({
|
|
93
|
+
name: '一号消控室',
|
|
94
|
+
space: '22222222-2222-4222-8222-222222222222',
|
|
95
|
+
area: '22222222-2222-4222-8222-222222222222'
|
|
96
|
+
}))
|
|
97
|
+
})
|
|
98
|
+
})
|
package/api/workSchedule.js
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
|
+
import urlcfg from '../config/urlcfg'
|
|
1
2
|
import { requestShow } from '../utils'
|
|
2
3
|
|
|
4
|
+
function isPlainObject(value) {
|
|
5
|
+
return Object.prototype.toString.call(value) === '[object Object]'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function mapAreaFieldToSpace(value) {
|
|
9
|
+
if (!isPlainObject(value)) {
|
|
10
|
+
return value
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const next = { ...value }
|
|
14
|
+
if (next.space === undefined && Object.prototype.hasOwnProperty.call(next, 'area')) {
|
|
15
|
+
next.space = next.area
|
|
16
|
+
}
|
|
17
|
+
delete next.area
|
|
18
|
+
return next
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function mapWorkScheduleRequestFields(value) {
|
|
22
|
+
if (!urlcfg.isV2() || !isPlainObject(value)) {
|
|
23
|
+
return value
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const next = mapAreaFieldToSpace(value)
|
|
27
|
+
if (isPlainObject(next.query)) {
|
|
28
|
+
next.query = mapAreaFieldToSpace(next.query)
|
|
29
|
+
} else if (typeof next.query === 'string') {
|
|
30
|
+
try {
|
|
31
|
+
const queryObject = JSON.parse(next.query)
|
|
32
|
+
if (isPlainObject(queryObject)) {
|
|
33
|
+
next.query = JSON.stringify(mapAreaFieldToSpace(queryObject))
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
// 保留原始 query 字符串,交给服务端按原行为处理。
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return next
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function mapWorkScheduleEntity(entity) {
|
|
43
|
+
if (!urlcfg.isV2() || !isPlainObject(entity)) {
|
|
44
|
+
return entity
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
...entity,
|
|
49
|
+
area: entity.area !== undefined ? entity.area : entity.space
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function mapWorkScheduleResponse(response) {
|
|
54
|
+
if (!urlcfg.isV2() || !isPlainObject(response)) {
|
|
55
|
+
return response
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (Array.isArray(response.rows)) {
|
|
59
|
+
return {
|
|
60
|
+
...response,
|
|
61
|
+
rows: response.rows.map(mapWorkScheduleEntity)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (response.data !== undefined) {
|
|
66
|
+
return {
|
|
67
|
+
...response,
|
|
68
|
+
data: Array.isArray(response.data)
|
|
69
|
+
? response.data.map(mapWorkScheduleEntity)
|
|
70
|
+
: mapWorkScheduleEntity(response.data)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return mapWorkScheduleEntity(response)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function requestWorkSchedule(config) {
|
|
78
|
+
const response = await requestShow(config)
|
|
79
|
+
return mapWorkScheduleResponse(response)
|
|
80
|
+
}
|
|
81
|
+
|
|
3
82
|
/**
|
|
4
83
|
* @file 排班表api
|
|
5
84
|
* @module 排班表接口
|
|
@@ -13,7 +92,7 @@ import { requestShow } from '../utils'
|
|
|
13
92
|
/**
|
|
14
93
|
* @typedef {Object} WorkScheduleDetail - 排班明细
|
|
15
94
|
* @property {number} day - 日期,1-31
|
|
16
|
-
* @property {
|
|
95
|
+
* @property {string} [shiftType] - 当日班次,如:早班、中班、晚班
|
|
17
96
|
* @property {boolean} isRestDay - 是否休息日
|
|
18
97
|
* @property {string|Object} [attendanceRecord] - 当日关联考勤记录id或考勤记录对象,联表对象通常包含 clockInTime、clockOutTime、clockInPhoto、clockOutPhoto、clockInStatus、clockOutStatus、status、remark
|
|
19
98
|
*/
|
|
@@ -21,12 +100,14 @@ import { requestShow } from '../utils'
|
|
|
21
100
|
/**
|
|
22
101
|
* @typedef {Object} WorkSchedule - 排班表
|
|
23
102
|
* @property {string} _id - 排班表 UUID
|
|
24
|
-
* @property {string|Object} user - 关联用户 UUID
|
|
103
|
+
* @property {string|Object|null} [user] - 关联用户 UUID
|
|
25
104
|
* @property {Array<string|Object>} users - 关联用户 UUID 数组
|
|
26
105
|
* @property {string|null} [space] - 关联空间 UUID,引用外部配置服务空间
|
|
106
|
+
* @property {string|null} [area] - v2 SDK 兼容字段,映射自 space
|
|
107
|
+
* @property {string|Object|null} [controlRoom] - 关联消控室 UUID,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
27
108
|
* @property {number} year - 年份
|
|
28
109
|
* @property {number} month - 月份,1-12
|
|
29
|
-
* @property {
|
|
110
|
+
* @property {string} shiftType - 默认班次类型,如:早班、中班、晚班
|
|
30
111
|
* @property {Array<WorkScheduleDetail>} scheduleDetails - 每日排班明细
|
|
31
112
|
* @property {number} status - 状态,0 草稿,1 已发布
|
|
32
113
|
* @property {string} [remark] - 备注
|
|
@@ -42,13 +123,14 @@ import { requestShow } from '../utils'
|
|
|
42
123
|
* "33333333-3333-4333-8333-333333333333"
|
|
43
124
|
* ],
|
|
44
125
|
* "space": "44444444-4444-4444-8444-444444444444",
|
|
126
|
+
* "controlRoom": "77777777-7777-4777-8777-777777777777",
|
|
45
127
|
* "year": 2026,
|
|
46
128
|
* "month": 3,
|
|
47
|
-
* "shiftType":
|
|
129
|
+
* "shiftType": "早班",
|
|
48
130
|
* "scheduleDetails": [
|
|
49
131
|
* {
|
|
50
132
|
* "day": 8,
|
|
51
|
-
* "shiftType":
|
|
133
|
+
* "shiftType": "中班",
|
|
52
134
|
* "isRestDay": false,
|
|
53
135
|
* "attendanceRecord": "55555555-5555-4555-8555-555555555555"
|
|
54
136
|
* },
|
|
@@ -74,9 +156,11 @@ import { requestShow } from '../utils'
|
|
|
74
156
|
* @param {string} [query.search] - 模糊查询值
|
|
75
157
|
* @param {string} [query.user] - 用户 UUID
|
|
76
158
|
* @param {string} [query.space] - 空间 UUID
|
|
159
|
+
* @param {string} [query.area] - v2 兼容别名,发送时映射为 space
|
|
160
|
+
* @param {string} [query.controlRoom] - 消控室 UUID
|
|
77
161
|
* @param {number} [query.year] - 年份
|
|
78
162
|
* @param {number} [query.month] - 月份
|
|
79
|
-
* @param {
|
|
163
|
+
* @param {string} [query.shiftType] - 默认班次类型,如:早班、中班、晚班
|
|
80
164
|
* @param {number} [query.status] - 状态
|
|
81
165
|
* @param {string} [query.sort] - 排序字段
|
|
82
166
|
* @returns {number} code - 返回码,0表示成功
|
|
@@ -84,22 +168,24 @@ import { requestShow } from '../utils'
|
|
|
84
168
|
* @returns {Array<WorkSchedule>} rows - 列表数据
|
|
85
169
|
*/
|
|
86
170
|
export function list(query) {
|
|
87
|
-
return
|
|
171
|
+
return requestWorkSchedule({
|
|
88
172
|
url: '/work-schedules',
|
|
89
173
|
method: 'get',
|
|
90
|
-
params: query
|
|
174
|
+
params: mapWorkScheduleRequestFields(query)
|
|
91
175
|
})
|
|
92
176
|
}
|
|
93
177
|
|
|
94
178
|
/**
|
|
95
179
|
* 新增排班表
|
|
96
180
|
* @param {Object} data - 请求体
|
|
97
|
-
* @param {string|Object} data.user - 用户 UUID,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
181
|
+
* @param {string|Object|null} [data.user] - 用户 UUID,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
98
182
|
* @param {Array<string|Object>} [data.users] - 用户 UUID 数组,支持传入 UUID 字符串或包含 id/_id 的对象数组
|
|
99
183
|
* @param {string|Object|null} [data.space] - 空间 UUID,引用外部配置服务空间,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
184
|
+
* @param {string|Object|null} [data.area] - v2 兼容别名,发送时映射为 space
|
|
185
|
+
* @param {string|Object|null} [data.controlRoom] - 消控室 UUID,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
100
186
|
* @param {number} data.year - 年份
|
|
101
187
|
* @param {number} data.month - 月份,1-12
|
|
102
|
-
* @param {
|
|
188
|
+
* @param {string} data.shiftType - 默认班次类型,如:早班、中班、晚班
|
|
103
189
|
* @param {Array<WorkScheduleDetail>|null} [data.scheduleDetails] - 每日排班明细
|
|
104
190
|
* @param {number} [data.status] - 状态,0 草稿,1 已发布
|
|
105
191
|
* @param {string|null} [data.remark] - 备注
|
|
@@ -107,10 +193,10 @@ export function list(query) {
|
|
|
107
193
|
* @returns {WorkSchedule} data - 新增成功的数据
|
|
108
194
|
*/
|
|
109
195
|
export function create(data) {
|
|
110
|
-
return
|
|
196
|
+
return requestWorkSchedule({
|
|
111
197
|
url: '/work-schedules',
|
|
112
198
|
method: 'post',
|
|
113
|
-
data
|
|
199
|
+
data: mapWorkScheduleRequestFields(data)
|
|
114
200
|
})
|
|
115
201
|
}
|
|
116
202
|
|
|
@@ -121,7 +207,7 @@ export function create(data) {
|
|
|
121
207
|
* @returns {WorkSchedule} data - 详情对象
|
|
122
208
|
*/
|
|
123
209
|
export function getOne(id) {
|
|
124
|
-
return
|
|
210
|
+
return requestWorkSchedule({
|
|
125
211
|
url: `/work-schedules/${id}`,
|
|
126
212
|
method: 'get'
|
|
127
213
|
})
|
|
@@ -134,9 +220,11 @@ export function getOne(id) {
|
|
|
134
220
|
* @param {string|Object} [data.user] - 用户 UUID,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
135
221
|
* @param {Array<string|Object>} [data.users] - 用户 UUID 数组,支持传入 UUID 字符串或包含 id/_id 的对象数组
|
|
136
222
|
* @param {string|Object|null} [data.space] - 空间 UUID,引用外部配置服务空间,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
223
|
+
* @param {string|Object|null} [data.area] - v2 兼容别名,发送时映射为 space
|
|
224
|
+
* @param {string|Object|null} [data.controlRoom] - 消控室 UUID,支持传入 UUID 字符串或包含 id/_id 的对象
|
|
137
225
|
* @param {number} [data.year] - 年份
|
|
138
226
|
* @param {number} [data.month] - 月份,1-12
|
|
139
|
-
* @param {
|
|
227
|
+
* @param {string} [data.shiftType] - 默认班次类型,如:早班、中班、晚班
|
|
140
228
|
* @param {Array<WorkScheduleDetail>|null} [data.scheduleDetails] - 每日排班明细
|
|
141
229
|
* @param {number} [data.status] - 状态,0 草稿,1 已发布
|
|
142
230
|
* @param {string|null} [data.remark] - 备注
|
|
@@ -144,10 +232,10 @@ export function getOne(id) {
|
|
|
144
232
|
* @returns {WorkSchedule} data - 修改后的数据
|
|
145
233
|
*/
|
|
146
234
|
export function updateOne(data) {
|
|
147
|
-
return
|
|
148
|
-
url: `/work-schedules/${data._id}`,
|
|
235
|
+
return requestWorkSchedule({
|
|
236
|
+
url: `/work-schedules/${data._id || data.id}`,
|
|
149
237
|
method: 'put',
|
|
150
|
-
data
|
|
238
|
+
data: mapWorkScheduleRequestFields(data)
|
|
151
239
|
})
|
|
152
240
|
}
|
|
153
241
|
|
|
@@ -158,7 +246,7 @@ export function updateOne(data) {
|
|
|
158
246
|
* @returns {WorkSchedule} data - 删除的数据
|
|
159
247
|
*/
|
|
160
248
|
export function deleteOne(id) {
|
|
161
|
-
return
|
|
249
|
+
return requestWorkSchedule({
|
|
162
250
|
url: `/work-schedules/${id}`,
|
|
163
251
|
method: 'delete'
|
|
164
252
|
})
|
|
@@ -170,7 +258,7 @@ export function deleteOne(id) {
|
|
|
170
258
|
* @returns {number} code - 返回码,0表示成功
|
|
171
259
|
*/
|
|
172
260
|
export function deleteMany(ids) {
|
|
173
|
-
return
|
|
261
|
+
return requestWorkSchedule({
|
|
174
262
|
url: '/work-schedules',
|
|
175
263
|
method: 'delete',
|
|
176
264
|
data: ids
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
jest.mock('../utils', () => ({
|
|
2
|
+
requestShow: jest.fn()
|
|
3
|
+
}))
|
|
4
|
+
|
|
5
|
+
const urlcfg = require('../config/urlcfg').default
|
|
6
|
+
const { requestShow } = require('../utils')
|
|
7
|
+
const workSchedule = require('./workSchedule').default
|
|
8
|
+
|
|
9
|
+
describe('workSchedule api v2 field compatibility', () => {
|
|
10
|
+
const originalVersion = urlcfg.version
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
urlcfg.version = originalVersion
|
|
14
|
+
jest.clearAllMocks()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('keeps legacy area payload in v1', async () => {
|
|
18
|
+
const query = {
|
|
19
|
+
area: 'space-legacy'
|
|
20
|
+
}
|
|
21
|
+
requestShow.mockResolvedValue({ code: 0, rows: [] })
|
|
22
|
+
|
|
23
|
+
await workSchedule.list(query)
|
|
24
|
+
|
|
25
|
+
expect(requestShow).toHaveBeenCalledWith({
|
|
26
|
+
url: '/work-schedules',
|
|
27
|
+
method: 'get',
|
|
28
|
+
params: query
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('maps legacy area request field to space in v2', async () => {
|
|
33
|
+
urlcfg.version = 'v2'
|
|
34
|
+
const data = {
|
|
35
|
+
_id: 'schedule-1',
|
|
36
|
+
area: '22222222-2222-4222-8222-222222222222',
|
|
37
|
+
controlRoom: '77777777-7777-4777-8777-777777777777',
|
|
38
|
+
year: 2026,
|
|
39
|
+
month: 6,
|
|
40
|
+
shiftType: '早班'
|
|
41
|
+
}
|
|
42
|
+
requestShow.mockResolvedValue({ code: 0, data: {} })
|
|
43
|
+
|
|
44
|
+
await workSchedule.updateOne(data)
|
|
45
|
+
|
|
46
|
+
expect(requestShow).toHaveBeenCalledWith({
|
|
47
|
+
url: '/work-schedules/schedule-1',
|
|
48
|
+
method: 'put',
|
|
49
|
+
data: {
|
|
50
|
+
_id: 'schedule-1',
|
|
51
|
+
space: '22222222-2222-4222-8222-222222222222',
|
|
52
|
+
controlRoom: '77777777-7777-4777-8777-777777777777',
|
|
53
|
+
year: 2026,
|
|
54
|
+
month: 6,
|
|
55
|
+
shiftType: '早班'
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('maps legacy area inside query filter to space in v2', async () => {
|
|
61
|
+
urlcfg.version = 'v2'
|
|
62
|
+
requestShow.mockResolvedValue({ code: 0, rows: [] })
|
|
63
|
+
|
|
64
|
+
await workSchedule.list({
|
|
65
|
+
page: 1,
|
|
66
|
+
query: JSON.stringify({
|
|
67
|
+
area: '22222222-2222-4222-8222-222222222222',
|
|
68
|
+
year: 2026
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
expect(requestShow).toHaveBeenCalledWith({
|
|
73
|
+
url: '/work-schedules',
|
|
74
|
+
method: 'get',
|
|
75
|
+
params: {
|
|
76
|
+
page: 1,
|
|
77
|
+
query: JSON.stringify({
|
|
78
|
+
year: 2026,
|
|
79
|
+
space: '22222222-2222-4222-8222-222222222222'
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('maps v2 response space back to legacy area alias', async () => {
|
|
86
|
+
urlcfg.version = 'v2'
|
|
87
|
+
requestShow.mockResolvedValue({
|
|
88
|
+
code: 0,
|
|
89
|
+
rows: [{
|
|
90
|
+
id: 'schedule-1',
|
|
91
|
+
space: '22222222-2222-4222-8222-222222222222',
|
|
92
|
+
controlRoom: '77777777-7777-4777-8777-777777777777'
|
|
93
|
+
}]
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
const response = await workSchedule.list({})
|
|
97
|
+
|
|
98
|
+
expect(response.rows[0]).toEqual(expect.objectContaining({
|
|
99
|
+
space: '22222222-2222-4222-8222-222222222222',
|
|
100
|
+
area: '22222222-2222-4222-8222-222222222222',
|
|
101
|
+
controlRoom: '77777777-7777-4777-8777-777777777777'
|
|
102
|
+
}))
|
|
103
|
+
})
|
|
104
|
+
})
|
package/index.js
CHANGED
|
@@ -42,6 +42,7 @@ import sensorStatusConfig from "./api/sensorStatusConfig";
|
|
|
42
42
|
import attendanceRecord from "./api/attendanceRecord";
|
|
43
43
|
import workSchedule from "./api/workSchedule";
|
|
44
44
|
import fireDrillRecords from "./api/fireDrillRecords";
|
|
45
|
+
import controlRoom from "./api/controlRoom";
|
|
45
46
|
const api = {
|
|
46
47
|
alarmRecord,
|
|
47
48
|
alarmProgress,
|
|
@@ -84,6 +85,7 @@ const api = {
|
|
|
84
85
|
attendanceRecord,
|
|
85
86
|
workSchedule,
|
|
86
87
|
fireDrillRecords,
|
|
88
|
+
controlRoom,
|
|
87
89
|
};
|
|
88
90
|
|
|
89
91
|
export default {
|