@ebiz/designer-components 0.1.48 → 0.1.50
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 +13851 -13579
- package/package.json +1 -1
- package/src/components/EbizApprovalForm.vue +8 -0
- package/src/components/EbizFileList.vue +92 -76
- package/src/components/EbizSApprovalProcess.vue +337 -6
package/package.json
CHANGED
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
<t-textarea placeholder="请输入" :maxLength="200" :maxCharacter="true" class="component-base-style"
|
|
16
16
|
v-model="comments"></t-textarea>
|
|
17
17
|
</t-form-item>
|
|
18
|
+
<t-form-item label="附件">
|
|
19
|
+
<ebiz-upload v-model="attachments" :multiple="true" theme="file" />
|
|
20
|
+
</t-form-item>
|
|
18
21
|
<t-form-item>
|
|
19
22
|
<div class="button-group">
|
|
20
23
|
<div class="more-actions">
|
|
@@ -95,6 +98,7 @@ import {
|
|
|
95
98
|
} from 'tdesign-vue-next'
|
|
96
99
|
import { defineProps, defineEmits, ref, reactive, computed, onMounted } from 'vue'
|
|
97
100
|
import { dataService, EbizEmployeeSelector, EbizApproval } from '../index'
|
|
101
|
+
import { EbizUpload } from '../index.js'
|
|
98
102
|
|
|
99
103
|
const request = (params = {}, apiConfig = {}, url = '') => {
|
|
100
104
|
return dataService.fetch(params, apiConfig, url)
|
|
@@ -134,6 +138,7 @@ const emit = defineEmits(['pass', 'reject', 'refresh'])
|
|
|
134
138
|
|
|
135
139
|
// 基础数据
|
|
136
140
|
const comments = ref('')
|
|
141
|
+
const attachments = ref([])
|
|
137
142
|
const showMoreActions = ref(false)
|
|
138
143
|
const taskType = ref('')
|
|
139
144
|
|
|
@@ -295,6 +300,7 @@ const handlePass = async () => {
|
|
|
295
300
|
const params = {
|
|
296
301
|
taskId: props.taskId,
|
|
297
302
|
comment: comments.value,
|
|
303
|
+
attachments: attachments.value,
|
|
298
304
|
approve: true,
|
|
299
305
|
ccList: selectedCCList.value || []
|
|
300
306
|
}
|
|
@@ -307,6 +313,7 @@ const handlePass = async () => {
|
|
|
307
313
|
try {
|
|
308
314
|
await emit('pass', params)
|
|
309
315
|
comments.value = ''
|
|
316
|
+
attachments.value = []
|
|
310
317
|
} catch (err) {
|
|
311
318
|
MessagePlugin.error(err.message || '操作失败')
|
|
312
319
|
}
|
|
@@ -317,6 +324,7 @@ const handleReject = async () => {
|
|
|
317
324
|
try {
|
|
318
325
|
await emit('reject', comments.value)
|
|
319
326
|
comments.value = ''
|
|
327
|
+
attachments.value = []
|
|
320
328
|
} catch (err) {
|
|
321
329
|
MessagePlugin.error(err.message || '操作失败')
|
|
322
330
|
}
|
|
@@ -1,73 +1,49 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="ebiz-file-list">
|
|
2
|
+
<div class="ebiz-file-list" :class="{ 'mini-mode': size === 'mini' }">
|
|
3
3
|
<div v-if="computedFiles.length === 0" class="empty-state">
|
|
4
4
|
<t-icon name="file" size="48px" />
|
|
5
5
|
<p>暂无文件</p>
|
|
6
6
|
</div>
|
|
7
|
-
<div v-else class="file-list-container">
|
|
8
|
-
<div
|
|
9
|
-
|
|
10
|
-
:key="index"
|
|
11
|
-
class="file-item"
|
|
12
|
-
@click="handleFileClick(file)"
|
|
13
|
-
>
|
|
7
|
+
<div v-else class="file-list-container" :class="{ 'mini-container': size === 'mini' }">
|
|
8
|
+
<div v-for="(file, index) in computedFiles" :key="index" class="file-item"
|
|
9
|
+
:class="{ 'mini-item': size === 'mini' }" @click="handleFileClick(file)">
|
|
14
10
|
<!-- 图片文件直接显示缩略图 -->
|
|
15
11
|
<div v-if="isImage(file.extension)" class="file-icon">
|
|
16
|
-
<t-image
|
|
17
|
-
:
|
|
18
|
-
:alt="file.name"
|
|
19
|
-
fit="cover"
|
|
20
|
-
loading="lazy"
|
|
21
|
-
:style="{ width: imageSize, height: imageSize, borderRadius: '4px' }"
|
|
22
|
-
@error="handleImageError"
|
|
23
|
-
/>
|
|
12
|
+
<t-image :src="file.url" :alt="file.name" fit="cover" loading="lazy"
|
|
13
|
+
:style="{ width: actualImageSize, height: actualImageSize, borderRadius: '4px' }" error="" />
|
|
24
14
|
</div>
|
|
25
|
-
|
|
15
|
+
|
|
26
16
|
<!-- 非图片文件显示图标 -->
|
|
27
17
|
<div v-else class="file-icon">
|
|
28
|
-
<t-icon :name="getFileIcon(file.extension)" :size="
|
|
18
|
+
<t-icon :name="getFileIcon(file.extension)" :size="actualImageSize"
|
|
19
|
+
:style="{ color: getFileColor(file.extension) }" />
|
|
29
20
|
</div>
|
|
30
|
-
|
|
31
|
-
<div class="file-info">
|
|
21
|
+
|
|
22
|
+
<div v-if="size !== 'mini'" class="file-info">
|
|
32
23
|
<div class="file-name" :title="file.name">{{ file.name }}</div>
|
|
33
24
|
<div class="file-meta">
|
|
34
25
|
<span v-if="showFileType" class="file-type">{{ file.extension?.toUpperCase() || '未知' }}</span>
|
|
35
26
|
<span v-if="showFileSize && file.size" class="file-size">{{ formatFileSize(file.size) }}</span>
|
|
36
27
|
</div>
|
|
37
28
|
</div>
|
|
38
|
-
|
|
29
|
+
|
|
39
30
|
<!-- 操作按钮 -->
|
|
40
|
-
<div v-if="showActions" class="file-actions">
|
|
41
|
-
<t-button
|
|
42
|
-
|
|
43
|
-
variant="text"
|
|
44
|
-
@click.stop="handleDownload(file)"
|
|
45
|
-
:title="isImage(file.extension) ? '查看' : '下载'"
|
|
46
|
-
>
|
|
31
|
+
<div v-if="showActions && size !== 'mini'" class="file-actions">
|
|
32
|
+
<t-button size="small" variant="text" @click.stop="handleDownload(file)"
|
|
33
|
+
:title="isImage(file.extension) ? '查看' : '下载'">
|
|
47
34
|
<t-icon :name="isImage(file.extension) ? 'view-list' : 'download'" />
|
|
48
35
|
</t-button>
|
|
49
|
-
<t-button
|
|
50
|
-
|
|
51
|
-
size="small"
|
|
52
|
-
variant="text"
|
|
53
|
-
theme="danger"
|
|
54
|
-
@click.stop="handleDelete(file, index)"
|
|
55
|
-
title="删除"
|
|
56
|
-
>
|
|
36
|
+
<t-button v-if="allowDelete" size="small" variant="text" theme="danger"
|
|
37
|
+
@click.stop="handleDelete(file, index)" title="删除">
|
|
57
38
|
<t-icon name="delete" />
|
|
58
39
|
</t-button>
|
|
59
40
|
</div>
|
|
60
41
|
</div>
|
|
61
42
|
</div>
|
|
62
|
-
|
|
43
|
+
|
|
63
44
|
<!-- 图片预览弹窗 -->
|
|
64
|
-
<t-image-viewer
|
|
65
|
-
|
|
66
|
-
:images="previewImages"
|
|
67
|
-
:index="previewIndex"
|
|
68
|
-
:close-on-esc="true"
|
|
69
|
-
@close="previewVisible = false"
|
|
70
|
-
/>
|
|
45
|
+
<t-image-viewer v-model:visible="previewVisible" :images="previewImages" :index="previewIndex" :close-on-esc="true"
|
|
46
|
+
@close="previewVisible = false" />
|
|
71
47
|
</div>
|
|
72
48
|
</template>
|
|
73
49
|
|
|
@@ -87,6 +63,11 @@ const props = defineProps({
|
|
|
87
63
|
type: [Array, String],
|
|
88
64
|
default: () => []
|
|
89
65
|
},
|
|
66
|
+
// 尺寸大小,支持default和mini
|
|
67
|
+
size: {
|
|
68
|
+
type: String,
|
|
69
|
+
default: 'default'
|
|
70
|
+
},
|
|
90
71
|
// 图片尺寸
|
|
91
72
|
imageSize: {
|
|
92
73
|
type: String,
|
|
@@ -145,18 +126,18 @@ const getFileExtension = (filename) => {
|
|
|
145
126
|
// 提取文件名
|
|
146
127
|
const extractFileName = (url) => {
|
|
147
128
|
if (!url) return '未知文件';
|
|
148
|
-
|
|
129
|
+
|
|
149
130
|
// 移除查询参数和锚点
|
|
150
131
|
const cleanUrl = url.split('?')[0].split('#')[0];
|
|
151
132
|
const parts = cleanUrl.split('/');
|
|
152
133
|
let fileName = parts[parts.length - 1] || '未知文件';
|
|
153
|
-
|
|
134
|
+
|
|
154
135
|
// 如果文件名为空或只是扩展名,生成一个默认名称
|
|
155
136
|
if (!fileName || fileName.startsWith('.')) {
|
|
156
137
|
const extension = getFileExtension(fileName || url);
|
|
157
138
|
fileName = extension ? `文件.${extension}` : '未知文件';
|
|
158
139
|
}
|
|
159
|
-
|
|
140
|
+
|
|
160
141
|
return fileName;
|
|
161
142
|
};
|
|
162
143
|
|
|
@@ -165,7 +146,7 @@ const parseFileInfo = (url) => {
|
|
|
165
146
|
const fullUrl = getFullUrl(url);
|
|
166
147
|
const fileName = extractFileName(url);
|
|
167
148
|
const extension = getFileExtension(fileName);
|
|
168
|
-
|
|
149
|
+
|
|
169
150
|
return {
|
|
170
151
|
name: fileName,
|
|
171
152
|
url: fullUrl,
|
|
@@ -177,12 +158,12 @@ const parseFileInfo = (url) => {
|
|
|
177
158
|
// 计算文件列表
|
|
178
159
|
const computedFiles = computed(() => {
|
|
179
160
|
let fileList = [];
|
|
180
|
-
|
|
161
|
+
|
|
181
162
|
if (typeof props.files === 'string') {
|
|
182
163
|
if (!props.files.trim()) {
|
|
183
164
|
return [];
|
|
184
165
|
}
|
|
185
|
-
|
|
166
|
+
|
|
186
167
|
// 判断是单个URL还是逗号分隔的多个URL
|
|
187
168
|
if (props.files.includes(',')) {
|
|
188
169
|
// 逗号分隔的多个URL
|
|
@@ -219,7 +200,7 @@ const computedFiles = computed(() => {
|
|
|
219
200
|
}
|
|
220
201
|
}).filter(file => file.url); // 过滤掉没有URL的文件
|
|
221
202
|
}
|
|
222
|
-
|
|
203
|
+
|
|
223
204
|
return fileList;
|
|
224
205
|
});
|
|
225
206
|
|
|
@@ -235,7 +216,7 @@ const getFileIcon = (extension) => {
|
|
|
235
216
|
// 文档类
|
|
236
217
|
'pdf': 'file-pdf',
|
|
237
218
|
'doc': 'file-word',
|
|
238
|
-
'docx': 'file-word',
|
|
219
|
+
'docx': 'file-word',
|
|
239
220
|
'xls': 'file-excel',
|
|
240
221
|
'xlsx': 'file-excel',
|
|
241
222
|
'ppt': 'file-powerpoint',
|
|
@@ -263,7 +244,7 @@ const getFileIcon = (extension) => {
|
|
|
263
244
|
'mov': 'file-video',
|
|
264
245
|
'wmv': 'file-video'
|
|
265
246
|
};
|
|
266
|
-
|
|
247
|
+
|
|
267
248
|
return iconMap[extension?.toLowerCase()] || 'file';
|
|
268
249
|
};
|
|
269
250
|
|
|
@@ -283,22 +264,27 @@ const getFileColor = (extension) => {
|
|
|
283
264
|
'mp3': '#FF9800',
|
|
284
265
|
'mp4': '#795548'
|
|
285
266
|
};
|
|
286
|
-
|
|
267
|
+
|
|
287
268
|
return colorMap[extension?.toLowerCase()] || '#666666';
|
|
288
269
|
};
|
|
289
270
|
|
|
271
|
+
// 计算实际使用的图片尺寸
|
|
272
|
+
const actualImageSize = computed(() => {
|
|
273
|
+
return props.size === 'mini' ? '20px' : props.imageSize;
|
|
274
|
+
});
|
|
275
|
+
|
|
290
276
|
// 格式化文件大小
|
|
291
277
|
const formatFileSize = (bytes) => {
|
|
292
278
|
if (!bytes) return '';
|
|
293
279
|
const units = ['B', 'KB', 'MB', 'GB'];
|
|
294
280
|
let size = bytes;
|
|
295
281
|
let unitIndex = 0;
|
|
296
|
-
|
|
282
|
+
|
|
297
283
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
298
284
|
size /= 1024;
|
|
299
285
|
unitIndex++;
|
|
300
286
|
}
|
|
301
|
-
|
|
287
|
+
|
|
302
288
|
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
|
303
289
|
};
|
|
304
290
|
|
|
@@ -317,7 +303,7 @@ const handleDownload = (file) => {
|
|
|
317
303
|
document.body.appendChild(link);
|
|
318
304
|
link.click();
|
|
319
305
|
document.body.removeChild(link);
|
|
320
|
-
|
|
306
|
+
|
|
321
307
|
emit('file-download', file);
|
|
322
308
|
};
|
|
323
309
|
|
|
@@ -327,14 +313,14 @@ const handlePreview = (file) => {
|
|
|
327
313
|
previewImages.value = imageFiles.map(f => f.url);
|
|
328
314
|
previewIndex.value = imageFiles.findIndex(f => f.url === file.url);
|
|
329
315
|
previewVisible.value = true;
|
|
330
|
-
|
|
316
|
+
|
|
331
317
|
emit('file-preview', file);
|
|
332
318
|
};
|
|
333
319
|
|
|
334
320
|
// 文件点击处理
|
|
335
321
|
const handleFileClick = (file) => {
|
|
336
322
|
emit('file-click', file);
|
|
337
|
-
|
|
323
|
+
|
|
338
324
|
if (isImage(file.extension)) {
|
|
339
325
|
// 图片文件,显示预览
|
|
340
326
|
handlePreview(file);
|
|
@@ -361,7 +347,16 @@ const handleImageError = () => {
|
|
|
361
347
|
<style lang="less" scoped>
|
|
362
348
|
.ebiz-file-list {
|
|
363
349
|
width: 100%;
|
|
364
|
-
|
|
350
|
+
|
|
351
|
+
&.mini-mode {
|
|
352
|
+
.file-list-container {
|
|
353
|
+
display: flex;
|
|
354
|
+
flex-direction: row;
|
|
355
|
+
flex-wrap: wrap;
|
|
356
|
+
gap: 4px;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
365
360
|
.empty-state {
|
|
366
361
|
display: flex;
|
|
367
362
|
flex-direction: column;
|
|
@@ -369,19 +364,24 @@ const handleImageError = () => {
|
|
|
369
364
|
justify-content: center;
|
|
370
365
|
padding: 40px;
|
|
371
366
|
color: #999;
|
|
372
|
-
|
|
367
|
+
|
|
373
368
|
p {
|
|
374
369
|
margin: 8px 0 0 0;
|
|
375
370
|
font-size: 14px;
|
|
376
371
|
}
|
|
377
372
|
}
|
|
378
|
-
|
|
373
|
+
|
|
379
374
|
.file-list-container {
|
|
380
375
|
display: flex;
|
|
381
376
|
flex-direction: column;
|
|
382
377
|
gap: 8px;
|
|
378
|
+
|
|
379
|
+
&.mini-container {
|
|
380
|
+
flex-direction: row;
|
|
381
|
+
flex-wrap: wrap;
|
|
382
|
+
}
|
|
383
383
|
}
|
|
384
|
-
|
|
384
|
+
|
|
385
385
|
.file-item {
|
|
386
386
|
display: flex;
|
|
387
387
|
align-items: center;
|
|
@@ -391,31 +391,49 @@ const handleImageError = () => {
|
|
|
391
391
|
cursor: pointer;
|
|
392
392
|
transition: all 0.3s;
|
|
393
393
|
background: #fff;
|
|
394
|
-
|
|
394
|
+
|
|
395
|
+
&.mini-item {
|
|
396
|
+
padding: 0;
|
|
397
|
+
border: none;
|
|
398
|
+
background: transparent;
|
|
399
|
+
box-shadow: none;
|
|
400
|
+
margin-right: 8px;
|
|
401
|
+
margin-bottom: 8px;
|
|
402
|
+
|
|
403
|
+
&:hover {
|
|
404
|
+
border-color: transparent;
|
|
405
|
+
box-shadow: none;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
395
409
|
&:hover {
|
|
396
410
|
border-color: #0052d9;
|
|
397
411
|
box-shadow: 0 2px 8px rgba(0, 82, 217, 0.15);
|
|
398
|
-
|
|
412
|
+
|
|
399
413
|
.file-actions {
|
|
400
414
|
opacity: 1;
|
|
401
415
|
}
|
|
402
416
|
}
|
|
403
417
|
}
|
|
404
|
-
|
|
418
|
+
|
|
405
419
|
.file-icon {
|
|
406
420
|
margin-right: 12px;
|
|
407
421
|
flex-shrink: 0;
|
|
408
422
|
display: flex;
|
|
409
423
|
align-items: center;
|
|
410
424
|
justify-content: center;
|
|
411
|
-
width: v-bind(
|
|
412
|
-
height: v-bind(
|
|
425
|
+
width: v-bind(actualImageSize);
|
|
426
|
+
height: v-bind(actualImageSize);
|
|
427
|
+
|
|
428
|
+
.mini-item & {
|
|
429
|
+
margin-right: 0;
|
|
430
|
+
}
|
|
413
431
|
}
|
|
414
|
-
|
|
432
|
+
|
|
415
433
|
.file-info {
|
|
416
434
|
flex: 1;
|
|
417
435
|
min-width: 0;
|
|
418
|
-
|
|
436
|
+
|
|
419
437
|
.file-name {
|
|
420
438
|
font-size: 14px;
|
|
421
439
|
font-weight: 500;
|
|
@@ -425,11 +443,11 @@ const handleImageError = () => {
|
|
|
425
443
|
text-overflow: ellipsis;
|
|
426
444
|
white-space: nowrap;
|
|
427
445
|
}
|
|
428
|
-
|
|
446
|
+
|
|
429
447
|
.file-meta {
|
|
430
448
|
display: flex;
|
|
431
449
|
gap: 8px;
|
|
432
|
-
|
|
450
|
+
|
|
433
451
|
.file-size,
|
|
434
452
|
.file-type {
|
|
435
453
|
font-size: 12px;
|
|
@@ -437,7 +455,7 @@ const handleImageError = () => {
|
|
|
437
455
|
}
|
|
438
456
|
}
|
|
439
457
|
}
|
|
440
|
-
|
|
458
|
+
|
|
441
459
|
.file-actions {
|
|
442
460
|
display: flex;
|
|
443
461
|
gap: 4px;
|
|
@@ -446,6 +464,4 @@ const handleImageError = () => {
|
|
|
446
464
|
flex-shrink: 0;
|
|
447
465
|
}
|
|
448
466
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
</style>
|
|
467
|
+
</style>
|