el-plus-crud 0.0.39 → 0.0.41

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 (73) hide show
  1. package/.eslintrc.js +78 -78
  2. package/.prettierrc.js +39 -39
  3. package/CHANGELOG.md +5 -1
  4. package/build.js +31 -31
  5. package/dist/el-plus-crud.mjs +1803 -1801
  6. package/dist/el-plus-crud.umd.js +7 -7
  7. package/dist/style.css +1 -1
  8. package/example/App.vue +67 -67
  9. package/example/main.js +18 -18
  10. package/index.html +13 -13
  11. package/lib/components/el-plus-form/ElPlusForm.vue +771 -774
  12. package/lib/components/el-plus-form/ElPlusFormDialog.vue +90 -90
  13. package/lib/components/el-plus-form/ElPlusFormGroup.vue +116 -116
  14. package/lib/components/el-plus-form/components/ElPlusFormArea.vue +61 -61
  15. package/lib/components/el-plus-form/components/ElPlusFormAutocomplete.vue +49 -49
  16. package/lib/components/el-plus-form/components/ElPlusFormBtn.vue +102 -102
  17. package/lib/components/el-plus-form/components/ElPlusFormBtns.vue +133 -133
  18. package/lib/components/el-plus-form/components/ElPlusFormCascader.vue +63 -63
  19. package/lib/components/el-plus-form/components/ElPlusFormCascaderPanel.vue +53 -53
  20. package/lib/components/el-plus-form/components/ElPlusFormCheckbox.vue +44 -44
  21. package/lib/components/el-plus-form/components/ElPlusFormCheckboxButton.vue +44 -44
  22. package/lib/components/el-plus-form/components/ElPlusFormColor.vue +38 -38
  23. package/lib/components/el-plus-form/components/ElPlusFormDate.vue +39 -39
  24. package/lib/components/el-plus-form/components/ElPlusFormDaterange.vue +46 -46
  25. package/lib/components/el-plus-form/components/ElPlusFormDatetime.vue +40 -40
  26. package/lib/components/el-plus-form/components/ElPlusFormFile.vue +47 -47
  27. package/lib/components/el-plus-form/components/ElPlusFormImage.vue +113 -113
  28. package/lib/components/el-plus-form/components/ElPlusFormLink.vue +281 -281
  29. package/lib/components/el-plus-form/components/ElPlusFormLkuser.vue +489 -489
  30. package/lib/components/el-plus-form/components/ElPlusFormNbinput.vue +53 -53
  31. package/lib/components/el-plus-form/components/ElPlusFormNumber.vue +146 -146
  32. package/lib/components/el-plus-form/components/ElPlusFormQuickInput.vue +94 -94
  33. package/lib/components/el-plus-form/components/ElPlusFormRadio.vue +42 -42
  34. package/lib/components/el-plus-form/components/ElPlusFormRate.vue +38 -38
  35. package/lib/components/el-plus-form/components/ElPlusFormSelect.vue +161 -161
  36. package/lib/components/el-plus-form/components/ElPlusFormSlider.vue +38 -38
  37. package/lib/components/el-plus-form/components/ElPlusFormSwitch.vue +38 -38
  38. package/lib/components/el-plus-form/components/ElPlusFormTag.vue +78 -78
  39. package/lib/components/el-plus-form/components/ElPlusFormText.vue +99 -99
  40. package/lib/components/el-plus-form/components/ElPlusFormTextarea.vue +49 -49
  41. package/lib/components/el-plus-form/components/ElPlusFormTransfer.vue +44 -44
  42. package/lib/components/el-plus-form/components/ElPlusFormTree.vue +76 -76
  43. package/lib/components/el-plus-form/components/ElPlusFormTreeSelect.vue +59 -59
  44. package/lib/components/el-plus-form/components/ElPlusFormUpload.vue +368 -368
  45. package/lib/components/el-plus-form/components/components/file-icons/FileIcons.vue +135 -135
  46. package/lib/components/el-plus-form/components/components/file-icons/data/index.ts +27 -27
  47. package/lib/components/el-plus-form/components/components/file-icons/images/doc.svg +12 -12
  48. package/lib/components/el-plus-form/components/components/file-icons/images/file.svg +18 -18
  49. package/lib/components/el-plus-form/components/components/file-icons/images/jpg.svg +13 -13
  50. package/lib/components/el-plus-form/components/components/file-icons/images/pdf.svg +12 -12
  51. package/lib/components/el-plus-form/components/components/file-icons/images/png.svg +12 -12
  52. package/lib/components/el-plus-form/components/components/file-icons/images/ppt.svg +12 -12
  53. package/lib/components/el-plus-form/components/components/file-icons/images/xls.svg +12 -12
  54. package/lib/components/el-plus-form/components/index.ts +17 -17
  55. package/lib/components/el-plus-form/data/file.ts +74 -74
  56. package/lib/components/el-plus-form/mixins/index.ts +115 -113
  57. package/lib/components/el-plus-form/util/index.ts +257 -257
  58. package/lib/components/el-plus-form/util/validate.ts +332 -332
  59. package/lib/components/el-plus-table/components/columnItem.vue +205 -205
  60. package/lib/components/el-plus-table/components/header.vue +240 -240
  61. package/lib/components/el-plus-table/components/statisticInfo.vue +47 -47
  62. package/lib/components/el-plus-table/util/index.ts +147 -147
  63. package/lib/config/index.ts +30 -30
  64. package/lib/index.d.ts +4 -4
  65. package/lib/index.ts +51 -51
  66. package/package.json +1 -1
  67. package/types/axios.d.ts +13 -13
  68. package/types/formList.d.ts +440 -440
  69. package/types/layout.d.ts +57 -57
  70. package/types/mitt.d.ts +38 -38
  71. package/types/pinia.d.ts +149 -149
  72. package/types/views.d.ts +329 -329
  73. package/vite.config.ts +78 -78
