sohelp-eleplus 1.1.24 → 1.1.25
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/http/SohelpHttp.js +21 -21
- package/package.json +1 -1
- package/sohelp-grid/index.vue +122 -107
- package/sohelp-grid/js/DefaultGridOptions.js +1 -1
- package/sohelp-grid/js/useSohelpGridConfig.js +3 -3
- package/sohelp-import/index.vue +372 -365
- package/sohelp-table/index.vue +113 -115
- package/sohelp-vform-eleplus/render.es.js +0 -1
- package/sohelp-vxe-table/index.vue +20 -32
- package/sohelp-workflow-drawer/components/form.vue +1 -1
- package/sohelp-workflow-drawer/components/table.vue +0 -1
- package/sohelp-workflow-drawer/components/timeline.vue +2 -2
- package/sohelp-workflow-drawer/components/workflow.vue +28 -0
- package/sohelp-workflow-drawer/index.vue +189 -200
package/sohelp-import/index.vue
CHANGED
|
@@ -12,17 +12,11 @@
|
|
|
12
12
|
</div>
|
|
13
13
|
</div>
|
|
14
14
|
<div class="upload-area" @drop.prevent="onDrop" @dragover.prevent>
|
|
15
|
-
<el-upload
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
:on-remove="onRemove"
|
|
21
|
-
:limit="1"
|
|
22
|
-
accept=".xls,.xlsx"
|
|
23
|
-
class="uploader"
|
|
24
|
-
>
|
|
25
|
-
<i class="el-icon"><UploadFilled /></i>
|
|
15
|
+
<el-upload drag :auto-upload="false" :show-file-list="false" :on-change="onFileChange" :on-remove="onRemove"
|
|
16
|
+
:limit="1" accept=".xls,.xlsx" class="uploader">
|
|
17
|
+
<i class="el-icon">
|
|
18
|
+
<UploadFilled />
|
|
19
|
+
</i>
|
|
26
20
|
<div class="el-upload__text">拖拽文件到此处或点击上传</div>
|
|
27
21
|
<div class="el-upload__tip">仅限 .xls/.xlsx,大小不超过 50MB</div>
|
|
28
22
|
</el-upload>
|
|
@@ -66,14 +60,9 @@
|
|
|
66
60
|
<el-button type="primary" @click="saveConfig">保存</el-button>
|
|
67
61
|
</template>
|
|
68
62
|
</ele-modal>
|
|
69
|
-
<ele-modal
|
|
70
|
-
:model-value="historyVisible"
|
|
71
|
-
title="导入历史"
|
|
72
|
-
:width="800"
|
|
73
|
-
@update:modelValue="(v) => (historyVisible = v)"
|
|
74
|
-
>
|
|
63
|
+
<ele-modal :model-value="historyVisible" title="导入历史" :width="800" @update:modelValue="(v) => (historyVisible = v)">
|
|
75
64
|
<div class="history-wrap">
|
|
76
|
-
<vxe-grid :
|
|
65
|
+
<sohelp-vxe-grid :gridOptions="gridOptions" :url="`/engine/web/import/history?refid=${props.refid}`" size="mini" border>
|
|
77
66
|
<template #op="{ row }">
|
|
78
67
|
<el-space :size="6">
|
|
79
68
|
<el-button size="small" plain @click="downloadHistoryFile(row)">下载文件</el-button>
|
|
@@ -81,7 +70,7 @@
|
|
|
81
70
|
<el-button size="small" plain type="danger" @click="deleteHistoryFile(row)">删除文件</el-button>
|
|
82
71
|
</el-space>
|
|
83
72
|
</template>
|
|
84
|
-
</vxe-grid>
|
|
73
|
+
</sohelp-vxe-grid>
|
|
85
74
|
</div>
|
|
86
75
|
<template #footer>
|
|
87
76
|
<el-button @click="historyVisible = false">关闭</el-button>
|
|
@@ -89,382 +78,400 @@
|
|
|
89
78
|
</ele-modal>
|
|
90
79
|
</template>
|
|
91
80
|
<script setup>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
81
|
+
import { ref, computed } from 'vue';
|
|
82
|
+
import { ElMessage } from 'element-plus/es';
|
|
83
|
+
import { EleMessage } from '@/components/ele-admin-plus/components';
|
|
84
|
+
import { UploadFilled } from '@element-plus/icons-vue';
|
|
85
|
+
import SohelpHttp from '../http/SohelpHttp.js';
|
|
97
86
|
|
|
98
|
-
|
|
87
|
+
const MAX_ROWS = 10000;
|
|
99
88
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
89
|
+
const props = defineProps({
|
|
90
|
+
modelValue: Boolean,
|
|
91
|
+
refid: {
|
|
92
|
+
type: String,
|
|
93
|
+
required: true
|
|
94
|
+
},
|
|
95
|
+
fields: {
|
|
96
|
+
type: Array,
|
|
97
|
+
default: () => []
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const emit = defineEmits(['update:modelValue', 'close']);
|
|
112
101
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
102
|
+
const loading = ref(false);
|
|
103
|
+
const fileName = ref('');
|
|
104
|
+
const fileSize = ref(0);
|
|
105
|
+
const progress = ref(0);
|
|
106
|
+
const progressStatus = ref('success');
|
|
107
|
+
const rowCount = ref(0);
|
|
108
|
+
const fileId = ref('');
|
|
109
|
+
const previewVisible = ref(false);
|
|
110
|
+
const previewData = ref([]);
|
|
111
|
+
const previewColumns = ref([]);
|
|
123
112
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
{ field: '
|
|
134
|
-
{ field: '
|
|
135
|
-
{ field: '
|
|
113
|
+
const configVisible = ref(false);
|
|
114
|
+
const whitelist = ref([]);
|
|
115
|
+
const mapping = ref({});
|
|
116
|
+
const historyVisible = ref(false);
|
|
117
|
+
const historyList = ref([]);
|
|
118
|
+
const downloadingTemplate = ref(false);
|
|
119
|
+
const gridOptions = ref({
|
|
120
|
+
maxHeight: 500,
|
|
121
|
+
columns: [
|
|
122
|
+
{ field: 'id', title: 'ID', align: 'center', width: 160 },
|
|
123
|
+
{ field: 'filename', title: '文件名', align: 'center', minWidth: 160 },
|
|
124
|
+
{ field: 'size', title: '大小', align: 'center', minWidth: 100,
|
|
125
|
+
formatter: ({ cellValue }) => formatSize(cellValue)
|
|
126
|
+
},
|
|
127
|
+
// { field: 'rows', title: '记录数', align: 'center', minWidth: 90 },
|
|
128
|
+
{ field: 'upload_usernamme', title: '导入人员', align: 'center', minWidth: 120 },
|
|
129
|
+
{ field: 'upload_time', title: '导入时间', align: 'center', minWidth: 180 },
|
|
136
130
|
{ field: 'op', title: '操作', align: 'center', minWidth: 220, slots: { default: 'op' } }
|
|
137
|
-
]
|
|
138
|
-
|
|
139
|
-
const canImport = computed(() => !!fileId.value && rowCount.value > 0 && rowCount.value <= MAX_ROWS);
|
|
131
|
+
]
|
|
132
|
+
});
|
|
140
133
|
|
|
141
|
-
|
|
142
|
-
emit('update:modelValue', val);
|
|
143
|
-
if (!val) {
|
|
144
|
-
onRemove();
|
|
145
|
-
}
|
|
146
|
-
};
|
|
134
|
+
const canImport = computed(() => !!fileId.value && rowCount.value > 0 && rowCount.value <= MAX_ROWS);
|
|
147
135
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
136
|
+
const updateModelValue = (val) => {
|
|
137
|
+
emit('update:modelValue', val);
|
|
138
|
+
if (!val) {
|
|
151
139
|
onRemove();
|
|
152
|
-
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
153
142
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
143
|
+
const onClose = () => {
|
|
144
|
+
emit('update:modelValue', false);
|
|
145
|
+
emit('close');
|
|
146
|
+
onRemove();
|
|
147
|
+
};
|
|
159
148
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
props.fields.forEach((f) => (mapping.value[f.name] = f.label || f.name));
|
|
166
|
-
}
|
|
167
|
-
configVisible.value = true;
|
|
168
|
-
};
|
|
169
|
-
const updateConfigVisible = (v) => (configVisible.value = v);
|
|
170
|
-
const saveConfig = () => {
|
|
171
|
-
configVisible.value = false;
|
|
172
|
-
};
|
|
173
|
-
const getFieldLabel = (name) => props.fields.find((f) => f.name === name)?.label || name;
|
|
149
|
+
const formatSize = (n) => {
|
|
150
|
+
if (n < 1024) return n + 'B';
|
|
151
|
+
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + 'KB';
|
|
152
|
+
return (n / 1024 / 1024).toFixed(1) + 'MB';
|
|
153
|
+
};
|
|
174
154
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
155
|
+
const openConfig = () => {
|
|
156
|
+
if (!whitelist.value.length) {
|
|
157
|
+
whitelist.value = props.fields.map((f) => f.name);
|
|
158
|
+
}
|
|
159
|
+
if (Object.keys(mapping.value).length === 0) {
|
|
160
|
+
props.fields.forEach((f) => (mapping.value[f.name] = f.label || f.name));
|
|
161
|
+
}
|
|
162
|
+
configVisible.value = true;
|
|
163
|
+
};
|
|
164
|
+
const updateConfigVisible = (v) => (configVisible.value = v);
|
|
165
|
+
const saveConfig = () => {
|
|
166
|
+
configVisible.value = false;
|
|
167
|
+
};
|
|
168
|
+
const getFieldLabel = (name) => props.fields.find((f) => f.name === name)?.label || name;
|
|
190
169
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
170
|
+
/**
|
|
171
|
+
* 下载导入模板
|
|
172
|
+
* - 绑定click事件监听器到 button 元素
|
|
173
|
+
* - 在事件处理函数中动态获取当前列表的refid值
|
|
174
|
+
* - 构造完整下载URL:/engine/web/import/downloadTemplate?refid=${动态获取的refid}
|
|
175
|
+
* - 使用SohelpHttp.download方法发起请求,参数格式为:{refid: '动态refid值'}
|
|
176
|
+
* - 错误处理:捕获refid无效、网络错误、服务器错误,并实现重试
|
|
177
|
+
* - 用户体验:显示loading,下载进度
|
|
178
|
+
*/
|
|
179
|
+
const downloadTemplate = async () => {
|
|
180
|
+
// 验证 refid 参数
|
|
181
|
+
if (!props.refid) {
|
|
182
|
+
EleMessage.error('请选择有效的模板');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
downloadingTemplate.value = true;
|
|
187
|
+
const maxRetries = 3;
|
|
188
|
+
let retryCount = 0;
|
|
189
|
+
let lastError = null;
|
|
195
190
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
191
|
+
// 错误重试机制(最多3次)
|
|
192
|
+
while (retryCount <= maxRetries) {
|
|
193
|
+
try {
|
|
194
|
+
await SohelpHttp.download(
|
|
195
|
+
'/engine/web/import/downloadTemplate',
|
|
196
|
+
{ refid: props.refid },
|
|
197
|
+
'导入模板.xlsx',
|
|
198
|
+
(loaded, total) => {
|
|
199
|
+
// 大文件下载时显示进度条
|
|
200
|
+
// 这里可以对接UI的进度条,目前简单处理,如果需要更复杂的UI交互可以扩展
|
|
201
|
+
if (total > 0) {
|
|
202
|
+
const percent = Math.floor((loaded / total) * 100);
|
|
203
|
+
console.log(`下载进度: ${percent}%`);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
{ timeout: 30000 } // 实现请求超时机制,默认设置为30秒
|
|
207
|
+
);
|
|
208
|
+
EleMessage.success('模板下载成功');
|
|
209
|
+
downloadingTemplate.value = false;
|
|
210
|
+
return;
|
|
211
|
+
} catch (error) {
|
|
212
|
+
lastError = error;
|
|
213
|
+
retryCount++;
|
|
214
|
+
if (retryCount <= maxRetries) {
|
|
215
|
+
// 简单的指数退避或固定等待
|
|
216
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
223
217
|
}
|
|
224
218
|
}
|
|
219
|
+
}
|
|
225
220
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
221
|
+
downloadingTemplate.value = false;
|
|
222
|
+
// 错误处理机制
|
|
223
|
+
const errorMsg = String(lastError);
|
|
224
|
+
if (errorMsg.includes('timeout') || errorMsg.includes('Network Error')) {
|
|
225
|
+
EleMessage.error('网络连接异常,请稍后重试');
|
|
226
|
+
} else {
|
|
227
|
+
EleMessage.error(errorMsg || '下载失败');
|
|
228
|
+
}
|
|
229
|
+
};
|
|
235
230
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
231
|
+
const onDrop = async (e) => {
|
|
232
|
+
const file = e.dataTransfer.files?.[0];
|
|
233
|
+
if (file) await handleFile(file);
|
|
234
|
+
};
|
|
235
|
+
const onFileChange = async (file) => {
|
|
236
|
+
const f = file?.raw || file;
|
|
237
|
+
if (f) await handleFile(f);
|
|
238
|
+
};
|
|
239
|
+
const onRemove = () => {
|
|
240
|
+
fileName.value = '';
|
|
241
|
+
fileSize.value = 0;
|
|
242
|
+
progress.value = 0;
|
|
243
|
+
rowCount.value = 0;
|
|
244
|
+
previewVisible.value = false;
|
|
245
|
+
fileId.value = '';
|
|
246
|
+
previewData.value = [];
|
|
247
|
+
previewColumns.value = [];
|
|
248
|
+
progressStatus.value = 'success';
|
|
249
|
+
loading.value = false;
|
|
250
|
+
};
|
|
256
251
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
252
|
+
const handleFile = async (file) => {
|
|
253
|
+
const ext = file.name.toLowerCase().split('.').pop();
|
|
254
|
+
if (!['xls', 'xlsx'].includes(ext)) {
|
|
255
|
+
ElMessage.error('仅支持 .xls 或 .xlsx 文件');
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (file.size > 50 * 1024 * 1024) {
|
|
259
|
+
ElMessage.error('文件大小超过 50MB 限制');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
fileName.value = file.name;
|
|
263
|
+
fileSize.value = file.size;
|
|
264
|
+
progress.value = 10;
|
|
265
|
+
const form = new FormData();
|
|
266
|
+
form.append('refid', props.refid);
|
|
267
|
+
form.append('file', file);
|
|
268
|
+
try {
|
|
269
|
+
const res = await SohelpHttp.post('/engine/web/import/upload', form);
|
|
270
|
+
if (!res.meta.success) {
|
|
271
|
+
progressStatus.value = 'exception';
|
|
272
|
+
ElMessage.error(res.meta.message || '上传失败');
|
|
265
273
|
return;
|
|
266
274
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const form = new FormData();
|
|
271
|
-
form.append('refid', props.refid);
|
|
272
|
-
form.append('file', file);
|
|
273
|
-
try {
|
|
274
|
-
const res = await SohelpHttp.post('/engine/web/import/upload', form);
|
|
275
|
-
if (!res.meta.success) {
|
|
276
|
-
progressStatus.value = 'exception';
|
|
277
|
-
ElMessage.error(res.meta.message || '上传失败');
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
fileId.value = res.data?.fileId || '';
|
|
281
|
-
rowCount.value = res.data?.rows || 0;
|
|
282
|
-
if (rowCount.value > MAX_ROWS) {
|
|
283
|
-
progressStatus.value = 'exception';
|
|
284
|
-
ElMessage.error('超过最大行数限制(10,000)');
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
progress.value = 60;
|
|
288
|
-
await loadPreview();
|
|
289
|
-
progress.value = 100;
|
|
290
|
-
progressStatus.value = 'success';
|
|
291
|
-
// 默认不显示预览数据
|
|
292
|
-
previewVisible.value = false;
|
|
293
|
-
} catch (e) {
|
|
275
|
+
fileId.value = res.data?.fileId || '';
|
|
276
|
+
rowCount.value = res.data?.rows || 0;
|
|
277
|
+
if (rowCount.value > MAX_ROWS) {
|
|
294
278
|
progressStatus.value = 'exception';
|
|
295
|
-
ElMessage.error(
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
const togglePreview = () => {
|
|
300
|
-
previewVisible.value = !previewVisible.value;
|
|
301
|
-
};
|
|
302
|
-
const downloadProcessed = () => {
|
|
303
|
-
if (!fileId.value) {
|
|
304
|
-
ElMessage.error('请先上传导入文件');
|
|
279
|
+
ElMessage.error('超过最大行数限制(10,000)');
|
|
305
280
|
return;
|
|
306
281
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
282
|
+
progress.value = 60;
|
|
283
|
+
await loadPreview();
|
|
284
|
+
progress.value = 100;
|
|
285
|
+
progressStatus.value = 'success';
|
|
286
|
+
// 默认不显示预览数据
|
|
287
|
+
previewVisible.value = false;
|
|
288
|
+
} catch (e) {
|
|
289
|
+
progressStatus.value = 'exception';
|
|
290
|
+
ElMessage.error(String(e));
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const togglePreview = () => {
|
|
295
|
+
previewVisible.value = !previewVisible.value;
|
|
296
|
+
};
|
|
297
|
+
const downloadProcessed = () => {
|
|
298
|
+
if (!fileId.value) {
|
|
299
|
+
ElMessage.error('请先上传导入文件');
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
SohelpHttp.download(
|
|
303
|
+
'/engine/web/import/download',
|
|
304
|
+
{ fileId: fileId.value },
|
|
305
|
+
fileName.value || '导入数据.xlsx'
|
|
306
|
+
).catch((e) => ElMessage.error(String(e)));
|
|
307
|
+
};
|
|
308
|
+
const viewHistory = async () => {
|
|
309
|
+
try {
|
|
310
|
+
const res = await SohelpHttp.get('/engine/web/import/history', { refid: props.refid });
|
|
311
|
+
if (res.meta.success) {
|
|
312
|
+
const list = res.data?.results || [];
|
|
313
|
+
historyList.value = list;
|
|
314
|
+
historyVisible.value = true;
|
|
315
|
+
} else {
|
|
316
|
+
ElMessage.error(res.meta.message || '获取历史失败');
|
|
331
317
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
318
|
+
} catch (e) {
|
|
319
|
+
ElMessage.error(String(e));
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
const commitImport = async () => {
|
|
323
|
+
if (!canImport.value) {
|
|
324
|
+
ElMessage.error('请上传有效的导入文件');
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const loadingTip = EleMessage.loading('导入中..');
|
|
328
|
+
try {
|
|
329
|
+
loading.value = true;
|
|
330
|
+
const res = await SohelpHttp.post('/engine/web/import/confirm', { fileId: fileId.value, refid: props.refid });
|
|
331
|
+
if (res.meta.success) {
|
|
332
|
+
ElMessage.success(res.meta.message || '导入完成');
|
|
333
|
+
emit('update:modelValue', false);
|
|
334
|
+
} else {
|
|
335
|
+
ElMessage.error(res.meta.message || '导入失败');
|
|
347
336
|
}
|
|
348
|
-
}
|
|
337
|
+
} catch (e) {
|
|
338
|
+
ElMessage.error(String(e));
|
|
339
|
+
} finally {
|
|
340
|
+
loadingTip.close();
|
|
341
|
+
loading.value = false;
|
|
342
|
+
}
|
|
343
|
+
};
|
|
349
344
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
} catch (e) {
|
|
372
|
-
ElMessage.error(String(e));
|
|
345
|
+
const loadPreview = async () => {
|
|
346
|
+
try {
|
|
347
|
+
const res = await SohelpHttp.get('/engine/web/import/preview', { refid: props.refid, fileId: fileId.value });
|
|
348
|
+
if (res.meta.success) {
|
|
349
|
+
const rows = Array.isArray(res.data.results) ? res.data.results : [];
|
|
350
|
+
previewData.value = rows.slice(0, 50);
|
|
351
|
+
const keys = rows.length
|
|
352
|
+
? Object.keys(rows[0])
|
|
353
|
+
: whitelist.value.length
|
|
354
|
+
? whitelist.value
|
|
355
|
+
: props.fields.map((f) => f.name);
|
|
356
|
+
previewColumns.value = keys.map((k) => ({
|
|
357
|
+
field: k,
|
|
358
|
+
title: getFieldLabel(k),
|
|
359
|
+
align: 'center',
|
|
360
|
+
minWidth: 120
|
|
361
|
+
}));
|
|
362
|
+
// previewVisible.value = true; // 加载数据后不自动显示
|
|
363
|
+
} else {
|
|
364
|
+
ElMessage.error(res.meta.message || '预览失败');
|
|
373
365
|
}
|
|
374
|
-
}
|
|
366
|
+
} catch (e) {
|
|
367
|
+
ElMessage.error(String(e));
|
|
368
|
+
}
|
|
369
|
+
};
|
|
375
370
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
389
|
-
} catch (e) {
|
|
390
|
-
ElMessage.error(String(e));
|
|
371
|
+
const downloadHistoryFile = (row) => {
|
|
372
|
+
SohelpHttp.download('/engine/web/import/download', { fileId: row.file_uuid }, row.file).catch((e) =>
|
|
373
|
+
ElMessage.error(String(e))
|
|
374
|
+
);
|
|
375
|
+
};
|
|
376
|
+
const restoreHistoryFile = async (row) => {
|
|
377
|
+
try {
|
|
378
|
+
const res = await SohelpHttp.post('/engine/web/import/restore', { fileId: row.file_uuid, refid: props.refid });
|
|
379
|
+
if (res.meta.success) {
|
|
380
|
+
ElMessage.success(res.meta.message || '恢复成功');
|
|
381
|
+
} else {
|
|
382
|
+
ElMessage.error(res.meta.message || '恢复失败');
|
|
391
383
|
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
}
|
|
403
|
-
ElMessage.error(
|
|
384
|
+
} catch (e) {
|
|
385
|
+
ElMessage.error(String(e));
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
const deleteHistoryFile = async (row) => {
|
|
389
|
+
try {
|
|
390
|
+
const res = await SohelpHttp.post('/engine/web/import/delete', { fileId: row.file_uuid, refid: props.refid });
|
|
391
|
+
if (res.meta.success) {
|
|
392
|
+
ElMessage.success(res.meta.message || '删除成功');
|
|
393
|
+
await viewHistory();
|
|
394
|
+
} else {
|
|
395
|
+
ElMessage.error(res.meta.message || '删除失败');
|
|
404
396
|
}
|
|
405
|
-
}
|
|
397
|
+
} catch (e) {
|
|
398
|
+
ElMessage.error(String(e));
|
|
399
|
+
}
|
|
400
|
+
};
|
|
406
401
|
</script>
|
|
407
402
|
<style scoped lang="scss">
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
403
|
+
.import-wrap {
|
|
404
|
+
display: flex;
|
|
405
|
+
flex-direction: column;
|
|
406
|
+
gap: 12px;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.import-header {
|
|
410
|
+
display: flex;
|
|
411
|
+
align-items: center;
|
|
412
|
+
justify-content: space-between;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.actions {
|
|
416
|
+
display: flex;
|
|
417
|
+
gap: 10px;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.actions :deep(.el-button:hover) {
|
|
421
|
+
opacity: 0.9;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.upload-area {
|
|
425
|
+
min-width: 300px;
|
|
426
|
+
min-height: 200px;
|
|
427
|
+
border: 1px dashed #bbb;
|
|
428
|
+
display: flex;
|
|
429
|
+
flex-direction: column;
|
|
430
|
+
align-items: center;
|
|
431
|
+
justify-content: center;
|
|
432
|
+
padding: 20px;
|
|
433
|
+
border-radius: 6px;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.uploader {
|
|
437
|
+
width: 100%;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.status {
|
|
441
|
+
width: 100%;
|
|
442
|
+
margin-top: 10px;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.result-actions {
|
|
446
|
+
display: flex;
|
|
447
|
+
gap: 10px;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.config-wrap {
|
|
451
|
+
display: flex;
|
|
452
|
+
flex-direction: column;
|
|
453
|
+
gap: 12px;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.mapping {
|
|
457
|
+
display: flex;
|
|
458
|
+
flex-direction: column;
|
|
459
|
+
gap: 8px;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.mapping .row {
|
|
463
|
+
display: flex;
|
|
464
|
+
align-items: center;
|
|
465
|
+
gap: 10px;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
.mapping .label {
|
|
469
|
+
width: 160px;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.history-wrap {
|
|
473
|
+
display: flex;
|
|
474
|
+
flex-direction: column;
|
|
475
|
+
gap: 10px;
|
|
476
|
+
}
|
|
470
477
|
</style>
|