@ticatec/batch-data-uploader 0.1.0 → 0.1.2

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.
@@ -2,29 +2,28 @@
2
2
  <script lang="ts">
3
3
  import Dialog from "@ticatec/uniface-element/Dialog";
4
4
  import type {ButtonAction, ButtonActions} from "@ticatec/uniface-element/ActionBar";
5
- import DataTable, {type IndicatorColumn} from "@ticatec/uniface-element/DataTable";
5
+ import DataTable, {type DataColumn as TableColumn, type IndicatorColumn} from "@ticatec/uniface-element/DataTable";
6
6
  import Box from "@ticatec/uniface-element/Box"
7
7
  import {onMount} from "svelte";
8
- import type DataColumn from "./DataColumn";
9
8
  import type BaseUploadTemplate from "./BaseUploadTemplate.js";
10
- import i18nRes from "./i18n_resources/i18nRes";
9
+ import i18nRes from "./i18n_res/i18nRes";
11
10
  import {i18nUtils} from "@ticatec/i18n";
11
+ import {ProcessStatus} from "./ProcessStatus";
12
+ import SheetPickupDialog from "./SheetPickupDialog.svelte";
12
13
 
13
14
  export let title: string;
14
15
  export let width: string = "800px";
15
16
  export let height: string = "600px"
16
- export let closeHandler: any;
17
17
  export let template: BaseUploadTemplate;
18
- export let afterUploaded: ()=>Promise<void>;
18
+ export let afterUploaded: () => Promise<void>;
19
19
 
20
- type ProcessStatus = 'Init' | 'Pending' | 'Uploading' | 'Done'; //初始状态,待上传,上传中,处理完成
21
20
 
22
- let status: ProcessStatus = 'Init';
21
+ let status: ProcessStatus = ProcessStatus.Init;
23
22
 
