widget.qw 1.0.83 → 1.0.84

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 (105) hide show
  1. package/.env.development +10 -10
  2. package/.env.production +8 -8
  3. package/README.md +75 -75
  4. package/build/style.css +471 -471
  5. package/build/widget.qw.es.js +141 -74
  6. package/build/widget.qw.umd.js +141 -74
  7. package/index.html +17 -17
  8. package/package.json +47 -47
  9. package/src/App.vue +26 -26
  10. package/src/api/index.js +165 -165
  11. package/src/components/AuditBar.vue +396 -396
  12. package/src/components/BillCard.vue +164 -164
  13. package/src/components/CascaderPicker.vue +132 -132
  14. package/src/components/CascaderPop.vue +373 -371
  15. package/src/components/CheckGroup.vue +113 -113
  16. package/src/components/DatetimeDropdown.vue +62 -0
  17. package/src/components/{DatetimePicker/index.vue → DatetimePicker.vue} +124 -124
  18. package/src/components/DayDropdown.vue +56 -56
  19. package/src/components/FilePicker.vue +169 -169
  20. package/src/components/Input.vue +80 -80
  21. package/src/components/MonthDropdown.vue +51 -51
  22. package/src/components/MultiPicker.vue +123 -123
  23. package/src/components/ObjsEditor.vue +334 -334
  24. package/src/components/SecretNotify.js +5 -5
  25. package/src/components/Sheet.vue +92 -92
  26. package/src/components/SingleApiPicker.vue +108 -108
  27. package/src/components/SinglePicker.vue +102 -102
  28. package/src/components/SingleUserSelector.vue +425 -425
  29. package/src/components/Switch.vue +64 -64
  30. package/src/components/TreePicker.vue +113 -113
  31. package/src/components/UserPicker.vue +106 -106
  32. package/src/components/UserProfile.vue +129 -129
  33. package/src/components/UsersPicker.vue +118 -118
  34. package/src/components/YearDropdown.vue +59 -59
  35. package/src/components/data_selector.vue +303 -303
  36. package/src/components/image_picker.vue +123 -123
  37. package/src/components/images_picker.vue +195 -195
  38. package/src/components/index.js +167 -162
  39. package/src/components/mult_list_selector.vue +155 -155
  40. package/src/components/subdepartment_selector.vue +481 -481
  41. package/src/components/user_selector.vue +639 -639
  42. package/src/components/widget/DataPop.vue +95 -95
  43. package/src/components/{DatetimePicker → widget}/DatetimePop.vue +342 -342
  44. package/src/components/widget/TreePop.vue +88 -88
  45. package/src/components/widget/UserPop.vue +347 -347
  46. package/src/main.js +117 -117
  47. package/src/router/index.ts +178 -173
  48. package/src/util/array_util.js +32 -32
  49. package/src/util/auth_util.js +72 -72
  50. package/src/util/bool_util.js +5 -5
  51. package/src/util/bus.js +1 -1
  52. package/src/util/cache_util.js +18 -18
  53. package/src/util/errer_code.js +6 -6
  54. package/src/util/eval_util.js +19 -19
  55. package/src/util/icon_util.js +36 -36
  56. package/src/util/image_util.js +27 -27
  57. package/src/util/index.js +57 -57
  58. package/src/util/num_util.js +70 -70
  59. package/src/util/obj_util.js +28 -28
  60. package/src/util/request.js +73 -73
  61. package/src/util/request_json.js +71 -71
  62. package/src/util/request_json_mute.js +65 -65
  63. package/src/util/request_upload.js +79 -79
  64. package/src/util/route_util.js +31 -31
  65. package/src/util/str_util.js +143 -143
  66. package/src/util/time_util.js +406 -406
  67. package/src/util/toast_util.js +24 -24
  68. package/src/util/tree_util.js +153 -153
  69. package/src/util/uuid_util.js +9 -9
  70. package/src/util/validate.js +182 -182
  71. package/src/util/vue_filter.js +223 -223
  72. package/src/views/auditbar/index.vue +78 -78
  73. package/src/views/billcard/index.vue +48 -48
  74. package/src/views/cascaderpicker/index.vue +0 -0
  75. package/src/views/cascaderpop/index.vue +90 -90
  76. package/src/views/checkgroup/index.vue +35 -35
  77. package/src/views/dataSelector/index.vue +48 -48
  78. package/src/views/datetimedropdown/index.vue +34 -0
  79. package/src/views/datetimepicker/index.vue +34 -34
  80. package/src/views/daydropdown/index.vue +31 -31
  81. package/src/views/filepicker/index.vue +32 -32
  82. package/src/views/home/index.vue +0 -0
  83. package/src/views/imagepicker/index.vue +31 -31
  84. package/src/views/imagespicker/index.vue +37 -37
  85. package/src/views/input/index.vue +35 -35
  86. package/src/views/monthdropdown/index.vue +31 -31
  87. package/src/views/multListSelector/index.vue +61 -61
  88. package/src/views/multipicker/index.vue +36 -36
  89. package/src/views/objseditor/index.vue +277 -277
  90. package/src/views/productSelector/index.vue +35 -35
  91. package/src/views/projectpicker/index.vue +41 -41
  92. package/src/views/secretnotify/index.vue +27 -27
  93. package/src/views/sheet/index.vue +45 -45
  94. package/src/views/singlepicker/index.vue +35 -35
  95. package/src/views/subdepartmentSelector/index.vue +40 -40
  96. package/src/views/switch/index.vue +34 -34
  97. package/src/views/treepicker/index.vue +41 -41
  98. package/src/views/userSelector/index.vue +54 -54
  99. package/src/views/userSelectorNew/index.vue +45 -45
  100. package/src/views/userpicker/index.vue +43 -43
  101. package/src/views/userprofile/index.vue +30 -30
  102. package/src/views/userspicker/index.vue +43 -43
  103. package/src/views/yeardropdown/index.vue +32 -32
  104. package/src/vm/index.js +1 -1
  105. package/vite.config.ts +122 -122
