@ctzy-web-client/plugin-component-vue 1.0.0

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 (138) hide show
  1. package/package.json +43 -0
  2. package/src/advance-select/advance-operation.vue +44 -0
  3. package/src/advance-select/advance-option.vue +115 -0
  4. package/src/advance-select/advance-select.vue +343 -0
  5. package/src/advance-select/events-helpers.js +40 -0
  6. package/src/advance-select/index.js +13 -0
  7. package/src/advance-select/use-advance-option.js +58 -0
  8. package/src/advance-select/use-advance-select.js +142 -0
  9. package/src/application-slot/application-slot.js +70 -0
  10. package/src/application-slot/breadcrumb-item.vue +12 -0
  11. package/src/application-slot/header-tools-item.vue +12 -0
  12. package/src/application-slot/index.js +17 -0
  13. package/src/breadcrumb-select/breadcrumb-select.vue +97 -0
  14. package/src/breadcrumb-select/index.js +6 -0
  15. package/src/components.js +39 -0
  16. package/src/contextmenu/contextmenu-item.vue +13 -0
  17. package/src/contextmenu/contextmenu.vue +56 -0
  18. package/src/contextmenu/index.js +11 -0
  19. package/src/contextmenu/use-contextmenu.js +117 -0
  20. package/src/data-form/data-form-item.vue +49 -0
  21. package/src/data-form/data-form.vue +212 -0
  22. package/src/data-form/dynamic-component.js +24 -0
  23. package/src/data-form/form-components/Blots/AtBlot.js +32 -0
  24. package/src/data-form/form-components/bwa-date-picker.vue +43 -0
  25. package/src/data-form/form-components/bwa-date-time-picker.vue +49 -0
  26. package/src/data-form/form-components/bwa-input-float.vue +41 -0
  27. package/src/data-form/form-components/bwa-input-integer.vue +58 -0
  28. package/src/data-form/form-components/bwa-input.vue +32 -0
  29. package/src/data-form/form-components/bwa-multi-select.vue +27 -0
  30. package/src/data-form/form-components/bwa-rich-text-tinymce.vue +561 -0
  31. package/src/data-form/form-components/bwa-rich-text.vue +395 -0
  32. package/src/data-form/form-components/bwa-select.vue +67 -0
  33. package/src/data-form/form-components/bwa-textarea.vue +28 -0
  34. package/src/data-form/form-components/bwa-upload.vue +145 -0
  35. package/src/data-form/form-components/bwa-user-multi-select.vue +25 -0
  36. package/src/data-form/form-components/bwa-user-select.vue +81 -0
  37. package/src/data-form/index.js +35 -0
  38. package/src/data-table/data-column-view.vue +131 -0
  39. package/src/data-table/data-table-card.vue +81 -0
  40. package/src/data-table/data-table-column.vue +52 -0
  41. package/src/data-table/data-table.vue +426 -0
  42. package/src/data-table/dynamic-component.js +58 -0
  43. package/src/data-table/index.js +13 -0
  44. package/src/data-table/use-datatable-drag.js +156 -0
  45. package/src/datatable-settings/datatable-settings.vue +323 -0
  46. package/src/datatable-settings/index.js +6 -0
  47. package/src/date-range/date-picker.vue +115 -0
  48. package/src/date-range/date-range.vue +202 -0
  49. package/src/date-range/index.js +6 -0
  50. package/src/drag-list/constants.js +1 -0
  51. package/src/drag-list/drag-item.vue +46 -0
  52. package/src/drag-list/drag-list.vue +50 -0
  53. package/src/drag-list/index.js +6 -0
  54. package/src/drag-list/use-drag-list.js +209 -0
  55. package/src/dragable/constants.js +3 -0
  56. package/src/dragable/dragable-item.vue +19 -0
  57. package/src/dragable/dragable-operation.vue +28 -0
  58. package/src/dragable/dragable.vue +26 -0
  59. package/src/dragable/index.js +14 -0
  60. package/src/dragable/use-dragable.js +227 -0
  61. package/src/filter-panel/conditions/condition.js +35 -0
  62. package/src/filter-panel/conditions/date-range-condition.vue +35 -0
  63. package/src/filter-panel/conditions/department-condition/data.json +29537 -0
  64. package/src/filter-panel/conditions/department-condition/department-condition.vue +92 -0
  65. package/src/filter-panel/conditions/department-condition/department-node.vue +52 -0
  66. package/src/filter-panel/conditions/index.js +22 -0
  67. package/src/filter-panel/conditions/input-condition.vue +63 -0
  68. package/src/filter-panel/conditions/multi-user-condition.vue +56 -0
  69. package/src/filter-panel/conditions/multiple-menu-condition.vue +45 -0
  70. package/src/filter-panel/conditions/single-menu-condition.vue +58 -0
  71. package/src/filter-panel/conditions/single-user-condition.vue +56 -0
  72. package/src/filter-panel/filter-panel-item.vue +46 -0
  73. package/src/filter-panel/filter-panel.vue +149 -0
  74. package/src/filter-panel/index.js +17 -0
  75. package/src/filter-panel/use-filter-panel-item.js +59 -0
  76. package/src/filter-panel/use-filter-panel.js +203 -0
  77. package/src/hooks/use-data/index.js +234 -0
  78. package/src/index.js +48 -0
  79. package/src/layout/index.js +6 -0
  80. package/src/layout/layout.vue +74 -0
  81. package/src/make-installer.js +36 -0
  82. package/src/math/Rectangle.js +28 -0
  83. package/src/menu/index.js +6 -0
  84. package/src/menu/menu-item.vue +41 -0
  85. package/src/menu/menu.vue +53 -0
  86. package/src/panel/index.js +6 -0
  87. package/src/panel/panel.vue +42 -0
  88. package/src/panel-tabs/index.js +6 -0
  89. package/src/panel-tabs/panel-tabs.js +92 -0
  90. package/src/pct-filter-panel/index.js +10 -0
  91. package/src/pct-filter-panel/pct-compents/index.js +10 -0
  92. package/src/pct-filter-panel/pct-compents/pct-Input-condition.vue +63 -0
  93. package/src/pct-filter-panel/pct-compents/pct-date-range-condition.vue +60 -0
  94. package/src/pct-filter-panel/pct-compents/pct-multiple-menu-condition.vue +177 -0
  95. package/src/pct-filter-panel/pct-compents/pct-multiple-menu-condition2.vue +142 -0
  96. package/src/pct-filter-panel/pct-filter-panel-item.vue +46 -0
  97. package/src/pct-filter-panel/pct-filter-panel.vue +201 -0
  98. package/src/pct-filter-panel/use-filter-panel-item.js +61 -0
  99. package/src/pct-filter-panel/use-filter-panel.js +206 -0
  100. package/src/plugins.js +3 -0
  101. package/src/progress/index.js +8 -0
  102. package/src/progress/progress-item.vue +81 -0
  103. package/src/progress/progress.vue +58 -0
  104. package/src/progress/use-progress.js +66 -0
  105. package/src/utils/db.js +8 -0
  106. package/src/utils.js +263 -0
  107. package/src/where-filter-panel/index.js +0 -0
  108. package/src/where-filter-panel/use-where-filter-panel.js +28 -0
  109. package/src/where-filter-panel/where-filter-panel.vue +9 -0
  110. package/style/advance-select.scss +316 -0
  111. package/style/breadcrumb-select.scss +80 -0
  112. package/style/common/var.scss +240 -0
  113. package/style/common.scss +48 -0
  114. package/style/contextmenu.scss +58 -0
  115. package/style/data-form.scss +35 -0
  116. package/style/data-table.scss +81 -0
  117. package/style/datatable-settings.scss +125 -0
  118. package/style/date-range.scss +136 -0
  119. package/style/department-condition.scss +39 -0
  120. package/style/drag-list.scss +68 -0
  121. package/style/dragable.scss +8 -0
  122. package/style/filter-panel.scss +199 -0
  123. package/style/index.scss +22 -0
  124. package/style/input-condition.scss +30 -0
  125. package/style/layout.scss +70 -0
  126. package/style/menu.scss +184 -0
  127. package/style/mixins/_var.scss +21 -0
  128. package/style/mixins/config.scss +4 -0
  129. package/style/mixins/function.scss +62 -0
  130. package/style/mixins/mixins.scss +88 -0
  131. package/style/panel-tabs.scss +60 -0
  132. package/style/panel.scss +110 -0
  133. package/style/pct-filter-panel.scss +306 -0
  134. package/style/progress.scss +122 -0
  135. package/style/rich-text.scss +30 -0
  136. package/style/theme/theme.scss +161 -0
  137. package/style/theme/var.scss +34 -0
  138. package/style/var.scss +21 -0
