@skyfox2000/webui 1.3.3 → 1.3.4
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/lib/assets/modules/{file-upload-D4Pqs8h3.js → file-upload-BBlFaIXB.js} +1 -1
- package/lib/assets/modules/index-4kDAt8nS.js +333 -0
- package/lib/assets/modules/{index-V1j9haWy.js → index-BG1SqSVl.js} +1 -1
- package/lib/assets/modules/{index-CSnwbbQT.js → index-m5rogIyM.js} +2 -2
- package/lib/assets/modules/{menuTabs-e8XoJN7m.js → menuTabs-tPIz4a89.js} +2 -2
- package/lib/assets/modules/{toolIcon-BSF7eiPf.js → toolIcon-DwWoD9TN.js} +1 -1
- package/lib/assets/modules/{uploadList-DA4TRDWR.js → uploadList-D_Z-Y2tw.js} +2 -2
- package/lib/assets/modules/{uploadList-Bcf7g1bf.js → uploadList-Da7mQUNK.js} +4 -4
- package/lib/es/AceEditor/index.js +3 -3
- package/lib/es/BasicLayout/index.js +3 -3
- package/lib/es/Error403/index.js +1 -1
- package/lib/es/Error404/index.js +1 -1
- package/lib/es/ExcelForm/index.js +332 -202
- package/lib/es/UploadForm/index.js +4 -4
- package/lib/index.d.ts +3 -2
- package/lib/utils/excel-view.d.ts +25 -0
- package/lib/utils/form-csv.d.ts +18 -0
- package/lib/utils/form-excel.d.ts +2 -13
- package/lib/webui.css +1 -1
- package/lib/webui.es.js +862 -833
- package/package.json +2 -2
- package/src/components/common/loading/index.vue +1 -1
- package/src/components/content/dialog/excelForm.vue +384 -106
- package/src/components/form/autoComplete/index.vue +1 -1
- package/src/index.ts +25 -2
- package/src/utils/excel-view.ts +340 -0
- package/src/utils/form-csv.ts +55 -0
- package/src/utils/form-excel.ts +59 -192
- package/vite.config.ts +0 -1
- package/lib/assets/modules/form-excel-D1vXB4c4.js +0 -235
package/src/utils/form-excel.ts
CHANGED
|
@@ -7,23 +7,9 @@ import message from 'vue-m-message';
|
|
|
7
7
|
import { ValidateRule } from '@/typings/form';
|
|
8
8
|
import { validMessages } from './form-validate';
|
|
9
9
|
import { UploadFile } from '@/typings/upload';
|
|
10
|
+
import { toExcel, type ExcelMarkInfo } from './excel-view';
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
* Excel数据处理需要标记的单元格
|
|
13
|
-
*/
|
|
14
|
-
export type ExcelMarkCell = {
|
|
15
|
-
row: number;
|
|
16
|
-
col: number;
|
|
17
|
-
color?: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Excel标记类型
|
|
22
|
-
*/
|
|
23
|
-
export type ExcelMarkInfo = {
|
|
24
|
-
markCells: ExcelMarkCell[];
|
|
25
|
-
markHeaders?: string[];
|
|
26
|
-
};
|
|
12
|
+
// ExcelMarkCell 和 ExcelMarkInfo 类型已移至 excel-view.ts 统一管理
|
|
27
13
|
|
|
28
14
|
/**
|
|
29
15
|
* 处理Excel文件的通用函数,用于提取表头和数据
|
|
@@ -133,31 +119,23 @@ export const processExcelFile = async (excelBuffer: ArrayBuffer) => {
|
|
|
133
119
|
};
|
|
134
120
|
|
|
135
121
|
/**
|
|
136
|
-
*
|
|
122
|
+
* 创建带错误标记的Excel预览
|
|
137
123
|
* @param excelBuffer 原始Excel文件的ArrayBuffer
|
|
138
|
-
* @param markInfo
|
|
139
|
-
* @
|
|
124
|
+
* @param markInfo 标记信息
|
|
125
|
+
* @param fileName 文件名
|
|
126
|
+
* @returns 标记后的Excel预览结果
|
|
140
127
|
*/
|
|
141
|
-
export const
|
|
142
|
-
|
|
143
|
-
markInfo: ExcelMarkInfo,
|
|
144
|
-
): Promise<{
|
|
145
|
-
hasError: boolean;
|
|
146
|
-
errBlob?: Blob;
|
|
147
|
-
}> => {
|
|
148
|
-
const ExcelJS = await import('exceljs');
|
|
149
|
-
// 处理Excel文件
|
|
128
|
+
export const createMarkedExcelView = async (excelBuffer: ArrayBuffer, markInfo: ExcelMarkInfo, fileName: string) => {
|
|
129
|
+
// 处理Excel文件获取数据
|
|
150
130
|
const excelData = await processExcelFile(excelBuffer);
|
|
151
|
-
if (!excelData)
|
|
152
|
-
|
|
153
|
-
const { worksheet, headers: originalHeaders } = excelData;
|
|
154
|
-
const { markCells, markHeaders } = markInfo;
|
|
155
|
-
|
|
156
|
-
if (markCells.length === 0 && (!markHeaders || markHeaders.length === 0)) {
|
|
157
|
-
return { hasError: false }; // 没有需要标记的内容
|
|
131
|
+
if (!excelData) {
|
|
132
|
+
return { success: false, error: 'Excel文件处理失败' };
|
|
158
133
|
}
|
|
159
134
|
|
|
160
|
-
|
|
135
|
+
const { headers: originalHeaders, excelRows } = excelData;
|
|
136
|
+
const { markHeaders } = markInfo;
|
|
137
|
+
|
|
138
|
+
// 处理缺失字段,添加到表头
|
|
161
139
|
const headers = [...originalHeaders];
|
|
162
140
|
if (markHeaders && markHeaders.length > 0) {
|
|
163
141
|
markHeaders.forEach((field) => {
|
|
@@ -167,158 +145,18 @@ export const createMarkedExcelBlob = async (
|
|
|
167
145
|
});
|
|
168
146
|
}
|
|
169
147
|
|
|
170
|
-
//
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// 创建错误单元格位置的查询表,用于快速检查
|
|
178
|
-
const cellMarkMap = new Map<string, string>();
|
|
179
|
-
markCells.forEach(({ row, col, color }) => {
|
|
180
|
-
const cellKey = `${row}-${col}`;
|
|
181
|
-
cellMarkMap.set(cellKey, color || 'FFFF0000'); // 默认红色
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// 复制列宽并应用于新工作表
|
|
185
|
-
for (let i = 0; i < headers.length; i++) {
|
|
186
|
-
const column = newWorksheet.getColumn(i + 1);
|
|
187
|
-
|
|
188
|
-
if (i < worksheet.columnCount && i < originalHeaders.length) {
|
|
189
|
-
const originalCol = worksheet.getColumn(i + 1);
|
|
190
|
-
if (originalCol && originalCol.width) {
|
|
191
|
-
column.width = originalCol.width;
|
|
192
|
-
} else {
|
|
193
|
-
column.width = defaultColumnWidth;
|
|
194
|
-
}
|
|
195
|
-
} else {
|
|
196
|
-
column.width = defaultColumnWidth;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// 复制表头行
|
|
201
|
-
const headerRow = newWorksheet.getRow(1);
|
|
202
|
-
headers.forEach((header, index) => {
|
|
203
|
-
const headerCell = headerRow.getCell(index + 1);
|
|
204
|
-
headerCell.value = header;
|
|
205
|
-
|
|
206
|
-
const isOriginalHeader = index < originalHeaders.length;
|
|
207
|
-
if (isOriginalHeader && index < worksheet.columnCount) {
|
|
208
|
-
// 复制原表头样式
|
|
209
|
-
const originalCell = worksheet.getRow(1).getCell(index + 1);
|
|
210
|
-
|
|
211
|
-
// 复制样式
|
|
212
|
-
if (originalCell.style) headerCell.style = JSON.parse(JSON.stringify(originalCell.style));
|
|
213
|
-
if (originalCell.font) headerCell.font = JSON.parse(JSON.stringify(originalCell.font));
|
|
214
|
-
if (originalCell.alignment) headerCell.alignment = JSON.parse(JSON.stringify(originalCell.alignment));
|
|
215
|
-
if (originalCell.border) headerCell.border = JSON.parse(JSON.stringify(originalCell.border));
|
|
216
|
-
if (originalCell.numFmt) headerCell.numFmt = originalCell.numFmt;
|
|
217
|
-
if (originalCell.fill) headerCell.fill = JSON.parse(JSON.stringify(originalCell.fill));
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// 仅标记缺失的表头字段,不标记数据重复的表头
|
|
221
|
-
if (markHeaders && markHeaders.includes(header) && !isOriginalHeader) {
|
|
222
|
-
headerCell.fill = {
|
|
223
|
-
type: 'pattern',
|
|
224
|
-
pattern: 'solid',
|
|
225
|
-
fgColor: { argb: 'FFFF0000' }, // 红色背景
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
// 添加白色文字
|
|
229
|
-
headerCell.font = {
|
|
230
|
-
name: 'Arial',
|
|
231
|
-
size: 10,
|
|
232
|
-
bold: true,
|
|
233
|
-
color: { argb: 'FFFFFFFF' }, // 白色文字
|
|
234
|
-
};
|
|
148
|
+
// 扩展数据行以匹配新的表头长度
|
|
149
|
+
const rows = excelRows.map((row) => {
|
|
150
|
+
const newRow = [...row];
|
|
151
|
+
// 为新增的表头字段添加空值
|
|
152
|
+
while (newRow.length < headers.length) {
|
|
153
|
+
newRow.push(null);
|
|
235
154
|
}
|
|
155
|
+
return newRow;
|
|
236
156
|
});
|
|
237
|
-
headerRow.commit();
|
|
238
|
-
|
|
239
|
-
// 处理数据行
|
|
240
|
-
worksheet.eachRow((row, rowNumber) => {
|
|
241
|
-
if (rowNumber > 1) {
|
|
242
|
-
// 跳过表头行
|
|
243
|
-
const newRow = newWorksheet.getRow(rowNumber);
|
|
244
|
-
|
|
245
|
-
// 使用表头长度来循环每个单元格
|
|
246
|
-
for (let colIndex = 0; colIndex < headers.length; colIndex++) {
|
|
247
|
-
const newCell = newRow.getCell(colIndex + 1);
|
|
248
|
-
const isOriginalHeader = colIndex < originalHeaders.length;
|
|
249
|
-
|
|
250
|
-
if (isOriginalHeader && colIndex < worksheet.columnCount) {
|
|
251
|
-
// 对原始数据中存在的列
|
|
252
|
-
const originalCell = row.getCell(colIndex + 1);
|
|
253
|
-
|
|
254
|
-
// 复制值
|
|
255
|
-
newCell.value = originalCell.value;
|
|
256
|
-
|
|
257
|
-
// 处理对象类型的单元格值,确保正确显示
|
|
258
|
-
if (newCell.value !== null && newCell.value !== undefined && typeof newCell.value === 'object') {
|
|
259
|
-
// 对于RichText,保留原格式
|
|
260
|
-
if (
|
|
261
|
-
!('richText' in newCell.value) &&
|
|
262
|
-
!('formula' in newCell.value) &&
|
|
263
|
-
!('hyperlink' in newCell.value) &&
|
|
264
|
-
!(newCell.value instanceof Date)
|
|
265
|
-
) {
|
|
266
|
-
// 尝试转换为字符串显示
|
|
267
|
-
try {
|
|
268
|
-
if ('text' in newCell.value && typeof newCell.value.text === 'string') {
|
|
269
|
-
newCell.value = newCell.value.text;
|
|
270
|
-
} else {
|
|
271
|
-
// 其他对象类型尝试JSON序列化
|
|
272
|
-
newCell.value = JSON.stringify(newCell.value);
|
|
273
|
-
}
|
|
274
|
-
} catch {
|
|
275
|
-
// 如果转换失败,使用toString
|
|
276
|
-
newCell.value = String(newCell.value);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
157
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (originalCell.font) newCell.font = JSON.parse(JSON.stringify(originalCell.font));
|
|
284
|
-
if (originalCell.alignment) newCell.alignment = JSON.parse(JSON.stringify(originalCell.alignment));
|
|
285
|
-
if (originalCell.border) newCell.border = JSON.parse(JSON.stringify(originalCell.border));
|
|
286
|
-
if (originalCell.numFmt) newCell.numFmt = originalCell.numFmt;
|
|
287
|
-
if (originalCell.fill) newCell.fill = JSON.parse(JSON.stringify(originalCell.fill));
|
|
288
|
-
|
|
289
|
-
// 检查是否为需要标记的单元格
|
|
290
|
-
const cellKey = `${rowNumber}-${colIndex + 1}`;
|
|
291
|
-
if (cellMarkMap.has(cellKey)) {
|
|
292
|
-
// 设置背景颜色
|
|
293
|
-
newCell.fill = {
|
|
294
|
-
type: 'pattern',
|
|
295
|
-
pattern: 'solid',
|
|
296
|
-
fgColor: { argb: cellMarkMap.get(cellKey) },
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
// 为新增列设置空值
|
|
301
|
-
newCell.value = null;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// 复制行属性
|
|
306
|
-
if (row.height) newRow.height = row.height;
|
|
307
|
-
if (row.outlineLevel) newRow.outlineLevel = row.outlineLevel;
|
|
308
|
-
|
|
309
|
-
newRow.commit();
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
// 生成Excel文件Buffer
|
|
314
|
-
const excelOutput = await newWorkbook.xlsx.writeBuffer();
|
|
315
|
-
|
|
316
|
-
// 创建Blob对象
|
|
317
|
-
const excelBlob = new Blob([excelOutput], {
|
|
318
|
-
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
return { hasError: true, errBlob: excelBlob };
|
|
158
|
+
// 调用excel-view的方法生成带标记的Excel
|
|
159
|
+
return await toExcel({ headers, rows }, fileName, markInfo);
|
|
322
160
|
};
|
|
323
161
|
|
|
324
162
|
/**
|
|
@@ -374,11 +212,24 @@ export const validateExcel = async (
|
|
|
374
212
|
color: 'FFFF0000', // 红色
|
|
375
213
|
}));
|
|
376
214
|
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
215
|
+
// 使用excel-view统一创建标记Excel
|
|
216
|
+
const markResult = await createMarkedExcelView(
|
|
217
|
+
excelBuffer,
|
|
218
|
+
{
|
|
219
|
+
markCells,
|
|
220
|
+
markHeaders: missingFields,
|
|
221
|
+
},
|
|
222
|
+
'validation_errors.xlsx',
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
if (markResult.success && markResult.blobUrl) {
|
|
226
|
+
// 从blob URL创建blob对象
|
|
227
|
+
const response = await fetch(markResult.blobUrl);
|
|
228
|
+
const errBlob = await response.blob();
|
|
229
|
+
return { hasError: true, errBlob };
|
|
230
|
+
} else {
|
|
231
|
+
return { hasError: true };
|
|
232
|
+
}
|
|
382
233
|
}
|
|
383
234
|
|
|
384
235
|
return { hasError: false }; // 没有错误时返回null
|
|
@@ -522,8 +373,24 @@ export const checkExcelDuplicates = async (
|
|
|
522
373
|
});
|
|
523
374
|
});
|
|
524
375
|
|
|
525
|
-
//
|
|
526
|
-
|
|
376
|
+
// 使用excel-view统一创建标记Excel
|
|
377
|
+
const markResult = await createMarkedExcelView(
|
|
378
|
+
excelBuffer,
|
|
379
|
+
{
|
|
380
|
+
markCells,
|
|
381
|
+
markHeaders: missingDuplicateFields,
|
|
382
|
+
},
|
|
383
|
+
'duplicate_errors.xlsx',
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
if (markResult.success && markResult.blobUrl) {
|
|
387
|
+
// 从blob URL创建blob对象
|
|
388
|
+
const response = await fetch(markResult.blobUrl);
|
|
389
|
+
const errBlob = await response.blob();
|
|
390
|
+
return { hasError: true, errBlob };
|
|
391
|
+
} else {
|
|
392
|
+
return { hasError: true };
|
|
393
|
+
}
|
|
527
394
|
}
|
|
528
395
|
|
|
529
396
|
return { hasError: false }; // 没有重复数据
|
package/vite.config.ts
CHANGED
|
@@ -47,7 +47,6 @@ export default defineConfig(({ mode }: ConfigEnv) => {
|
|
|
47
47
|
'@': path.resolve('./src'),
|
|
48
48
|
'@skyfox2000/fapi': path.resolve('../502417_fapi'),
|
|
49
49
|
'@skyfox2000/microbase': path.resolve('../502424_MicroBase'),
|
|
50
|
-
'@skyfox2000/webbase': path.resolve('../502428_WebBase'),
|
|
51
50
|
},
|
|
52
51
|
extensions: ['.js', '.ts', '.vue', 'json'],
|
|
53
52
|
},
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import k from "async-validator";
|
|
2
|
-
import { httpPost as J, ResStatus as C } from "@skyfox2000/fapi";
|
|
3
|
-
import { i as N, ag as R } from "./uploadList-DA4TRDWR.js";
|
|
4
|
-
import E from "vue-m-message";
|
|
5
|
-
const F = async (d) => {
|
|
6
|
-
const o = await import("exceljs"), g = new o.default.Workbook();
|
|
7
|
-
await g.xlsx.load(d);
|
|
8
|
-
const c = g.worksheets[0];
|
|
9
|
-
if (!c)
|
|
10
|
-
return E.error("Excel文件不包含工作表"), null;
|
|
11
|
-
const s = [], h = [], i = [];
|
|
12
|
-
return c.getRow(1).eachCell((e) => {
|
|
13
|
-
let r = "";
|
|
14
|
-
if (e.value !== null && e.value !== void 0)
|
|
15
|
-
if (typeof e.value == "object")
|
|
16
|
-
if ("richText" in e.value && Array.isArray(e.value.richText))
|
|
17
|
-
r = e.value.richText.map((a) => a.text || "").join("");
|
|
18
|
-
else if ("text" in e.value && typeof e.value.text == "string")
|
|
19
|
-
r = e.value.text;
|
|
20
|
-
else if (e.value instanceof Date)
|
|
21
|
-
r = e.value.toLocaleDateString();
|
|
22
|
-
else
|
|
23
|
-
try {
|
|
24
|
-
r = JSON.stringify(e.value);
|
|
25
|
-
} catch {
|
|
26
|
-
r = String(e.value);
|
|
27
|
-
}
|
|
28
|
-
else
|
|
29
|
-
r = String(e.value);
|
|
30
|
-
s.push(r);
|
|
31
|
-
}), c.eachRow((e, r) => {
|
|
32
|
-
if (r > 1) {
|
|
33
|
-
const a = {}, n = [];
|
|
34
|
-
s.forEach((l, y) => {
|
|
35
|
-
if (l) {
|
|
36
|
-
const m = e.getCell(y + 1).value;
|
|
37
|
-
m != null ? typeof m == "object" ? "richText" in m && Array.isArray(m.richText) ? a[l] = m.richText.map((O) => O.text || "").join("") : "text" in m && typeof m.text == "string" ? a[l] = m.text : (m instanceof Date, a[l] = m) : a[l] = m : a[l] = null, n.push(a[l]);
|
|
38
|
-
}
|
|
39
|
-
}), h.push(a), i.push(n);
|
|
40
|
-
}
|
|
41
|
-
}), { workbook: g, worksheet: c, headers: s, excelData: h, excelRows: i };
|
|
42
|
-
}, b = async (d, o) => {
|
|
43
|
-
const g = await import("exceljs"), c = await F(d);
|
|
44
|
-
if (!c) return { hasError: !0 };
|
|
45
|
-
const { worksheet: s, headers: h } = c, { markCells: i, markHeaders: e } = o;
|
|
46
|
-
if (i.length === 0 && (!e || e.length === 0))
|
|
47
|
-
return { hasError: !1 };
|
|
48
|
-
const r = [...h];
|
|
49
|
-
e && e.length > 0 && e.forEach((f) => {
|
|
50
|
-
r.includes(f) || r.push(f);
|
|
51
|
-
});
|
|
52
|
-
const a = new g.default.Workbook(), n = a.addWorksheet("Sheet1"), l = 15, y = /* @__PURE__ */ new Map();
|
|
53
|
-
i.forEach(({ row: f, col: p, color: u }) => {
|
|
54
|
-
const v = `${f}-${p}`;
|
|
55
|
-
y.set(v, u || "FFFF0000");
|
|
56
|
-
});
|
|
57
|
-
for (let f = 0; f < r.length; f++) {
|
|
58
|
-
const p = n.getColumn(f + 1);
|
|
59
|
-
if (f < s.columnCount && f < h.length) {
|
|
60
|
-
const u = s.getColumn(f + 1);
|
|
61
|
-
u && u.width ? p.width = u.width : p.width = l;
|
|
62
|
-
} else
|
|
63
|
-
p.width = l;
|
|
64
|
-
}
|
|
65
|
-
const x = n.getRow(1);
|
|
66
|
-
r.forEach((f, p) => {
|
|
67
|
-
const u = x.getCell(p + 1);
|
|
68
|
-
u.value = f;
|
|
69
|
-
const v = p < h.length;
|
|
70
|
-
if (v && p < s.columnCount) {
|
|
71
|
-
const t = s.getRow(1).getCell(p + 1);
|
|
72
|
-
t.style && (u.style = JSON.parse(JSON.stringify(t.style))), t.font && (u.font = JSON.parse(JSON.stringify(t.font))), t.alignment && (u.alignment = JSON.parse(JSON.stringify(t.alignment))), t.border && (u.border = JSON.parse(JSON.stringify(t.border))), t.numFmt && (u.numFmt = t.numFmt), t.fill && (u.fill = JSON.parse(JSON.stringify(t.fill)));
|
|
73
|
-
}
|
|
74
|
-
e && e.includes(f) && !v && (u.fill = {
|
|
75
|
-
type: "pattern",
|
|
76
|
-
pattern: "solid",
|
|
77
|
-
fgColor: { argb: "FFFF0000" }
|
|
78
|
-
// 红色背景
|
|
79
|
-
}, u.font = {
|
|
80
|
-
name: "Arial",
|
|
81
|
-
size: 10,
|
|
82
|
-
bold: !0,
|
|
83
|
-
color: { argb: "FFFFFFFF" }
|
|
84
|
-
// 白色文字
|
|
85
|
-
});
|
|
86
|
-
}), x.commit(), s.eachRow((f, p) => {
|
|
87
|
-
if (p > 1) {
|
|
88
|
-
const u = n.getRow(p);
|
|
89
|
-
for (let v = 0; v < r.length; v++) {
|
|
90
|
-
const t = u.getCell(v + 1);
|
|
91
|
-
if (v < h.length && v < s.columnCount) {
|
|
92
|
-
const w = f.getCell(v + 1);
|
|
93
|
-
if (t.value = w.value, t.value !== null && t.value !== void 0 && typeof t.value == "object" && !("richText" in t.value) && !("formula" in t.value) && !("hyperlink" in t.value) && !(t.value instanceof Date))
|
|
94
|
-
try {
|
|
95
|
-
"text" in t.value && typeof t.value.text == "string" ? t.value = t.value.text : t.value = JSON.stringify(t.value);
|
|
96
|
-
} catch {
|
|
97
|
-
t.value = String(t.value);
|
|
98
|
-
}
|
|
99
|
-
w.style && (t.style = JSON.parse(JSON.stringify(w.style))), w.font && (t.font = JSON.parse(JSON.stringify(w.font))), w.alignment && (t.alignment = JSON.parse(JSON.stringify(w.alignment))), w.border && (t.border = JSON.parse(JSON.stringify(w.border))), w.numFmt && (t.numFmt = w.numFmt), w.fill && (t.fill = JSON.parse(JSON.stringify(w.fill)));
|
|
100
|
-
const S = `${p}-${v + 1}`;
|
|
101
|
-
y.has(S) && (t.fill = {
|
|
102
|
-
type: "pattern",
|
|
103
|
-
pattern: "solid",
|
|
104
|
-
fgColor: { argb: y.get(S) }
|
|
105
|
-
});
|
|
106
|
-
} else
|
|
107
|
-
t.value = null;
|
|
108
|
-
}
|
|
109
|
-
f.height && (u.height = f.height), f.outlineLevel && (u.outlineLevel = f.outlineLevel), u.commit();
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
const m = await a.xlsx.writeBuffer();
|
|
113
|
-
return { hasError: !0, errBlob: new Blob([m], {
|
|
114
|
-
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
115
|
-
}) };
|
|
116
|
-
}, W = async (d, o) => {
|
|
117
|
-
if (!o || N(o))
|
|
118
|
-
return { hasError: !1 };
|
|
119
|
-
const g = await F(d);
|
|
120
|
-
if (!g) return { hasError: !0 };
|
|
121
|
-
const { headers: c, excelData: s } = g, h = [];
|
|
122
|
-
if (Object.keys(o).forEach((r) => {
|
|
123
|
-
c.includes(r) || h.push(r);
|
|
124
|
-
}), c.length === 0 || s.length === 0)
|
|
125
|
-
return E.error("Excel文件不包含足够的数据"), { hasError: !0 };
|
|
126
|
-
const i = new k({});
|
|
127
|
-
i.messages(R.messages()), i.define(o);
|
|
128
|
-
const e = await D(c, s, i);
|
|
129
|
-
if (e.length > 0 || h.length > 0) {
|
|
130
|
-
const r = e.map((a) => ({
|
|
131
|
-
row: a.row + 2,
|
|
132
|
-
// 转为Excel行号(+2是因为表头占一行,且是1-based索引)
|
|
133
|
-
col: a.col + 1,
|
|
134
|
-
// 转为Excel列号(+1是因为是1-based索引)
|
|
135
|
-
color: "FFFF0000"
|
|
136
|
-
// 红色
|
|
137
|
-
}));
|
|
138
|
-
return b(d, {
|
|
139
|
-
markCells: r,
|
|
140
|
-
markHeaders: h
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
return { hasError: !1 };
|
|
144
|
-
}, D = async (d, o, g) => {
|
|
145
|
-
const c = [];
|
|
146
|
-
for (let s = 0; s < o.length; s++) {
|
|
147
|
-
const h = o[s];
|
|
148
|
-
try {
|
|
149
|
-
await g.validate(h).catch(({ errors: i }) => {
|
|
150
|
-
const e = [];
|
|
151
|
-
i.forEach((r) => {
|
|
152
|
-
const a = d.indexOf(r.field);
|
|
153
|
-
a >= 0 && (e.some((l) => l.row === s && l.col === a) || e.push({
|
|
154
|
-
row: s,
|
|
155
|
-
col: a,
|
|
156
|
-
header: r.field,
|
|
157
|
-
message: r.message.replace("${label}", d[a])
|
|
158
|
-
}));
|
|
159
|
-
}), c.push(...e);
|
|
160
|
-
});
|
|
161
|
-
} catch (i) {
|
|
162
|
-
console.error("验证表格数据时发生错误:", i), E.error("验证表格数据时发生错误:" + i);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return c;
|
|
166
|
-
}, $ = async (d, o, g) => {
|
|
167
|
-
if (!o || o.length === 0)
|
|
168
|
-
return { hasError: !1 };
|
|
169
|
-
const c = await F(d);
|
|
170
|
-
if (!c) return { hasError: !0 };
|
|
171
|
-
const { headers: s, excelData: h } = c, i = [];
|
|
172
|
-
if (o.forEach((n) => {
|
|
173
|
-
s.includes(n) || i.push(n);
|
|
174
|
-
}), i.length > 0)
|
|
175
|
-
return E.error(`表头缺少重复检测所需字段: ${i.join(", ")}`), { hasError: !0 };
|
|
176
|
-
const e = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set(), a = new Array();
|
|
177
|
-
if (h.forEach((n, l) => {
|
|
178
|
-
const y = o.map((x) => n[x]).join("|");
|
|
179
|
-
a.push(y), e.has(y) ? (r.add(l), r.add(e.get(y))) : e.set(y, l);
|
|
180
|
-
}), g) {
|
|
181
|
-
const n = await J(g, {
|
|
182
|
-
Data: a
|
|
183
|
-
});
|
|
184
|
-
if (n != null && n.data && n.data.forEach((l) => {
|
|
185
|
-
r.add(l);
|
|
186
|
-
}), (n == null ? void 0 : n.status) === C.ERROR)
|
|
187
|
-
throw new Error(n.msg);
|
|
188
|
-
}
|
|
189
|
-
if (r.size > 0) {
|
|
190
|
-
const n = [];
|
|
191
|
-
return r.forEach((l) => {
|
|
192
|
-
o.forEach((y) => {
|
|
193
|
-
const x = s.indexOf(y);
|
|
194
|
-
x >= 0 && n.push({
|
|
195
|
-
row: l + 2,
|
|
196
|
-
// Excel行号 = 数组索引 + 2(表头和1-based索引)
|
|
197
|
-
col: x + 1,
|
|
198
|
-
// Excel列号 = 数组索引 + 1(1-based索引)
|
|
199
|
-
color: "FFFF0000"
|
|
200
|
-
// 红色
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
}), b(d, { markCells: n, markHeaders: i });
|
|
204
|
-
}
|
|
205
|
-
return { hasError: !1 };
|
|
206
|
-
}, B = async (d, o, g) => {
|
|
207
|
-
const c = d.originFileObj;
|
|
208
|
-
if (c) {
|
|
209
|
-
const s = await c.arrayBuffer(), h = await F(s);
|
|
210
|
-
if (!h) {
|
|
211
|
-
E.error("上传的文件不是Excel文件");
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
const { headers: i, excelRows: e, excelData: r } = h;
|
|
215
|
-
g && g.length > 0 ? g.forEach((a) => {
|
|
216
|
-
switch (a) {
|
|
217
|
-
case "Headers":
|
|
218
|
-
o.Headers = i;
|
|
219
|
-
break;
|
|
220
|
-
case "RawRows":
|
|
221
|
-
o.RawRows = e;
|
|
222
|
-
break;
|
|
223
|
-
case "Records":
|
|
224
|
-
o.Records = r;
|
|
225
|
-
break;
|
|
226
|
-
}
|
|
227
|
-
}) : (o.Headers = i, o.RawRows = e, o.Records = r);
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
export {
|
|
231
|
-
B as a,
|
|
232
|
-
$ as c,
|
|
233
|
-
F as p,
|
|
234
|
-
W as v
|
|
235
|
-
};
|