@ebiz/designer-components 0.1.12 → 0.1.13
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/dist/designer-components.css +1 -1
- package/dist/index.mjs +11057 -11011
- package/package.json +1 -1
- package/src/components/EbizApproval.vue +74 -17
- package/src/components/EbizEmployeeSelector.vue +310 -336
- package/src/components/EbizSApprovalProcess.vue +2 -0
- package/src/views/EbizApprovalDemo.vue +11 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="ebiz-employee-selector">
|
|
3
3
|
<!-- 选择框展示区 -->
|
|
4
|
-
<div v-if="showDefault" style="display: flex; flex-direction: column; align-items: flex-start; gap: 10px
|
|
4
|
+
<div v-if="showDefault" style="display: flex; flex-direction: column; align-items: flex-start; gap: 10px">
|
|
5
5
|
<div class="selected-items" v-if="selectedItems && selectedItems.length">
|
|
6
6
|
<div v-for="(item, index) in selectedItems" :key="index" class="selected-item">
|
|
7
7
|
<t-avatar v-if="item.avatar" :image="item.avatar" size="small" />
|
|
@@ -17,9 +17,16 @@
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
19
|
<!-- 选择弹窗 -->
|
|
20
|
-
<t-dialog
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
<t-dialog
|
|
21
|
+
v-model:visible="dialogVisible"
|
|
22
|
+
:header="props.content"
|
|
23
|
+
:width="800"
|
|
24
|
+
footer
|
|
25
|
+
:close-btn="true"
|
|
26
|
+
:close-on-esc-keydown="true"
|
|
27
|
+
:close-on-overlay-click="true"
|
|
28
|
+
destroyOnClose
|
|
29
|
+
>
|
|
23
30
|
<!-- 选项卡 -->
|
|
24
31
|
<t-tabs v-model="activeTab" class="selector-tabs">
|
|
25
32
|
<t-tab-panel value="organization" label="组织架构" :destroyOnHide="false"></t-tab-panel>
|
|
@@ -29,9 +36,7 @@
|
|
|
29
36
|
<!-- <t-tab-panel value="subordinate" label="我的下属" :destroyOnHide="false"></t-tab-panel> -->
|
|
30
37
|
</t-tabs>
|
|
31
38
|
|
|
32
|
-
|
|
33
39
|
<div>
|
|
34
|
-
|
|
35
40
|
<div class="selector-dialog-content">
|
|
36
41
|
<!-- 左侧选择区域 -->
|
|
37
42
|
<div class="left-panel">
|
|
@@ -42,21 +47,43 @@
|
|
|
42
47
|
</div>
|
|
43
48
|
<!-- 组织架构 -->
|
|
44
49
|
<div v-show="activeTab === 'organization'" class="tab-content">
|
|
45
|
-
<t-tree
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
<t-tree
|
|
51
|
+
ref="organizationTree"
|
|
52
|
+
:data="organizationData"
|
|
53
|
+
expandAll
|
|
54
|
+
:keys="{ label: 'name', value: 'id', children: 'children' }"
|
|
55
|
+
hover
|
|
56
|
+
activable
|
|
57
|
+
:active="currentActive"
|
|
58
|
+
@click="handleActive"
|
|
59
|
+
/>
|
|
48
60
|
</div>
|
|
49
61
|
|
|
50
62
|
<!-- 角色 -->
|
|
51
63
|
<div v-show="activeTab === 'role'" class="tab-content">
|
|
52
|
-
<t-tree
|
|
53
|
-
|
|
64
|
+
<t-tree
|
|
65
|
+
ref="roleTree"
|
|
66
|
+
:data="roleData"
|
|
67
|
+
expandAll
|
|
68
|
+
:keys="{ label: 'name', value: 'code' }"
|
|
69
|
+
hover
|
|
70
|
+
activable
|
|
71
|
+
:active="currentActive"
|
|
72
|
+
@click="handleActive"
|
|
73
|
+
/>
|
|
54
74
|
</div>
|
|
55
75
|
|
|
56
76
|
<!-- 岗位 -->
|
|
57
77
|
<div v-show="activeTab === 'position'" class="tab-content">
|
|
58
|
-
<t-tree
|
|
59
|
-
|
|
78
|
+
<t-tree
|
|
79
|
+
ref="positionTree"
|
|
80
|
+
:data="positionData"
|
|
81
|
+
:keys="{ label: 'name', value: 'id' }"
|
|
82
|
+
hover
|
|
83
|
+
activable
|
|
84
|
+
:active="currentActive"
|
|
85
|
+
@click="handleActive"
|
|
86
|
+
/>
|
|
60
87
|
</div>
|
|
61
88
|
|
|
62
89
|
<!-- 同部门 -->
|
|
@@ -100,24 +127,35 @@
|
|
|
100
127
|
|
|
101
128
|
<!-- 搜索框 -->
|
|
102
129
|
<div class="search-box">
|
|
103
|
-
<t-input
|
|
130
|
+
<t-input
|
|
131
|
+
v-model="searchText"
|
|
132
|
+
placeholder="请输入姓名/拼音/工号搜索"
|
|
133
|
+
clearable
|
|
134
|
+
@keyup.enter="handleSearch"
|
|
135
|
+
>
|
|
104
136
|
<template #suffix-icon>
|
|
105
|
-
<t-icon name="search" @click="
|
|
137
|
+
<t-icon name="search" @click="handleSearch"></t-icon>
|
|
106
138
|
</template>
|
|
107
139
|
</t-input>
|
|
108
|
-
<t-button v-if="searchText" size="small" theme="default" class="clear-search-btn"
|
|
109
|
-
|
|
140
|
+
<t-button v-if="searchText" size="small" theme="default" class="clear-search-btn" @click="clearSearch"
|
|
141
|
+
>清除搜索</t-button
|
|
142
|
+
>
|
|
110
143
|
</div>
|
|
111
144
|
|
|
112
145
|
<div class="employee-list">
|
|
113
|
-
<div
|
|
114
|
-
|
|
146
|
+
<div
|
|
147
|
+
v-for="(item, index) in filteredEmployeeList"
|
|
148
|
+
:key="index"
|
|
149
|
+
class="employee-item"
|
|
150
|
+
@click="handleCheckChange(item)"
|
|
151
|
+
>
|
|
152
|
+
<t-checkbox v-model="item.checked" style="pointer-events: none"></t-checkbox>
|
|
115
153
|
<div class="employee-avatar">
|
|
116
154
|
<t-avatar v-if="item.avatar" :image="item.avatar" size="small" />
|
|
117
155
|
<t-avatar v-else size="small">{{ getAvatarText(item.name) }}</t-avatar>
|
|
118
156
|
</div>
|
|
119
157
|
<div class="employee-info">
|
|
120
|
-
<div class="employee-code">{{ item.no }}
|
|
158
|
+
<div class="employee-code">{{ item.no }} -</div>
|
|
121
159
|
<div class="employee-name">{{ item.name }}</div>
|
|
122
160
|
</div>
|
|
123
161
|
</div>
|
|
@@ -129,7 +167,6 @@
|
|
|
129
167
|
</div>
|
|
130
168
|
</div>
|
|
131
169
|
|
|
132
|
-
|
|
133
170
|
<!-- 底部按钮区域 -->
|
|
134
171
|
<template #footer>
|
|
135
172
|
<div class="dialog-footer">
|
|
@@ -158,7 +195,7 @@
|
|
|
158
195
|
</template>
|
|
159
196
|
|
|
160
197
|
<script setup>
|
|
161
|
-
import { ref, computed, watch, onMounted } from 'vue'
|
|
198
|
+
import { ref, computed, watch, onMounted } from 'vue'
|
|
162
199
|
import {
|
|
163
200
|
Dialog as TDialog,
|
|
164
201
|
Button as TButton,
|
|
@@ -174,8 +211,8 @@ import {
|
|
|
174
211
|
List as TList,
|
|
175
212
|
ListItem as TListItem,
|
|
176
213
|
MessagePlugin
|
|
177
|
-
} from 'tdesign-vue-next'
|
|
178
|
-
import dataService from '../apiService/simpleDataService'
|
|
214
|
+
} from 'tdesign-vue-next'
|
|
215
|
+
import dataService from '../apiService/simpleDataService'
|
|
179
216
|
|
|
180
217
|
// 定义组件属性
|
|
181
218
|
const props = defineProps({
|
|
@@ -226,16 +263,16 @@ const props = defineProps({
|
|
|
226
263
|
type: String,
|
|
227
264
|
default: '选择人员'
|
|
228
265
|
}
|
|
229
|
-
})
|
|
266
|
+
})
|
|
230
267
|
|
|
231
268
|
// 定义组件事件
|
|
232
|
-
const emit = defineEmits(['update:modelValue', 'change', 'update:visible', 'confirm'])
|
|
233
|
-
const tempVisible = ref(false)
|
|
269
|
+
const emit = defineEmits(['update:modelValue', 'change', 'update:visible', 'confirm'])
|
|
270
|
+
const tempVisible = ref(false)
|
|
234
271
|
// 内部状态变量
|
|
235
272
|
const dialogVisible = computed({
|
|
236
273
|
set(val) {
|
|
237
274
|
if (props.visible == null) {
|
|
238
|
-
tempVisible.value = val
|
|
275
|
+
tempVisible.value = val
|
|
239
276
|
return
|
|
240
277
|
}
|
|
241
278
|
emit('update:visible', val)
|
|
@@ -243,79 +280,75 @@ const dialogVisible = computed({
|
|
|
243
280
|
get() {
|
|
244
281
|
return props.visible ?? tempVisible.value
|
|
245
282
|
}
|
|
246
|
-
})
|
|
283
|
+
})
|
|
247
284
|
|
|
248
|
-
const searchText = ref('')
|
|
249
|
-
const activeTab = ref(props.defaultTab)
|
|
250
|
-
const loading = ref(false)
|
|
251
|
-
const selectedItems = ref([])
|
|
285
|
+
const searchText = ref('')
|
|
286
|
+
const activeTab = ref(props.defaultTab)
|
|
287
|
+
const loading = ref(false)
|
|
288
|
+
const selectedItems = ref([])
|
|
252
289
|
// 对话框中临时保存的选中员工列表
|
|
253
|
-
const tempSelectedEmployees =
|
|
290
|
+
const tempSelectedEmployees = computed(() => employeeList.value.filter((i) => i.checked))
|
|
254
291
|
// 是否查询子部门
|
|
255
|
-
const childDeptEnable = ref(false)
|
|
292
|
+
const childDeptEnable = ref(false)
|
|
256
293
|
|
|
257
294
|
// 数据源
|
|
258
|
-
const organizationData = ref([])
|
|
259
|
-
const roleData = ref([])
|
|
260
|
-
const positionData = ref([])
|
|
261
|
-
const departmentData = ref([])
|
|
262
|
-
const subordinateData = ref([])
|
|
263
|
-
const employeeList = ref([])
|
|
264
|
-
const currentActive = ref([])
|
|
265
|
-
const currentNodeName = ref('')
|
|
266
|
-
const selectAll =
|
|
295
|
+
const organizationData = ref([])
|
|
296
|
+
const roleData = ref([])
|
|
297
|
+
const positionData = ref([])
|
|
298
|
+
const departmentData = ref([])
|
|
299
|
+
const subordinateData = ref([])
|
|
300
|
+
const employeeList = ref([])
|
|
301
|
+
const currentActive = ref([])
|
|
302
|
+
const currentNodeName = ref('')
|
|
303
|
+
const selectAll = computed(() => employeeList.value > 0 && employeeList.value.every((i) => i.checked))
|
|
267
304
|
|
|
268
305
|
// 从名称中获取头像显示文本
|
|
269
306
|
const getAvatarText = (name) => {
|
|
270
|
-
return name ? name.substring(0, 1) : ''
|
|
271
|
-
}
|
|
307
|
+
return name ? name.substring(0, 1) : ''
|
|
308
|
+
}
|
|
272
309
|
|
|
273
310
|
// 处理组织数据,转换为树形结构
|
|
274
311
|
const _processOrgData = (data) => {
|
|
275
312
|
// 转换数据结构为树形结构
|
|
276
|
-
const map = {}
|
|
277
|
-
const result = []
|
|
313
|
+
const map = {}
|
|
314
|
+
const result = []
|
|
278
315
|
|
|
279
|
-
data.forEach(item => {
|
|
316
|
+
data.forEach((item) => {
|
|
280
317
|
map[item.id] = {
|
|
281
318
|
...item,
|
|
282
319
|
name: item.name,
|
|
283
320
|
id: item.id,
|
|
284
321
|
children: []
|
|
285
|
-
}
|
|
286
|
-
})
|
|
322
|
+
}
|
|
323
|
+
})
|
|
287
324
|
|
|
288
|
-
data.forEach(item => {
|
|
289
|
-
const node = map[item.id]
|
|
325
|
+
data.forEach((item) => {
|
|
326
|
+
const node = map[item.id]
|
|
290
327
|
|
|
291
328
|
if (item.manager_dept && map[item.manager_dept]) {
|
|
292
|
-
map[item.manager_dept].children.push(node)
|
|
329
|
+
map[item.manager_dept].children.push(node)
|
|
293
330
|
} else {
|
|
294
331
|
// 只有在显示根组织或不存在父节点时才添加到结果中
|
|
295
332
|
if (props.showRootOrg || !item.manager_dept) {
|
|
296
|
-
result.push(node)
|
|
333
|
+
result.push(node)
|
|
297
334
|
}
|
|
298
335
|
}
|
|
299
|
-
})
|
|
336
|
+
})
|
|
300
337
|
|
|
301
|
-
return result
|
|
302
|
-
}
|
|
338
|
+
return result
|
|
339
|
+
}
|
|
303
340
|
|
|
304
341
|
// 更新全选状态
|
|
305
|
-
const updateSelectAllStatus = () => {
|
|
306
|
-
selectAll.value = employeeList.value.length > 0 && employeeList.value.every(item => item.checked);
|
|
307
|
-
};
|
|
308
|
-
|
|
309
342
|
const updateSelectStatus = () => {
|
|
310
|
-
employeeList.value.forEach(item => {
|
|
311
|
-
item.checked = props.modelValue.includes(item.id)
|
|
343
|
+
employeeList.value.forEach((item) => {
|
|
344
|
+
item.checked = props.modelValue.includes(item.id)
|
|
312
345
|
})
|
|
313
346
|
}
|
|
314
347
|
|
|
315
348
|
// 选中的员工列表
|
|
316
349
|
const selectedEmployees = computed(() => {
|
|
317
|
-
return employeeList.value.filter((item) => item.checked)
|
|
318
|
-
})
|
|
350
|
+
return employeeList.value.filter((item) => item.checked)
|
|
351
|
+
})
|
|
319
352
|
|
|
320
353
|
// 根据搜索文本过滤的员工列表
|
|
321
354
|
const filteredEmployeeList = computed(() => {
|
|
@@ -333,84 +366,68 @@ const filteredEmployeeList = computed(() => {
|
|
|
333
366
|
// (item.code && item.code.toLowerCase().includes(keyword))
|
|
334
367
|
// );
|
|
335
368
|
// });
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
const allData = ref([])
|
|
339
|
-
|
|
340
|
-
const fetchAllData = async () => {
|
|
341
|
-
const response = await dataService.fetch({}, {}, '/process/deptList');
|
|
342
|
-
employeeList.value = response ?? [];
|
|
343
|
-
}
|
|
344
|
-
fetchAllData()
|
|
369
|
+
})
|
|
345
370
|
|
|
346
371
|
// 获取组织架构数据
|
|
347
372
|
const fetchOrganizationData = async () => {
|
|
348
|
-
loading.value = true
|
|
373
|
+
loading.value = true
|
|
349
374
|
try {
|
|
350
375
|
const response = await dataService.fetch(
|
|
351
376
|
{},
|
|
352
377
|
{
|
|
353
378
|
apiId: 1933,
|
|
354
379
|
key: 'organizationalStructure'
|
|
355
|
-
},
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
380
|
+
},
|
|
381
|
+
'/process/deptList'
|
|
382
|
+
)
|
|
383
|
+
organizationData.value = response
|
|
384
|
+
// handleActive(response[0].id, 'organization')
|
|
359
385
|
// organizationData.value = processOrgData(response.data || []);
|
|
360
386
|
} catch (error) {
|
|
361
387
|
MessagePlugin.error({
|
|
362
388
|
content: '获取组织架构数据失败',
|
|
363
389
|
duration: 3000
|
|
364
|
-
})
|
|
390
|
+
})
|
|
365
391
|
} finally {
|
|
366
|
-
loading.value = false
|
|
392
|
+
loading.value = false
|
|
367
393
|
}
|
|
368
|
-
}
|
|
394
|
+
}
|
|
369
395
|
|
|
370
396
|
// 获取角色数据
|
|
371
397
|
const fetchRoleData = async () => {
|
|
372
|
-
loading.value = true
|
|
398
|
+
loading.value = true
|
|
373
399
|
try {
|
|
374
|
-
const response = await dataService.fetch(
|
|
375
|
-
|
|
376
|
-
{},
|
|
377
|
-
'/process/roleList'
|
|
378
|
-
);
|
|
379
|
-
roleData.value = response || [];
|
|
400
|
+
const response = await dataService.fetch({}, {}, '/process/roleList')
|
|
401
|
+
roleData.value = response || []
|
|
380
402
|
} catch (error) {
|
|
381
403
|
MessagePlugin.error({
|
|
382
404
|
content: '获取角色数据失败',
|
|
383
405
|
duration: 3000
|
|
384
|
-
})
|
|
406
|
+
})
|
|
385
407
|
} finally {
|
|
386
|
-
loading.value = false
|
|
408
|
+
loading.value = false
|
|
387
409
|
}
|
|
388
|
-
}
|
|
410
|
+
}
|
|
389
411
|
|
|
390
412
|
// 获取岗位数据
|
|
391
413
|
const fetchPositionData = async () => {
|
|
392
|
-
loading.value = true
|
|
414
|
+
loading.value = true
|
|
393
415
|
try {
|
|
394
|
-
const response = await dataService.fetch(
|
|
395
|
-
|
|
396
|
-
{
|
|
397
|
-
},
|
|
398
|
-
'/process/roleList'
|
|
399
|
-
);
|
|
400
|
-
positionData.value = response?.data || [];
|
|
416
|
+
const response = await dataService.fetch({}, {}, '/process/roleList')
|
|
417
|
+
positionData.value = response?.data || []
|
|
401
418
|
} catch (error) {
|
|
402
419
|
MessagePlugin.error({
|
|
403
420
|
content: '获取岗位数据失败',
|
|
404
421
|
duration: 3000
|
|
405
|
-
})
|
|
422
|
+
})
|
|
406
423
|
} finally {
|
|
407
|
-
loading.value = false
|
|
424
|
+
loading.value = false
|
|
408
425
|
}
|
|
409
|
-
}
|
|
426
|
+
}
|
|
410
427
|
|
|
411
428
|
// 获取部门数据
|
|
412
429
|
const fetchDepartmentData = async () => {
|
|
413
|
-
loading.value = true
|
|
430
|
+
loading.value = true
|
|
414
431
|
try {
|
|
415
432
|
const response = await dataService.fetch(
|
|
416
433
|
{},
|
|
@@ -419,21 +436,21 @@ const fetchDepartmentData = async () => {
|
|
|
419
436
|
key: 'departmentList',
|
|
420
437
|
apiType: 'MULTIPLE_DATA_SEARCH'
|
|
421
438
|
}
|
|
422
|
-
)
|
|
423
|
-
departmentData.value = response?.data || []
|
|
439
|
+
)
|
|
440
|
+
departmentData.value = response?.data || []
|
|
424
441
|
} catch (error) {
|
|
425
442
|
MessagePlugin.error({
|
|
426
443
|
content: '获取部门数据失败',
|
|
427
444
|
duration: 3000
|
|
428
|
-
})
|
|
445
|
+
})
|
|
429
446
|
} finally {
|
|
430
|
-
loading.value = false
|
|
447
|
+
loading.value = false
|
|
431
448
|
}
|
|
432
|
-
}
|
|
449
|
+
}
|
|
433
450
|
|
|
434
451
|
// 获取下属数据
|
|
435
452
|
const fetchSubordinateData = async () => {
|
|
436
|
-
loading.value = true
|
|
453
|
+
loading.value = true
|
|
437
454
|
try {
|
|
438
455
|
const response = await dataService.fetch(
|
|
439
456
|
{},
|
|
@@ -441,390 +458,347 @@ const fetchSubordinateData = async () => {
|
|
|
441
458
|
apiKey: 'subordinateList',
|
|
442
459
|
apiType: 'MULTIPLE_DATA_SEARCH'
|
|
443
460
|
}
|
|
444
|
-
)
|
|
445
|
-
subordinateData.value = response?.data || []
|
|
461
|
+
)
|
|
462
|
+
subordinateData.value = response?.data || []
|
|
446
463
|
} catch (error) {
|
|
447
464
|
MessagePlugin.error({
|
|
448
465
|
content: '获取下属数据失败',
|
|
449
466
|
duration: 3000
|
|
450
|
-
})
|
|
467
|
+
})
|
|
451
468
|
} finally {
|
|
452
|
-
loading.value = false
|
|
469
|
+
loading.value = false
|
|
453
470
|
}
|
|
454
|
-
}
|
|
471
|
+
}
|
|
455
472
|
|
|
456
473
|
// 根据节点ID获取员工列表
|
|
457
|
-
const fetchEmployeesByNode = async (nodeId,
|
|
458
|
-
loading.value = true
|
|
474
|
+
const fetchEmployeesByNode = async (nodeId, keyword = searchText.value) => {
|
|
475
|
+
loading.value = true
|
|
459
476
|
try {
|
|
460
|
-
const params = {}
|
|
477
|
+
const params = {}
|
|
461
478
|
|
|
462
479
|
// 只有当nodeId不为空且type有效时,添加对应参数
|
|
463
|
-
if (nodeId &&
|
|
480
|
+
if (nodeId && activeTab.value) {
|
|
464
481
|
// 根据不同类型设置不同的查询参数
|
|
465
|
-
switch (
|
|
482
|
+
switch (activeTab.value) {
|
|
466
483
|
case 'organization':
|
|
467
|
-
params.deptId = Array.isArray(nodeId) ? nodeId[0] : nodeId
|
|
484
|
+
params.deptId = Array.isArray(nodeId) ? nodeId[0] : nodeId
|
|
468
485
|
// 添加子部门查询参数
|
|
469
|
-
params.childDeptEnable = childDeptEnable.value
|
|
470
|
-
break
|
|
486
|
+
params.childDeptEnable = childDeptEnable.value
|
|
487
|
+
break
|
|
471
488
|
case 'role':
|
|
472
|
-
params.roleKeyWork = nodeId[0]
|
|
473
|
-
break
|
|
489
|
+
params.roleKeyWork = nodeId[0]
|
|
490
|
+
break
|
|
474
491
|
case 'position':
|
|
475
|
-
params.positionId = nodeId
|
|
476
|
-
break
|
|
492
|
+
params.positionId = nodeId
|
|
493
|
+
break
|
|
477
494
|
case 'department':
|
|
478
|
-
params.departmentId = nodeId
|
|
479
|
-
break
|
|
495
|
+
params.departmentId = nodeId
|
|
496
|
+
break
|
|
480
497
|
case 'subordinate':
|
|
481
|
-
params.managerId = nodeId
|
|
482
|
-
break
|
|
498
|
+
params.managerId = nodeId
|
|
499
|
+
break
|
|
483
500
|
}
|
|
484
501
|
}
|
|
485
502
|
|
|
486
503
|
// 如果有搜索关键词,添加到查询参数中
|
|
487
504
|
if (keyword) {
|
|
488
|
-
params.keyWord = keyword
|
|
505
|
+
params.keyWord = keyword
|
|
489
506
|
}
|
|
490
507
|
|
|
491
|
-
const response = await dataService.fetch(
|
|
492
|
-
params,
|
|
493
|
-
{},
|
|
494
|
-
'/process/userList'
|
|
495
|
-
);
|
|
508
|
+
const response = await dataService.fetch(params, {}, '/process/userList')
|
|
496
509
|
// 获取当前已选择的员工ID列表
|
|
497
|
-
const selectedIds = [...new Set(tempSelectedEmployees.value.map(emp => emp.id))]
|
|
510
|
+
const selectedIds = [...new Set(tempSelectedEmployees.value.map((emp) => emp.id))]
|
|
498
511
|
|
|
499
512
|
// 处理返回数据,添加checked属性,保留已选状态
|
|
500
|
-
const employees = (response || []).map(emp => ({
|
|
513
|
+
const employees = (response || []).map((emp) => ({
|
|
501
514
|
...emp,
|
|
502
515
|
checked: selectedIds.includes(emp.id)
|
|
503
|
-
}))
|
|
516
|
+
}))
|
|
504
517
|
|
|
505
|
-
employeeList.value = employees
|
|
506
|
-
updateSelectAllStatus();
|
|
518
|
+
employeeList.value = employees
|
|
507
519
|
} catch (error) {
|
|
508
520
|
MessagePlugin.error({
|
|
509
521
|
content: '获取员工列表失败',
|
|
510
522
|
duration: 3000
|
|
511
|
-
})
|
|
523
|
+
})
|
|
512
524
|
} finally {
|
|
513
|
-
loading.value = false
|
|
525
|
+
loading.value = false
|
|
514
526
|
}
|
|
515
|
-
}
|
|
527
|
+
}
|
|
516
528
|
|
|
517
529
|
// 根据ID列表批量获取员工信息
|
|
518
|
-
const fetchEmployeesByIds =
|
|
530
|
+
const fetchEmployeesByIds = (ids) => {
|
|
519
531
|
if (!ids || ids.length === 0) {
|
|
520
|
-
selectedItems.value = []
|
|
521
|
-
return
|
|
532
|
+
selectedItems.value = []
|
|
533
|
+
return
|
|
522
534
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const response = await dataService.fetch(
|
|
535
|
+
loading.value = true
|
|
536
|
+
dataService
|
|
537
|
+
.fetch(
|
|
527
538
|
{
|
|
528
539
|
userIds: ids // 使用新的接口参数格式
|
|
529
540
|
},
|
|
530
541
|
{},
|
|
531
542
|
'/process/userList' // 直接使用新的API路径
|
|
532
|
-
)
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
selectedItems.value = []
|
|
538
|
-
MessagePlugin.
|
|
539
|
-
content: '
|
|
543
|
+
)
|
|
544
|
+
.then((res) => {
|
|
545
|
+
selectedItems.value = res ?? []
|
|
546
|
+
})
|
|
547
|
+
.catch((error) => {
|
|
548
|
+
selectedItems.value = []
|
|
549
|
+
MessagePlugin.error({
|
|
550
|
+
content: '获取员工详情失败: ' + (error.message || '未知错误'),
|
|
540
551
|
duration: 3000
|
|
541
|
-
})
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
duration: 3000
|
|
548
|
-
});
|
|
549
|
-
} finally {
|
|
550
|
-
loading.value = false;
|
|
551
|
-
}
|
|
552
|
-
};
|
|
552
|
+
})
|
|
553
|
+
})
|
|
554
|
+
.finally(() => {
|
|
555
|
+
loading.value = false
|
|
556
|
+
})
|
|
557
|
+
}
|
|
553
558
|
|
|
554
559
|
// 处理节点激活
|
|
555
|
-
const handleActive = (
|
|
556
|
-
currentActive.value =
|
|
557
|
-
currentNodeName.value =
|
|
558
|
-
|
|
560
|
+
const handleActive = ({ node }) => {
|
|
561
|
+
currentActive.value = node?.value
|
|
562
|
+
currentNodeName.value = node?.label || ''
|
|
559
563
|
// 获取该节点下的员工
|
|
560
|
-
fetchEmployeesByNode(
|
|
561
|
-
}
|
|
564
|
+
fetchEmployeesByNode(node.value)
|
|
565
|
+
}
|
|
562
566
|
|
|
563
567
|
// 选择部门
|
|
564
568
|
const selectDepartment = (department) => {
|
|
565
|
-
currentNodeName.value = department.name
|
|
566
|
-
fetchEmployeesByNode(department.id
|
|
567
|
-
}
|
|
569
|
+
currentNodeName.value = department.name
|
|
570
|
+
fetchEmployeesByNode(department.id)
|
|
571
|
+
}
|
|
568
572
|
|
|
569
573
|
// 处理全选
|
|
570
574
|
const handleSelectAll = (checked) => {
|
|
571
|
-
employeeList.value.forEach(item => {
|
|
572
|
-
item.checked = checked
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
if (checked && !tempSelectedEmployees.value.some(emp => emp.id === item.id)) {
|
|
576
|
-
tempSelectedEmployees.value.push(item);
|
|
577
|
-
}
|
|
578
|
-
});
|
|
579
|
-
};
|
|
575
|
+
employeeList.value.forEach((item) => {
|
|
576
|
+
item.checked = checked
|
|
577
|
+
})
|
|
578
|
+
}
|
|
580
579
|
|
|
581
580
|
// 处理选中状态变更
|
|
582
581
|
const handleCheckChange = (item) => {
|
|
583
582
|
// 单选模式下,取消其他选中
|
|
584
583
|
if (props.single) {
|
|
585
|
-
employeeList.value.forEach(emp => {
|
|
584
|
+
employeeList.value.forEach((emp) => {
|
|
586
585
|
if (emp.id !== item.id) {
|
|
587
|
-
emp.checked = false
|
|
586
|
+
emp.checked = false
|
|
588
587
|
}
|
|
589
|
-
})
|
|
590
|
-
|
|
591
|
-
tempSelectedEmployees.value = item.checked ? [item] : [];
|
|
588
|
+
})
|
|
589
|
+
item.checked = true
|
|
592
590
|
} else {
|
|
593
591
|
// 多选模式
|
|
594
592
|
// 如果选中,添加到临时选中列表
|
|
595
|
-
|
|
596
|
-
tempSelectedEmployees.value.push(item);
|
|
597
|
-
} else if (!item.checked) {
|
|
598
|
-
// 如果取消选中,从临时选中列表中移除
|
|
599
|
-
const index = tempSelectedEmployees.value.findIndex(emp => emp.id === item.id);
|
|
600
|
-
if (index !== -1) {
|
|
601
|
-
tempSelectedEmployees.value.splice(index, 1);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
593
|
+
item.checked = !item.checked
|
|
604
594
|
}
|
|
605
595
|
|
|
606
596
|
// 检查最大选择数量限制
|
|
607
597
|
if (props.maxCount > 0) {
|
|
608
|
-
const checkedCount = tempSelectedEmployees.value.length
|
|
598
|
+
const checkedCount = tempSelectedEmployees.value.length
|
|
609
599
|
if (checkedCount > props.maxCount) {
|
|
610
|
-
item.checked = false
|
|
611
|
-
const index = tempSelectedEmployees.value.findIndex(emp => emp.id === item.id);
|
|
612
|
-
if (index !== -1) {
|
|
613
|
-
tempSelectedEmployees.value.splice(index, 1);
|
|
614
|
-
}
|
|
600
|
+
item.checked = false
|
|
615
601
|
MessagePlugin.warning({
|
|
616
602
|
content: `最多只能选择${props.maxCount}个人员`,
|
|
617
603
|
duration: 3000
|
|
618
|
-
})
|
|
604
|
+
})
|
|
619
605
|
}
|
|
620
606
|
}
|
|
621
|
-
|
|
622
|
-
updateSelectAllStatus();
|
|
623
|
-
};
|
|
607
|
+
}
|
|
624
608
|
|
|
625
609
|
// 移除已选择的项目
|
|
626
610
|
const removeItem = (index, id) => {
|
|
627
611
|
// 移除ID
|
|
628
|
-
const newIds = [...props.modelValue]
|
|
629
|
-
const idIndex = newIds.indexOf(id)
|
|
612
|
+
const newIds = [...props.modelValue]
|
|
613
|
+
const idIndex = newIds.indexOf(id)
|
|
630
614
|
if (idIndex !== -1) {
|
|
631
|
-
newIds.splice(idIndex, 1)
|
|
632
|
-
emit('update:modelValue', newIds)
|
|
633
|
-
emit('change', newIds)
|
|
615
|
+
newIds.splice(idIndex, 1)
|
|
616
|
+
emit('update:modelValue', newIds)
|
|
617
|
+
emit('change', newIds)
|
|
634
618
|
}
|
|
635
619
|
|
|
636
620
|
// 移除展示项
|
|
637
|
-
selectedItems.value.splice(index, 1)
|
|
638
|
-
}
|
|
621
|
+
selectedItems.value.splice(index, 1)
|
|
622
|
+
}
|
|
639
623
|
|
|
640
624
|
// 从已选列表中移除员工
|
|
641
625
|
const removeSelectedEmployee = (employee) => {
|
|
642
626
|
// 将员工的checked状态设为false
|
|
643
|
-
const foundEmployee = employeeList.value.find(item => item.id === employee.id)
|
|
627
|
+
const foundEmployee = employeeList.value.find((item) => item.id === employee.id)
|
|
644
628
|
if (foundEmployee) {
|
|
645
|
-
foundEmployee.checked = false
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// 从临时选中列表中移除
|
|
649
|
-
const index = tempSelectedEmployees.value.findIndex(emp => emp.id === employee.id);
|
|
650
|
-
if (index !== -1) {
|
|
651
|
-
tempSelectedEmployees.value.splice(index, 1);
|
|
629
|
+
foundEmployee.checked = false
|
|
652
630
|
}
|
|
653
|
-
|
|
654
|
-
// 更新全选状态
|
|
655
|
-
updateSelectAllStatus();
|
|
656
|
-
};
|
|
631
|
+
}
|
|
657
632
|
|
|
658
633
|
// 初始化选择器
|
|
659
634
|
const initSelector = async () => {
|
|
660
635
|
// 获取数据
|
|
661
636
|
if (activeTab.value === 'organization' && organizationData.value.length === 0) {
|
|
662
|
-
await fetchOrganizationData()
|
|
637
|
+
await fetchOrganizationData()
|
|
663
638
|
} else if (activeTab.value === 'role' && roleData.value.length === 0) {
|
|
664
|
-
await fetchRoleData()
|
|
639
|
+
await fetchRoleData()
|
|
665
640
|
} else if (activeTab.value === 'position' && positionData.value.length === 0) {
|
|
666
|
-
await fetchPositionData()
|
|
641
|
+
await fetchPositionData()
|
|
667
642
|
} else if (activeTab.value === 'department' && departmentData.value.length === 0) {
|
|
668
|
-
await fetchDepartmentData()
|
|
643
|
+
await fetchDepartmentData()
|
|
669
644
|
} else if (activeTab.value === 'subordinate' && subordinateData.value.length === 0) {
|
|
670
|
-
await fetchSubordinateData()
|
|
645
|
+
await fetchSubordinateData()
|
|
671
646
|
}
|
|
672
|
-
}
|
|
647
|
+
}
|
|
673
648
|
|
|
674
649
|
// 显示对话框
|
|
675
650
|
const showDialog = () => {
|
|
676
651
|
// 初始化临时选中列表
|
|
677
652
|
if (selectedItems.value.length > 0) {
|
|
678
|
-
tempSelectedEmployees.value = [...selectedItems.value]
|
|
653
|
+
tempSelectedEmployees.value = [...selectedItems.value]
|
|
679
654
|
updateSelectStatus()
|
|
680
655
|
} else {
|
|
681
|
-
tempSelectedEmployees.value = []
|
|
656
|
+
tempSelectedEmployees.value = []
|
|
682
657
|
}
|
|
683
658
|
|
|
684
659
|
// 初始化数据
|
|
685
660
|
if (props.visible == null) {
|
|
686
|
-
initSelector()
|
|
661
|
+
initSelector()
|
|
687
662
|
}
|
|
688
|
-
dialogVisible.value = true
|
|
689
|
-
}
|
|
663
|
+
dialogVisible.value = true
|
|
664
|
+
}
|
|
690
665
|
|
|
691
666
|
// 确认选择
|
|
692
667
|
const handleConfirm = () => {
|
|
693
|
-
const selectedEmployeeIds = tempSelectedEmployees.value.map(item => item.id)
|
|
668
|
+
const selectedEmployeeIds = tempSelectedEmployees.value.map((item) => item.id)
|
|
694
669
|
|
|
695
|
-
emit('update:modelValue', selectedEmployeeIds)
|
|
696
|
-
emit('change', selectedEmployeeIds)
|
|
697
|
-
emit('confirm', selectedEmployeeIds)
|
|
698
|
-
dialogVisible.value = false
|
|
699
|
-
}
|
|
670
|
+
emit('update:modelValue', selectedEmployeeIds)
|
|
671
|
+
emit('change', selectedEmployeeIds)
|
|
672
|
+
emit('confirm', selectedEmployeeIds)
|
|
673
|
+
dialogVisible.value = false
|
|
674
|
+
}
|
|
700
675
|
|
|
701
676
|
// 取消选择
|
|
702
677
|
const handleCancel = () => {
|
|
703
678
|
// 放弃临时选择
|
|
704
|
-
tempSelectedEmployees.value = []
|
|
705
|
-
dialogVisible.value = false
|
|
706
|
-
}
|
|
679
|
+
tempSelectedEmployees.value = []
|
|
680
|
+
dialogVisible.value = false
|
|
681
|
+
}
|
|
707
682
|
|
|
708
683
|
// 监听标签页切换
|
|
709
684
|
watch(activeTab, () => {
|
|
710
685
|
// 切换标签页时重新加载数据
|
|
711
|
-
initSelector()
|
|
712
|
-
})
|
|
686
|
+
initSelector()
|
|
687
|
+
})
|
|
713
688
|
|
|
714
689
|
// 监听modelValue变化,更新展示的员工信息
|
|
715
|
-
watch(
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
watch(() => props.visible, (val) => {
|
|
726
|
-
tempSelectedEmployees.value = [];
|
|
727
|
-
currentActive.value = [];
|
|
728
|
-
currentNodeName.value = '';
|
|
729
|
-
|
|
730
|
-
if (val) {
|
|
731
|
-
fetchOrganizationData()
|
|
732
|
-
}
|
|
733
|
-
}, { immediate: true })
|
|
734
|
-
// 监听选中员工变化,更新临时已选列表
|
|
735
|
-
watch(selectedEmployees, (newVal) => {
|
|
736
|
-
// 更新临时选中列表,保留之前不在当前列表中的已选员工
|
|
737
|
-
const currentIds = new Set(newVal.map(emp => emp.id));
|
|
738
|
-
|
|
739
|
-
// 移除tempSelectedEmployees中已经不再选中的员工
|
|
740
|
-
tempSelectedEmployees.value = tempSelectedEmployees.value.filter(emp =>
|
|
741
|
-
!currentIds.has(emp.id) || newVal.some(item => item.id === emp.id)
|
|
742
|
-
);
|
|
743
|
-
|
|
744
|
-
// 添加新选中的员工
|
|
745
|
-
newVal.forEach(emp => {
|
|
746
|
-
if (!tempSelectedEmployees.value.some(item => item.id === emp.id)) {
|
|
747
|
-
tempSelectedEmployees.value.push(emp);
|
|
690
|
+
watch(
|
|
691
|
+
() => props.modelValue,
|
|
692
|
+
(newIds, oldIds) => {
|
|
693
|
+
// 判断值是否真的变化了 (通过比较JSON字符串)
|
|
694
|
+
const newIdsStr = JSON.stringify(newIds || [])
|
|
695
|
+
const oldIdsStr = JSON.stringify(oldIds || [])
|
|
696
|
+
|
|
697
|
+
if (newIdsStr !== oldIdsStr) {
|
|
698
|
+
// 获取员工详情数据
|
|
699
|
+
fetchEmployeesByIds(newIds)
|
|
748
700
|
}
|
|
749
|
-
}
|
|
750
|
-
|
|
701
|
+
},
|
|
702
|
+
{ immediate: true, deep: true }
|
|
703
|
+
)
|
|
704
|
+
watch(
|
|
705
|
+
() => props.visible,
|
|
706
|
+
(val) => {
|
|
707
|
+
tempSelectedEmployees.value = []
|
|
708
|
+
currentActive.value = []
|
|
709
|
+
currentNodeName.value = ''
|
|
710
|
+
|
|
711
|
+
if (val) {
|
|
712
|
+
fetchOrganizationData()
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
{ immediate: true }
|
|
716
|
+
)
|
|
717
|
+
// 监听选中员工变化,更新临时已选列表
|
|
718
|
+
watch(
|
|
719
|
+
selectedEmployees,
|
|
720
|
+
(newVal) => {
|
|
721
|
+
// 更新临时选中列表,保留之前不在当前列表中的已选员工
|
|
722
|
+
const currentIds = new Set(newVal.map((emp) => emp.id))
|
|
723
|
+
|
|
724
|
+
// 移除tempSelectedEmployees中已经不再选中的员工
|
|
725
|
+
tempSelectedEmployees.value = tempSelectedEmployees.value.filter(
|
|
726
|
+
(emp) => !currentIds.has(emp.id) || newVal.some((item) => item.id === emp.id)
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
// 添加新选中的员工
|
|
730
|
+
newVal.forEach((emp) => {
|
|
731
|
+
if (!tempSelectedEmployees.value.some((item) => item.id === emp.id)) {
|
|
732
|
+
tempSelectedEmployees.value.push(emp)
|
|
733
|
+
}
|
|
734
|
+
})
|
|
735
|
+
},
|
|
736
|
+
{ deep: true }
|
|
737
|
+
)
|
|
751
738
|
|
|
752
739
|
// 监听子部门查询开关变化
|
|
753
740
|
watch(childDeptEnable, () => {
|
|
754
741
|
// 如果当前在组织架构页面且有选中节点,重新加载员工列表
|
|
755
742
|
if (activeTab.value === 'organization' && currentActive.value && currentActive.value.length > 0) {
|
|
756
|
-
fetchEmployeesByNode(currentActive.value[0]
|
|
743
|
+
fetchEmployeesByNode(currentActive.value[0])
|
|
757
744
|
}
|
|
758
|
-
})
|
|
745
|
+
})
|
|
759
746
|
|
|
760
747
|
// 防抖函数
|
|
761
748
|
const debounce = (fn, delay) => {
|
|
762
|
-
let timer = null
|
|
749
|
+
let timer = null
|
|
763
750
|
return function (...args) {
|
|
764
|
-
if (timer) clearTimeout(timer)
|
|
751
|
+
if (timer) clearTimeout(timer)
|
|
765
752
|
timer = setTimeout(() => {
|
|
766
|
-
fn.apply(this, args)
|
|
767
|
-
}, delay)
|
|
768
|
-
}
|
|
769
|
-
}
|
|
753
|
+
fn.apply(this, args)
|
|
754
|
+
}, delay)
|
|
755
|
+
}
|
|
756
|
+
}
|
|
770
757
|
|
|
771
758
|
// 防抖处理过的搜索函数
|
|
772
759
|
const debouncedSearch = debounce((keyword) => {
|
|
773
760
|
if (keyword) {
|
|
774
|
-
const nodeId = currentActive.value && currentActive.value.length > 0 ? currentActive.value[0] : null
|
|
775
|
-
|
|
776
|
-
fetchEmployeesByNode(nodeId, type, keyword);
|
|
761
|
+
const nodeId = currentActive.value && currentActive.value.length > 0 ? currentActive.value[0] : null
|
|
762
|
+
fetchEmployeesByNode(nodeId, keyword)
|
|
777
763
|
} else if (currentActive.value && currentActive.value.length > 0) {
|
|
778
764
|
// 如果搜索框清空,恢复显示当前选中节点的员工列表
|
|
779
|
-
fetchEmployeesByNode(currentActive.value[0]
|
|
765
|
+
fetchEmployeesByNode(currentActive.value[0])
|
|
780
766
|
} else {
|
|
781
767
|
// 如果没有选中节点,清空员工列表
|
|
782
|
-
employeeList.value = []
|
|
768
|
+
employeeList.value = []
|
|
783
769
|
}
|
|
784
|
-
}, 300)
|
|
770
|
+
}, 300) // 300ms防抖
|
|
785
771
|
|
|
786
772
|
// 监听搜索文本变化,触发搜索
|
|
787
|
-
watch(
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
fetchEmployeesByIds(props.modelValue);
|
|
795
|
-
});
|
|
773
|
+
watch(
|
|
774
|
+
searchText,
|
|
775
|
+
(newValue) => {
|
|
776
|
+
debouncedSearch(newValue)
|
|
777
|
+
},
|
|
778
|
+
{ immediate: false }
|
|
779
|
+
)
|
|
796
780
|
|
|
797
781
|
// 处理搜索图标点击
|
|
798
|
-
const
|
|
782
|
+
const handleSearch = () => {
|
|
799
783
|
if (searchText.value) {
|
|
800
|
-
const nodeId = currentActive.value && currentActive.value.length > 0 ? currentActive.value[0] : null
|
|
801
|
-
|
|
802
|
-
fetchEmployeesByNode(nodeId, type, searchText.value);
|
|
784
|
+
const nodeId = currentActive.value && currentActive.value.length > 0 ? currentActive.value[0] : null
|
|
785
|
+
fetchEmployeesByNode(nodeId, searchText.value)
|
|
803
786
|
}
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
// 处理回车键搜索
|
|
807
|
-
const handleSearchEnter = () => {
|
|
808
|
-
if (searchText.value) {
|
|
809
|
-
const nodeId = currentActive.value && currentActive.value.length > 0 ? currentActive.value[0] : null;
|
|
810
|
-
const type = nodeId ? activeTab.value : null;
|
|
811
|
-
fetchEmployeesByNode(nodeId, type, searchText.value);
|
|
812
|
-
}
|
|
813
|
-
};
|
|
787
|
+
}
|
|
814
788
|
|
|
815
789
|
// 清除搜索
|
|
816
790
|
const clearSearch = () => {
|
|
817
|
-
searchText.value = ''
|
|
791
|
+
searchText.value = ''
|
|
818
792
|
if (currentActive.value && currentActive.value.length > 0) {
|
|
819
|
-
fetchEmployeesByNode(currentActive.value[0]
|
|
793
|
+
fetchEmployeesByNode(currentActive.value[0])
|
|
820
794
|
} else {
|
|
821
795
|
// 如果没有选中节点,重置员工列表但保留选中状态
|
|
822
|
-
employeeList.value = employeeList.value.map(emp => ({
|
|
796
|
+
employeeList.value = employeeList.value.map((emp) => ({
|
|
823
797
|
...emp,
|
|
824
|
-
checked: tempSelectedEmployees.value.some(item => item.id === emp.id)
|
|
825
|
-
}))
|
|
798
|
+
checked: tempSelectedEmployees.value.some((item) => item.id === emp.id)
|
|
799
|
+
}))
|
|
826
800
|
}
|
|
827
|
-
}
|
|
801
|
+
}
|
|
828
802
|
</script>
|
|
829
803
|
|
|
830
804
|
<style scoped>
|
|
@@ -884,7 +858,7 @@ const clearSearch = () => {
|
|
|
884
858
|
}
|
|
885
859
|
|
|
886
860
|
.item-remove:hover {
|
|
887
|
-
color: #
|
|
861
|
+
color: #e34d59;
|
|
888
862
|
}
|
|
889
863
|
|
|
890
864
|
/* 选择弹窗 */
|
|
@@ -1096,6 +1070,6 @@ const clearSearch = () => {
|
|
|
1096
1070
|
}
|
|
1097
1071
|
|
|
1098
1072
|
.selected-people-item .item-remove:hover {
|
|
1099
|
-
color: #
|
|
1073
|
+
color: #e34d59;
|
|
1100
1074
|
}
|
|
1101
1075
|
</style>
|