@@ -0,0 +1,395 @@
1
+ <template>
2
+ <div :class="ns.b()" ref="quillEditorContainer">
3
+ <div :class="ns.e('editor')" ref="quillEditorRef" @click="quillEditorRefClick"></div>
4
+
5
+ <BwaAdvanceSelect
6
+ :showSelection="false"
7
+ :virtual-triggering="true"
8
+ :virtual-ref="virtualRef"
9
+ :loading="loading"
10
+ @search="loadUserList"
11
+ @update:modelValue="handleChange"
12
+ @visibleChange="handleVisibleChange"
13
+ >
14
+ <BwaAdvanceOption
15
+ v-for="item of userList"
16
+ :key="item.value"
17
+ :value="item.value"
18
+ :label="item.label"
19
+ />
20
+ </BwaAdvanceSelect>
21
+ </div>
22
+ </template>
23
+
24
+ <script setup>
25
+ import {
26
+ ref,
27
+ unref,
28
+ watch,
29
+ computed,
30
+ getCurrentScope,
31
+ onScopeDispose,
32
+ onMounted,
33
+ markRaw,
34
+ } from 'vue';
35
+ import { useNamespace, useService } from 'web-base-client-vue';
36
+ import Quill from 'quill';
37
+ import 'quill/dist/quill.snow.css';
38
+ // import './Blots/AtBlot';
39
+ import { ElMessage } from 'element-plus';
40
+
41
+ let editor = null;
42
+
43
+ const userService = useService('UserService');
44
+
45
+ const loading = ref(false);
46
+ const userList = ref([
47
+ { value: '1', label: '用户1' },
48
+ { value: '2', label: '用户2' },
49
+ { value: '3', label: '用户3' },
50
+ ]);
51
+
52
+ const handleChange = ([userId]) => {
53
+ if (!editor || !userId) {
54
+ return;
55
+ }
56
+
57
+ const userInfo = unref(userList).find((item) => item.value === userId);
58
+
59
+ if (!userInfo) {
60
+ return;
61
+ }
62
+
63
+ editor.focus();
64
+
65
+ //获取当前光标位置
66
+ let length = editor.getSelection()
67
+ ? editor.getSelection().index || 0
68
+ : editor.getLength();
69
+
70
+ // 设置@
71
+ editor.insertEmbed(
72
+ length,
73
+ 'at',
74
+ { id: userInfo.value, desc: userInfo.label },
75
+ 'user'
76
+ );
77
+
78
+ editor.insertText(length + 1, ' ');
79
+
80
+ //设置光标
81
+ editor.setSelection(length + 2);
82
+ };
83
+
84
+ const loadUserList = async (search = '') => {
85
+ try {
86
+ if (unref(loading)) {
87
+ return;
88
+ }
89
+
90
+ loading.value = true;
91
+ if (!unref(userService)) {
92
+ ElMessage.error('无法获取用户');
93
+ return;
94
+ }
95
+
96
+ const userListResult = await unref(userService).getUserList({
97
+ name: search,
98
+ });
99
+
100
+ if (userListResult.code != 0) {
101
+ ElMessage.error(userListResult.msg);
102
+ return;
103
+ }
104
+
105
+ userList.value = userListResult.data;
106
+ } finally {
107
+ loading.value = false;
108
+ }
109
+ };
110
+
111
+ const handleVisibleChange = (visible) => {
112
+ if (!visible) {
113
+ return;
114
+ }
115
+
116
+ loadUserList();
117
+ };
118
+
119
+ const props = defineProps({
120
+ placeholder: {
121
+ type: String,
122
+ default: '',
123
+ },
124
+ modelValue: {
125
+ type: null,
126
+ },
127
+ disabled: {
128
+ type: Boolean,
129
+ default: false,
130
+ },
131
+ showAt: {
132
+ type: Boolean,
133
+ default: false,
134
+ },
135
+ userIds: {
136
+ typee: Array,
137
+ default: () => [],
138
+ },
139
+ });
140
+
141
+ const virtualRef = ref(null);
142
+
143
+ const emit = defineEmits(['update:modelValue', 'update:userIds']);
144
+
145
+ defineOptions({
146
+ name: 'BwaRichText',
147
+ });
148
+
149
+ const ns = useNamespace('rich-text');
150
+
151
+ const fileService = useService('FileService');
152
+
153
+ const quillEditorContainer = ref(null);
154
+ const quillEditorRef = ref(null);
155
+
156
+ const currentScope = getCurrentScope();
157
+
158
+ const editorInstance = ref(null);
159
+
160
+ const toolbarOptions = [
161
+ [{ header: [1, 2, 3, 4, 5, 6, false] }],
162
+ [{ font: [] }],
163
+ ['bold', 'italic', 'underline', 'strike'],
164
+ [{ align: [] }],
165
+ ['blockquote', 'code-block'],
166
+ [{ header: 1 }, { header: 2 }],
167
+ [{ list: 'ordered' }, { list: 'bullet' }],
168
+ [{ script: 'sub' }, { script: 'super' }],
169
+ [{ indent: '-1' }, { indent: '+1' }],
170
+ [{ color: [] }, { background: [] }],
171
+ ['clean'].concat(props.showAt ? ['at'] : []),
172
+ ];
173
+
174
+ const value = computed({
175
+ get: () => props.modelValue || '',
176
+ set: (v) => {
177
+ // 解决当只有一张图片的时候 回显html报文异常
178
+ let str = ''
179
+ if (!v && editor && editor.root.innerHTML && editor.root.innerHTML.indexOf('<img') != -1) {
180
+ str = editor.root.innerHTML
181
+ }
182
+ emit('update:modelValue', v || str);
183
+ },
184
+ });
185
+
186
+ const userIds = computed({
187
+ get: () => props.userIds,
188
+ set: (v) => {
189
+ emit('update:userIds', v);
190
+ },
191
+ });
192
+
193
+ const updateImage = async (file) => {
194
+ if (!unref(fileService)) {
195
+ return;
196
+ }
197
+
198
+ const uploadFileResult = await unref(fileService).uploadFile(file);
199
+
200
+ if (uploadFileResult.code != 0) {
201
+ return uploadFileResult;
202
+ }
203
+
204
+ const fileID = uploadFileResult.data.id;
205
+
206
+ const filePathResult = await unref(fileService).getFilePath(fileID);
207
+
208
+ if (filePathResult.code != 0) {
209
+ return filePathResult;
210
+ }
211
+
212
+ return {
213
+ ...filePathResult,
214
+ data: { id: fileID, path: filePathResult.data },
215
+ };
216
+ };
217
+ const quillEditorRefClick = () => {
218
+ if (!editor) {
219
+ return;
220
+ }
221
+ editor.focus();
222
+ }
223
+ onMounted(() => {
224
+ editor = new Quill(unref(quillEditorRef), {
225
+ theme: 'snow',
226
+ placeholder: props.placeholder,
227
+ modules: {
228
+ toolbar: {
229
+ container: toolbarOptions,
230
+ handlers: {
231
+ at: function (value) {},
232
+ },
233
+ },
234
+ },
235
+ });
236
+
237
+ virtualRef.value = quillEditorContainer.value.querySelector('button.ql-at');
238
+
239
+ editorInstance.value = markRaw(editor);
240
+
241
+ const el = document.createElement('div');
242
+
243
+ const getUserIds = (html) => {
244
+ el.innerHTML = html;
245
+
246
+ const items = Array.from(el.querySelectorAll('span.ptp-at-item'));
247
+
248
+ userIds.value = [
249
+ ...new Set(items.map((item) => item.getAttribute('d-id'))),
250
+ ];
251
+ };
252
+
253
+ getUserIds(unref(value));
254
+
255
+ const handleTextChange = (delta, oldDelta, source) => {
256
+ const _value = editor.getText() === '\n' ? '' : editor.root.innerHTML;
257
+
258
+ value.value = _value;
259
+
260
+ getUserIds(_value);
261
+ // if (source === 'user') {
262
+ // var range = editor.getLength();
263
+ // console.log(range)
264
+ // // if (range != null) {
265
+ // // setTimeout(() => {
266
+ // // editor.setSelection(range.index, range.length); // 重新设置选区
267
+ // // }, 300)
268
+ // // }
269
+ // }
270
+ };
271
+
272
+ const handlePaste = (evt) => {
273
+ if (
274
+ evt.clipboardData &&
275
+ evt.clipboardData.files &&
276
+ evt.clipboardData.files.length
277
+ ) {
278
+ evt.preventDefault();
279
+ [].forEach.call(evt.clipboardData.files, async (file) => {
280
+ console.log(file)
281
+ if (file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
282
+ const filePathResult = await updateImage(file);
283
+
284
+ if (filePathResult.code != 0) {
285
+ return;
286
+ }
287
+
288
+ const fileData = filePathResult.data;
289
+ // const fileData = { id: 1, path: 'https://img1.baidu.com/it/u=2335299816,3552592887&fm=253&fmt=auto&app=138&f=JPEG?w=126&h=189' }
290
+ var range = editor.getSelection();
291
+ if (range && fileData) {
292
+ // 在当前光标位置插入图片
293
+ editor.insertEmbed(range.index, 'image', fileData.path);
294
+ editor.formatText(range.index, 1, {
295
+ alt: fileData.id,
296
+ });
297
+ // 将光标移动到图片后面
298
+ setTimeout(() => {
299
+ editor.setSelection(range.index + 1);
300
+ // console.log(editor.getSelection(), editor.getLength())
301
+ // editor.setSelection(editor.getSelection().index, editor.getSelection().length);
302
+ }, 300)
303
+ }
304
+ }
305
+ });
306
+ }
307
+ };
308
+
309
+ currentScope.run(() => {
310
+ watch(
311
+ computed(() => props.disabled),
312
+ (disabled) => {
313
+ editor.enable(!disabled);
314
+ },
315
+ { immediate: true }
316
+ );
317
+ const getFilePaths = async (alt) => {
318
+ const filePathResult = await unref(fileService).getFilePath(alt);
319
+ return filePathResult
320
+ }
321
+ let artArr2 = [] // 防止重复加载图片
322
+ watch(
323
+ value,
324
+ async () => {
325
+ if ((unref(value).indexOf('data:image/png') != -1 || unref(value).indexOf('base64') != -1)) {
326
+ editor.root.innerHTML = unref(value);
327
+ return
328
+ }
329
+ // console.log(unref(value))
330
+ if (!unref(value)) {
331
+ artArr2 = []
332
+ }
333
+ let afterHtml = ''
334
+ let artArr = []
335
+ let artArrOption = []
336
+ if (unref(value).indexOf('<img') != -1) {
337
+ unref(value).replace(/<img [^>]*alt=['"]([^'"]+)[^>]*>/gi, (img, alt) => {
338
+ if (!artArr2.includes(alt)) {
339
+ artArr.push(alt)
340
+ }
341
+ })
342
+ for (const alt of artArr) {
343
+ artArrOption.push({
344
+ alt,
345
+ src: await getFilePaths(alt)
346
+ // src: 'https://img1.baidu.com/it/u=2335299816,3552592887&fm=253&fmt=auto&app=138&f=JPEG?w=126&h=189'
347
+ })
348
+ }
349
+ // console.log(artArrOption)
350
+ afterHtml = unref(value).replace(/<img [^>]*alt=['"]([^'"]+)[^>]*>/gi, (img, alt) => {
351
+ if (artArr.includes(alt)) {
352
+ return `<img src="${artArrOption.find(a => a.alt === alt)?.src.data}" alt="${alt}">`
353
+ } else {
354
+ return img
355
+ }
356
+
357
+ })
358
+ }
359
+ console.log('afterHtml =>', afterHtml)
360
+ artArr2 = [...artArr2, ...artArr]
361
+ artArr = []
362
+ artArrOption = []
363
+ if (editor.root.innerHTML === (afterHtml || unref(value))) {
364
+ return;
365
+ }
366
+ const range = editor.getSelection()
367
+ editor.root.innerHTML = afterHtml || unref(value);
368
+ setTimeout(() => {
369
+ if (range) {
370
+ editor.setSelection(range.index + 1);
371
+ editor.focus()
372
+ }
373
+ }, 100)
374
+ },
375
+ { immediate: true }
376
+ );
377
+
378
+ editor.on('text-change', handleTextChange);
379
+
380
+ editor.root.addEventListener('paste', handlePaste);
381
+
382
+ onScopeDispose(() => {
383
+ editor.off('text-change', handleTextChange);
384
+
385
+ editor.root.removeEventListener('paste', handlePaste);
386
+ });
387
+ });
388
+ });
389
+
390
+ defineExpose({
391
+ getEditorInstance() {
392
+ return unref(editorInstance);
393
+ },
394
+ });
395
+ </script>
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <ElSelect v-bind="attrs" v-model="modelValue" clearable :multiple="multiple" :teleported="false">
3
+ <slot>
4
+ <ElOption
5
+ v-for="item of options"
6
+ :key="item.value"
7
+ :value="item.value"
8
+ :label="item.label"
9
+ />
10
+ </slot>
11
+ </ElSelect>
12
+ </template>
13
+
14
+ <script setup>
15
+ import { ElOption, ElSelect } from 'element-plus';
16
+ import { computed, useAttrs } from 'vue';
17
+
18
+ defineOptions({
19
+ name: 'BwaSelect',
20
+ });
21
+
22
+ const props = defineProps({
23
+ modelValue: {
24
+ type: null,
25
+ },
26
+ options: {
27
+ type: Array,
28
+ default: () => [],
29
+ },
30
+ labelProp: {
31
+ type: String,
32
+ default: 'label',
33
+ },
34
+ valueProp: {
35
+ type: String,
36
+ default: 'value',
37
+ },
38
+ multiple: {
39
+ type: Boolean,
40
+ default: false,
41
+ },
42
+ });
43
+
44
+ const options = computed(() =>
45
+ (props.options || []).map((item) => ({
46
+ ...item,
47
+ value: item.value + '',
48
+ }))
49
+ );
50
+
51
+ const attrs = useAttrs();
52
+
53
+ const emit = defineEmits(['update:modelValue']);
54
+
55
+ const modelValue = computed({
56
+ get: () => {
57
+ if (props.multiple) {
58
+ return Array.isArray(props.modelValue)
59
+ ? props.modelValue.map((item) => item + '')
60
+ : [];
61
+ } else {
62
+ return props.modelValue == null ? '' : props.modelValue + '';
63
+ }
64
+ },
65
+ set: (v) => emit('update:modelValue', v),
66
+ });
67
+ </script>
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <el-input type="textarea" v-bind="attrs" v-model="modelValue" />
3
+ </template>
4
+
5
+ <script setup>
6
+ import { useAttrs, computed } from 'vue';
7
+ import { ElInput } from 'element-plus';
8
+
9
+ defineOptions({
10
+ name: 'BwaTextarea',
11
+ });
12
+
13
+ const props = defineProps({
14
+ value: {
15
+ type: [String, Number],
16
+ default: '',
17
+ },
18
+ });
19
+
20
+ const attrs = useAttrs();
21
+
22
+ const emit = defineEmits(['update:model-value']);
23
+
24
+ const modelValue = computed({
25
+ get: () => props.modelValue,
26
+ set: (v) => emit('update:model-value', v),
27
+ });
28
+ </script>
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <ElUpload
3
+ v-bind="attrs"
4
+ :file-list="fileList"
5
+ :http-request="handleHttpRequest"
6
+ :class="ns.b()"
7
+ :on-success="handleSuccess"
8
+ :on-error="handleError"
9
+ >
10
+ <template #trigger>
11
+ <ElButton>
12
+ <ElIcon><Plus /></ElIcon>
13
+ 上传文件
14
+ </ElButton>
15
+ </template>
16
+
17
+ <template #file="{ file }">
18
+ <div :class="ns.b('item')">
19
+ <div :class="ns.be('item', 'info')">
20
+ <ElTooltip :content="file.name">
21
+ <div :class="ns.be('item', 'file-name')">
22
+ {{ file.name }}
23
+ </div>
24
+ </ElTooltip>
25
+ </div>
26
+
27
+ <div :class="ns.be('item', 'tools')">
28
+ <ElIcon
29
+ :class="ns.be('item', 'tools-item')"
30
+ @click="handleDownload(file)"
31
+ >
32
+ <Download></Download>
33
+ </ElIcon>
34
+
35
+ <ElIcon
36
+ :class="ns.be('item', 'tools-item')"
37
+ @click="handleDelete(file)"
38
+ >
39
+ <Delete></Delete>
40
+ </ElIcon>
41
+ </div>
42
+ </div>
43
+ </template>
44
+ </ElUpload>
45
+ </template>
46
+
47
+ <script setup>
48
+ import { Delete, Download } from '@element-plus/icons';
49
+ import { ElButton, ElIcon, ElMessage, ElUpload } from 'element-plus';
50
+ import { computed, ref, unref, useAttrs, watch } from 'vue';
51
+ import { useNamespace, useService } from 'web-base-client-vue';
52
+
53
+ defineOptions({
54
+ name: 'BwaUpload',
55
+ });
56
+
57
+ const props = defineProps({
58
+ modelValue: { type: Array, default: () => [] },
59
+ });
60
+
61
+ const emit = defineEmits(['update:modelValue']);
62
+
63
+ watch(
64
+ computed(() => props.modelValue),
65
+ (modelValue) => {
66
+ if (!Array.isArray(modelValue)) {
67
+ emit('update:modelValue', []);
68
+ }
69
+ },
70
+ { immediate: true }
71
+ );
72
+
73
+ const fileList = computed(() =>
74
+ (Array.isArray(props.modelValue) ? props.modelValue : []).map((fileInfo) => {
75
+ return {
76
+ name: fileInfo.fileName,
77
+ response: fileInfo,
78
+ };
79
+ })
80
+ );
81
+
82
+ const attrs = useAttrs();
83
+
84
+ const ns = useNamespace('upload');
85
+ const fileService = useService('FileService');
86
+
87
+ const handleHttpRequest = ({ file, onProgress, onSuccess, onError }) => {
88
+ if (!unref(fileService)) {
89
+ ElMessage.error('无法上传文件。');
90
+ return;
91
+ }
92
+
93
+ unref(fileService)
94
+ .uploadFile(file, {
95
+ onUploadProgress: (event) => {
96
+ onProgress({ ...event, percent: event.progress });
97
+ },
98
+ })
99
+ .then((res) => {
100
+ if (res.code != 0) {
101
+ onError(res.msg);
102
+ return;
103
+ }
104
+ onSuccess(res.data);
105
+ }, onError);
106
+ };
107
+
108
+ const handleSuccess = (fileInfo) => {
109
+ const value = Array.isArray(props.modelValue) ? props.modelValue : [];
110
+ emit('update:modelValue', value.concat(fileInfo));
111
+ };
112
+
113
+ const handleError = (error) => {
114
+ console.error(error);
115
+ ElMessage.error('文件上传失败。');
116
+ };
117
+
118
+ const handleDelete = (file) => {
119
+ emit(
120
+ 'update:modelValue',
121
+ props.modelValue.filter((fileInfo) => fileInfo !== file.response)
122
+ );
123
+ };
124
+
125
+ const handleDownload = async (file) => {
126
+ if (!unref(fileService)) {
127
+ ElMessage.error('无法下载文件。');
128
+ return;
129
+ }
130
+
131
+ try {
132
+ const downloadFileResult = await unref(fileService).downloadFile(
133
+ file.response
134
+ );
135
+
136
+ if (downloadFileResult.code != 0) {
137
+ ElMessage.error(downloadFileResult.msg);
138
+ return;
139
+ }
140
+ } catch (e) {
141
+ console.error(e);
142
+ ElMessage.error('下载文件失败。');
143
+ }
144
+ };
145
+ </script>
@@ -0,0 +1,25 @@
1
+ <template>
2
+ <BwaUserSelect v-model="modelValue" v-bind="attrs" multiple />
3
+ </template>
4
+
5
+ <script setup>
6
+ import { computed, unref, useAttrs } from 'vue';
7
+ import BwaUserSelect from './bwa-user-select.vue';
8
+
9
+ defineOptions({
10
+ name: 'BwaUserMultiSelect',
11
+ });
12
+
13
+ const props = defineProps({
14
+ modelValue: null,
15
+ });
16
+
17
+ const emit = defineEmits(['update:model-value']);
18
+
19
+ const modelValue = computed({
20
+ get: () => props.modelValue,
21
+ set: (v) => emit('update:model-value', v),
22
+ });
23
+
24
+ const attrs = useAttrs();
25
+ </script>