24
23
  const btnChoose: ButtonAction = {
25
24
  label: i18nRes.button.open,
26
25
  type: 'primary',
27
- handler: () => {
26
+ handler: async () => {
28
27
  uploadField.value = '';
29
28
  uploadField.click();
30
29
  }
@@ -33,13 +32,13 @@
33
32
  const btnUpload: ButtonAction = {
34
33
  label: i18nRes.button.upload,
35
34
  type: 'primary',
36
- handler: async ()=> {
37
- status = 'Uploading';
35
+ handler: async () => {
36
+ status = ProcessStatus.Uploading;
38
37
  try {
39
38
  await template.upload();
40
39
  await afterUploaded?.();
41
40
  } finally {
42
- status = 'Done';
41
+ status = ProcessStatus.Done;
43
42
  }
44
43
  }
45
44
  }
@@ -48,7 +47,7 @@
48
47
  const btnSave: ButtonAction = {
49
48
  label: i18nRes.button.save,
50
49
  type: 'primary',
51
- handler: async ()=> {
50
+ handler: async () => {
52
51
  const baseFilename = filename.replace(/\.[^/.]+$/, ""); // 移除扩展名
53
52
  template.exportErrorRowsToExcel(`error-${baseFilename}.xlsx`);
54
53
  }
@@ -56,11 +55,11 @@
56
55
 
57
56
  // 新增:导出用于重新上传的数据
58
57
  const btnExportForReupload: ButtonAction = {
59
- label: '导出失败数据',
58
+ label: i18nRes.buttonExportException,
60
59
  type: 'secondary',
61
- handler: async ()=> {
60
+ handler: async () => {
62
61
  const baseFilename = filename.replace(/\.[^/.]+$/, ""); // 移除扩展名
63
- template.exportErrorData(`重传-${baseFilename}.xlsx`, {
62
+ template.exportErrorData(`${baseFilename}.xlsx`, {
64
63
  includeAllData: false,
65
64
  separateSheets: true,
66
65
  originalFormat: true
@@ -70,11 +69,11 @@
70
69
 
71
70
  // 新增:导出完整报告
72
71
  const btnExportFullReport: ButtonAction = {
73
- label: '导出完整报告',
72
+ label: i18nRes.buttonExportFull,
74
73
  type: 'secondary',
75
- handler: async ()=> {
74
+ handler: async () => {
76
75
  const baseFilename = filename.replace(/\.[^/.]+$/, ""); // 移除扩展名
77
- template.exportErrorData(`报告-${baseFilename}.xlsx`, {
76
+ template.exportErrorData(`report-${baseFilename}.xlsx`, {
78
77
  includeAllData: true,
79
78
  separateSheets: true,
80
79
  originalFormat: true
@@ -84,12 +83,12 @@
84
83
 
85
84
  // 新增:重置失败数据状态
86
85
  const btnResetErrors: ButtonAction = {
87
- label: '重置失败数据',
86
+ label: i18nRes.buttonReset,
88
87
  type: 'secondary',
89
- handler: async ()=> {
88
+ handler: async () => {
90
89
  template.resetUploadStatus();
91
90
  list = template.list;
92
- status = 'Pending';
91
+ status = ProcessStatus.Pending;
93
92
  }
94
93
  }
95
94
 
@@ -98,29 +97,63 @@
98
97
  let list: Array<any> = [];
99
98
  let filename: string;
100
99
 
100
+ const showSheetChooseDialog = (sheetNames: Array<any>): Promise<any> => {
101
+ return new Promise((resolve, reject) => {
102
+ window.Dialog.showModal(SheetPickupDialog, {
103
+ confirmCallback: (sheet: string) => {
104
+ resolve(sheet);
105
+ }, onClose: () => {
106
+ resolve(null);
107
+ }, sheets: sheetNames
108
+ })
109
+ });
110
+ }
111
+
112
+ const openExcelFile = async (excelFile: File) => {
113
+ window.Indicator.show(i18nRes.parsing.toString());
114
+ try {
115
+ return await template.setFile(excelFile);
116
+ } catch (ex) {
117
+ console.error('Parse file error:', ex);
118
+ window.Toast.show(i18nUtils.formatText(i18nRes.parseFailure, {name: excelFile.name}));
119
+ throw ex;
120
+ } finally {
121
+ window.Indicator.hide();
122
+ }
123
+ }
124
+
101
125
  const parseExcelFile = async (excelFile: File) => {
102
126
  if (excelFile) {
127
+ const sheetNames = await openExcelFile(excelFile);
103
128
  filename = excelFile.name;
104
- window.Indicator.show(i18nRes.parsing);
105
- try {
106
- await template.parseExcelFile(excelFile);
107
- list = template.list;
108
- status = list.length > 0 ? 'Pending' : 'Init';
109
- } catch (ex) {
110
- console.error('Parse file error:', ex);
111
- window.Toast.show(i18nUtils.formatText(i18nRes.parseFailure, {name: excelFile.name}));
112
- status = 'Init'; // 确保解析失败时重置状态
113
- } finally {
114
- window.Indicator.hide();
129
+ let sheetName = sheetNames[0];
130
+ if (sheetNames.length > 1) {
131
+ sheetName = await showSheetChooseDialog(sheetNames)
132
+ }
133
+ if (sheetName) {
134
+ window.Indicator.show(i18nRes.parsing.toString());
135
+ try {
136
+ await template.parseSheet(sheetName);
137
+ list = template.list;
138
+ status = list.length > 0 ? ProcessStatus.Pending : ProcessStatus.Init;
139
+ } catch (ex) {
140
+ console.error('Parse file error:', ex);
141
+ window.Toast.show(i18nUtils.formatText(i18nRes.parseFailure, {name: excelFile.name}));
142
+ status = ProcessStatus.Init; // 确保解析失败时重置状态
143
+ } finally {
144
+ window.Indicator.hide();
145
+ }
146
+ } else {
147
+ status = ProcessStatus.Init; // 没有选择退出重置状态
115
148
  }
116
149
  }
117
150
  }
118
151
 
119
- let columns: Array<DataColumn>;
152
+ let columns: Array<TableColumn>;
120
153
 
121
154
  onMount(async () => {
122
155
  columns = template.columns;
123
- template.setProgressStatusListener(()=> {
156
+ template.setProgressStatusListener(() => {
124
157
  list = template.list;
125
158
  })
126
159
  });
@@ -131,20 +164,20 @@
131
164
  displayNo: true
132
165
  }
133
166
 
134
- $: {
135
- switch (status) {
136
- case 'Init':
167
+ const invalidateStatus = (ps: ProcessStatus) => {
168
+ switch (ps) {
169
+ case ProcessStatus.Init:
137
170
  actions = [btnChoose];
138
171
  break;
139
- case 'Pending':
172
+ case ProcessStatus.Pending:
140
173
  actions = [btnUpload, btnChoose];
141
174
  break;
142
- case 'Uploading':
175
+ case ProcessStatus.Uploading:
143
176
  btnUpload.disabled = true;
144
177
  btnChoose.disabled = true;
145
178
  actions = [...actions];
146
179
  break;
147
- case 'Done':
180
+ case ProcessStatus.Done:
148
181
  btnUpload.disabled = false;
149
182
  btnChoose.disabled = false;
150
183
 
@@ -181,8 +214,10 @@
181
214
  }
182
215
  }
183
216
 
184
- const confirmCloseDialog = async ():Promise<boolean> => {
185
- if (status == 'Uploading') {
217
+ $: invalidateStatus(status);
218
+
219
+ const confirmCloseDialog = async (): Promise<boolean> => {
220
+ if (status == ProcessStatus.Uploading) {
186
221
  window.Toast.show(i18nRes.waitUploading);
187
222
  return false;
188
223
  } else {
@@ -192,26 +227,27 @@
192
227
 
193
228
  // 显示上传统计信息
194
229
  $: uploadStatsText = (() => {
195
- if (status === 'Done' && list.length > 0) {
230
+ if (status === ProcessStatus.Done && list.length > 0) {
196
231
  const stats = template.uploadStats;
197
- return `总计: ${stats.total}, 成功: ${stats.success}, 失败: ${stats.failed}`;
232
+ return i18nUtils.formatText(i18nRes.uploadStatText, stats);
198
233
  }
199
234
  return '';
200
235
  })();
201
236
 
202
237
  </script>
203
238
 
204
- <Dialog {title} {closeHandler} {actions} closeConfirm={confirmCloseDialog}
205
- content$style="width: {width}; height: {height}; padding: 12px;">
239
+ <Dialog {title} {actions} closeConfirm={confirmCloseDialog}
240
+ content$style="width: {width}; height: {height}; padding: 12px; display: flex; flex-direction: column;">
206
241
 
207
242
  <!-- 添加状态信息显示 -->
208
243
  {#if uploadStatsText}
209
- <div style="margin-bottom: 8px; padding: 8px; background: #f5f5f5; border-radius: 4px; font-size: 14px;">
244
+ <div style="margin-bottom: 8px; padding: 8px; background: #f5f5f5; border-radius: 4px; font-size: 14px; flex: 0 0 auto">
210
245
  {uploadStatsText}
211
246
  </div>
212
247
  {/if}
213
248
 
214
- <Box style="border: 1px solid var(--uniface-editor-border-color, #F8FAFC); width: 100%; height: 100%; cursor: {status == 'Uploading' ? 'progress' : 'default'}" round>
249
+ <Box style="flex: 1 1 auto; border: 1px solid var(--uniface-editor-border-color, #F8FAFC); width: 100%; height: 100%; cursor: {status == ProcessStatus.Uploading ? 'progress' : 'default'}"
250
+ round>
215
251
  <DataTable style="width: 100%; height: 100%" {list} {indicatorColumn} {columns}>
216
252
  </DataTable>
217
253
  </Box>
@@ -16,7 +16,6 @@ declare const FileUploadWizard: $$__sveltets_2_IsomorphicComponent<{
16
16
  title: string;
17
17
  width?: string;
18
18
  height?: string;
19
- closeHandler: any;
20
19
  template: BaseUploadTemplate;
21
20
  afterUploaded: () => Promise<void>;
22
21
  }, {
@@ -0,0 +1,6 @@
1
+ export declare enum ProcessStatus {
2
+ Init = 0,
3
+ Pending = 1,
4
+ Uploading = 2,
5
+ Done = 3
6
+ }
@@ -0,0 +1,7 @@
1
+ export var ProcessStatus;
2
+ (function (ProcessStatus) {
3
+ ProcessStatus[ProcessStatus["Init"] = 0] = "Init";
4
+ ProcessStatus[ProcessStatus["Pending"] = 1] = "Pending";
5
+ ProcessStatus[ProcessStatus["Uploading"] = 2] = "Uploading";
6
+ ProcessStatus[ProcessStatus["Done"] = 3] = "Done";
7
+ })(ProcessStatus || (ProcessStatus = {}));
@@ -0,0 +1,6 @@
1
+ <script lang="ts">
2
+ export let item;
3
+ </script>
4
+ <div style="padding: 0 12px; height: 42px; display: flex; align-items: center; ">
5
+ <span style="font-size: 1.15em">{item}</span>
6
+ </div>
@@ -0,0 +1,20 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: Props & {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const SheetNameViewRender: $$__sveltets_2_IsomorphicComponent<{
15
+ item: any;
16
+ }, {
17
+ [evt: string]: CustomEvent<any>;
18
+ }, {}, {}, string>;
19
+ type SheetNameViewRender = InstanceType<typeof SheetNameViewRender>;
20
+ export default SheetNameViewRender;
@@ -0,0 +1,35 @@
1
+ <!-- 更新的FileUploadWizard.svelte - 彻底清理includeMetadata -->
2
+ <script lang="ts">
3
+ import CommonDialog from "@ticatec/uniface-element/CommonDialog";
4
+ import Box from "@ticatec/uniface-element/Box"
5
+ import i18nRes from "./i18n_res/i18nRes";
6
+ import ListBox from "@ticatec/uniface-element/ListBox";
7
+ import SheetNameViewRender from "./SheetNameViewRender.svelte";
8
+
9
+
10
+ export let confirmCallback: any;
11
+
12
+ export let sheets: Array<string>;
13
+
14
+ export let onClose: any;
15
+
16
+ let selectedSheet: any;
17
+
18
+ let width: string = "360px";
19
+ let height: string = "480px";
20
+
21
+ const confirmSelection = () => {
22
+ confirmCallback?.(selectedSheet);
23
+ return true;
24
+ }
25
+
26
+
27
+ </script>
28
+
29
+ <CommonDialog title={i18nRes.titleChooseSheet} {onClose} confirmHandler={confirmSelection} enableConfirm={selectedSheet != null}
30
+ content$style="width: {width}; height: {height}; padding: 12px;">
31
+ <Box style="border: 1px solid var(--uniface-editor-border-color, #F8FAFC); width: 100%; height: 100%;" round>
32
+ <ListBox style="width: 100%; height: 100%" list={sheets} selectMode="single" bind:selectedItem={selectedSheet}
33
+ itemRender={SheetNameViewRender}/>
34
+ </Box>
35
+ </CommonDialog>
@@ -0,0 +1,22 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: Props & {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const SheetPickupDialog: $$__sveltets_2_IsomorphicComponent<{
15
+ confirmCallback: any;
16
+ sheets: Array<string>;
17
+ onClose: any;
18
+ }, {
19
+ [evt: string]: CustomEvent<any>;
20
+ }, {}, {}, string>;
21
+ type SheetPickupDialog = InstanceType<typeof SheetPickupDialog>;
22
+ export default SheetPickupDialog;
@@ -0,0 +1,32 @@
1
+ import { i18nUtils } from "@ticatec/i18n";
2
+ const langRes = {
3
+ status: {
4
+ pending: "To upload",
5
+ uploading: "Uploading...",
6
+ successful: "Success",
7
+ fail: "Failure"
8
+ },
9
+ parsing: "Parsing file...",
10
+ parseFailure: "Cannot parse file: {{name}}",
11
+ waitUploading: "Cannot exit during uploading!",
12
+ button: {
13
+ upload: "Upload",
14
+ save: "Save error data",
15
+ open: "Open",
16
+ confirm: "Confirm"
17
+ },
18
+ titleChooseSheet: 'Choose a sheet',
19
+ errorTitle: "Error",
20
+ sheetName: "Abnormal data",
21
+ labelStatus: "Status",
22
+ labelValid: "Validity",
23
+ textValid: "Yes",
24
+ textInvalid: "No",
25
+ labelHint: "Hint",
26
+ uploadStatText: "Total: {{total}}, Success: {{success}}, Failed: {{failed}}",
27
+ buttonExportException: "Error report",
28
+ buttonExportFull: "Full report",
29
+ buttonReset: "Reset"
30
+ };
31
+ const i18nRes = i18nUtils.createResourceProxy(langRes, 'batchUploading');
32
+ export default i18nRes;
@@ -0,0 +1,2 @@
1
+ import i18nRes from "./i18nRes";
2
+ export default i18nRes;
@@ -0,0 +1,2 @@
1
+ import i18nRes from "./i18nRes";
2
+ export default i18nRes;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  import FileUploadWizard from "./FileUploadWizard.svelte";
2
+ import "@ticatec/uniface-element/Dialog";
3
+ import "@ticatec/uniface-element/Toast";
4
+ import "@ticatec/uniface-element/IndicatorBoard";
2
5
  export default FileUploadWizard;
package/dist/index.js CHANGED
@@ -1,2 +1,5 @@
1
1
  import FileUploadWizard from "./FileUploadWizard.svelte";
2
+ import "@ticatec/uniface-element/Dialog";
3
+ import "@ticatec/uniface-element/Toast";
4
+ import "@ticatec/uniface-element/IndicatorBoard";
2
5
  export default FileUploadWizard;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ticatec/batch-data-uploader",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A reusable Svelte component for batch uploading Excel data with support for error handling, multi-language, and preprocessing.",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -73,8 +73,8 @@
73
73
  "@sveltejs/kit": "^2.0.0",
74
74
  "@sveltejs/package": "^2.0.0",
75
75
  "@sveltejs/vite-plugin-svelte": "^4.0.0",
76
- "@ticatec/i18n": "^0.2.0",
77
- "@ticatec/uniface-element": "^0.1.71",
76
+ "@ticatec/i18n": "^0.2.3",
77
+ "@ticatec/uniface-element": "^0.3.5",
78
78
  "@ticatec/uniface-google-material-icons": "^0.1.2",
79
79
  "dayjs": "^1.11.10",
80
80
  "publint": "^0.3.2",
@@ -1,22 +0,0 @@
1
- declare const langRes: {
2
- batchUploading: {
3
- status: {
4
- pending: string;
5
- uploading: string;
6
- successful: string;
7
- fail: string;
8
- };
9
- parsing: string;
10
- parseFailure: string;
11
- waitUploading: string;
12
- button: {
13
- upload: string;
14
- save: string;
15
- open: string;
16
- };
17
- errorTitle: string;
18
- sheetName: string;
19
- labelStatus: string;
20
- };
21
- };
22
- export default langRes;
@@ -1,22 +0,0 @@
1
- const langRes = {
2
- batchUploading: {
3
- status: {
4
- pending: '待上传',
5
- uploading: "上传中...",
6
- successful: '处理成功',
7
- fail: '处理失败'
8
- },
9
- parsing: '解析文件...',
10
- parseFailure: '无法解析文件{{name}}',
11
- waitUploading: '上传过程中无法退出!',
12
- button: {
13
- upload: '上传',
14
- save: '导出异常',
15
- open: '文件'
16
- },
17
- errorTitle: '异常原因',
18
- sheetName: '错误数据',
19
- labelStatus: "状态"
20
- }
21
- };
22
- export default langRes;
@@ -1,27 +0,0 @@
1
- declare const langRes: {
2
- batchUploading: {
3
- status: {
4
- pending: string;
5
- uploading: string;
6
- successful: string;
7
- fail: string;
8
- };
9
- parsing: string;
10
- parseFailure: string;
11
- waitUploading: string;
12
- button: {
13
- upload: string;
14
- save: string;
15
- open: string;
16
- confirm: string;
17
- };
18
- errorTitle: string;
19
- sheetName: string;
20
- labelStatus: string;
21
- labelValid: string;
22
- textValid: string;
23
- textInvalid: string;
24
- labelHint: string;
25
- };
26
- };
27
- export default langRes;
@@ -1,27 +0,0 @@
1
- const langRes = {
2
- batchUploading: {
3
- status: {
4
- pending: "To upload",
5
- uploading: "Uploading...",
6
- successful: "Success",
7
- fail: "Failure"
8
- },
9
- parsing: "Parsing file...",
10
- parseFailure: "Cannot parse file: {{name}}",
11
- waitUploading: "Cannot exit during uploading!",
12
- button: {
13
- upload: "Upload",
14
- save: "Save error data",
15
- open: "Open",
16
- confirm: "Confirm"
17
- },
18
- errorTitle: "Error",
19
- sheetName: "Abnormal data",
20
- labelStatus: "Status",
21
- labelValid: "Validity",
22
- textValid: "Yes",
23
- textInvalid: "No",
24
- labelHint: "Hint"
25
- }
26
- };
27
- export default langRes;
@@ -1,79 +0,0 @@
1
- declare const i18nKeys: {
2
- status: {
3
- pending: {
4
- key: string;
5
- text: string;
6
- };
7
- uploading: {
8
- key: string;
9
- text: string;
10
- };
11
- successful: {
12
- key: string;
13
- text: string;
14
- };
15
- fail: {
16
- key: string;
17
- text: string;
18
- };
19
- };
20
- labelValid: {
21
- key: string;
22
- text: string;
23
- };
24
- labelHint: {
25
- key: string;
26
- text: string;
27
- };
28
- labelStatus: {
29
- key: string;
30
- text: string;
31
- };
32
- parsing: {
33
- key: string;
34
- text: string;
35
- };
36
- parseFailure: {
37
- key: string;
38
- text: string;
39
- };
40
- waitUploading: {
41
- key: string;
42
- text: string;
43
- };
44
- button: {
45
- upload: {
46
- key: string;
47
- text: string;
48
- };
49
- save: {
50
- key: string;
51
- text: string;
52
- };
53
- open: {
54
- key: string;
55
- text: string;
56
- };
57
- confirm: {
58
- key: string;
59
- text: string;
60
- };
61
- };
62
- errorTitle: {
63
- key: string;
64
- text: string;
65
- };
66
- sheetName: {
67
- key: string;
68
- text: string;
69
- };
70
- textValid: {
71
- key: string;
72
- text: string;
73
- };
74
- textInvalid: {
75
- key: string;
76
- text: string;
77
- };
78
- };
79
- export default i18nKeys;