@@ -1,489 +1,489 @@
1
- <template>
2
- <div class="el-plus-form-link-user">
3
- <el-select ref="selectRef" style="width: 100%" :class="desc.class" :style="desc.style" v-bind="topAttrs" :teleported="false" :loading="loading" :modelValue="values" @visible-change="handelVisibleChange" @clear="handelClear">
4
- <el-option v-for="option in options" :key="option.value" v-bind="option" />
5
- </el-select>
6
- <!-- 弹框 -->
7
- <el-dialog :width="desc.dialogWidth || '900px'" :title="desc.placeholder || '选择' + desc.label" draggable :closeOnClickModal="false" showCancel v-model="isShowDialog" append-to-body destroy-on-close>
8
- <div style="width: 100%" class="form-link-user-dialog">
9
- <div class="panel-left">
10
- <!-- 搜索 -->
11
- <el-select style="width: 300px" placeholder="输入用户名进行搜索" v-bind="selectAttrs" @change="handelSelectChange">
12
- <el-option v-for="option in selectOptions" :key="option.value" v-bind="option" />
13
- </el-select>
14
- <el-divider></el-divider>
15
- <div class="dept-breadcrumb">
16
- <el-breadcrumb separator="/">
17
- <el-breadcrumb-item @click="goIndex(-1)">组织架构</el-breadcrumb-item>
18
- <el-breadcrumb-item v-for="(item, i) in deptTreeItems" :key="i" @click="goIndex(i)">
19
- {{ item.label }}
20
- </el-breadcrumb-item>
21
- </el-breadcrumb>
22
- </div>
23
- <!-- 组织机构列表 -->
24
- <el-table ref="multipleTableRef" :data="tableData" style="width: 100%; height: 500px" max-height="500px" @select="handelTableSelect" @select-all="handelTableSelectAll">
25
- <el-table-column type="selection" width="55" :selectable="handelTableSelectable" />
26
- <el-table-column label="组织/部门/人员" prop="label">
27
- <template #default="{ row }">
28
- <div style="display: flex; align-items: center">
29
- <el-icon style="margin-right: 5px">
30
- <Share v-if="row.type === 2" />
31
- <UserFilled v-else />
32
- </el-icon>
33
- {{ row.label }}
34
- </div>
35
- </template>
36
- </el-table-column>
37
- <el-table-column label="操作" width="80">
38
- <template #default="{ row, $index }">
39
- <el-button v-if="row.type === 2" :disabled="selectUser.some((item) => item.value === row.value)" type="primary" text plain @click="goInto(row, $index)">进入</el-button>
40
- </template>
41
- </el-table-column>
42
- </el-table>
43
- </div>
44
- <div class="panel-right">
45
- <div class="right-title">已选中项:</div>
46
- <el-scrollbar height="480px" class="tag-list">
47
- <el-tag style="margin-right: 10px; margin-bottom: 10px" v-for="tag in selectUser" :key="tag.value" closable @close="() => handelTagRemove(tag)">
48
- <el-icon style="margin-right: 5px">
49
- <Share v-if="tag.type === 2" />
50
- <UserFilled v-else />
51
- </el-icon>
52
- {{ tag.label }}
53
- </el-tag>
54
- </el-scrollbar>
55
- <div class="btn-panel">
56
- <el-button @click="cancel">取消</el-button>
57
- <el-button type="primary" @click="submit">确定</el-button>
58
- </div>
59
- </div>
60
- </div>
61
- </el-dialog>
62
- </div>
63
- </template>
64
- <script lang="ts">
65
- export default {
66
- name: 'ElPlusFormLkuser',
67
- inheritAttrs: false,
68
- typeName: 'lkuser',
69
- customOptions: {}
70
- }
71
- </script>
72
- <script lang="ts" setup>
73
- import { ref, reactive, nextTick, watch, onMounted, computed, inject, onBeforeMount, useAttrs } from 'vue'
74
- import { Share, UserFilled } from '@element-plus/icons-vue'
75
- import { cloneDeep } from 'lodash'
76
- import { getAttrs } from '../mixins'
77
-
78
- const globalData = inject('globalData') as any
79
- const defaultConf = inject('defaultConf') as ICRUDConfig
80
-
81
- interface ILinkItem {
82
- // 选中类型: 1,用户、 2:部门
83
- type: 1 | 2
84
- label: string
85
- value: string
86
- }
87
-
88
- const props = defineProps<{
89
- modelValue?: []
90
- field: string
91
- loading?: boolean
92
- desc: { [key: string]: any }
93
- formData: { [key: string]: any }
94
- }>()
95
-
96
- const onEvents = ref(getEvents(props))
97
-
98
- const emits = defineEmits(['update:modelValue', 'change', 'input', 'validateThis'])
99
-
100
- const currentValue = ref((props.modelValue || []) as any[])
101
- emits('update:modelValue', currentValue)
102
-
103
- // 顶部的select
104
- const selectRef = ref()
105
- const values = reactive([] as Array<string>)
106
- const options = reactive([] as Array<ILinkItem>)
107
- const topAttrs = reactive({
108
- multiple: true,
109
- size: props.desc.size,
110
- collapseTags: false,
111
- collapseTagsTooltip: false,
112
- clearable: true
113
- })
114
-
115
- const isShowDialog = ref(false)
116
-
117
- // 存储的值
118
- const selectUser = reactive([] as Array<ILinkItem>)
119
-
120
- // 搜索框
121
- const selectOptions = reactive([] as any[])
122
- const selectAttrs = ref({})
123
-
124
- /**
125
- * 处理自定义请求
126
- * @param param
127
- */
128
- async function remoteMethod(query: string) {
129
- selectOptions.splice(0, selectOptions.length, ...(await selectRemote(query)))
130
- }
131
-
132
- // 组织架构数据
133
- const deptTreeIndex = ref([] as number[])
134
- const deptTreeItems = ref([] as any[])
135
- // 用户数据列表
136
- const tableUserData = ref([] as any[])
137
-
138
- // 机构列表数据
139
- const multipleTableRef = ref()
140
- const tableData = computed(() => {
141
- const tempList = [] as ILinkItem[]
142
- // 遍历组织架构数据
143
- let tempData = cloneDeep(globalData[defaultConf.form?.linkUser?.deptListKey || ''])
144
- if (deptTreeIndex.value && deptTreeIndex.value.length > 0) {
145
- deptTreeIndex.value.map((item) => {
146
- tempData = tempData[item].children || []
147
- })
148
- }
149
- tempData.map((item: any) => tempList.push({ type: 2, label: item.name, value: item.id }))
150
- // 遍历用户数据
151
- tableUserData.value.map((item) => tempList.push({ type: 1, label: item.nickname, value: item.userId }))
152
-
153
- // 这里默认选中
154
- nextTick(() => {
155
- setTimeout(() => {
156
- tempList.map((item) => {
157
- multipleTableRef.value?.toggleRowSelection(
158
- item,
159
- selectUser.some((i) => i.value === item.value)
160
- )
161
- })
162
- }, 10)
163
- })
164
- return tempList
165
- })
166
-
167
- /**
168
- * 获取事件
169
- * @returns
170
- */
171
- function getEvents(props: any) {
172
- const tempOn = {} as any
173
- if (props.desc?.on) {
174
- Object.keys(props.desc.on).map((key: string) => {
175
- tempOn[key] = (val: any) => {
176
- props.desc.on[key](props.formData, props.rowIndex, val)
177
- }
178
- })
179
- }
180
- return tempOn
181
- }
182
-
183
- /**
184
- * 处理点击事件
185
- * @param val
186
- */
187
- function handelVisibleChange(val: any) {
188
- if (val) {
189
- selectRef.value.blur()
190
- isShowDialog.value = true
191
- }
192
- }
193
-
194
- /**
195
- * 处理清空选项
196
- */
197
- function handelClear() {
198
- selectUser.splice(0, selectUser.length)
199
- // 清空列表选中项
200
- tableData.value.map((item) => {
201
- multipleTableRef.value?.toggleRowSelection(
202
- item,
203
- selectUser.some((i) => i.value === item.value)
204
- )
205
- })
206
- submit()
207
- }
208
-
209
- /**
210
- * 处理自定义请求
211
- * @param param
212
- */
213
-
214
- /**
215
- * 处理下拉框选中
216
- * @param val
217
- */
218
- function handelSelectChange(val: any) {
219
- addAndRemove({ ...selectOptions.find((item) => item.value === val), type: 1 })
220
- }
221
-
222
- /**
223
- * 远程查询用户列表
224
- * @param nickname
225
- */
226
- async function selectRemote(nickname: string) {
227
- if (nickname.length > 0) {
228
- return ((await defaultConf.form?.linkUser?.getUserList({ nickname, current: 1, size: 10, enabled: 1 })) as any).records?.map((item: any) => {
229
- return { value: item.userId, label: item.nickname }
230
- })
231
- }
232
- return []
233
- }
234
-
235
- /**
236
- * 进入下级组织架构
237
- * @param item
238
- */
239
- async function goInto(item: ILinkItem, index: number) {
240
- // 查询机构用户
241
- tableUserData.value = (await defaultConf.form?.linkUser?.getUserList({ deptId: item.value, size: 999 })).records as any[]
242
- deptTreeIndex.value.push(index)
243
- deptTreeItems.value.push(item)
244
- }
245
-
246
- /**
247
- * 返回上级组织架构
248
- * @param index
249
- */
250
- async function goIndex(index: number) {
251
- // 查询机构用户
252
- tableUserData.value = index >= 0 ? ((await defaultConf.form?.linkUser?.getUserList({ deptId: deptTreeItems.value[index].value, size: 999 })).records as any[]) : []
253
- deptTreeIndex.value.splice(index + 1)
254
- deptTreeItems.value.splice(index + 1)
255
- }
256
-
257
- /**
258
- * 处理当前行是否能够被选中
259
- * @param row
260
- */
261
- function handelTableSelectable(row: any) {
262
- if (props.desc.onlyUser) {
263
- return row.type === 1
264
- }
265
- return true
266
- }
267
-
268
- /**
269
- * 处理单个选中的情况
270
- * @param selection
271
- * @param row
272
- */
273
- function handelTableSelect(selection: ILinkItem[], item: ILinkItem) {
274
- addAndRemove(item, !selection.some((i) => i.value === item.value))
275
- }
276
-
277
- /**
278
- * 处理全选
279
- * @param selection
280
- * @param row
281
- */
282
- function handelTableSelectAll(selection: ILinkItem[]) {
283
- const isRemove = !(selection && selection.length > 0)
284
- tableData.value.map((item) => {
285
- if (!props.desc.onlyUser || (props.desc.onlyUser && item.type === 1)) {
286
- addAndRemove(item, isRemove)
287
- }
288
- })
289
- }
290
-
291
- /**
292
- * 处理删除标签
293
- * @param item
294
- */
295
- function handelTagRemove(item: ILinkItem) {
296
- if (tableData.value.some((i) => i.value === item.value)) {
297
- multipleTableRef.value?.toggleRowSelection(item, false)
298
- }
299
- addAndRemove(item, true)
300
- }
301
-
302
- /**
303
- * 添加或者移除
304
- * @param item
305
- */
306
- function addAndRemove(item: ILinkItem, isRemove: boolean = false) {
307
- // 校验是否已经有了
308
- const index = selectUser.findIndex((i) => i.value === item.value)
309
- if (isRemove) {
310
- if (index >= 0) {
311
- selectUser.splice(index, 1)
312
- }
313
- } else {
314
- if (index < 0) {
315
- selectUser.push(item)
316
- }
317
- }
318
- }
319
-
320
- /**
321
- * 取消按钮
322
- */
323
- function cancel() {
324
- isShowDialog.value = false
325
- }
326
-
327
- /**
328
- * 确认按钮
329
- */
330
- function submit() {
331
- options.splice(0, options.length, ...selectUser)
332
- const userIds = [] as string[]
333
- const deptIds = [] as string[]
334
- const userNames = [] as string[]
335
- const deptNames = [] as string[]
336
- values.splice(0, values.length)
337
-
338
- // 遍历数据
339
- selectUser.map((item) => {
340
- values.push(item.value)
341
- if (item.type === 1) {
342
- userIds.push(item.value)
343
- userNames.push(item.label)
344
- } else {
345
- deptIds.push(item.value)
346
- deptNames.push(item.label)
347
- }
348
- })
349
-
350
- isShowDialog.value = false
351
- currentValue.value = selectUser.length > 0 ? [userIds, deptIds, userNames, deptNames] : []
352
- // 触发外部change事件
353
- if (onEvents.value.change) {
354
- onEvents.value.change(props.formData, null, currentValue.value)
355
- }
356
- emits('validateThis')
357
- }
358
-
359
- /**
360
- * 初始化选中数据
361
- */
362
- function initSelectData() {
363
- const tempList = [] as Array<ILinkItem>
364
- if (props.modelValue) {
365
- let [userIds, deptIds, userNames, deptNames] = props.modelValue as any
366
- if (deptIds && deptNames && deptIds.length === deptNames.length) {
367
- deptIds.map((id: string, i: number) => {
368
- tempList.push({ type: 2, value: id, label: deptNames[i] })
369
- })
370
- }
371
- if (userIds && userNames && userIds.length === userNames.length) {
372
- userIds.map((id: string, i: number) => {
373
- tempList.push({ type: 1, value: id, label: userNames[i] })
374
- })
375
- }
376
- }
377
- return tempList
378
- }
379
-
380
- /**
381
- * 初始化选中Id
382
- */
383
- function initSelectIds() {
384
- const tempList = [] as Array<string>
385
- if (props.modelValue) {
386
- let [userIds, deptIds] = props.modelValue as any
387
- tempList.push(...(deptIds || []))
388
- tempList.push(...(userIds || []))
389
- }
390
- return tempList
391
- }
392
-
393
- /**
394
- * 初始化数据
395
- */
396
- function init() {
397
- selectUser.splice(0, selectUser.length, ...initSelectData())
398
- options.splice(0, options.length, ...initSelectData())
399
- values.splice(0, values.length, ...initSelectIds())
400
- }
401
-
402
- onBeforeMount(async () => {
403
- // // 如果没有配置,则抛出一个警告
404
- selectAttrs.value = await getAttrs(props, {
405
- remote: true,
406
- filterable: true,
407
- remoteShowSuffix: true,
408
- loadingText: '远程查询中...',
409
- remoteMethod: remoteMethod,
410
- ...useAttrs()
411
- })
412
- })
413
-
414
- watch(
415
- () => props.modelValue,
416
- () => init(),
417
- { deep: true }
418
- )
419
-
420
- onMounted(async () => {
421
- init()
422
- })
423
- </script>
424
- <style lang="scss" scoped>
425
- .el-plus-form-link-user {
426
- width: 100%;
427
-
428
- .items-panel {
429
- :deep(.el-input__inner) {
430
- cursor: pointer;
431
- }
432
- }
433
-
434
- :deep(.el-tag__close) {
435
- display: none !important;
436
- }
437
- }
438
- </style>
439
- <style lang="scss">
440
- .form-link-user-dialog {
441
- width: 100%;
442
- display: flex;
443
- box-sizing: border-box;
444
-
445
- .panel-left {
446
- width: 60%;
447
- display: flex;
448
- flex-direction: column;
449
-
450
- .dept-breadcrumb {
451
- width: 100%;
452
- padding: 0 10px;
453
- margin-bottom: 20px;
454
- cursor: pointer;
455
- }
456
- }
457
-
458
- .panel-right {
459
- width: 40%;
460
- margin-left: 20px;
461
- border-left: 1px var(--el-border-color) var(--el-border-style);
462
- padding: 20px;
463
- display: flex;
464
- overflow: hidden;
465
- flex-direction: column;
466
-
467
- .right-title {
468
- width: 100%;
469
- font-size: 14px;
470
- color: #999999;
471
- margin-bottom: 20px;
472
- }
473
-
474
- .tag-list {
475
- width: 100%;
476
- flex: 1;
477
- overflow-y: hidden;
478
- }
479
-
480
- .btn-panel {
481
- width: 100%;
482
- min-height: 50px;
483
- padding-top: 10px;
484
- display: flex;
485
- justify-content: center;
486
- }
487
- }
488
- }
489
- </style>
1
+ <template>
2
+ <div class="el-plus-form-link-user">
3
+ <el-select ref="selectRef" style="width: 100%" :class="desc.class" :style="desc.style" v-bind="topAttrs" :teleported="false" :loading="loading" :modelValue="values" @visible-change="handelVisibleChange" @clear="handelClear">
4
+ <el-option v-for="option in options" :key="option.value" v-bind="option" />
5
+ </el-select>
6
+ <!-- 弹框 -->
7
+ <el-dialog :width="desc.dialogWidth || '900px'" :title="desc.placeholder || '选择' + desc.label" draggable :closeOnClickModal="false" showCancel v-model="isShowDialog" append-to-body destroy-on-close>
8
+ <div style="width: 100%" class="form-link-user-dialog">
9
+ <div class="panel-left">
10
+ <!-- 搜索 -->
11
+ <el-select style="width: 300px" placeholder="输入用户名进行搜索" v-bind="selectAttrs" @change="handelSelectChange">
12
+ <el-option v-for="option in selectOptions" :key="option.value" v-bind="option" />
13
+ </el-select>
14
+ <el-divider></el-divider>
15
+ <div class="dept-breadcrumb">
16
+ <el-breadcrumb separator="/">
17
+ <el-breadcrumb-item @click="goIndex(-1)">组织架构</el-breadcrumb-item>
18
+ <el-breadcrumb-item v-for="(item, i) in deptTreeItems" :key="i" @click="goIndex(i)">
19
+ {{ item.label }}
20
+ </el-breadcrumb-item>
21
+ </el-breadcrumb>
22
+ </div>
23
+ <!-- 组织机构列表 -->
24
+ <el-table ref="multipleTableRef" :data="tableData" style="width: 100%; height: 500px" max-height="500px" @select="handelTableSelect" @select-all="handelTableSelectAll">
25
+ <el-table-column type="selection" width="55" :selectable="handelTableSelectable" />
26
+ <el-table-column label="组织/部门/人员" prop="label">
27
+ <template #default="{ row }">
28
+ <div style="display: flex; align-items: center">
29
+ <el-icon style="margin-right: 5px">
30
+ <Share v-if="row.type === 2" />
31
+ <UserFilled v-else />
32
+ </el-icon>
33
+ {{ row.label }}
34
+ </div>
35
+ </template>
36
+ </el-table-column>
37
+ <el-table-column label="操作" width="80">
38
+ <template #default="{ row, $index }">
39
+ <el-button v-if="row.type === 2" :disabled="selectUser.some((item) => item.value === row.value)" type="primary" text plain @click="goInto(row, $index)">进入</el-button>
40
+ </template>
41
+ </el-table-column>
42
+ </el-table>
43
+ </div>
44
+ <div class="panel-right">
45
+ <div class="right-title">已选中项:</div>
46
+ <el-scrollbar height="480px" class="tag-list">
47
+ <el-tag style="margin-right: 10px; margin-bottom: 10px" v-for="tag in selectUser" :key="tag.value" closable @close="() => handelTagRemove(tag)">
48
+ <el-icon style="margin-right: 5px">
49
+ <Share v-if="tag.type === 2" />
50
+ <UserFilled v-else />
51
+ </el-icon>
52
+ {{ tag.label }}
53
+ </el-tag>
54
+ </el-scrollbar>
55
+ <div class="btn-panel">
56
+ <el-button @click="cancel">取消</el-button>
57
+ <el-button type="primary" @click="submit">确定</el-button>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </el-dialog>
62
+ </div>
63
+ </template>
64
+ <script lang="ts">
65
+ export default {
66
+ name: 'ElPlusFormLkuser',
67
+ inheritAttrs: false,
68
+ typeName: 'lkuser',
69
+ customOptions: {}
70
+ }
71
+ </script>
72
+ <script lang="ts" setup>
73
+ import { ref, reactive, nextTick, watch, onMounted, computed, inject, onBeforeMount, useAttrs } from 'vue'
74
+ import { Share, UserFilled } from '@element-plus/icons-vue'
75
+ import { cloneDeep } from 'lodash'
76
+ import { getAttrs } from '../mixins'
77
+
78
+ const globalData = inject('globalData') as any
79
+ const defaultConf = inject('defaultConf') as ICRUDConfig
80
+
81
+ interface ILinkItem {
82
+ // 选中类型: 1,用户、 2:部门
83
+ type: 1 | 2
84
+ label: string
85
+ value: string
86
+ }
87
+
88
+ const props = defineProps<{
89
+ modelValue?: []
90
+ field: string
91
+ loading?: boolean
92
+ desc: { [key: string]: any }
93
+ formData: { [key: string]: any }
94
+ }>()
95
+
96
+ const onEvents = ref(getEvents(props))
97
+
98
+ const emits = defineEmits(['update:modelValue', 'change', 'input', 'validateThis'])
99
+
100
+ const currentValue = ref((props.modelValue || []) as any[])
101
+ emits('update:modelValue', currentValue)
102
+
103
+ // 顶部的select
104
+ const selectRef = ref()
105
+ const values = reactive([] as Array<string>)
106
+ const options = reactive([] as Array<ILinkItem>)
107
+ const topAttrs = reactive({
108
+ multiple: true,
109
+ size: props.desc.size,
110
+ collapseTags: false,
111
+ collapseTagsTooltip: false,
112
+ clearable: true
113
+ })
114
+
115
+ const isShowDialog = ref(false)
116
+
117
+ // 存储的值
118
+ const selectUser = reactive([] as Array<ILinkItem>)
119
+
120
+ // 搜索框
121
+ const selectOptions = reactive([] as any[])
122
+ const selectAttrs = ref({})
123
+
124
+ /**
125
+ * 处理自定义请求
126
+ * @param param
127
+ */
128
+ async function remoteMethod(query: string) {
129
+ selectOptions.splice(0, selectOptions.length, ...(await selectRemote(query)))
130
+ }
131
+
132
+ // 组织架构数据
133
+ const deptTreeIndex = ref([] as number[])
134
+ const deptTreeItems = ref([] as any[])
135
+ // 用户数据列表
136
+ const tableUserData = ref([] as any[])
137
+
138
+ // 机构列表数据
139
+ const multipleTableRef = ref()
140
+ const tableData = computed(() => {
141
+ const tempList = [] as ILinkItem[]
142
+ // 遍历组织架构数据
143
+ let tempData = cloneDeep(globalData[defaultConf.form?.linkUser?.deptListKey || ''])
144
+ if (deptTreeIndex.value && deptTreeIndex.value.length > 0) {
145
+ deptTreeIndex.value.map((item) => {
146
+ tempData = tempData[item].children || []
147
+ })
148
+ }
149
+ tempData.map((item: any) => tempList.push({ type: 2, label: item.name, value: item.id }))
150
+ // 遍历用户数据
151
+ tableUserData.value.map((item) => tempList.push({ type: 1, label: item.nickname, value: item.userId }))
152
+
153
+ // 这里默认选中
154
+ nextTick(() => {
155
+ setTimeout(() => {
156
+ tempList.map((item) => {
157
+ multipleTableRef.value?.toggleRowSelection(
158
+ item,
159
+ selectUser.some((i) => i.value === item.value)
160
+ )
161
+ })
162
+ }, 10)
163
+ })
164
+ return tempList
165
+ })
166
+
167
+ /**
168
+ * 获取事件
169
+ * @returns
170
+ */
171
+ function getEvents(props: any) {
172
+ const tempOn = {} as any
173
+ if (props.desc?.on) {
174
+ Object.keys(props.desc.on).map((key: string) => {
175
+ tempOn[key] = (val: any) => {
176
+ props.desc.on[key](props.formData, props.rowIndex, val)
177
+ }
178
+ })
179
+ }
180
+ return tempOn
181
+ }
182
+
183
+ /**
184
+ * 处理点击事件
185
+ * @param val
186
+ */
187
+ function handelVisibleChange(val: any) {
188
+ if (val) {
189
+ selectRef.value.blur()
190
+ isShowDialog.value = true
191
+ }
192
+ }
193
+
194
+ /**
195
+ * 处理清空选项
196
+ */
197
+ function handelClear() {
198
+ selectUser.splice(0, selectUser.length)
199
+ // 清空列表选中项
200
+ tableData.value.map((item) => {
201
+ multipleTableRef.value?.toggleRowSelection(
202
+ item,
203
+ selectUser.some((i) => i.value === item.value)
204
+ )
205
+ })
206
+ submit()
207
+ }
208
+
209
+ /**
210
+ * 处理自定义请求
211
+ * @param param
212
+ */
213
+
214
+ /**
215
+ * 处理下拉框选中
216
+ * @param val
217
+ */
218
+ function handelSelectChange(val: any) {
219
+ addAndRemove({ ...selectOptions.find((item) => item.value === val), type: 1 })
220
+ }
221
+
222
+ /**
223
+ * 远程查询用户列表
224
+ * @param nickname
225
+ */
226
+ async function selectRemote(nickname: string) {
227
+ if (nickname.length > 0) {
228
+ return ((await defaultConf.form?.linkUser?.getUserList({ nickname, current: 1, size: 10, enabled: 1 })) as any).records?.map((item: any) => {
229
+ return { value: item.userId, label: item.nickname }
230
+ })
231
+ }
232
+ return []
233
+ }
234
+
235
+ /**
236
+ * 进入下级组织架构
237
+ * @param item
238
+ */
239
+ async function goInto(item: ILinkItem, index: number) {
240
+ // 查询机构用户
241
+ tableUserData.value = (await defaultConf.form?.linkUser?.getUserList({ deptId: item.value, size: 999 })).records as any[]
242
+ deptTreeIndex.value.push(index)
243
+ deptTreeItems.value.push(item)
244
+ }
245
+
246
+ /**
247
+ * 返回上级组织架构
248
+ * @param index
249
+ */
250
+ async function goIndex(index: number) {
251
+ // 查询机构用户
252
+ tableUserData.value = index >= 0 ? ((await defaultConf.form?.linkUser?.getUserList({ deptId: deptTreeItems.value[index].value, size: 999 })).records as any[]) : []
253
+ deptTreeIndex.value.splice(index + 1)
254
+ deptTreeItems.value.splice(index + 1)
255
+ }
256
+
257
+ /**
258
+ * 处理当前行是否能够被选中
259
+ * @param row
260
+ */
261
+ function handelTableSelectable(row: any) {
262
+ if (props.desc.onlyUser) {
263
+ return row.type === 1
264
+ }
265
+ return true
266
+ }
267
+
268
+ /**
269
+ * 处理单个选中的情况
270
+ * @param selection
271
+ * @param row
272
+ */
273
+ function handelTableSelect(selection: ILinkItem[], item: ILinkItem) {
274
+ addAndRemove(item, !selection.some((i) => i.value === item.value))
275
+ }
276
+
277
+ /**
278
+ * 处理全选
279
+ * @param selection
280
+ * @param row
281
+ */
282
+ function handelTableSelectAll(selection: ILinkItem[]) {
283
+ const isRemove = !(selection && selection.length > 0)
284
+ tableData.value.map((item) => {
285
+ if (!props.desc.onlyUser || (props.desc.onlyUser && item.type === 1)) {
286
+ addAndRemove(item, isRemove)
287
+ }
288
+ })
289
+ }
290
+
291
+ /**
292
+ * 处理删除标签
293
+ * @param item
294
+ */
295
+ function handelTagRemove(item: ILinkItem) {
296
+ if (tableData.value.some((i) => i.value === item.value)) {
297
+ multipleTableRef.value?.toggleRowSelection(item, false)
298
+ }
299
+ addAndRemove(item, true)
300
+ }
301
+
302
+ /**
303
+ * 添加或者移除
304
+ * @param item
305
+ */
306
+ function addAndRemove(item: ILinkItem, isRemove: boolean = false) {
307
+ // 校验是否已经有了
308
+ const index = selectUser.findIndex((i) => i.value === item.value)
309
+ if (isRemove) {
310
+ if (index >= 0) {
311
+ selectUser.splice(index, 1)
312
+ }
313
+ } else {
314
+ if (index < 0) {
315
+ selectUser.push(item)
316
+ }
317
+ }
318
+ }
319
+
320
+ /**
321
+ * 取消按钮
322
+ */
323
+ function cancel() {
324
+ isShowDialog.value = false
325
+ }
326
+
327
+ /**
328
+ * 确认按钮
329
+ */
330
+ function submit() {
331
+ options.splice(0, options.length, ...selectUser)
332
+ const userIds = [] as string[]
333
+ const deptIds = [] as string[]
334
+ const userNames = [] as string[]
335
+ const deptNames = [] as string[]
336
+ values.splice(0, values.length)
337
+
338
+ // 遍历数据
339
+ selectUser.map((item) => {
340
+ values.push(item.value)
341
+ if (item.type === 1) {
342
+ userIds.push(item.value)
343
+ userNames.push(item.label)
344
+ } else {
345
+ deptIds.push(item.value)
346
+ deptNames.push(item.label)
347
+ }
348
+ })
349
+
350
+ isShowDialog.value = false
351
+ currentValue.value = selectUser.length > 0 ? [userIds, deptIds, userNames, deptNames] : []
352
+ // 触发外部change事件
353
+ if (onEvents.value.change) {
354
+ onEvents.value.change(props.formData, null, currentValue.value)
355
+ }
356
+ emits('validateThis')
357
+ }
358
+
359
+ /**
360
+ * 初始化选中数据
361
+ */
362
+ function initSelectData() {
363
+ const tempList = [] as Array<ILinkItem>
364
+ if (props.modelValue) {
365
+ let [userIds, deptIds, userNames, deptNames] = props.modelValue as any
366
+ if (deptIds && deptNames && deptIds.length === deptNames.length) {
367
+ deptIds.map((id: string, i: number) => {
368
+ tempList.push({ type: 2, value: id, label: deptNames[i] })
369
+ })
370
+ }
371
+ if (userIds && userNames && userIds.length === userNames.length) {
372
+ userIds.map((id: string, i: number) => {
373
+ tempList.push({ type: 1, value: id, label: userNames[i] })
374
+ })
375
+ }
376
+ }
377
+ return tempList
378
+ }
379
+
380
+ /**
381
+ * 初始化选中Id
382
+ */
383
+ function initSelectIds() {
384
+ const tempList = [] as Array<string>
385
+ if (props.modelValue) {
386
+ let [userIds, deptIds] = props.modelValue as any
387
+ tempList.push(...(deptIds || []))
388
+ tempList.push(...(userIds || []))
389
+ }
390
+ return tempList
391
+ }
392
+
393
+ /**
394
+ * 初始化数据
395
+ */
396
+ function init() {
397
+ selectUser.splice(0, selectUser.length, ...initSelectData())
398
+ options.splice(0, options.length, ...initSelectData())
399
+ values.splice(0, values.length, ...initSelectIds())
400
+ }
401
+
402
+ onBeforeMount(async () => {
403
+ // // 如果没有配置,则抛出一个警告
404
+ selectAttrs.value = await getAttrs(props, {
405
+ remote: true,
406
+ filterable: true,
407
+ remoteShowSuffix: true,
408
+ loadingText: '远程查询中...',
409
+ remoteMethod: remoteMethod,
410
+ ...useAttrs()
411
+ })
412
+ })
413
+
414
+ watch(
415
+ () => props.modelValue,
416
+ () => init(),
417
+ { deep: true }
418
+ )
419
+
420
+ onMounted(async () => {
421
+ init()
422
+ })
423
+ </script>
424
+ <style lang="scss" scoped>
425
+ .el-plus-form-link-user {
426
+ width: 100%;
427
+
428
+ .items-panel {
429
+ :deep(.el-input__inner) {
430
+ cursor: pointer;
431
+ }
432
+ }
433
+
434
+ :deep(.el-tag__close) {
435
+ display: none !important;
436
+ }
437
+ }
438
+ </style>
439
+ <style lang="scss">
440
+ .form-link-user-dialog {
441
+ width: 100%;
442
+ display: flex;
443
+ box-sizing: border-box;
444
+
445
+ .panel-left {
446
+ width: 60%;
447
+ display: flex;
448
+ flex-direction: column;
449
+
450
+ .dept-breadcrumb {
451
+ width: 100%;
452
+ padding: 0 10px;
453
+ margin-bottom: 20px;
454
+ cursor: pointer;
455
+ }
456
+ }
457
+
458
+ .panel-right {
459
+ width: 40%;
460
+ margin-left: 20px;
461
+ border-left: 1px var(--el-border-color) var(--el-border-style);
462
+ padding: 20px;
463
+ display: flex;
464
+ overflow: hidden;
465
+ flex-direction: column;
466
+
467
+ .right-title {
468
+ width: 100%;
469
+ font-size: 14px;
470
+ color: #999999;
471
+ margin-bottom: 20px;
472
+ }
473
+
474
+ .tag-list {
475
+ width: 100%;
476
+ flex: 1;
477
+ overflow-y: hidden;
478
+ }
479
+
480
+ .btn-panel {
481
+ width: 100%;
482
+ min-height: 50px;
483
+ padding-top: 10px;
484
+ display: flex;
485
+ justify-content: center;
486
+ }
487
+ }
488
+ }
489
+ </style>