syntec3-0-ui-components-test 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 (99) hide show
  1. package/README.md +5 -0
  2. package/dist/S3_0UC_main.csv +4 -0
  3. package/dist/S3_0UC_sub.csv +2 -0
  4. package/dist/globalVariableS3_0UC.json +1 -0
  5. package/dist/style.css +1 -0
  6. package/dist/syntec3-0-ui-components.es.js +19518 -0
  7. package/dist/syntec3-0-ui-components.es.js.map +1 -0
  8. package/dist/syntec3-0-ui-components.umd.js +23 -0
  9. package/dist/syntec3-0-ui-components.umd.js.map +1 -0
  10. package/dist/vite.svg +1 -0
  11. package/dist/web.config +17 -0
  12. package/package.json +137 -0
  13. package/src/App.vue +31 -0
  14. package/src/assets/fonts/genYoGothicTW-normal.js +7 -0
  15. package/src/assets/image/defaultImage.png +0 -0
  16. package/src/assets/vue.svg +1 -0
  17. package/src/components/Layout/modules/fullPageGlobal.vue +113 -0
  18. package/src/components/Layout/modules/viewFile/config.js +65 -0
  19. package/src/components/Layout/modules/viewFile/createView.vue +1000 -0
  20. package/src/components/Layout/modules/viewFile/filterCriteria.vue +816 -0
  21. package/src/components/Layout/modules/viewFile/viewList.vue +291 -0
  22. package/src/components/Layout/modules/viewFile/viewManageTool.js +271 -0
  23. package/src/components/Layout/modules/viewFile/viewRecord.vue +472 -0
  24. package/src/components/Layout/modules/viewFile/viewTabs.vue +542 -0
  25. package/src/components/Layout/tools/GlobalDialog.vue +115 -0
  26. package/src/components/Pagination.vue +139 -0
  27. package/src/components/columnConfigNext.vue +273 -0
  28. package/src/components/customFilter/customFilter.vue +492 -0
  29. package/src/components/customFilter/filterCriteria.vue +769 -0
  30. package/src/components/customTable/components/headerOperation/index.vue +136 -0
  31. package/src/components/customTable/components/headerTabs/index.vue +171 -0
  32. package/src/components/customTable/components/tableContent/index.vue +440 -0
  33. package/src/components/customTable/index.vue +305 -0
  34. package/src/components/dialog.vue +85 -0
  35. package/src/components/pageContent.vue +48 -0
  36. package/src/components/popover.vue +402 -0
  37. package/src/configFiles/apiFile/baseApiList.json +11 -0
  38. package/src/configFiles/apiFile/coreApiList.json +24 -0
  39. package/src/configFiles/apiFile/mesApiList.json +4 -0
  40. package/src/configFiles/apiFile/mmsApiList.json +3 -0
  41. package/src/configFiles/errorCode.json +291 -0
  42. package/src/configFiles/version.js +2 -0
  43. package/src/i18n/lang/en-us.json +2060 -0
  44. package/src/i18n/lang/errorCodeTranslate.mjs +847 -0
  45. package/src/i18n/lang/zh-cn.json +2062 -0
  46. package/src/i18n/lang/zh-tw.json +2059 -0
  47. package/src/index.js +115 -0
  48. package/src/main.js +51 -0
  49. package/src/plugins/excel.js +88 -0
  50. package/src/router/index.js +41 -0
  51. package/src/scriptFiles/apiConfig/baseApis.js +10 -0
  52. package/src/scriptFiles/apiConfig/mesApis.js +10 -0
  53. package/src/scriptFiles/apiConfig/mmsApis.js +10 -0
  54. package/src/scriptFiles/apiConfig/privateCloudCoreApis.js +13 -0
  55. package/src/scriptFiles/apiConfig/serviceRoute.js +23 -0
  56. package/src/scriptFiles/apis/baseApiFunction.js +63 -0
  57. package/src/scriptFiles/apis/mesApiFunction.js +15 -0
  58. package/src/scriptFiles/apis/mmsApiFunction.js +9 -0
  59. package/src/scriptFiles/apis/privateCloudCoreApiFunction.js +101 -0
  60. package/src/scriptFiles/backendApiFunction.js +11 -0
  61. package/src/scriptFiles/checkApiErrorMechanism.js +137 -0
  62. package/src/scriptFiles/common/objectDataProcessing.js +65 -0
  63. package/src/scss/base/commom.scss +1068 -0
  64. package/src/scss/base/dialog.scss +45 -0
  65. package/src/scss/base/index.scss +3 -0
  66. package/src/scss/base/table.scss +28 -0
  67. package/src/store/index.js +25 -0
  68. package/src/store/module/langStore.js +116 -0
  69. package/src/style.css +52 -0
  70. package/src/utils/excel.js +86 -0
  71. package/src/utils/formula.js +69 -0
  72. package/src/utils/https.js +13 -0
  73. package/src/utils/i18n.js +42 -0
  74. package/src/utils/shiftSelect.js +164 -0
  75. package/src/utils/summation.js +77 -0
  76. package/src/utils/tableWidth.js +29 -0
  77. package/src/utils/toolFun.js +93 -0
  78. package/src/views/productionWorkOrder/components/columnConfig.vue +242 -0
  79. package/src/views/productionWorkOrder/components/docCustomFieldForm.vue +739 -0
  80. package/src/views/productionWorkOrder/components/filePreview.vue +148 -0
  81. package/src/views/productionWorkOrder/components/querySearch.vue +363 -0
  82. package/src/views/productionWorkOrder/configFiles/excelImportErrorCode.json +94 -0
  83. package/src/views/productionWorkOrder/configFiles/pdfDefaultConfig.js +933 -0
  84. package/src/views/productionWorkOrder/configFiles/planMakingScript.js +600 -0
  85. package/src/views/productionWorkOrder/configFiles/productionRelatedScript.js +368 -0
  86. package/src/views/productionWorkOrder/configFiles/rulse.js +23 -0
  87. package/src/views/productionWorkOrder/configFiles/status.js +50 -0
  88. package/src/views/productionWorkOrder/index.vue +2174 -0
  89. package/src/views/productionWorkOrder/productionFlowLabel/component/addCirculationLabel.vue +394 -0
  90. package/src/views/productionWorkOrder/productionFlowLabel/component/circulationLabelTable.vue +124 -0
  91. package/src/views/productionWorkOrder/productionFlowLabel/component/materialPartFilePreview.vue +167 -0
  92. package/src/views/productionWorkOrder/productionFlowLabel/component/workOrderInformation.vue +28 -0
  93. package/src/views/productionWorkOrder/productionFlowLabel/index.vue +604 -0
  94. package/src/views/production_work_order/components/priorityTooltip.vue +53 -0
  95. package/src/views/production_work_order/index.vue +1307 -0
  96. package/src/views/review_record/components/materialInfo.vue +50 -0
  97. package/src/views/review_record/components/rootCause.vue +42 -0
  98. package/src/views/review_record/components/workDetail.vue +115 -0
  99. package/src/views/review_record/index.vue +884 -0
