@ticatec/batch-data-uploader 0.0.2 → 0.0.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/README.md CHANGED
@@ -29,10 +29,10 @@ npm i @ticatec/batch-data-uploader
29
29
  Extend `BaseTemplate`, provide field definitions and upload logic, and optionally override `consolidateData` to process data.
30
30
 
31
31
  ```ts
32
- import BaseTemplate from '$lib/BaseTemplate';
33
- import type DataColumn from './DataColumn';
32
+ import BaseUploadTemplate from '@ticatec/batch-data-uploader/BaseUploadTemplate';
33
+ import type DataColumn from '@ticatec/batch-data-uploader/DataColumn';
34
34
 
35
- class MyDataTemplate extends BaseTemplate {
35
+ class MyDataTemplate extends BaseUploadTemplate {
36
36
  constructor(uploadFun: UploadFun) {
37
37
  const columns: DataColumn[] = [
38
38
  { text: 'Name', field: 'name', pos: 0 },
@@ -0,0 +1,18 @@
1
+ import BaseTemplate from "./BaseTemplate";
2
+ import type DataColumn from "./DataColumn";
3
+ export type DataFetcher = (rows: Array<any>) => Promise<Array<any>>;
4
+ export type CheckMatch = (o1: any, o2: any) => boolean;
5
+ /**
6
+ * 用于前台数据和服务器端的数据整合
7
+ */
8
+ export default abstract class BaseLoadTemplate extends BaseTemplate {
9
+ protected fetcher: DataFetcher;
10
+ protected isMatch: CheckMatch;
11
+ protected constructor(columns: Array<DataColumn>, fetcher: DataFetcher, checkMatch: CheckMatch, rowOffset?: number);
12
+ /**
13
+ * 从服务器抓取数据,然后根据主键进行数据合并
14
+ * @param rows
15
+ * @protected
16
+ */
17
+ protected consolidateData(rows: Array<any>): Promise<Array<any>>;
18
+ }
@@ -0,0 +1,25 @@
1
+ import BaseTemplate from "./BaseTemplate";
2
+ /**
3
+ * 用于前台数据和服务器端的数据整合
4
+ */
5
+ export default class BaseLoadTemplate extends BaseTemplate {
6
+ fetcher;
7
+ isMatch;
8
+ constructor(columns, fetcher, checkMatch, rowOffset = 1) {
9
+ super(columns, rowOffset);
10
+ this.fetcher = fetcher;
11
+ this.isMatch = checkMatch;
12
+ }
13
+ /**
14
+ * 从服务器抓取数据,然后根据主键进行数据合并
15
+ * @param rows
16
+ * @protected
17
+ */
18
+ async consolidateData(rows) {
19
+ let data = await this.fetcher?.(rows);
20
+ return rows.map(row => {
21
+ let item = data.find(el => this.isMatch(row, el));
22
+ return [...row, ...item];
23
+ });
24
+ }
25
+ }
@@ -1,28 +1,16 @@
1
1
  import type DataColumn from "./DataColumn";
2
2
  import type { DataColumn as TableColumn } from "@ticatec/uniface-element/DataTable";
3
- export type UploadFun = (arr: Array<any>) => Promise<void>;
4
- export type UpdateProgressStatus = () => void;
5
3
  export default abstract class BaseTemplate {
6
4
  protected readonly _columns: Array<DataColumn>;
7
5
  protected readonly rowOffset: number;
8
6
  protected _list: Array<any>;
9
- protected uploadFun: UploadFun;
10
- protected batchSize: number;
11
- protected updateProgressStatus: UpdateProgressStatus | null;
12
7
  /**
13
8
  *
14
9
  * @param columns
15
- * @param uploadFun
16
- * @param batchSize
17
10
  * @param rowOffset
18
11
  * @protected
19
12
  */
20
- protected constructor(columns: Array<DataColumn>, uploadFun: UploadFun, batchSize?: number, rowOffset?: number);
21
- /**
22
- * 状态更新的监听器
23
- * @param value
24
- */
25
- setProgressStatusListener(value: UpdateProgressStatus): void;
13
+ protected constructor(columns: Array<DataColumn>, rowOffset?: number);
26
14
  /**
27
15
  * 整理数据,在子类可以通过重载完成数据的二次处理
28
16
  * @param rows
@@ -35,9 +23,11 @@ export default abstract class BaseTemplate {
35
23
  */
36
24
  parseExcelFile(file: File): Promise<void>;
37
25
  /**
38
- * 上传数据
26
+ * 包裹数据
27
+ * @param data
28
+ * @protected
39
29
  */
40
- upload(): Promise<void>;
30
+ protected wrapData(data: any): any;
41
31
  /**
42
32
  * 获取表格的列定义
43
33
  */
@@ -46,9 +36,4 @@ export default abstract class BaseTemplate {
46
36
  * 获取数据
47
37
  */
48
38
  get list(): Array<any>;
49
- /**
50
- * 导出处理异常的数据
51
- * @param filename
52
- */
53
- exportErrorRowsToExcel(filename: string): void;
54
39
  }
@@ -1,55 +1,18 @@
1
1
  import * as XLSX from 'xlsx';
2
2
  import utils from "./utils";
3
- import { getI18nText } from "@ticatec/i18n";
4
- import i18nKeys from "./i18n_resources/i18nKeys";
5
- const statusColumn = {
6
- text: "status",
7
- width: 150,
8
- resizable: true,
9
- formatter: row => {
10
- if (row.status == 'P') {
11
- return getI18nText(i18nKeys.status.pending);
12
- }
13
- else if (row.status == 'U') {
14
- return getI18nText(i18nKeys.status.uploading);
15
- }
16
- else {
17
- if (row.error) {
18
- return row.errorText;
19
- }
20
- else {
21
- return getI18nText(i18nKeys.status.successful);
22
- }
23
- }
24
- }
25
- };
26
3
  export default class BaseTemplate {
27
4
  _columns;
28
5
  rowOffset;
29
6
  _list = [];
30
- uploadFun;
31
- batchSize;
32
- updateProgressStatus = null;
33
7
  /**
34
8
  *
35
9
  * @param columns
36
- * @param uploadFun
37
- * @param batchSize
38
10
  * @param rowOffset
39
11
  * @protected
40
12
  */
41
- constructor(columns, uploadFun, batchSize = 50, rowOffset = 1) {
13
+ constructor(columns, rowOffset = 1) {
42
14
  this._columns = columns;
43
15
  this.rowOffset = rowOffset;
44
- this.uploadFun = uploadFun;
45
- this.batchSize = batchSize;
46
- }
47
- /**
48
- * 状态更新的监听器
49
- * @param value
50
- */
51
- setProgressStatusListener(value) {
52
- this.updateProgressStatus = value;
53
16
  }
54
17
  /**
55
18
  * 整理数据,在子类可以通过重载完成数据的二次处理
@@ -69,7 +32,7 @@ export default class BaseTemplate {
69
32
  const sheet = workbook.Sheets[workbook.SheetNames[0]];
70
33
  const range = XLSX.utils.decode_range(sheet['!ref'] || ''); // 获取范围
71
34
  const rows = [];
72
- for (let rowIndex = range.s.r + 1 + this.rowOffset; rowIndex <= range.e.r; rowIndex++) {
35
+ for (let rowIndex = range.s.r + this.rowOffset; rowIndex <= range.e.r; rowIndex++) {
73
36
  const rowObject = {};
74
37
  for (const colDef of this._columns) {
75
38
  const cellAddress = { r: rowIndex, c: colDef.pos };
@@ -79,29 +42,23 @@ export default class BaseTemplate {
79
42
  const formattedValue = colDef.parser ? colDef.parser(rawValue) : rawValue;
80
43
  utils.setNestedValue(rowObject, colDef.field, formattedValue);
81
44
  }
82
- rows.push({ data: rowObject, status: 'P' });
45
+ rows.push(this.wrapData(rowObject));
83
46
  }
84
47
  this._list = await this.consolidateData(rows);
85
48
  }
86
49
  /**
87
- * 上传数据
50
+ * 包裹数据
51
+ * @param data
52
+ * @protected
88
53
  */
89
- async upload() {
90
- for (let i = 0; i < this.list.length; i += this.batchSize) {
91
- const chunk = this.list.slice(i, i + this.batchSize);
92
- chunk.forEach(item => item.status = 'U');
93
- this.updateProgressStatus?.();
94
- await this.uploadFun(chunk);
95
- chunk.forEach(item => item.status = 'D');
96
- this.updateProgressStatus?.();
97
- }
54
+ wrapData(data) {
55
+ return data;
98
56
  }
99
57
  /**
100
58
  * 获取表格的列定义
101
59
  */
102
60
  get columns() {
103
- let columns = this._columns.map(col => ({ ...col, field: `data.${col.field}` }));
104
- return [...columns, statusColumn];
61
+ return this._columns.map(col => ({ ...col }));
105
62
  }
106
63
  /**
107
64
  * 获取数据
@@ -109,41 +66,4 @@ export default class BaseTemplate {
109
66
  get list() {
110
67
  return [...this._list];
111
68
  }
112
- /**
113
- * 导出处理异常的数据
114
- * @param filename
115
- */
116
- exportErrorRowsToExcel(filename) {
117
- // 筛选出有错误的行
118
- const errorRows = this._list.filter(row => row.error != null);
119
- // 生成 Excel 数据(第一行为标题)
120
- const header = [...this._columns.map(col => col.text), getI18nText(i18nKeys.errorTitle)];
121
- const data = errorRows.map(row => {
122
- const values = this._columns.map(col => {
123
- return utils.getNestedValue(row.data, col.field);
124
- });
125
- return [...values, row.error];
126
- });
127
- const worksheetData = [header, ...data];
128
- const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);
129
- const workbook = XLSX.utils.book_new();
130
- XLSX.utils.book_append_sheet(workbook, worksheet, getI18nText(i18nKeys.sheetName));
131
- const wbout = XLSX.write(workbook, {
132
- bookType: 'xlsx',
133
- type: 'array'
134
- });
135
- // 创建 Blob 并触发下载
136
- const blob = new Blob([wbout], {
137
- type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
138
- });
139
- const url = URL.createObjectURL(blob);
140
- const a = document.createElement('a');
141
- a.href = url;
142
- a.download = filename;
143
- a.style.display = 'none';
144
- document.body.appendChild(a);
145
- a.click();
146
- document.body.removeChild(a);
147
- URL.revokeObjectURL(url);
148
- }
149
69
  }
@@ -0,0 +1,35 @@
1
+ import BaseTemplate from "./BaseTemplate";
2
+ import type { DataColumn as TableColumn } from "@ticatec/uniface-element/DataTable";
3
+ import type DataColumn from "./DataColumn";
4
+ export type UploadFun = (arr: Array<any>) => Promise<void>;
5
+ export type UpdateProgressStatus = () => void;
6
+ export default abstract class BaseUploadTemplate extends BaseTemplate {
7
+ protected uploadFun: UploadFun;
8
+ protected batchSize: number;
9
+ protected updateProgressStatus: UpdateProgressStatus | null;
10
+ protected constructor(columns: Array<DataColumn>, uploadFun: UploadFun, batchSize?: number, rowOffset?: number);
11
+ /**
12
+ * 状态更新的监听器
13
+ * @param value
14
+ */
15
+ setProgressStatusListener(value: UpdateProgressStatus): void;
16
+ /**
17
+ * 上传数据
18
+ */
19
+ upload(): Promise<void>;
20
+ /**
21
+ * 将数据包裹着一个对象里面
22
+ * @param data
23
+ * @protected
24
+ */
25
+ protected wrapData(data: any): any;
26
+ /**
27
+ * 获取表格的列定义
28
+ */
29
+ get columns(): Array<TableColumn>;
30
+ /**
31
+ * 导出处理异常的数据
32
+ * @param filename
33
+ */
34
+ exportErrorRowsToExcel(filename: string): void;
35
+ }
@@ -0,0 +1,108 @@
1
+ import BaseTemplate from "./BaseTemplate";
2
+ import { getI18nText } from "@ticatec/i18n";
3
+ import i18nKeys from "./i18n_resources/i18nKeys";
4
+ import utils from "./utils";
5
+ import * as XLSX from 'xlsx';
6
+ const statusColumn = {
7
+ text: "status",
8
+ width: 150,
9
+ resizable: true,
10
+ formatter: row => {
11
+ if (row.status == 'P') {
12
+ return getI18nText(i18nKeys.status.pending);
13
+ }
14
+ else if (row.status == 'U') {
15
+ return getI18nText(i18nKeys.status.uploading);
16
+ }
17
+ else {
18
+ if (row.error) {
19
+ return row.errorText;
20
+ }
21
+ else {
22
+ return getI18nText(i18nKeys.status.successful);
23
+ }
24
+ }
25
+ }
26
+ };
27
+ export default class BaseUploadTemplate extends BaseTemplate {
28
+ uploadFun;
29
+ batchSize;
30
+ updateProgressStatus = null;
31
+ constructor(columns, uploadFun, batchSize = 50, rowOffset = 1) {
32
+ super(columns, rowOffset);
33
+ ;
34
+ this.uploadFun = uploadFun;
35
+ this.batchSize = batchSize;
36
+ }
37
+ /**
38
+ * 状态更新的监听器
39
+ * @param value
40
+ */
41
+ setProgressStatusListener(value) {
42
+ this.updateProgressStatus = value;
43
+ }
44
+ /**
45
+ * 上传数据
46
+ */
47
+ async upload() {
48
+ for (let i = 0; i < this.list.length; i += this.batchSize) {
49
+ const chunk = this.list.slice(i, i + this.batchSize);
50
+ chunk.forEach(item => item.status = 'U');
51
+ this.updateProgressStatus?.();
52
+ await this.uploadFun(chunk);
53
+ chunk.forEach(item => item.status = 'D');
54
+ this.updateProgressStatus?.();
55
+ }
56
+ }
57
+ /**
58
+ * 将数据包裹着一个对象里面
59
+ * @param data
60
+ * @protected
61
+ */
62
+ wrapData(data) {
63
+ return { data, status: 'P' };
64
+ }
65
+ /**
66
+ * 获取表格的列定义
67
+ */
68
+ get columns() {
69
+ return [...this._columns.map(col => ({ ...col, field: `data.${col.field}` })), statusColumn];
70
+ }
71
+ /**
72
+ * 导出处理异常的数据
73
+ * @param filename
74
+ */
75
+ exportErrorRowsToExcel(filename) {
76
+ // 筛选出有错误的行
77
+ const errorRows = this._list.filter(row => row.error != null);
78
+ // 生成 Excel 数据(第一行为标题)
79
+ const header = [...this._columns.map(col => col.text), getI18nText(i18nKeys.errorTitle)];
80
+ const data = errorRows.map(row => {
81
+ const values = this._columns.map(col => {
82
+ return utils.getNestedValue(row.data, col.field);
83
+ });
84
+ return [...values, row.error];
85
+ });
86
+ const worksheetData = [header, ...data];
87
+ const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);
88
+ const workbook = XLSX.utils.book_new();
89
+ XLSX.utils.book_append_sheet(workbook, worksheet, getI18nText(i18nKeys.sheetName));
90
+ const wbout = XLSX.write(workbook, {
91
+ bookType: 'xlsx',
92
+ type: 'array'
93
+ });
94
+ // 创建 Blob 并触发下载
95
+ const blob = new Blob([wbout], {
96
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
97
+ });
98
+ const url = URL.createObjectURL(blob);
99
+ const a = document.createElement('a');
100
+ a.href = url;
101
+ a.download = filename;
102
+ a.style.display = 'none';
103
+ document.body.appendChild(a);
104
+ a.click();
105
+ document.body.removeChild(a);
106
+ URL.revokeObjectURL(url);
107
+ }
108
+ }
@@ -8,6 +8,7 @@
8
8
  import type BaseTemplate from "./BaseTemplate";
9
9
  import type DataColumn from "@ticatec/uniface-element/DataTable";
10
10
  import i18nKeys from "./i18n_resources/i18nKeys";
11
+ import type BaseUploadTemplate from "./BaseUploadTemplate.js";
11
12
 
12
13
  export let title: string;
13
14
 
@@ -15,7 +16,7 @@
15
16
  export let height: string = "600px"
16
17
 
17
18
  export let closeHandler: any;
18
- export let template: BaseTemplate;
19
+ export let template: BaseUploadTemplate;
19
20
 
20
21
  type ProcessStatus = 'Init' | 'Pending' | 'Uploading' | 'Done'; //初始状态,待上传,上传中,处理完成
21
22
 
@@ -1,4 +1,4 @@
1
- import type BaseTemplate from "./BaseTemplate";
1
+ import type BaseUploadTemplate from "./BaseUploadTemplate.js";
2
2
  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> {
3
3
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
4
  $$bindings?: Bindings;
@@ -17,7 +17,7 @@ declare const FileUploadWizard: $$__sveltets_2_IsomorphicComponent<{
17
17
  width?: string;
18
18
  height?: string;
19
19
  closeHandler: any;
20
- template: BaseTemplate;
20
+ template: BaseUploadTemplate;
21
21
  }, {
22
22
  [evt: string]: CustomEvent<any>;
23
23
  }, {}, {}, string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ticatec/batch-data-uploader",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
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",
@@ -42,6 +42,14 @@
42
42
  "types": "./dist/BaseTemplate.d.ts",
43
43
  "import": "./dist/BaseTemplate.js"
44
44
  },
45
+ "./BaseUploadTemplate": {
46
+ "types": "./dist/BaseUploadTemplate.d.ts",
47
+ "import": "./dist/BaseUploadTemplate.js"
48
+ },
49
+ "./BaseLoadTemplate": {
50
+ "types": "./dist/BaseLoadTemplate.d.ts",
51
+ "import": "./dist/BaseLoadTemplate.js"
52
+ },
45
53
  "./DataColumn": {
46
54
  "types": "./dist/DataColumn.d.ts",
47
55
  "import": "./dist/DataColumn.js"