@@ -1,425 +1,425 @@
1
- <template>
2
- <van-field v-if="!isGone" :is-link="isReadonly ? false : true" readonly :label="props.label"
3
- :placeholder="props.placeholder" @click="show = !isReadonly" :model-value="selectedUserInfo" :required="isRequired"
4
- :rules="props.rules" input-align="center" />
5
- <van-popup v-model:show="show" round position="bottom" class="user-popup">
6
- <div class="department-selector">
7
- <div class="picker-header">
8
- <div class="header-left">
9
- <van-button @click="goBack" icon="arrow-left" size="small" v-show="currentPath !== '请选择部门'" />
10
- </div>
11
-
12
- <!-- 移除header-center包装,直接使用current-path -->
13
- <div class="current-path">{{ currentPath }}</div>
14
-
15
- <div class="header-right">
16
- <van-button size="small" @click="handleClear" class="cancel-btn">清空</van-button>
17
-
18
- <van-button type="primary" size="small" @click="confirmSelection" class="confirm-btn">确定</van-button>
19
- </div>
20
- </div>
21
-
22
- <!-- 搜索框 -->
23
- <van-search v-model="searchValue" placeholder="输入工号查询" @clear="clearSearch" @search="handleSearch"
24
- @cancel="clearSearch" show-action>
25
- <template #action>
26
- <div @click="handleSearch">搜索</div>
27
- </template>
28
- </van-search>
29
-
30
- <div class="scroll-container">
31
- <!-- 遍历部门列表 -->
32
- <van-cell-group>
33
- <van-cell v-for="department in departments" :key="department.id" :title="department.name" is-link
34
- @click="toggleDepartment(department)" />
35
- </van-cell-group>
36
-
37
- <!-- 遍历人员列表 -->
38
- <van-radio-group v-model="tempSelectedUser">
39
- <van-cell-group>
40
- <van-cell v-for="user in userlist" :key="user.id" :title="user.name">
41
- <template #right-icon>
42
- <van-radio :name="user.userid" />
43
- </template>
44
- </van-cell>
45
- </van-cell-group>
46
- </van-radio-group>
47
- </div>
48
- </div>
49
- </van-popup>
50
- </template>
51
- <script setup>
52
- import { ref, onMounted, watch } from "vue";
53
- import util from "../util"
54
- import { useVModel } from '@vueuse/core'
55
-
56
- // 弹出层
57
- const show = ref(false);
58
-
59
- const props = defineProps({
60
- modelValue: {
61
- type: String,
62
- default: "",
63
- },
64
- label: {
65
- type: String,
66
- default: "选择人员",
67
- },
68
- placeholder: {
69
- type: String,
70
- default: "请选择人员",
71
- },
72
- required: {
73
- type: Boolean,
74
- default: false,
75
- },
76
- readonly: {
77
- type: Boolean,
78
- default: false,
79
- },
80
- rules: {
81
- type: Array,
82
- default: () => [],
83
- },
84
- // 默认查询所有组织机构
85
- currentDeptId: {
86
- type: String,
87
- default: "1", //组织机构id
88
- },
89
- // 二级部门取值范围字典id
90
- // 取dictionary库.dict的配置id
91
- deptRangeId: {
92
- type: String,
93
- default: ''
94
- },
95
- auth: {
96
- type: String,
97
- default: "",
98
- },
99
- });
100
- // 定义emit
101
- const emit = defineEmits(["update:modelValue", "select"]);
102
- const modelValue = useVModel(props, 'modelValue', emit)
103
- const { isRequired, isReadonly, isGone, isDisabled } = util.props2auth(props);
104
-
105
- // 部门列表
106
- let departments = ref([]);
107
- let departmentFulls = ref([])
108
- const searchValue = ref("");
109
- const currentPath = ref("请选择部门");
110
- // 定义用户
111
- const userlist = ref([]);
112
- // 定义选择单选按钮的值
113
- const tempSelectedUser = ref(null);
114
- // 定义展示表单展示区的值
115
- const selectedUserInfo = ref([]);
116
-
117
- // 获得部门列表
118
- const fetchAllDepartments = async () => {
119
- // 查询所有部门
120
- const response = await util.get_subdepartments({ departmentId: props.currentDeptId })
121
- let level2Depts = response.data.subDepartments
122
-
123
- // 取配置的二级部门取值范围
124
- let level2DeptIds = []
125
- if (props.deptRangeId) {
126
- let res = await util.dictionary_dict({ id: props.deptRangeId })
127
- if (res.data.parseValue && res.data.parseValue.length>0) {
128
- level2DeptIds = res.data.parseValue
129
- }
130
-
131
- // 当前用户所在二级部门列表
132
- const user = await getUserInfoById(props.modelValue)
133
- if (user && user.department.id) {
134
- level2DeptIds = [...level2DeptIds, user.department.id]
135
- }
136
- }
137
-
138
- // 只保留指定二级部门列表、当前用户的二级部门
139
- if (props.deptRangeId) {
140
- if (level2DeptIds && level2DeptIds.length > 0) {
141
- level2Depts = level2Depts.filter(item => {
142
- return level2DeptIds.includes(item.id)
143
- })
144
- }
145
- }
146
-
147
- //departments
148
- departments.value = getCurrentDepartments(level2Depts || [])
149
- departmentFulls.value = departments.value;
150
- };
151
-
152
- //嵌套处理获得树形结构
153
- const getCurrentDepartments = (data) => {
154
- let result = data.map((item) => {
155
- return {
156
- id: item.id,
157
- name: item.name,
158
- subDepartments: getCurrentDepartments(item.subDepartments || []),
159
- };
160
- });
161
- return result;
162
- };
163
- // 添加部门路径查找方法
164
- function findDeptPath(deptId, tree, path = []) {
165
- for (const dept of tree) {
166
- if (dept.id === deptId) {
167
- return [...path, dept];
168
- }
169
- if (dept.subDepartments?.length) {
170
- const found = findDeptPath(deptId, dept.subDepartments, [...path, dept]);
171
- if (found && found.length>0) return found;
172
- }
173
- }
174
- return [];
175
- }
176
-
177
- // 获得人员列表
178
- const fetchAllUsers = async (departmentId) => {
179
- const response = await util.get_subdepartments_users({ departmentId });
180
- return response.data.users || [];
181
- };
182
-
183
- // 通过id获得人员信息
184
- const getUserInfoById = async (userId) => {
185
- const response = await util.get_wxuser_by_id({ userId });
186
- return response.data;
187
- };
188
-
189
- // 清空搜索
190
- const clearSearch = () => {
191
- searchValue.value = ""; // 清空搜索框
192
- // 部门列表赋初始值
193
- departments.value = departmentFulls.value;
194
- };
195
-
196
- // 搜索人员
197
- const handleSearch = () => {
198
- // 在这里可以处理搜索逻辑
199
- if (searchValue.value) {
200
- departments.value = []; // 清空部门列表
201
- // 搜索用户
202
- getUserInfoById(searchValue.value).then((user) => {
203
- if (user) {
204
- userlist.value = [user];
205
- //更新currentPath显示用户部门
206
- const path = findDeptPath(user.mainDepartment, departmentFulls.value);
207
- console.log("path", path);
208
- currentPath.value = "";
209
- path.forEach((dept) => {
210
- currentPath.value += dept.name + "/";
211
- });
212
- } else {
213
- userlist.value = []; // 清空人员列表
214
- }
215
- });
216
- }
217
- };
218
-
219
- // 切换部门
220
- const toggleDepartment = (department) => {
221
- console.log("选择了部门:", department.subDepartments);
222
- departments.value = department.subDepartments;
223
- // 在这里可以处理部门选择逻辑
224
- console.log("选择的部门:", departments);
225
- // 更新当前路径
226
- if (currentPath.value === "请选择部门") {
227
- currentPath.value = "";
228
- }
229
- currentPath.value += department.name + "/";
230
- // 请求加载人员
231
- fetchAllUsers(department.id).then((users) => {
232
- // 在这里可以处理人员列表逻辑
233
- userlist.value = users;
234
- })
235
- };
236
-
237
- // 返回上一级部门
238
- const goBack = () => {
239
- searchValue.value = ""; // 清空搜索框
240
- if (currentPath.value === "请选择部门") return;
241
- currentPath.value = currentPath.value.replace(/\/+$/, "");
242
- currentPath.value = currentPath.value.substring(
243
- 0,
244
- currentPath.value.lastIndexOf("/")
245
- );
246
-
247
- if (currentPath.value !== "") {
248
- // 加载当前路径的部门列表
249
- const departmentlist = departmentFulls.value.find(
250
- (dept) => dept.name === currentPath.value.split("/")[0]
251
- );
252
- departments.value = departmentlist.subDepartments;
253
- // 加载当前路径的人员列表
254
- fetchAllUsers(departmentlist.id).then((users) => {
255
- userlist.value = users;
256
- });
257
- } else {
258
- currentPath.value = "请选择部门";
259
- departments.value = departmentFulls.value;
260
- }
261
- };
262
-
263
- // 确认按钮
264
- const confirmSelection = () => {
265
- modelValue.value = tempSelectedUser.value
266
- //对应的人员信息
267
- const selectedUser = userlist.value.find(
268
- (user) => user.userid === tempSelectedUser.value
269
- );
270
-
271
- selectedUserInfo.value = selectedUser.name;
272
-
273
- emit('select', selectedUser)
274
-
275
- show.value = false;
276
- };
277
- // 清空按钮
278
- const handleClear = () => {
279
- tempSelectedUser.value = null;
280
- selectedUserInfo.value = null;
281
- // 清空人员列表
282
- userlist.value = [];
283
- show.value = false;
284
- currentPath.value = "请选择部门";
285
- departments.value = departmentFulls.value;
286
- modelValue.value = tempSelectedUser.value
287
- };
288
-
289
- //首页加载
290
- onMounted(async () => {
291
- await fetchAllDepartments();
292
- await initDepartment();
293
- });
294
-
295
- // 人员初始化
296
- const initUser = async () => {
297
- console.log('initUser', props.modelValue, departmentFulls.value)
298
- if (!props.modelValue || !departmentFulls.value || departmentFulls.value.length < 1)
299
- return
300
-
301
- const user = await getUserInfoById(props.modelValue);
302
- if (user) {
303
- //更新currentPath显示用户部门
304
- const path = findDeptPath(user.mainDepartment, departmentFulls.value);
305
- currentPath.value = "";
306
- path.forEach((dept) => {
307
- currentPath.value += dept.name + "/";
308
- });
309
- // 清空部门列表
310
- departments.value = []; // 清空部门列表
311
- // 加载当前路径的人员列表
312
- fetchAllUsers(user.mainDepartment).then((users) => {
313
- userlist.value = users;
314
- // 选中当前用户
315
- tempSelectedUser.value = user.userid;
316
- selectedUserInfo.value = user.name;
317
- });
318
- } else {
319
- userlist.value = []; // 清空人员列表
320
- }
321
- };
322
- // 部门初始化
323
- const initDepartment = async () => {
324
- //更新currentPath显示用户部门
325
- const path = findDeptPath(props.currentDeptId, departmentFulls.value);
326
- currentPath.value = "";
327
- path.forEach((dept) => {
328
- currentPath.value += dept.name + "/";
329
- });
330
- // 更新部门列表
331
- departments.value = departmentFulls.value; // 重置部门列表
332
- };
333
-
334
- //监听searchValue变化
335
- watch(searchValue, (newValue, oldValue) => {
336
- if (newValue.length === 0) {
337
- // 重新加载部门列表
338
- departments.value = departmentFulls.value;
339
- // 清空人员列表
340
- userlist.value = [];
341
- }
342
- });
343
- watch(() => modelValue.value, (n, o) => {
344
- initUser()
345
- }, {
346
- immediate: true
347
- })
348
- watch(() => departmentFulls.value, (n, o) => {
349
- initUser()
350
- }, {
351
- immediate: true
352
- })
353
- </script>
354
-
355
- <style scoped>
356
- .user-popup {
357
- width: 100%;
358
- overflow: hidden;
359
- }
360
-
361
- .department-selector {
362
- padding: 10px;
363
- }
364
-
365
- .search-buttons {
366
- display: flex;
367
- gap: 10px;
368
- }
369
-
370
- .clear-btn {
371
- background-color: #f2f3f5;
372
- border: none;
373
- border-radius: 4px;
374
- padding: 4px 8px;
375
- font-size: 14px;
376
- }
377
-
378
- .confirm-btn {
379
- background-color: #1989fa;
380
- color: white;
381
- border: none;
382
- border-radius: 4px;
383
- padding: 4px 8px;
384
- font-size: 14px;
385
- }
386
-
387
- .no-results {
388
- text-align: center;
389
- padding: 20px;
390
- color: #969799;
391
- }
392
-
393
- .picker-header {
394
- padding: 10px;
395
- border-bottom: 1px solid #ebedf0;
396
- display: flex;
397
- justify-content: space-between;
398
- align-items: center;
399
- }
400
-
401
- .current-path {
402
- flex: 1;
403
- font-size: 14px;
404
- color: #323233;
405
- white-space: nowrap;
406
- overflow: hidden;
407
- text-overflow: ellipsis;
408
- }
409
-
410
- .header-right {
411
- display: flex;
412
- gap: 8px;
413
- margin-left: auto;
414
- }
415
-
416
- .cancel-btn {
417
- color: #969799;
418
- margin-right: 5px;
419
- }
420
-
421
- .scroll-container {
422
- height: calc(80vh - 150px);
423
- overflow-y: auto;
424
- }
425
- </style>
1
+ <template>
2
+ <van-field v-if="!isGone" :is-link="isReadonly ? false : true" readonly :label="props.label"
3
+ :placeholder="props.placeholder" @click="show = !isReadonly" :model-value="selectedUserInfo" :required="isRequired"
4
+ :rules="props.rules" input-align="center" />
5
+ <van-popup v-model:show="show" round position="bottom" class="user-popup">
6
+ <div class="department-selector">
7
+ <div class="picker-header">
8
+ <div class="header-left">
9
+ <van-button @click="goBack" icon="arrow-left" size="small" v-show="currentPath !== '请选择部门'" />
10
+ </div>
11
+
12
+ <!-- 移除header-center包装,直接使用current-path -->
13
+ <div class="current-path">{{ currentPath }}</div>
14
+
15
+ <div class="header-right">
16
+ <van-button size="small" @click="handleClear" class="cancel-btn">清空</van-button>
17
+
18
+ <van-button type="primary" size="small" @click="confirmSelection" class="confirm-btn">确定</van-button>
19
+ </div>
20
+ </div>
21
+
22
+ <!-- 搜索框 -->
23
+ <van-search v-model="searchValue" placeholder="输入工号查询" @clear="clearSearch" @search="handleSearch"
24
+ @cancel="clearSearch" show-action>
25
+ <template #action>
26
+ <div @click="handleSearch">搜索</div>
27
+ </template>
28
+ </van-search>
29
+
30
+ <div class="scroll-container">
31
+ <!-- 遍历部门列表 -->
32
+ <van-cell-group>
33
+ <van-cell v-for="department in departments" :key="department.id" :title="department.name" is-link
34
+ @click="toggleDepartment(department)" />
35
+ </van-cell-group>
36
+
37
+ <!-- 遍历人员列表 -->
38
+ <van-radio-group v-model="tempSelectedUser">
39
+ <van-cell-group>
40
+ <van-cell v-for="user in userlist" :key="user.id" :title="user.name">
41
+ <template #right-icon>
42
+ <van-radio :name="user.userid" />
43
+ </template>
44
+ </van-cell>
45
+ </van-cell-group>
46
+ </van-radio-group>
47
+ </div>
48
+ </div>
49
+ </van-popup>
50
+ </template>
51
+ <script setup>
52
+ import { ref, onMounted, watch } from "vue";
53
+ import util from "../util"
54
+ import { useVModel } from '@vueuse/core'
55
+
56
+ // 弹出层
57
+ const show = ref(false);
58
+
59
+ const props = defineProps({
60
+ modelValue: {
61
+ type: String,
62
+ default: "",
63
+ },
64
+ label: {
65
+ type: String,
66
+ default: "选择人员",
67
+ },
68
+ placeholder: {
69
+ type: String,
70
+ default: "请选择人员",
71
+ },
72
+ required: {
73
+ type: Boolean,
74
+ default: false,
75
+ },
76
+ readonly: {
77
+ type: Boolean,
78
+ default: false,
79
+ },
80
+ rules: {
81
+ type: Array,
82
+ default: () => [],
83
+ },
84
+ // 默认查询所有组织机构
85
+ currentDeptId: {
86
+ type: String,
87
+ default: "1", //组织机构id
88
+ },
89
+ // 二级部门取值范围字典id
90
+ // 取dictionary库.dict的配置id
91
+ deptRangeId: {
92
+ type: String,
93
+ default: ''
94
+ },
95
+ auth: {
96
+ type: String,
97
+ default: "",
98
+ },
99
+ });
100
+ // 定义emit
101
+ const emit = defineEmits(["update:modelValue", "select"]);
102
+ const modelValue = useVModel(props, 'modelValue', emit)
103
+ const { isRequired, isReadonly, isGone, isDisabled } = util.props2auth(props);
104
+
105
+ // 部门列表
106
+ let departments = ref([]);
107
+ let departmentFulls = ref([])
108
+ const searchValue = ref("");
109
+ const currentPath = ref("请选择部门");
110
+ // 定义用户
111
+ const userlist = ref([]);
112
+ // 定义选择单选按钮的值
113
+ const tempSelectedUser = ref(null);
114
+ // 定义展示表单展示区的值
115
+ const selectedUserInfo = ref([]);
116
+
117
+ // 获得部门列表
118
+ const fetchAllDepartments = async () => {
119
+ // 查询所有部门
120
+ const response = await util.get_subdepartments({ departmentId: props.currentDeptId })
121
+ let level2Depts = response.data.subDepartments
122
+
123
+ // 取配置的二级部门取值范围
124
+ let level2DeptIds = []
125
+ if (props.deptRangeId) {
126
+ let res = await util.dictionary_dict({ id: props.deptRangeId })
127
+ if (res.data.parseValue && res.data.parseValue.length>0) {
128
+ level2DeptIds = res.data.parseValue
129
+ }
130
+
131
+ // 当前用户所在二级部门列表
132
+ const user = await getUserInfoById(props.modelValue)
133
+ if (user && user.department.id) {
134
+ level2DeptIds = [...level2DeptIds, user.department.id]
135
+ }
136
+ }
137
+
138
+ // 只保留指定二级部门列表、当前用户的二级部门
139
+ if (props.deptRangeId) {
140
+ if (level2DeptIds && level2DeptIds.length > 0) {
141
+ level2Depts = level2Depts.filter(item => {
142
+ return level2DeptIds.includes(item.id)
143
+ })
144
+ }
145
+ }
146
+
147
+ //departments
148
+ departments.value = getCurrentDepartments(level2Depts || [])
149
+ departmentFulls.value = departments.value;
150
+ };
151
+
152
+ //嵌套处理获得树形结构
153
+ const getCurrentDepartments = (data) => {
154
+ let result = data.map((item) => {
155
+ return {
156
+ id: item.id,
157
+ name: item.name,
158
+ subDepartments: getCurrentDepartments(item.subDepartments || []),
159
+ };
160
+ });
161
+ return result;
162
+ };
163
+ // 添加部门路径查找方法
164
+ function findDeptPath(deptId, tree, path = []) {
165
+ for (const dept of tree) {
166
+ if (dept.id === deptId) {
167
+ return [...path, dept];
168
+ }
169
+ if (dept.subDepartments?.length) {
170
+ const found = findDeptPath(deptId, dept.subDepartments, [...path, dept]);
171
+ if (found && found.length>0) return found;
172
+ }
173
+ }
174
+ return [];
175
+ }
176
+
177
+ // 获得人员列表
178
+ const fetchAllUsers = async (departmentId) => {
179
+ const response = await util.get_subdepartments_users({ departmentId });
180
+ return response.data.users || [];
181
+ };
182
+
183
+ // 通过id获得人员信息
184
+ const getUserInfoById = async (userId) => {
185
+ const response = await util.get_wxuser_by_id({ userId });
186
+ return response.data;
187
+ };
188
+
189
+ // 清空搜索
190
+ const clearSearch = () => {
191
+ searchValue.value = ""; // 清空搜索框
192
+ // 部门列表赋初始值
193
+ departments.value = departmentFulls.value;
194
+ };
195
+
196
+ // 搜索人员
197
+ const handleSearch = () => {
198
+ // 在这里可以处理搜索逻辑
199
+ if (searchValue.value) {
200
+ departments.value = []; // 清空部门列表
201
+ // 搜索用户
202
+ getUserInfoById(searchValue.value).then((user) => {
203
+ if (user) {
204
+ userlist.value = [user];
205
+ //更新currentPath显示用户部门
206
+ const path = findDeptPath(user.mainDepartment, departmentFulls.value);
207
+ console.log("path", path);
208
+ currentPath.value = "";
209
+ path.forEach((dept) => {
210
+ currentPath.value += dept.name + "/";
211
+ });
212
+ } else {
213
+ userlist.value = []; // 清空人员列表
214
+ }
215
+ });
216
+ }
217
+ };
218
+
219
+ // 切换部门
220
+ const toggleDepartment = (department) => {
221
+ console.log("选择了部门:", department.subDepartments);
222
+ departments.value = department.subDepartments;
223
+ // 在这里可以处理部门选择逻辑
224
+ console.log("选择的部门:", departments);
225
+ // 更新当前路径
226
+ if (currentPath.value === "请选择部门") {
227
+ currentPath.value = "";
228
+ }
229
+ currentPath.value += department.name + "/";
230
+ // 请求加载人员
231
+ fetchAllUsers(department.id).then((users) => {
232
+ // 在这里可以处理人员列表逻辑
233
+ userlist.value = users;
234
+ })
235
+ };
236
+
237
+ // 返回上一级部门
238
+ const goBack = () => {
239
+ searchValue.value = ""; // 清空搜索框
240
+ if (currentPath.value === "请选择部门") return;
241
+ currentPath.value = currentPath.value.replace(/\/+$/, "");
242
+ currentPath.value = currentPath.value.substring(
243
+ 0,
244
+ currentPath.value.lastIndexOf("/")
245
+ );
246
+
247
+ if (currentPath.value !== "") {
248
+ // 加载当前路径的部门列表
249
+ const departmentlist = departmentFulls.value.find(
250
+ (dept) => dept.name === currentPath.value.split("/")[0]
251
+ );
252
+ departments.value = departmentlist.subDepartments;
253
+ // 加载当前路径的人员列表
254
+ fetchAllUsers(departmentlist.id).then((users) => {
255
+ userlist.value = users;
256
+ });
257
+ } else {
258
+ currentPath.value = "请选择部门";
259
+ departments.value = departmentFulls.value;
260
+ }
261
+ };
262
+
263
+ // 确认按钮
264
+ const confirmSelection = () => {
265
+ modelValue.value = tempSelectedUser.value
266
+ //对应的人员信息
267
+ const selectedUser = userlist.value.find(
268
+ (user) => user.userid === tempSelectedUser.value
269
+ );
270
+
271
+ selectedUserInfo.value = selectedUser.name;
272
+
273
+ emit('select', selectedUser)
274
+
275
+ show.value = false;
276
+ };
277
+ // 清空按钮
278
+ const handleClear = () => {
279
+ tempSelectedUser.value = null;
280
+ selectedUserInfo.value = null;
281
+ // 清空人员列表
282
+ userlist.value = [];
283
+ show.value = false;
284
+ currentPath.value = "请选择部门";
285
+ departments.value = departmentFulls.value;
286
+ modelValue.value = tempSelectedUser.value
287
+ };
288
+
289
+ //首页加载
290
+ onMounted(async () => {
291
+ await fetchAllDepartments();
292
+ await initDepartment();
293
+ });
294
+
295
+ // 人员初始化
296
+ const initUser = async () => {
297
+ console.log('initUser', props.modelValue, departmentFulls.value)
298
+ if (!props.modelValue || !departmentFulls.value || departmentFulls.value.length < 1)
299
+ return
300
+
301
+ const user = await getUserInfoById(props.modelValue);
302
+ if (user) {
303
+ //更新currentPath显示用户部门
304
+ const path = findDeptPath(user.mainDepartment, departmentFulls.value);
305
+ currentPath.value = "";
306
+ path.forEach((dept) => {
307
+ currentPath.value += dept.name + "/";
308
+ });
309
+ // 清空部门列表
310
+ departments.value = []; // 清空部门列表
311
+ // 加载当前路径的人员列表
312
+ fetchAllUsers(user.mainDepartment).then((users) => {
313
+ userlist.value = users;
314
+ // 选中当前用户
315
+ tempSelectedUser.value = user.userid;
316
+ selectedUserInfo.value = user.name;
317
+ });
318
+ } else {
319
+ userlist.value = []; // 清空人员列表
320
+ }
321
+ };
322
+ // 部门初始化
323
+ const initDepartment = async () => {
324
+ //更新currentPath显示用户部门
325
+ const path = findDeptPath(props.currentDeptId, departmentFulls.value);
326
+ currentPath.value = "";
327
+ path.forEach((dept) => {
328
+ currentPath.value += dept.name + "/";
329
+ });
330
+ // 更新部门列表
331
+ departments.value = departmentFulls.value; // 重置部门列表
332
+ };
333
+
334
+ //监听searchValue变化
335
+ watch(searchValue, (newValue, oldValue) => {
336
+ if (newValue.length === 0) {
337
+ // 重新加载部门列表
338
+ departments.value = departmentFulls.value;
339
+ // 清空人员列表
340
+ userlist.value = [];
341
+ }
342
+ });
343
+ watch(() => modelValue.value, (n, o) => {
344
+ initUser()
345
+ }, {
346
+ immediate: true
347
+ })
348
+ watch(() => departmentFulls.value, (n, o) => {
349
+ initUser()
350
+ }, {
351
+ immediate: true
352
+ })
353
+ </script>
354
+
355
+ <style scoped>
356
+ .user-popup {
357
+ width: 100%;
358
+ overflow: hidden;
359
+ }
360
+
361
+ .department-selector {
362
+ padding: 10px;
363
+ }
364
+
365
+ .search-buttons {
366
+ display: flex;
367
+ gap: 10px;
368
+ }
369
+
370
+ .clear-btn {
371
+ background-color: #f2f3f5;
372
+ border: none;
373
+ border-radius: 4px;
374
+ padding: 4px 8px;
375
+ font-size: 14px;
376
+ }
377
+
378
+ .confirm-btn {
379
+ background-color: #1989fa;
380
+ color: white;
381
+ border: none;
382
+ border-radius: 4px;
383
+ padding: 4px 8px;
384
+ font-size: 14px;
385
+ }
386
+
387
+ .no-results {
388
+ text-align: center;
389
+ padding: 20px;
390
+ color: #969799;
391
+ }
392
+
393
+ .picker-header {
394
+ padding: 10px;
395
+ border-bottom: 1px solid #ebedf0;
396
+ display: flex;
397
+ justify-content: space-between;
398
+ align-items: center;
399
+ }
400
+
401
+ .current-path {
402
+ flex: 1;
403
+ font-size: 14px;
404
+ color: #323233;
405
+ white-space: nowrap;
406
+ overflow: hidden;
407
+ text-overflow: ellipsis;
408
+ }
409
+
410
+ .header-right {
411
+ display: flex;
412
+ gap: 8px;
413
+ margin-left: auto;
414
+ }
415
+
416
+ .cancel-btn {
417
+ color: #969799;
418
+ margin-right: 5px;
419
+ }
420
+
421
+ .scroll-container {
422
+ height: calc(80vh - 150px);
423
+ overflow-y: auto;
424
+ }
425
+ </style>