@@ -0,0 +1,739 @@
1
+ <template>
2
+ <el-form ref="cfForm" :model="formData" label-width="auto" data-test-id="EL-FORM-77wT2R">
3
+ <el-row :gutter="2" data-test-id="EL-ROW-9p85J9">
4
+ <el-col v-for="(item, index) in formData" :key="item[itemId]" :span="12" data-test-id="EL-COL-MLQi95">
5
+ <el-form-item :prop="String(item[itemId])" :rules="getRules(item)" data-test-id="EL-FORM-ITEM-U79ddx">
6
+ <template #label>
7
+ <el-tooltip
8
+ v-if="item[itemName].length > 10"
9
+ effect="dark"
10
+ :content="item[itemName]"
11
+ placement="top"
12
+ data-test-id="EL-TOOLTIP-Z5VtdY"
13
+ >
14
+ <template #default>
15
+ <span v-if="item[itemRequired]" data-test-id="SPAN-XoJ0Jg">
16
+ <span style="color: #f56c6c" data-test-id="SPAN-1QZ2GD">* </span>
17
+ {{ `${item[itemName].slice(0, 10)}...` }}
18
+ </span>
19
+ <span v-else data-test-id="SPAN-tE51QL">{{ `${item[itemName].slice(0, 10)}...` }}</span>
20
+ </template>
21
+ </el-tooltip>
22
+ <span v-else data-test-id="SPAN-Jjoz0y">
23
+ <span v-if="item[itemRequired]" style="color: #f56c6c" data-test-id="SPAN-vPBYAF">* </span>
24
+ {{ item[itemName] }}
25
+ </span>
26
+ </template>
27
+ <!-- 文本 -->
28
+ <el-input
29
+ v-if="getType(item[itemTypeId]) === 'text'"
30
+ v-model="item.value"
31
+ :placeholder="item[itemPlaceholder]"
32
+ maxlength="50"
33
+ clearable
34
+ show-word-limit
35
+ data-test-id="EL-INPUT-KUCjOh"
36
+ />
37
+ <!-- 数字 -->
38
+ <el-input
39
+ v-if="getType(item[itemTypeId]) === 'number'"
40
+ v-model="item.value"
41
+ :placeholder="item[itemPlaceholder]"
42
+ maxlength="15"
43
+ type="number"
44
+ clearable
45
+ show-word-limit
46
+ data-test-id="EL-INPUT-JIdFTM"
47
+ />
48
+ <!-- 日期 -->
49
+ <el-date-picker
50
+ v-if="getType(item[itemTypeId]) === 'date'"
51
+ v-model="item.value"
52
+ :placeholder="item[itemPlaceholder]"
53
+ type="datetime"
54
+ clearable
55
+ show-word-limit
56
+ style="width: 100%"
57
+ data-test-id="EL-DATE-PICKER-kUWAoM"
58
+ />
59
+ <!-- 日期区间 -->
60
+ <el-date-picker
61
+ v-if="getType(item[itemTypeId]) === 'dateRange'"
62
+ v-model="item.value"
63
+ :placeholder="item[itemPlaceholder]"
64
+ type="datetimerange"
65
+ clearable
66
+ show-word-limit
67
+ style="width: 100%"
68
+ data-test-id="EL-DATE-PICKER-KCacHl"
69
+ />
70
+ <!-- 附件 -->
71
+ <div v-if="getType(item[itemTypeId]) === 'attachment'" data-test-id="DIV-mCZ1Au">
72
+ <el-upload
73
+ ref="uploadRef"
74
+ v-model="item.value"
75
+ class="upload-attachment"
76
+ clearable
77
+ drag
78
+ :on-change="
79
+ (file) => {
80
+ uploadHandleChange(file, item, index);
81
+ }
82
+ "
83
+ :auto-upload="false"
84
+ :show-file-list="false"
85
+ data-test-id="EL-UPLOAD-DCMYwD"
86
+ >
87
+ <el-icon class="el-icon--upload" data-test-id="EL-ICON-xlUkii"><upload-filled data-test-id="UPLOAD-FILLED-6OLhtP"/></el-icon>
88
+ <div class="el-upload__text" data-test-id="DIV-z3CeRc">
89
+ {{ t('dragFileHereOr') }} <em data-test-id="EM-rxmE2t">{{ t('clickToUpload') }}</em>
90
+ </div>
91
+ </el-upload>
92
+ <div data-test-id="DIV-S68oYj">
93
+ <div v-for="ite in item.value" :key="ite.uid" class="file-list-show-text" data-test-id="DIV-iOW1Zp">
94
+ <span class="mdi mdi-file-document-outline mr-2" data-test-id="SPAN-FBYDht" />
95
+ <el-tooltip effect="dark" :content="ite.name" placement="bottom" data-test-id="EL-TOOLTIP-Woq2U9">
96
+ <span class="ellipsis-single-line file-list-show-text-name" data-test-id="SPAN-4qgDqO">{{
97
+ ite.name
98
+ }}</span>
99
+ </el-tooltip>
100
+ <span
101
+ v-if="isShowViewIconFun(ite)"
102
+ class="mdi mdi-eye eye-icon"
103
+ data-test-id="SPAN-Ug65md"
104
+ @click="viewFileItem(ite, item)"
105
+ />
106
+ <span
107
+ v-if="!isShowViewIconFun(ite)"
108
+ class="mdi mdi-arrow-down down-icon"
109
+ data-test-id="SPAN-rv5p9U"
110
+ @click="dowFileItem(ite, item)"
111
+ />
112
+ <span class="mdi mdi-close close-icon" data-test-id="SPAN-M144mc" @click="clearFileItem(ite, index)" />
113
+ </div>
114
+ </div>
115
+ </div>
116
+ <!-- 超链接 -->
117
+ <el-input
118
+ v-if="getType(item[itemTypeId]) === 'hyperLink'"
119
+ v-model="item.value"
120
+ :placeholder="item[itemPlaceholder]"
121
+ maxlength="200"
122
+ clearable
123
+ show-word-limit
124
+ data-test-id="EL-INPUT-3CIGMF"
125
+ />
126
+ <!-- 单选框 -->
127
+ <el-select
128
+ v-if="getType(item[itemTypeId]) === 'radio'"
129
+ v-model="item.value"
130
+ :placeholder="item[itemPlaceholder]"
131
+ clearable
132
+ show-word-limit
133
+ data-test-id="EL-SELECT-fij3Bf"
134
+ >
135
+ <el-option
136
+ v-for="(ite, ind) in getArrOfJSONStr(item.fieldSelectOptions)"
137
+ :key="ind"
138
+ :label="ite"
139
+ :value="ite"
140
+ :data-test-id="`EL-OPTION-1BmHu8${ind}`"
141
+ />
142
+ </el-select>
143
+ <!-- 多选框 -->
144
+ <el-select
145
+ v-if="getType(item[itemTypeId]) === 'checkBox'"
146
+ v-model="item.value"
147
+ multiple
148
+ :placeholder="item[itemPlaceholder]"
149
+ clearable
150
+ collapse-tags
151
+ collapse-tags-tooltip
152
+ :max-collapse-tags="2"
153
+ show-word-limit
154
+ data-test-id="EL-SELECT-56o5LQ"
155
+ >
156
+ <el-option
157
+ v-for="(ite, ind) in getArrOfJSONStr(item.fieldSelectOptions)"
158
+ :key="ind"
159
+ :label="ite"
160
+ :value="ite"
161
+ :data-test-id="`EL-OPTION-zcSCz5${ind}`"
162
+ />
163
+ </el-select>
164
+ </el-form-item>
165
+ </el-col>
166
+ </el-row>
167
+ <el-image-viewer
168
+ v-if="showImage"
169
+ hide-on-click-modal
170
+ :url-list="[imageSrc]"
171
+ data-test-id="EL-IMAGE-VIEWER-gDQR71"
172
+ @close="
173
+ () => {
174
+ showImage = false;
175
+ }
176
+ "
177
+ />
178
+ </el-form>
179
+ </template>
180
+
181
+ <script>
182
+ import { ref, watch } from 'vue';
183
+ import { useI18n } from 'vue-i18n';
184
+ import dayjs from 'dayjs';
185
+ import { UploadFilled } from '@element-plus/icons-vue';
186
+ import apiFunction from '@/scriptFiles/checkApiErrorMechanism.js';
187
+ import { ElLoading, ElMessage } from 'element-plus';
188
+ import toolFun from '@/utils/toolFun.js';
189
+
190
+ export default {
191
+ props: {
192
+ isEdit: {
193
+ type: Boolean,
194
+ default: false,
195
+ },
196
+ items: {
197
+ type: Array,
198
+ default: () => [],
199
+ },
200
+ cols: {
201
+ type: Number,
202
+ default: 4,
203
+ },
204
+ outlined: {
205
+ type: Boolean,
206
+ default: false,
207
+ },
208
+ itemId: {
209
+ type: String,
210
+ default: 'customFieldId',
211
+ },
212
+ itemName: {
213
+ type: String,
214
+ default: 'customFieldName',
215
+ },
216
+ itemTypeId: {
217
+ type: String,
218
+ default: 'fieldTypeId',
219
+ },
220
+ itemPlaceholder: {
221
+ type: String,
222
+ default: 'placeHolder',
223
+ },
224
+ itemEnable: {
225
+ type: String,
226
+ default: 'isEnable',
227
+ },
228
+ itemRequired: {
229
+ type: String,
230
+ default: 'fieldProperty',
231
+ },
232
+ },
233
+ components: {
234
+ UploadFilled,
235
+ },
236
+ setup(props, { expose }) {
237
+ const { t } = useI18n();
238
+ const cfForm = ref(null);
239
+ const formData = ref([]);
240
+ const uploadFileMaxSize = 20 * 1024 * 1024; // 设置最大文件大小为20MB
241
+ const uploadRef = ref(null);
242
+ const customFieldIdConfig = [
243
+ {
244
+ id: 1,
245
+ type: 'text',
246
+ },
247
+ {
248
+ id: 2,
249
+ type: 'number',
250
+ },
251
+ {
252
+ id: 3,
253
+ type: 'date',
254
+ },
255
+ {
256
+ id: 4,
257
+ type: 'dateRange',
258
+ },
259
+ {
260
+ id: 5,
261
+ type: 'attachment',
262
+ },
263
+ {
264
+ id: 6,
265
+ type: 'hyperLink',
266
+ },
267
+ {
268
+ id: 7,
269
+ type: 'radio',
270
+ },
271
+ {
272
+ id: 8,
273
+ type: 'checkBox',
274
+ },
275
+ ];
276
+ /**
277
+ * loading加载框方法
278
+ * @param {boolean} type 类型:true->打开,false->关闭
279
+ */
280
+ function loadingFun(type = false) {
281
+ const loading = ElLoading.service({
282
+ lock: true,
283
+ text: '',
284
+ background: 'rgba(255, 255, 255, 0.7)',
285
+ });
286
+ if (!type) {
287
+ loading.close();
288
+ }
289
+ }
290
+ function getType(id) {
291
+ return customFieldIdConfig.find((item) => item.id === id)?.type;
292
+ }
293
+ function getRules(item) {
294
+ return [
295
+ {
296
+ validator: (rule, val, callback) => {
297
+ const v = item.value;
298
+ if (typeof v === 'string' && v !== v.trim()) {
299
+ callback(t('haveSpace'));
300
+ }
301
+ if (getType(item[props.itemTypeId]) !== 'text' && v !== null && v !== '' && v?.length > 50) {
302
+ callback(t('strLengthLimit50'));
303
+ }
304
+ if (item[props.itemRequired] && getType(item[props.itemTypeId]) !== 'attachment') {
305
+ if (!v && (v !== 0 || v?.length === 0)) {
306
+ callback(t('requiredField'));
307
+ }
308
+ if (Array.isArray(v) && Object.keys(v)?.length === 0) {
309
+ callback(t('requiredField'));
310
+ }
311
+ }
312
+ if (getType(item[props.itemTypeId]) === 'number') {
313
+ if (v !== null && v !== '' && v?.toString()?.length > 15) {
314
+ callback(t('strLengthLimit15'));
315
+ }
316
+ if (!/^-?\d+(\.\d+)?$/.test(v) && v !== '' && v !== null) {
317
+ callback(t('mustNumber'));
318
+ }
319
+ }
320
+ if (v !== null && v !== '' && getType(item[props.itemTypeId]) === 'hyperLink') {
321
+ if (v?.toString()?.length > 200) {
322
+ callback(t('strLengthLimit200'));
323
+ }
324
+ // 使用正则表达式来校验URL
325
+ if (!toolFun.isValidURL(v)) {
326
+ callback(t('pleaseEnterQualifiedHyperlink'));
327
+ }
328
+ }
329
+ callback();
330
+ },
331
+ trigger: ['blur', 'change'],
332
+ },
333
+ ];
334
+ }
335
+ function getItemValue(item) {
336
+ let returnValue = null;
337
+ if (!item.value && item.value !== 0) {
338
+ return returnValue;
339
+ }
340
+ switch (getType(item[props.itemTypeId])) {
341
+ case 'date':
342
+ returnValue = dayjs(JSON.parse(item.value)).format('YYYY-MM-DD HH:mm:ss');
343
+ break;
344
+ case 'dateRange':
345
+ returnValue = JSON.parse(item.value);
346
+ break;
347
+ case 'attachment':
348
+ if (props.isEdit) {
349
+ returnValue = item.fileData?.map((ite) => ({
350
+ ...ite,
351
+ name: ite.fileName,
352
+ }));
353
+ } else {
354
+ returnValue = item.value;
355
+ }
356
+ break;
357
+ case 'checkBox':
358
+ returnValue = JSON.parse(item.value);
359
+ break;
360
+ default:
361
+ returnValue = item.value || null;
362
+ break;
363
+ }
364
+ return returnValue;
365
+ }
366
+ function formatItemValue(item) {
367
+ let returnValue = null;
368
+ switch (getType(item[props.itemTypeId])) {
369
+ case 'date':
370
+ if (item.value) {
371
+ returnValue = Number(dayjs(item.value).format('x'));
372
+ } else {
373
+ returnValue = null;
374
+ }
375
+ break;
376
+ case 'dateRange':
377
+ if (item.value?.length) {
378
+ returnValue = JSON.stringify([
379
+ Number(dayjs(item.value[0]).format('x')),
380
+ Number(dayjs(item.value[0]).format('x')),
381
+ ]);
382
+ } else {
383
+ returnValue = [];
384
+ }
385
+ break;
386
+ case 'attachment':
387
+ if (item.value?.length) {
388
+ returnValue = JSON.stringify(item.value);
389
+ } else {
390
+ returnValue = null;
391
+ }
392
+ break;
393
+ case 'checkBox':
394
+ if (item.value?.length) {
395
+ returnValue = JSON.stringify(item.value);
396
+ } else {
397
+ returnValue = null;
398
+ }
399
+ break;
400
+ default:
401
+ returnValue = item.value;
402
+ break;
403
+ }
404
+ return returnValue;
405
+ }
406
+ /**
407
+ * 检验附件必填方法
408
+ */
409
+ function inspectionAttachmentsAreRequired() {
410
+ const attachmentArr = formData.value.filter((item) => item.fieldTypeId === 5);
411
+ if (attachmentArr.length) {
412
+ let flag = false;
413
+ for (let index = 0; index < attachmentArr.length; index += 1) {
414
+ const ite = attachmentArr[index];
415
+ if (ite.fieldProperty) {
416
+ if (!ite.value) {
417
+ flag = true;
418
+ break;
419
+ }
420
+ if (!ite.value?.length) {
421
+ flag = true;
422
+ break;
423
+ }
424
+ }
425
+ }
426
+ if (flag) {
427
+ return false;
428
+ }
429
+ }
430
+ return true;
431
+ }
432
+ async function getData() {
433
+ let cfFormValidate = false;
434
+ const flag = inspectionAttachmentsAreRequired();
435
+ await cfForm.value?.validate((valid) => {
436
+ if (valid) {
437
+ cfFormValidate = true;
438
+ if (!flag) {
439
+ cfFormValidate = false;
440
+ ElMessage.error(t('pleaseCheckUploaded'));
441
+ }
442
+ } else {
443
+ cfFormValidate = false;
444
+ }
445
+ });
446
+ if (cfFormValidate) {
447
+ return JSON.parse(
448
+ JSON.stringify(
449
+ formData.value.map((item) => ({
450
+ ...item,
451
+ value: formatItemValue(item),
452
+ })),
453
+ ),
454
+ );
455
+ }
456
+ return false;
457
+ }
458
+ expose({ getData });
459
+ watch(
460
+ () => props.items,
461
+ () => {
462
+ formData.value = JSON.parse(
463
+ JSON.stringify(
464
+ props.items.map((item) => ({
465
+ ...item,
466
+ value: getItemValue(item),
467
+ })),
468
+ ),
469
+ );
470
+ },
471
+ {
472
+ immediate: true,
473
+ deep: true,
474
+ },
475
+ );
476
+ /**
477
+ * JSON字符串序列话方法
478
+ * @param {string} JSONStr JSON字符串
479
+ */
480
+ function getArrOfJSONStr(JSONStr) {
481
+ if (JSONStr) {
482
+ return JSON.parse(JSONStr);
483
+ }
484
+ return [];
485
+ }
486
+
487
+ /**
488
+ * 附件上传接口
489
+ * @param {file} uploadFile 当前上传的附件
490
+ * @param {object} customItem 自定义字段对象
491
+ * @param {number} index 自定义字段索引
492
+ */
493
+ async function uploadHandleChange(uploadFile, customItem, index) {
494
+ loadingFun(true);
495
+ if (formData.value[index].value?.length === 5) {
496
+ ElMessage.error(t('numberUploadsCannotExceed5'));
497
+ loadingFun(false);
498
+ return;
499
+ }
500
+ // 在这里可以进行文件验证
501
+ const isLt20MB = uploadFile.size < uploadFileMaxSize;
502
+ if (!isLt20MB) {
503
+ ElMessage.error(t('uploadFileSize20MB'));
504
+ loadingFun(false);
505
+ } else {
506
+ const params = {
507
+ DocCode: 'doc_5',
508
+ DocCustomId: customItem.customFieldId,
509
+ file: {
510
+ file: uploadFile.raw,
511
+ },
512
+ };
513
+ await apiFunction
514
+ .docCustomUpload(params)
515
+ .then((res) => {
516
+ loadingFun(false);
517
+ if (res.data.code === 0) {
518
+ ElMessage.success(t('uploadSuccess'));
519
+ if (!formData.value[index].value) {
520
+ formData.value[index].value = [];
521
+ }
522
+ formData.value[index].value.push({
523
+ ...uploadFile,
524
+ fileId: res.data.content.fileID,
525
+ });
526
+ } else {
527
+ ElMessage.error(t(res.data.message));
528
+ }
529
+ })
530
+ .catch(() => {
531
+ loadingFun(false);
532
+ ElMessage.error(t('apiError'));
533
+ });
534
+ }
535
+ loadingFun(false);
536
+ }
537
+ /**
538
+ * 下载附件序列化方法
539
+ * @param {string} fileName 文件名
540
+ * @param {object} res 请求响应对象
541
+ */
542
+ function fileDownSerialize(fileName, res) {
543
+ // 创建一个 Blob URL 指向这个 Blob 对象
544
+ const url = window.URL.createObjectURL(new Blob([res.data], { type: res.headers['content-type'] }));
545
+
546
+ // 创建一个临时的 <a> 元素
547
+ const link = document.createElement('a');
548
+ link.href = url;
549
+
550
+ // 设置下载的文件名(可选,但推荐)
551
+ // 如果服务器没有在响应头中提供 Content-Disposition,你需要手动设置文件名
552
+ link.setAttribute('download', fileName);
553
+
554
+ // 将 <a> 元素添加到文档中(不需要真正添加到可视区域)
555
+ document.body.appendChild(link);
556
+
557
+ // 触发点击事件以下载文件
558
+ link.click();
559
+
560
+ // 释放 Blob URL(可选,但推荐)
561
+ // 注意:这应该在确保文件下载已经开始之后进行,否则在某些浏览器中可能会导致下载失败
562
+ setTimeout(() => {
563
+ window.URL.revokeObjectURL(url);
564
+ document.body.removeChild(link);
565
+ }, 0);
566
+ }
567
+ // 控制是否打开预览图片插件
568
+ const showImage = ref(false);
569
+ // 预览图片地址
570
+ const imageSrc = ref('');
571
+ /**
572
+ * 图片预览方法
573
+ * @param {object} item 附件对象
574
+ * @param {object} outItem 自定义字段对象
575
+ */
576
+ async function viewFileItem(item, outItem) {
577
+ const data = {
578
+ docCode: 'doc_5',
579
+ docCustomId: outItem.docCustomId,
580
+ fileId: item.fileId,
581
+ };
582
+ const fileExtension = item.name.toLowerCase().split('.').pop();
583
+ await apiFunction
584
+ .docViewFile(data)
585
+ .then((res) => {
586
+ loadingFun(false);
587
+ if (res.data.code === 0) {
588
+ imageSrc.value = `data:image/${fileExtension};base64,${res.data.content.fileContent}`;
589
+ showImage.value = true;
590
+ } else {
591
+ ElMessage.error(t('apiError'));
592
+ }
593
+ })
594
+ .catch(() => {
595
+ loadingFun(false);
596
+ ElMessage.error(t('apiError'));
597
+ });
598
+ }
599
+ /**
600
+ * 附件下载方法
601
+ * @param {object} item 附件对象
602
+ * @param {object} outItem 自定义字段对象
603
+ */
604
+ async function dowFileItem(item, outItem) {
605
+ loadingFun(true);
606
+ const fileName = item.name;
607
+ if (item) {
608
+ const data = {
609
+ docCode: 'doc_5',
610
+ docCustomId: outItem.docCustomId,
611
+ fileId: item.fileId,
612
+ };
613
+ await apiFunction
614
+ .docDownloadFile(data)
615
+ .then((res) => {
616
+ loadingFun(false);
617
+ if (res.status === 200) {
618
+ fileDownSerialize(fileName, res);
619
+ ElMessage.success(t('downloadSuccessful'));
620
+ } else {
621
+ ElMessage.error(t('apiError'));
622
+ }
623
+ })
624
+ .catch(() => {
625
+ loadingFun(false);
626
+ ElMessage.error(t('apiError'));
627
+ });
628
+ }
629
+ loadingFun(false);
630
+ }
631
+ /**
632
+ * 删除附件方法
633
+ * @param {object} item 附件对象
634
+ * @param {number} index 自定义字段索引
635
+ */
636
+ function clearFileItem(item, index) {
637
+ formData.value[index].value = formData.value[index].value.filter((ite) => ite.fileId !== item.fileId);
638
+ }
639
+ /**
640
+ * 附件是否是图片标识方法
641
+ * @param {object} item 附件对象
642
+ */
643
+ function isShowViewIconFun(item) {
644
+ const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'jfif'];
645
+ const fileExtension = item.name.toLowerCase().split('.').pop();
646
+ return imageExtensions.includes(fileExtension);
647
+ }
648
+ return {
649
+ t,
650
+ formData,
651
+ cfForm,
652
+ getType,
653
+ getRules,
654
+ getArrOfJSONStr,
655
+ uploadHandleChange,
656
+ uploadRef,
657
+ clearFileItem,
658
+ dowFileItem,
659
+ viewFileItem,
660
+ isShowViewIconFun,
661
+ showImage,
662
+ imageSrc,
663
+ };
664
+ },
665
+ };
666
+ </script>
667
+
668
+ <style lang="scss" scoped>
669
+ ::v-deep.upload-attachment {
670
+ .el-upload.el-upload--text.is-drag {
671
+ padding: 0;
672
+ width: 10rem;
673
+ height: 10rem;
674
+ .el-upload-dragger {
675
+ padding: 0;
676
+ width: 10rem;
677
+ height: 10rem;
678
+ .el-icon--upload {
679
+ width: 2rem;
680
+ margin: 0;
681
+ line-height: 2rem;
682
+ }
683
+ .el-upload__text {
684
+ line-height: 2rem;
685
+ }
686
+ }
687
+ }
688
+ }
689
+ .file-list-show-text {
690
+ position: relative;
691
+ color: rgb(96, 98, 102);
692
+ padding-left: 5px;
693
+ margin-bottom: 5px;
694
+ box-sizing: border-box;
695
+ .file-list-show-text-name {
696
+ display: inline-block;
697
+ vertical-align: top;
698
+ width: 75%;
699
+ }
700
+ }
701
+ .file-list-show-text:hover {
702
+ background-color: rgb(245, 247, 250);
703
+ border-radius: 4px;
704
+ .eye-icon,
705
+ .down-icon,
706
+ .close-icon {
707
+ opacity: 1;
708
+ }
709
+ }
710
+ .eye-icon,
711
+ .close-icon,
712
+ .down-icon {
713
+ position: absolute;
714
+ cursor: pointer;
715
+ right: 0;
716
+ margin: 0 0 0 5px;
717
+ opacity: 0;
718
+ }
719
+ .eye-icon {
720
+ margin-right: 5px;
721
+ right: 20px;
722
+ }
723
+ .close-icon {
724
+ margin-right: 5px;
725
+ }
726
+ .down-icon {
727
+ right: 20px;
728
+ }
729
+ .eye-icon:hover,
730
+ .down-icon:hover,
731
+ .close-icon:hover {
732
+ color: rgb(64, 158, 255);
733
+ }
734
+ .ellipsis-single-line {
735
+ white-space: nowrap; /* 禁止换行 */
736
+ overflow: hidden; /* 隐藏超出内容 */
737
+ text-overflow: ellipsis; /* 显示省略号 */
738
+ }
739
+ </style>