@visactor/vtable-plugins 1.19.1 → 1.19.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.
@@ -0,0 +1,52 @@
1
+ import type { ListTable } from '@visactor/vtable';
2
+ import * as VTable from '@visactor/vtable';
3
+ export interface ImportResult {
4
+ columns: VTable.ColumnsDefine;
5
+ records: Record<string, unknown>[];
6
+ }
7
+ export interface ExcelImportOptions {
8
+ id?: string;
9
+ headerRowCount?: number;
10
+ exportData?: boolean;
11
+ autoTable?: boolean;
12
+ autoColumns?: boolean;
13
+ delimiter?: string;
14
+ batchSize?: number;
15
+ enableBatchProcessing?: boolean;
16
+ asyncDelay?: number;
17
+ }
18
+ export declare class ExcelImportPlugin implements VTable.plugins.IVTablePlugin {
19
+ id: string;
20
+ name: string;
21
+ runTime: "initialized"[];
22
+ private options;
23
+ private _tableInstance;
24
+ constructor(options?: ExcelImportOptions);
25
+ run(...args: [unknown, unknown, ListTable]): void;
26
+ release(): void;
27
+ importFile(): Promise<ImportResult>;
28
+ import(type: 'file' | 'csv' | 'json' | 'html', source?: string | object, options?: Partial<ExcelImportOptions>): Promise<ImportResult>;
29
+ private _importFromFileDialog;
30
+ private _importFromString;
31
+ private _importFromData;
32
+ private _parseFile;
33
+ private _getFileExtension;
34
+ private _parseExcelFile;
35
+ private _parseCsvFile;
36
+ private _parseJsonFile;
37
+ private _parseHtmlFile;
38
+ private _buildColumnsFromHeaders;
39
+ static importExcelToVTableData(file: File, options?: ExcelImportOptions): Promise<{
40
+ columns: VTable.TYPES.ColumnsDefine;
41
+ records: Record<string, unknown>[];
42
+ }>;
43
+ private static detectHeaderRowCount;
44
+ private static buildColumns;
45
+ private _parseCSVString;
46
+ private _parseJSONString;
47
+ private _parseHTMLString;
48
+ private _parseJSONData;
49
+ private static _generateJavaScriptExport;
50
+ private _exportToJS;
51
+ private _processBatchRecords;
52
+ }
@@ -0,0 +1,410 @@
1
+ var __awaiter = this && this.__awaiter || function(thisArg, _arguments, P, generator) {
2
+ return new (P || (P = Promise))((function(resolve, reject) {
3
+ function fulfilled(value) {
4
+ try {
5
+ step(generator.next(value));
6
+ } catch (e) {
7
+ reject(e);
8
+ }
9
+ }
10
+ function rejected(value) {
11
+ try {
12
+ step(generator.throw(value));
13
+ } catch (e) {
14
+ reject(e);
15
+ }
16
+ }
17
+ function step(result) {
18
+ var value;
19
+ result.done ? resolve(result.value) : (value = result.value, value instanceof P ? value : new P((function(resolve) {
20
+ resolve(value);
21
+ }))).then(fulfilled, rejected);
22
+ }
23
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
24
+ }));
25
+ };
26
+
27
+ import ExcelJS from "exceljs";
28
+
29
+ import * as VTable from "@visactor/vtable";
30
+
31
+ export class ExcelImportPlugin {
32
+ constructor(options) {
33
+ this.id = `excel-import-plugin-${Date.now()}`, this.name = "ExcelImportPlugin",
34
+ this.runTime = [ VTable.TABLE_EVENT_TYPE.INITIALIZED ], this._tableInstance = null,
35
+ this.options = Object.assign({
36
+ autoTable: !0,
37
+ autoColumns: !0,
38
+ delimiter: ",",
39
+ exportData: !1,
40
+ batchSize: 1e3,
41
+ enableBatchProcessing: !0,
42
+ asyncDelay: 5
43
+ }, options), (null == options ? void 0 : options.id) && (this.id = options.id);
44
+ }
45
+ run(...args) {
46
+ const tableInstance = args[2];
47
+ this._tableInstance = tableInstance;
48
+ }
49
+ release() {
50
+ this._tableInstance = null;
51
+ }
52
+ importFile() {
53
+ return __awaiter(this, void 0, void 0, (function*() {
54
+ return this.import("file");
55
+ }));
56
+ }
57
+ import(type, source, options) {
58
+ return __awaiter(this, void 0, void 0, (function*() {
59
+ const mergedOptions = Object.assign(Object.assign({}, this.options), options);
60
+ if ("file" === type) return this._importFromFileDialog(mergedOptions);
61
+ if ("string" == typeof source) return this._importFromString(type, source, mergedOptions);
62
+ if (Array.isArray(source) || "object" == typeof source) {
63
+ if ("json" !== type) throw new Error("只有JSON格式支持从对象导入");
64
+ return this._importFromData("json", source, mergedOptions);
65
+ }
66
+ throw new Error("Invalid import source");
67
+ }));
68
+ }
69
+ _importFromFileDialog(options) {
70
+ return __awaiter(this, void 0, void 0, (function*() {
71
+ return new Promise(((resolve, reject) => {
72
+ if (!this._tableInstance) return void reject(new Error("表格实例不存在或已销毁,无法导入数据!"));
73
+ const input = document.createElement("input");
74
+ input.type = "file", input.style.display = "none", document.body.appendChild(input),
75
+ input.addEventListener("change", (e => __awaiter(this, void 0, void 0, (function*() {
76
+ var _a;
77
+ try {
78
+ const file = null === (_a = e.target.files) || void 0 === _a ? void 0 : _a[0];
79
+ if (!file) return document.body.removeChild(input), void reject(new Error("未选择文件"));
80
+ const result = yield this._parseFile(file, options);
81
+ options.autoTable && this._tableInstance && (options.autoColumns && this._tableInstance.updateOption({
82
+ columns: result.columns,
83
+ plugins: [ this ]
84
+ }), this._tableInstance.setRecords(result.records)), input.value = "", document.body.removeChild(input),
85
+ resolve(result);
86
+ } catch (error) {
87
+ document.body.removeChild(input), reject(error);
88
+ }
89
+ })))), input.click();
90
+ }));
91
+ }));
92
+ }
93
+ _importFromString(type, data, options) {
94
+ return __awaiter(this, void 0, void 0, (function*() {
95
+ let result;
96
+ switch (type) {
97
+ case "csv":
98
+ result = yield this._parseCSVString(data, options);
99
+ break;
100
+
101
+ case "json":
102
+ result = yield this._parseJSONString(data, options);
103
+ break;
104
+
105
+ case "html":
106
+ result = yield this._parseHTMLString(data, options);
107
+ break;
108
+
109
+ default:
110
+ throw new Error(`不支持的导入类型: ${type}`);
111
+ }
112
+ return options.autoTable && this._tableInstance && (options.autoColumns && this._tableInstance.updateOption({
113
+ columns: result.columns,
114
+ plugins: [ this ]
115
+ }), this._tableInstance.setRecords(result.records)), result;
116
+ }));
117
+ }
118
+ _importFromData(type, data, options) {
119
+ return __awaiter(this, void 0, void 0, (function*() {
120
+ let result;
121
+ if ("json" !== type) throw new Error(`不支持的数据类型: ${type}`);
122
+ return result = yield this._parseJSONData(data, options), options.autoTable && this._tableInstance && (options.autoColumns && this._tableInstance.updateOption({
123
+ columns: result.columns,
124
+ plugins: [ this ]
125
+ }), this._tableInstance.setRecords(result.records)), result;
126
+ }));
127
+ }
128
+ _parseFile(file, options) {
129
+ return __awaiter(this, void 0, void 0, (function*() {
130
+ const mergedOptions = Object.assign(Object.assign({}, this.options), options), fileExtension = this._getFileExtension(file.name).toLowerCase();
131
+ switch (fileExtension) {
132
+ case "xlsx":
133
+ case "xls":
134
+ return yield this._parseExcelFile(file, mergedOptions);
135
+
136
+ case "csv":
137
+ return yield this._parseCsvFile(file, mergedOptions);
138
+
139
+ case "json":
140
+ return yield this._parseJsonFile(file, mergedOptions);
141
+
142
+ case "html":
143
+ case "htm":
144
+ return yield this._parseHtmlFile(file, mergedOptions);
145
+
146
+ default:
147
+ throw new Error(`不支持的文件类型: ${fileExtension}`);
148
+ }
149
+ }));
150
+ }
151
+ _getFileExtension(filename) {
152
+ const parts = filename.split(".");
153
+ return parts.length > 1 ? parts[parts.length - 1] : "";
154
+ }
155
+ _parseExcelFile(file, options) {
156
+ return __awaiter(this, void 0, void 0, (function*() {
157
+ const mergedOptions = Object.assign(Object.assign({}, this.options), options);
158
+ return yield ExcelImportPlugin.importExcelToVTableData(file, mergedOptions);
159
+ }));
160
+ }
161
+ _parseCsvFile(file, options) {
162
+ return __awaiter(this, void 0, void 0, (function*() {
163
+ const mergedOptions = Object.assign(Object.assign({}, this.options), options), text = yield file.text();
164
+ return this._parseCSVString(text, mergedOptions);
165
+ }));
166
+ }
167
+ _parseJsonFile(file, options) {
168
+ return __awaiter(this, void 0, void 0, (function*() {
169
+ const mergedOptions = Object.assign(Object.assign({}, this.options), options), text = yield file.text();
170
+ return this._parseJSONString(text, mergedOptions);
171
+ }));
172
+ }
173
+ _parseHtmlFile(file, options) {
174
+ return __awaiter(this, void 0, void 0, (function*() {
175
+ const mergedOptions = Object.assign(Object.assign({}, this.options), options), text = yield file.text();
176
+ return this._parseHTMLString(text, mergedOptions);
177
+ }));
178
+ }
179
+ _buildColumnsFromHeaders(headerRows) {
180
+ return 1 === headerRows.length ? headerRows[0].map(((title, index) => ({
181
+ field: `col${index}`,
182
+ title: title || `列${index + 1}`,
183
+ cellType: "text",
184
+ headerType: "text"
185
+ }))) : ExcelImportPlugin.buildColumns(headerRows);
186
+ }
187
+ static importExcelToVTableData(file, options) {
188
+ var _a;
189
+ return __awaiter(this, void 0, void 0, (function*() {
190
+ const workbook = new ExcelJS.Workbook;
191
+ yield workbook.xlsx.load(yield file.arrayBuffer());
192
+ const worksheet = workbook.worksheets[0];
193
+ if (!worksheet) throw new Error("Excel 文件无有效工作表");
194
+ const detectedHeaderRows = null !== (_a = null == options ? void 0 : options.headerRowCount) && void 0 !== _a ? _a : this.detectHeaderRowCount(worksheet), headerRows = [];
195
+ for (let i = 1; i <= detectedHeaderRows; i++) {
196
+ const row = worksheet.getRow(i);
197
+ headerRows.push(Array.prototype.slice.call(row.values, 1));
198
+ }
199
+ const columns = ExcelImportPlugin.buildColumns(headerRows), records = [], dataRows = [];
200
+ worksheet.eachRow(((row, rowNumber) => {
201
+ if (rowNumber <= detectedHeaderRows) return;
202
+ const cells = Array.prototype.slice.call(row.values, 1);
203
+ dataRows.push(cells);
204
+ }));
205
+ const batchSize = (null == options ? void 0 : options.batchSize) || 1e3;
206
+ if (!1 !== (null == options ? void 0 : options.enableBatchProcessing) && dataRows.length > batchSize) for (let i = 0; i < dataRows.length; i += batchSize) {
207
+ const batchRecords = dataRows.slice(i, i + batchSize).map((cells => {
208
+ const record = {};
209
+ return cells.forEach(((cell, j) => {
210
+ record[`col${j}`] = cell;
211
+ })), record;
212
+ }));
213
+ records.push(...batchRecords), i + batchSize < dataRows.length && (yield new Promise((resolve => setTimeout(resolve, (null == options ? void 0 : options.asyncDelay) || 5))));
214
+ } else dataRows.forEach((cells => {
215
+ const record = {};
216
+ cells.forEach(((cell, i) => {
217
+ record[`col${i}`] = cell;
218
+ })), records.push(record);
219
+ }));
220
+ if (null == options ? void 0 : options.exportData) {
221
+ const jsContent = ExcelImportPlugin._generateJavaScriptExport(columns, records), blob = new Blob([ jsContent ], {
222
+ type: "text/javascript"
223
+ }), url = URL.createObjectURL(blob), a = document.createElement("a");
224
+ a.href = url, a.download = "vtable-data.js", document.body.appendChild(a), a.click(),
225
+ setTimeout((() => {
226
+ document.body.removeChild(a), URL.revokeObjectURL(url);
227
+ }), 100);
228
+ }
229
+ return {
230
+ columns: columns,
231
+ records: records
232
+ };
233
+ }));
234
+ }
235
+ static detectHeaderRowCount(worksheet) {
236
+ let rowIndex = 1, headerRowCount = 1;
237
+ for (;;) {
238
+ const row = worksheet.getRow(rowIndex), cells = Array.prototype.slice.call(row.values, 1);
239
+ let hasConsecutive = !1;
240
+ for (let i = 1; i < cells.length; i++) if (void 0 !== cells[i] && "" !== cells[i] && cells[i] === cells[i - 1]) {
241
+ hasConsecutive = !0;
242
+ break;
243
+ }
244
+ if (!hasConsecutive) break;
245
+ headerRowCount++, rowIndex++;
246
+ }
247
+ return headerRowCount;
248
+ }
249
+ static buildColumns(headerRows, colStart = 0, colEnd, level = 0) {
250
+ const row = headerRows[level], columns = [];
251
+ colEnd = null != colEnd ? colEnd : row.length;
252
+ let i = colStart;
253
+ for (;i < colEnd; ) {
254
+ const title = String(row[i] || `列${i + 1}`);
255
+ let span = 1;
256
+ for (;i + span < colEnd && row[i + span] === title; ) span++;
257
+ if (level < headerRows.length - 1) {
258
+ const subColumns = ExcelImportPlugin.buildColumns(headerRows, i, i + span, level + 1);
259
+ 1 === subColumns.length ? columns.push(subColumns[0]) : columns.push({
260
+ title: title,
261
+ columns: subColumns,
262
+ hideColumnsSubHeader: !1
263
+ });
264
+ } else columns.push({
265
+ field: `col${i}`,
266
+ title: title,
267
+ cellType: "text",
268
+ headerType: "text"
269
+ });
270
+ i += span;
271
+ }
272
+ return columns;
273
+ }
274
+ _parseCSVString(text, options) {
275
+ return __awaiter(this, void 0, void 0, (function*() {
276
+ const lines = text.split("\n").filter((line => line.trim()));
277
+ if (0 === lines.length) throw new Error("CSV文件为空");
278
+ const delimiter = options.delimiter || ",", parseCSVLine = line => line.split(delimiter).map((cell => cell.trim().replace(/^"|"$/g, ""))), headerRows = lines.slice(0, 1).map(parseCSVLine), dataRows = lines.slice(1), columns = this._buildColumnsFromHeaders(headerRows), records = [];
279
+ return yield this._processBatchRecords(dataRows, options, (batch => __awaiter(this, void 0, void 0, (function*() {
280
+ const batchRecords = batch.map((line => {
281
+ const parsedRow = parseCSVLine(line), record = {};
282
+ return parsedRow.forEach(((cell, i) => {
283
+ record[`col${i}`] = cell || "";
284
+ })), record;
285
+ }));
286
+ records.push(...batchRecords);
287
+ })))), options.exportData && this._exportToJS(columns, records), {
288
+ columns: columns,
289
+ records: records
290
+ };
291
+ }));
292
+ }
293
+ _parseJSONString(text, options) {
294
+ return __awaiter(this, void 0, void 0, (function*() {
295
+ let jsonData;
296
+ try {
297
+ jsonData = JSON.parse(text);
298
+ } catch (error) {
299
+ throw new Error("JSON文件格式错误");
300
+ }
301
+ const result = yield this._parseJSONData(jsonData, options);
302
+ return options.exportData && this._exportToJS(result.columns, result.records), result;
303
+ }));
304
+ }
305
+ _parseHTMLString(text, options) {
306
+ return __awaiter(this, void 0, void 0, (function*() {
307
+ const table = (new DOMParser).parseFromString(text, "text/html").querySelector("table");
308
+ if (!table) throw new Error("HTML文件中未找到表格");
309
+ const rows = Array.from(table.querySelectorAll("tr"));
310
+ if (0 === rows.length) throw new Error("表格中没有数据行");
311
+ const headerRows = rows.slice(0, 1).map((row => Array.from(row.querySelectorAll("th, td")).map((cell => {
312
+ var _a;
313
+ return (null === (_a = cell.textContent) || void 0 === _a ? void 0 : _a.trim()) || "";
314
+ })))), dataRows = rows.slice(1), columns = this._buildColumnsFromHeaders(headerRows), records = [];
315
+ return yield this._processBatchRecords(dataRows, options, (batch => __awaiter(this, void 0, void 0, (function*() {
316
+ const batchRecords = batch.map((row => {
317
+ const cells = Array.from(row.querySelectorAll("td")).map((cell => {
318
+ var _a;
319
+ return (null === (_a = cell.textContent) || void 0 === _a ? void 0 : _a.trim()) || "";
320
+ })), record = {};
321
+ return cells.forEach(((cell, i) => {
322
+ record[`col${i}`] = cell || "";
323
+ })), record;
324
+ }));
325
+ records.push(...batchRecords);
326
+ })))), options.exportData && this._exportToJS(columns, records), {
327
+ columns: columns,
328
+ records: records
329
+ };
330
+ }));
331
+ }
332
+ _parseJSONData(jsonData, options) {
333
+ return __awaiter(this, void 0, void 0, (function*() {
334
+ let result;
335
+ if ("object" == typeof jsonData && !Array.isArray(jsonData) && jsonData && "columns" in jsonData && "records" in jsonData) {
336
+ const data = jsonData, records = [];
337
+ yield this._processBatchRecords(data.records, options, (batch => __awaiter(this, void 0, void 0, (function*() {
338
+ const batchRecords = batch.map((record => Object.assign({}, record)));
339
+ records.push(...batchRecords);
340
+ })))), result = {
341
+ columns: data.columns,
342
+ records: records
343
+ };
344
+ } else {
345
+ if (!(Array.isArray(jsonData) && jsonData.length > 0)) throw new Error("不支持的JSON格式");
346
+ {
347
+ const firstRecord = jsonData[0], columns = Object.keys(firstRecord).map((key => ({
348
+ field: key,
349
+ title: key,
350
+ cellType: "text",
351
+ headerType: "text"
352
+ }))), records = [];
353
+ yield this._processBatchRecords(jsonData, options, (batch => __awaiter(this, void 0, void 0, (function*() {
354
+ const batchRecords = batch.map((record => Object.assign({}, record)));
355
+ records.push(...batchRecords);
356
+ })))), result = {
357
+ columns: columns,
358
+ records: records
359
+ };
360
+ }
361
+ }
362
+ return options.exportData && this._exportToJS(result.columns, result.records), result;
363
+ }));
364
+ }
365
+ static _generateJavaScriptExport(columns, records) {
366
+ const formatValue = (value, indent = "") => {
367
+ if (null == value) return "null";
368
+ if ("string" == typeof value) return `'${value.replace(/'/g, "\\'")}'`;
369
+ if ("number" == typeof value || "boolean" == typeof value) return String(value);
370
+ if (Array.isArray(value)) {
371
+ if (0 === value.length) return "[]";
372
+ return `[${value.map((item => formatValue(item, indent + " "))).join(", ")}]`;
373
+ }
374
+ if ("object" == typeof value) {
375
+ return `{\n${Object.entries(value).map((([key, val]) => `${indent} ${key}: ${formatValue(val, indent + " ")}`)).join(",\n")}\n${indent}}`;
376
+ }
377
+ return String(value);
378
+ }, formatColumn = (column, baseIndent = " ") => {
379
+ const props = Object.entries(column).map((([key, value]) => {
380
+ if ("columns" === key && Array.isArray(value)) {
381
+ const nestedColumns = value.map((col => formatColumn(col, baseIndent + " "))).join(",\n");
382
+ return `${baseIndent} ${key}: [\n${nestedColumns}\n${baseIndent} ]`;
383
+ }
384
+ return `${baseIndent} ${key}: ${formatValue(value)}`;
385
+ })).join(",\n");
386
+ return `${baseIndent}{\n${props}\n${baseIndent}}`;
387
+ }, columnsStr = columns.map((col => formatColumn(col))).join(",\n"), recordsStr = records.map((record => ` {\n${Object.entries(record).map((([key, value]) => ` ${key}: ${formatValue(value)}`)).join(",\n")}\n }`)).join(",\n");
388
+ return `// VTable 数据导出 - JavaScript 对象字面量格式\n// 生成时间: ${(new Date).toLocaleString()}\n\nconst vtableData = {\n columns: [\n${columnsStr}\n ],\n records: [\n${recordsStr}\n ]\n};\n`;
389
+ }
390
+ _exportToJS(columns, records) {
391
+ const jsContent = ExcelImportPlugin._generateJavaScriptExport(columns, records), blob = new Blob([ jsContent ], {
392
+ type: "text/javascript"
393
+ }), url = URL.createObjectURL(blob), a = document.createElement("a");
394
+ a.href = url, a.download = "vtable-data.js", document.body.appendChild(a), a.click(),
395
+ setTimeout((() => {
396
+ document.body.removeChild(a), URL.revokeObjectURL(url);
397
+ }), 100);
398
+ }
399
+ _processBatchRecords(records, options, processor) {
400
+ return __awaiter(this, void 0, void 0, (function*() {
401
+ if (!options.enableBatchProcessing || records.length <= (options.batchSize || 1e3)) return void (yield processor(records, 0));
402
+ const batchSize = options.batchSize || 1e3, totalBatches = Math.ceil(records.length / batchSize);
403
+ for (let i = 0; i < totalBatches; i++) {
404
+ const start = i * batchSize, end = Math.min(start + batchSize, records.length), batch = records.slice(start, end);
405
+ yield processor(batch, i), i < totalBatches - 1 && (yield new Promise((resolve => setTimeout(resolve, options.asyncDelay || 5))));
406
+ }
407
+ }));
408
+ }
409
+ }
410
+ //# sourceMappingURL=excel-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["excel-import.ts"],"names":[],"mappings":"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","file":"excel-import.js","sourcesContent":["import ExcelJS from 'exceljs';\r\nimport type { ListTable } from '@visactor/vtable';\r\nimport * as VTable from '@visactor/vtable';\r\n\r\n// 数据导入结果类型\r\nexport interface ImportResult {\r\n columns: VTable.ColumnsDefine;\r\n records: Record<string, unknown>[];\r\n}\r\n\r\nexport interface ExcelImportOptions {\r\n id?: string;\r\n headerRowCount?: number; // 指定头的层数,不指定会使用detectHeaderRowCount来自动判断,但是只有excel才有\r\n exportData?: boolean; // 是否导出JavaScript对象字面量格式文件\r\n autoTable?: boolean; // 是否自动替换表格数据\r\n autoColumns?: boolean; // 是否自动生成列配置\r\n delimiter?: string; // CSV分隔符,默认逗号\r\n batchSize?: number; // 批处理大小,默认1000行\r\n enableBatchProcessing?: boolean; // 是否启用分批处理,默认true\r\n asyncDelay?: number; // 异步处理延迟时间(ms),默认5ms\r\n}\r\n\r\nexport class ExcelImportPlugin implements VTable.plugins.IVTablePlugin {\r\n id: string = `excel-import-plugin-${Date.now()}`;\r\n name = 'ExcelImportPlugin';\r\n runTime = [VTable.TABLE_EVENT_TYPE.INITIALIZED];\r\n private options: ExcelImportOptions;\r\n private _tableInstance: ListTable | null = null;\r\n constructor(options?: ExcelImportOptions) {\r\n this.options = {\r\n autoTable: true,\r\n autoColumns: true,\r\n delimiter: ',',\r\n exportData: false,\r\n batchSize: 1000,\r\n enableBatchProcessing: true,\r\n asyncDelay: 5,\r\n ...options\r\n };\r\n if (options?.id) {\r\n this.id = options.id;\r\n }\r\n }\r\n\r\n run(...args: [unknown, unknown, ListTable]) {\r\n const tableInstance = args[2];\r\n this._tableInstance = tableInstance;\r\n }\r\n\r\n release() {\r\n this._tableInstance = null;\r\n }\r\n /**\r\n * 调用导入文件接口\r\n * @returns Promise<ImportResult>\r\n */\r\n async importFile(): Promise<ImportResult> {\r\n return this.import('file');\r\n }\r\n\r\n /**\r\n * @param type 导入类型: \"file\" | \"csv\" | \"json\" | \"html\"\r\n * @param source 数据源: 文件选择器 | 字符串数据\r\n * @param options 导入选项\r\n * @returns Promise<ImportResult>\r\n */\r\n async import(\r\n type: 'file' | 'csv' | 'json' | 'html',\r\n source?: string | object,\r\n options?: Partial<ExcelImportOptions>\r\n ): Promise<ImportResult> {\r\n const mergedOptions = { ...this.options, ...options };\r\n\r\n if (type === 'file') {\r\n return this._importFromFileDialog(mergedOptions);\r\n }\r\n if (typeof source === 'string') {\r\n return this._importFromString(type as 'csv' | 'json' | 'html', source, mergedOptions);\r\n }\r\n if (Array.isArray(source) || typeof source === 'object') {\r\n if (type !== 'json') {\r\n throw new Error('只有JSON格式支持从对象导入');\r\n }\r\n return this._importFromData('json', source, mergedOptions);\r\n }\r\n throw new Error('Invalid import source');\r\n }\r\n\r\n /**\r\n * 从文件对话框导入\r\n */\r\n private async _importFromFileDialog(options: ExcelImportOptions): Promise<ImportResult> {\r\n return new Promise((resolve, reject) => {\r\n if (!this._tableInstance) {\r\n reject(new Error('表格实例不存在或已销毁,无法导入数据!'));\r\n return;\r\n }\r\n\r\n const input = document.createElement('input');\r\n input.type = 'file';\r\n input.style.display = 'none';\r\n document.body.appendChild(input);\r\n\r\n input.addEventListener('change', async e => {\r\n try {\r\n const file = (e.target as HTMLInputElement).files?.[0];\r\n if (!file) {\r\n document.body.removeChild(input);\r\n reject(new Error('未选择文件'));\r\n return;\r\n }\r\n\r\n const result = await this._parseFile(file, options);\r\n\r\n // 根据配置决定是否自动更新表格\r\n if (options.autoTable && this._tableInstance) {\r\n if (options.autoColumns) {\r\n this._tableInstance.updateOption({\r\n columns: result.columns,\r\n plugins: [this]\r\n });\r\n }\r\n this._tableInstance.setRecords(result.records);\r\n }\r\n\r\n // 清理\r\n input.value = '';\r\n document.body.removeChild(input);\r\n\r\n resolve(result);\r\n } catch (error) {\r\n document.body.removeChild(input);\r\n reject(error);\r\n }\r\n });\r\n\r\n input.click();\r\n });\r\n }\r\n\r\n /**\r\n * 从字符串数据导入\r\n */\r\n private async _importFromString(\r\n type: 'csv' | 'json' | 'html',\r\n data: string,\r\n options: ExcelImportOptions\r\n ): Promise<ImportResult> {\r\n let result: ImportResult;\r\n\r\n switch (type) {\r\n case 'csv':\r\n result = await this._parseCSVString(data, options);\r\n break;\r\n case 'json':\r\n result = await this._parseJSONString(data, options);\r\n break;\r\n case 'html':\r\n result = await this._parseHTMLString(data, options);\r\n break;\r\n default:\r\n throw new Error(`不支持的导入类型: ${type}`);\r\n }\r\n\r\n // 自动更新表格\r\n if (options.autoTable && this._tableInstance) {\r\n if (options.autoColumns) {\r\n this._tableInstance.updateOption({\r\n columns: result.columns,\r\n plugins: [this]\r\n });\r\n }\r\n this._tableInstance.setRecords(result.records);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * 从数据对象导入\r\n */\r\n private async _importFromData(\r\n type: 'json',\r\n data: unknown[] | object,\r\n options: ExcelImportOptions\r\n ): Promise<ImportResult> {\r\n let result: ImportResult;\r\n\r\n if (type === 'json') {\r\n result = await this._parseJSONData(data, options);\r\n } else {\r\n throw new Error(`不支持的数据类型: ${type}`);\r\n }\r\n\r\n // 自动更新表格\r\n if (options.autoTable && this._tableInstance) {\r\n if (options.autoColumns) {\r\n this._tableInstance.updateOption({\r\n columns: result.columns,\r\n plugins: [this]\r\n });\r\n }\r\n this._tableInstance.setRecords(result.records);\r\n }\r\n\r\n return result;\r\n }\r\n /**\r\n * 根据文件类型解析文件\r\n */\r\n private async _parseFile(file: File, options?: ExcelImportOptions): Promise<ImportResult> {\r\n const mergedOptions = { ...this.options, ...options };\r\n const fileExtension = this._getFileExtension(file.name).toLowerCase();\r\n\r\n switch (fileExtension) {\r\n case 'xlsx':\r\n case 'xls':\r\n return await this._parseExcelFile(file, mergedOptions);\r\n case 'csv':\r\n return await this._parseCsvFile(file, mergedOptions);\r\n case 'json':\r\n return await this._parseJsonFile(file, mergedOptions);\r\n case 'html':\r\n case 'htm':\r\n return await this._parseHtmlFile(file, mergedOptions);\r\n default:\r\n throw new Error(`不支持的文件类型: ${fileExtension}`);\r\n }\r\n }\r\n\r\n /**\r\n * 获取文件扩展名\r\n */\r\n private _getFileExtension(filename: string): string {\r\n const parts = filename.split('.');\r\n return parts.length > 1 ? parts[parts.length - 1] : '';\r\n }\r\n /**\r\n * 解析Excel文件\r\n */\r\n private async _parseExcelFile(file: File, options?: ExcelImportOptions): Promise<ImportResult> {\r\n const mergedOptions = { ...this.options, ...options };\r\n return await ExcelImportPlugin.importExcelToVTableData(file, mergedOptions);\r\n }\r\n\r\n /**\r\n * 解析CSV文件\r\n */\r\n private async _parseCsvFile(file: File, options?: ExcelImportOptions): Promise<ImportResult> {\r\n const mergedOptions = { ...this.options, ...options };\r\n const text = await file.text();\r\n return this._parseCSVString(text, mergedOptions);\r\n }\r\n\r\n /**\r\n * 解析JSON文件\r\n */\r\n private async _parseJsonFile(file: File, options?: ExcelImportOptions): Promise<ImportResult> {\r\n const mergedOptions = { ...this.options, ...options };\r\n const text = await file.text();\r\n return this._parseJSONString(text, mergedOptions);\r\n }\r\n\r\n /**\r\n * 解析HTML表格文件\r\n */\r\n private async _parseHtmlFile(file: File, options?: ExcelImportOptions): Promise<ImportResult> {\r\n const mergedOptions = { ...this.options, ...options };\r\n const text = await file.text();\r\n return this._parseHTMLString(text, mergedOptions);\r\n }\r\n\r\n /**\r\n * 从表头行构建列配置\r\n */\r\n private _buildColumnsFromHeaders(headerRows: string[][]): VTable.ColumnsDefine {\r\n if (headerRows.length === 1) {\r\n return headerRows[0].map((title, index) => ({\r\n field: `col${index}`,\r\n title: title || `列${index + 1}`,\r\n cellType: 'text' as const,\r\n headerType: 'text' as const\r\n }));\r\n }\r\n return ExcelImportPlugin.buildColumns(headerRows);\r\n }\r\n\r\n static async importExcelToVTableData(file: File, options?: ExcelImportOptions) {\r\n const workbook = new ExcelJS.Workbook();\r\n await workbook.xlsx.load(await file.arrayBuffer());\r\n const worksheet = workbook.worksheets[0];\r\n if (!worksheet) {\r\n throw new Error('Excel 文件无有效工作表');\r\n }\r\n const detectedHeaderRows = options?.headerRowCount ?? this.detectHeaderRowCount(worksheet);\r\n const headerRows = [];\r\n for (let i = 1; i <= detectedHeaderRows; i++) {\r\n const row = worksheet.getRow(i);\r\n headerRows.push(Array.prototype.slice.call(row.values, 1));\r\n }\r\n const columns = ExcelImportPlugin.buildColumns(headerRows);\r\n const records: Record<string, unknown>[] = [];\r\n const dataRows: unknown[][] = [];\r\n worksheet.eachRow((row, rowNumber) => {\r\n if (rowNumber <= detectedHeaderRows) {\r\n return;\r\n }\r\n const cells = Array.prototype.slice.call(row.values, 1);\r\n dataRows.push(cells);\r\n });\r\n\r\n // 分批处理数据行,提升大文件性能\r\n const batchSize = options?.batchSize || 1000;\r\n const enableBatch = options?.enableBatchProcessing !== false && dataRows.length > batchSize;\r\n if (enableBatch) {\r\n for (let i = 0; i < dataRows.length; i += batchSize) {\r\n const batch = dataRows.slice(i, i + batchSize);\r\n const batchRecords = batch.map(cells => {\r\n const record: Record<string, unknown> = {};\r\n cells.forEach((cell: unknown, j: number) => {\r\n record[`col${j}`] = cell;\r\n });\r\n return record;\r\n });\r\n records.push(...batchRecords);\r\n if (i + batchSize < dataRows.length) {\r\n await new Promise(resolve => setTimeout(resolve, options?.asyncDelay || 5));\r\n }\r\n }\r\n } else {\r\n // 小文件直接处理\r\n dataRows.forEach(cells => {\r\n const record: Record<string, unknown> = {};\r\n cells.forEach((cell: unknown, i: number) => {\r\n record[`col${i}`] = cell;\r\n });\r\n records.push(record);\r\n });\r\n }\r\n if (options?.exportData) {\r\n // 导出为JavaScript对象字面量格式\r\n const jsContent = ExcelImportPlugin._generateJavaScriptExport(columns, records);\r\n const blob = new Blob([jsContent], { type: 'text/javascript' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = 'vtable-data.js';\r\n document.body.appendChild(a);\r\n a.click();\r\n setTimeout(() => {\r\n document.body.removeChild(a);\r\n URL.revokeObjectURL(url);\r\n }, 100);\r\n }\r\n return { columns, records };\r\n }\r\n\r\n private static detectHeaderRowCount(worksheet: any): number {\r\n let rowIndex = 1;\r\n let headerRowCount = 1;\r\n while (true) {\r\n const row = worksheet.getRow(rowIndex);\r\n const cells = Array.prototype.slice.call(row.values, 1);\r\n let hasConsecutive = false;\r\n for (let i = 1; i < cells.length; i++) {\r\n if (cells[i] !== undefined && cells[i] !== '' && cells[i] === cells[i - 1]) {\r\n hasConsecutive = true;\r\n break;\r\n }\r\n }\r\n if (hasConsecutive) {\r\n headerRowCount++;\r\n rowIndex++;\r\n } else {\r\n break;\r\n }\r\n }\r\n return headerRowCount;\r\n }\r\n\r\n private static buildColumns(headerRows: unknown[][], colStart = 0, colEnd?: number, level = 0): VTable.ColumnsDefine {\r\n const row = headerRows[level] as unknown[];\r\n const columns: VTable.ColumnsDefine = [];\r\n colEnd = colEnd ?? row.length;\r\n let i = colStart;\r\n while (i < colEnd) {\r\n const title = String(row[i] || `列${i + 1}`);\r\n let span = 1;\r\n while (i + span < colEnd && row[i + span] === title) {\r\n span++;\r\n }\r\n if (level < headerRows.length - 1) {\r\n const subColumns = ExcelImportPlugin.buildColumns(headerRows, i, i + span, level + 1);\r\n if (subColumns.length === 1) {\r\n columns.push(subColumns[0]);\r\n } else {\r\n columns.push({\r\n title,\r\n columns: subColumns,\r\n hideColumnsSubHeader: false\r\n });\r\n }\r\n } else {\r\n columns.push({\r\n field: `col${i}`,\r\n title,\r\n cellType: 'text' as const,\r\n headerType: 'text' as const\r\n });\r\n }\r\n i += span;\r\n }\r\n return columns;\r\n }\r\n\r\n /**\r\n * 解析CSV字符串\r\n */\r\n private async _parseCSVString(text: string, options: ExcelImportOptions): Promise<ImportResult> {\r\n const lines = text.split('\\n').filter(line => line.trim());\r\n\r\n if (lines.length === 0) {\r\n throw new Error('CSV文件为空');\r\n }\r\n\r\n // 解析CSV行(支持自定义分隔符)\r\n const delimiter = options.delimiter || ',';\r\n const parseCSVLine = (line: string): string[] => {\r\n return line.split(delimiter).map(cell => cell.trim().replace(/^\"|\"$/g, ''));\r\n };\r\n\r\n const headerRowCount = 1;\r\n const headerRows = lines.slice(0, headerRowCount).map(parseCSVLine);\r\n const dataRows = lines.slice(headerRowCount);\r\n\r\n const columns = this._buildColumnsFromHeaders(headerRows);\r\n const records: Record<string, unknown>[] = [];\r\n\r\n await this._processBatchRecords(dataRows, options, async (batch: string[]) => {\r\n const batchRecords = batch.map(line => {\r\n const parsedRow = parseCSVLine(line);\r\n const record: Record<string, unknown> = {};\r\n parsedRow.forEach((cell, i) => {\r\n record[`col${i}`] = cell || '';\r\n });\r\n return record;\r\n });\r\n records.push(...batchRecords);\r\n });\r\n if (options.exportData) {\r\n this._exportToJS(columns, records);\r\n }\r\n\r\n return { columns, records };\r\n }\r\n\r\n /**\r\n * 解析JSON字符串\r\n */\r\n private async _parseJSONString(text: string, options: ExcelImportOptions): Promise<ImportResult> {\r\n let jsonData;\r\n\r\n try {\r\n jsonData = JSON.parse(text);\r\n } catch (error) {\r\n throw new Error('JSON文件格式错误');\r\n }\r\n\r\n const result = await this._parseJSONData(jsonData, options);\r\n if (options.exportData) {\r\n this._exportToJS(result.columns, result.records);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * 解析HTML字符串\r\n */\r\n private async _parseHTMLString(text: string, options: ExcelImportOptions): Promise<ImportResult> {\r\n const parser = new DOMParser();\r\n const doc = parser.parseFromString(text, 'text/html');\r\n const table = doc.querySelector('table');\r\n\r\n if (!table) {\r\n throw new Error('HTML文件中未找到表格');\r\n }\r\n\r\n const rows = Array.from(table.querySelectorAll('tr'));\r\n if (rows.length === 0) {\r\n throw new Error('表格中没有数据行');\r\n }\r\n\r\n const headerRowCount = 1;\r\n const headerRows = rows\r\n .slice(0, headerRowCount)\r\n .map(row => Array.from(row.querySelectorAll('th, td')).map(cell => cell.textContent?.trim() || ''));\r\n const dataRows = rows.slice(headerRowCount);\r\n\r\n const columns = this._buildColumnsFromHeaders(headerRows);\r\n const records: Record<string, unknown>[] = [];\r\n\r\n // 分批处理数据行\r\n await this._processBatchRecords(dataRows, options, async (batch: Element[]) => {\r\n const batchRecords = batch.map(row => {\r\n const cells = Array.from(row.querySelectorAll('td')).map(cell => cell.textContent?.trim() || '');\r\n const record: Record<string, unknown> = {};\r\n cells.forEach((cell, i) => {\r\n record[`col${i}`] = cell || '';\r\n });\r\n return record;\r\n });\r\n records.push(...batchRecords);\r\n });\r\n\r\n // 如果启用了导出功能,则导出为JS文件\r\n if (options.exportData) {\r\n this._exportToJS(columns, records);\r\n }\r\n\r\n return { columns, records };\r\n }\r\n\r\n /**\r\n * 解析JSON数据对象\r\n */\r\n private async _parseJSONData(jsonData: unknown[] | object, options: ExcelImportOptions): Promise<ImportResult> {\r\n let result: ImportResult;\r\n\r\n // 如果JSON直接包含columns和records\r\n if (\r\n typeof jsonData === 'object' &&\r\n !Array.isArray(jsonData) &&\r\n jsonData &&\r\n 'columns' in jsonData &&\r\n 'records' in jsonData\r\n ) {\r\n const data = jsonData as { columns: VTable.ColumnsDefine; records: Record<string, unknown>[] };\r\n const records: Record<string, unknown>[] = [];\r\n await this._processBatchRecords(data.records, options, async (batch: Record<string, unknown>[]) => {\r\n const batchRecords = batch.map(record => ({ ...record }));\r\n records.push(...batchRecords);\r\n });\r\n result = {\r\n columns: data.columns,\r\n records: records\r\n };\r\n } else if (Array.isArray(jsonData) && jsonData.length > 0) {\r\n const firstRecord = jsonData[0] as Record<string, unknown>;\r\n const columns: VTable.ColumnsDefine = Object.keys(firstRecord).map(key => ({\r\n field: key,\r\n title: key,\r\n cellType: 'text' as const,\r\n headerType: 'text' as const\r\n }));\r\n\r\n const records: Record<string, unknown>[] = [];\r\n await this._processBatchRecords(\r\n jsonData as Record<string, unknown>[],\r\n options,\r\n async (batch: Record<string, unknown>[]) => {\r\n const batchRecords = batch.map(record => ({ ...record }));\r\n records.push(...batchRecords);\r\n }\r\n );\r\n\r\n result = { columns, records };\r\n } else {\r\n throw new Error('不支持的JSON格式');\r\n }\r\n\r\n if (options.exportData) {\r\n this._exportToJS(result.columns, result.records);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * 生成JavaScript对象字面量格式的导出内容\r\n */\r\n private static _generateJavaScriptExport(columns: VTable.ColumnsDefine, records: Record<string, unknown>[]): string {\r\n // 格式化值,确保正确的缩进\r\n const formatValue = (value: unknown, indent: string = ''): string => {\r\n if (value === null || value === undefined) {\r\n return 'null';\r\n }\r\n if (typeof value === 'string') {\r\n return `'${value.replace(/'/g, \"\\\\'\")}'`;\r\n }\r\n if (typeof value === 'number' || typeof value === 'boolean') {\r\n return String(value);\r\n }\r\n if (Array.isArray(value)) {\r\n if (value.length === 0) {\r\n return '[]';\r\n }\r\n const items = value.map(item => formatValue(item, indent + ' ')).join(', ');\r\n return `[${items}]`;\r\n }\r\n if (typeof value === 'object') {\r\n const props = Object.entries(value)\r\n .map(([key, val]) => `${indent} ${key}: ${formatValue(val, indent + ' ')}`)\r\n .join(',\\n');\r\n return `{\\n${props}\\n${indent}}`;\r\n }\r\n return String(value);\r\n };\r\n\r\n // 格式化记录对象\r\n const formatRecord = (record: unknown): string => {\r\n const props = Object.entries(record)\r\n .map(([key, value]) => ` ${key}: ${formatValue(value)}`)\r\n .join(',\\n');\r\n return ` {\\n${props}\\n }`;\r\n };\r\n\r\n // 格式化列对象(支持嵌套列)\r\n const formatColumn = (column: unknown, baseIndent: string = ' '): string => {\r\n const props = Object.entries(column)\r\n .map(([key, value]) => {\r\n if (key === 'columns' && Array.isArray(value)) {\r\n // 递归处理嵌套列,增加缩进\r\n const nestedColumns = value.map(col => formatColumn(col, baseIndent + ' ')).join(',\\n');\r\n return `${baseIndent} ${key}: [\\n${nestedColumns}\\n${baseIndent} ]`;\r\n }\r\n return `${baseIndent} ${key}: ${formatValue(value)}`;\r\n })\r\n .join(',\\n');\r\n return `${baseIndent}{\\n${props}\\n${baseIndent}}`;\r\n };\r\n\r\n const columnsStr = columns.map(col => formatColumn(col)).join(',\\n');\r\n const recordsStr = records.map(formatRecord).join(',\\n');\r\n\r\n return `// VTable 数据导出 - JavaScript 对象字面量格式\r\n// 生成时间: ${new Date().toLocaleString()}\r\n\r\nconst vtableData = {\r\n columns: [\r\n${columnsStr}\r\n ],\r\n records: [\r\n${recordsStr}\r\n ]\r\n};\r\n`;\r\n }\r\n\r\n /**\r\n * 导出数据为JavaScript对象字面量格式\r\n */\r\n private _exportToJS(columns: VTable.ColumnDefine[], records: Record<string, unknown>[]): void {\r\n const jsContent = ExcelImportPlugin._generateJavaScriptExport(columns, records);\r\n const blob = new Blob([jsContent], { type: 'text/javascript' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = 'vtable-data.js';\r\n document.body.appendChild(a);\r\n a.click();\r\n setTimeout(() => {\r\n document.body.removeChild(a);\r\n URL.revokeObjectURL(url);\r\n }, 100);\r\n }\r\n\r\n /**\r\n * 分批处理大数据记录,避免UI阻塞\r\n */\r\n private async _processBatchRecords<T>(\r\n records: T[],\r\n options: ExcelImportOptions,\r\n processor: (batch: T[], batchIndex: number) => Promise<void> | void\r\n ): Promise<void> {\r\n if (!options.enableBatchProcessing || records.length <= (options.batchSize || 1000)) {\r\n // 小数据量直接处理\r\n await processor(records, 0);\r\n return;\r\n }\r\n\r\n const batchSize = options.batchSize || 1000;\r\n const totalBatches = Math.ceil(records.length / batchSize);\r\n for (let i = 0; i < totalBatches; i++) {\r\n const start = i * batchSize;\r\n const end = Math.min(start + batchSize, records.length);\r\n const batch = records.slice(start, end);\r\n await processor(batch, i);\r\n // 让出控制权给浏览器,避免长时间阻塞UI\r\n if (i < totalBatches - 1) {\r\n await new Promise(resolve => setTimeout(resolve, options.asyncDelay || 5));\r\n }\r\n }\r\n }\r\n}\r\n"]}
@@ -102,5 +102,4 @@ export const generateAutoFillData = (originalData, columns, startRange, currentE
102
102
  }
103
103
  }
104
104
  return Array.isArray(null == originalData ? void 0 : originalData[0]) ? newData : translateRowArrayToObj(newData, columns);
105
- };
106
- //# sourceMappingURL=autoFillHandle.js.map
105
+ };
@@ -5,4 +5,5 @@ export function translateRowObjToArray(dataSource, columns) {
5
5
  export function translateRowArrayToObj(dataSource, columns) {
6
6
  return dataSource.map((item => columns.reduce(((pre, cur, index) => (pre[cur.field] = item[index],
7
7
  pre)), {})));
8
- }
8
+ }
9
+ //# sourceMappingURL=translateRowObj.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["gantt-export-image.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,KAAK,WAAW,MAAM,wBAAwB,CAAC;AAiBtD,MAAM,OAAO,iBAAiB;IAA9B;QACI,OAAE,GAAG,qBAAqB,CAAC;QAC3B,SAAI,GAAG,qBAAqB,CAAC;QACrB,WAAM,GAA6B,IAAI,CAAC;IAiLpD,CAAC;IA9KG,GAAG,CAAC,GAAG,IAAW;QACd,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,CAAsB,CAAC;QACnD,IAAI,CAAC,aAAa,EAAE;YACf,OAAO,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC;YAC/E,OAAO;SACX;QACD,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC;IAChC,CAAC;IAQY,aAAa,CAAC,UAAyB,EAAE;;;YAClD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;gBAEd,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;gBAClE,OAAO,SAAS,CAAC;aACpB;YAED,MAAM,EACF,QAAQ,GAAG,cAAc,EACzB,IAAI,GAAG,KAAK,EACZ,OAAO,GAAG,CAAC,EACX,eAAe,GAAG,SAAS,EAC3B,KAAK,GAAG,MAAM,CAAC,gBAAgB,IAAI,CAAC,EACpC,QAAQ,GAAG,IAAI,EAClB,GAAG,OAAO,CAAC;YAEZ,IAAI;gBACA,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;gBAE3E,IAAI;oBACA,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;oBAE7D,MAAM,UAAU,GAAG,CAAC,WAAW,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,WAAW,CAAC,mBAAmB,EAAE,CAAC,GAAG,KAAK,CAAC;oBACrH,MAAM,WAAW,GAAG,WAAW,CAAC,gBAAgB,EAAE,GAAG,KAAK,CAAC;oBAE3D,MAAM,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;oBACtD,YAAY,CAAC,KAAK,GAAG,UAAU,CAAC;oBAChC,YAAY,CAAC,MAAM,GAAG,WAAW,CAAC;oBAClC,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;oBAE3C,GAAG,CAAC,SAAS,GAAG,eAAe,CAAC;oBAChC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;oBAE5C,IAAI,MAAA,WAAW,CAAC,qBAAqB,0CAAE,MAAM,EAAE;wBAC3C,GAAG,CAAC,SAAS,CACT,WAAW,CAAC,qBAAqB,CAAC,MAAM,EACxC,CAAC,EAAE,CAAC,EACJ,WAAW,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,KAAK,EAC3D,WAAW,CACd,CAAC;qBACL;oBAED,MAAM,cAAc,GAAG,CAAC,GAAG,KAAK,CAAC;oBACjC,MAAM,UAAU,GAAG,WAAW,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,KAAK,CAAC;oBAC/E,GAAG,CAAC,SAAS,GAAG,oBAAoB,CAAC;oBACrC,GAAG,CAAC,QAAQ,CACR,UAAU,GAAG,cAAc,GAAG,CAAC,EAC/B,CAAC,EACD,cAAc,EACd,WAAW,CACd,CAAC;oBAEF,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC;oBAC1B,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC;oBAEvD,IAAI,WAAW,CAAC,MAAM,EAAE;wBACnB,GAAG,CAAC,SAAS,CACT,WAAW,CAAC,MAAM,EAClB,OAAO,EAAE,CAAC,EACV,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EACtC,CAAC,WAAW,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,EACtE,CAAC,WAAW,CAAC,mBAAmB,EAAE,GAAG,GAAG,CAAC,GAAG,KAAK,EACjD,WAAW,CAAsB,CAAC;qBAC1C;oBAED,OAAO,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;iBAC/E;wBAAS;oBACN,aAAa,CAAC,MAAM,EAAE,CAAC;oBAEvB,WAAW,CAAC,OAAO,EAAE,CAAC;iBACzB;aACJ;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;gBAC7D,MAAM,IAAI,KAAK,CAAC,YAAY,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;aAClF;;KACJ;IASY,cAAc,CAAC,UAA2C,EAAE;;YAErE,OAAO,IAAI,CAAC,aAAa,iCAClB,OAAO,KACV,QAAQ,EAAE,KAAK,IACjB,CAAC;QACP,CAAC;KAAA;IAEO,uBAAuB,CAAC,KAAa;;QACzC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAEd,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;SAC3F;QAED,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACpD,aAAa,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC;QACvC,aAAa,CAAC,KAAK,CAAC,IAAI,GAAG,SAAS,CAAC;QACrC,aAAa,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACxC,aAAa,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,MAAM,CAAC,UAAU,GAAG,GAAG,IAAI,CAAC;QAC3D,aAAa,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,GAAG,GAAG,IAAI,CAAC;QAC7D,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;QAEzC,MAAM,eAAe,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAEtD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAC3G,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAEnD,eAAe,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,UAAU,IAAI,CAAC;QAChD,eAAe,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,WAAW,IAAI,CAAC;QAClD,aAAa,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;QAE3C,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,KAAK,CAAC,eAAe,kCAClD,IAAI,CAAC,MAAM,CAAC,OAAO,KACtB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EACxD,aAAa,kCACN,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,KACpC,UAAU,EAAE,SAA8B,EAC1C,aAAa,EAAE,SAA8B,EAC7C,aAAa,EAAE,SAA8B,KAEjD,OAAO,EAAE,EAAE,IACb,CAAC;QAEH,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAGjC,IAAI,MAAC,WAAmB,CAAC,UAAU,0CAAE,UAAU,EAAE;YAC3C,WAAmB,CAAC,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;SAC3E;QACD,IAAI,MAAA,MAAC,WAAW,CAAC,qBAA6B,0CAAE,UAAU,0CAAE,UAAU,EAAE;YACnE,WAAW,CAAC,qBAA6B,CAAC,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;SAChG;QAED,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAEtC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC;IAC1C,CAAC;IAAY,cAAc,CAAC,MAAyB,EAAE,QAAgB,EAAE,IAAY,EAAE,OAAe,EAAE,WAAoB,IAAI;QAC5H,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAG1D,IAAI,QAAQ,EAAE;YACV,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,CAAC,QAAQ,GAAG,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC;YACnB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;SACnC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,OAAO;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACvB,CAAC;CACJ","file":"gantt-export-image.js","sourcesContent":["import * as VTableGantt from '@visactor/vtable-gantt';\r\n\r\n// 甘特图导出配置项接口\r\nexport interface ExportOptions {\r\n fileName?: string;\r\n type?: 'png' | 'jpeg';\r\n quality?: number;\r\n backgroundColor?: string;\r\n scale?: number;\r\n download?: boolean;\r\n}\r\n\r\n\r\n/**\r\n * 甘特图导出插件\r\n * @description 提供完整的甘特图导出功能,支持高分辨率输出和精准布局保留\r\n */\r\nexport class ExportGanttPlugin implements VTableGantt.plugins.IGanttPlugin {\r\n id = 'gantt-export-helper';\r\n name = 'Gantt Export Helper';\r\n private _gantt: VTableGantt.Gantt | null = null;\r\n\r\n // run 方法,在插件初始化时由 PluginManager调用\r\n run(...args: any[]): void {\r\n const ganttInstance = args[0] as VTableGantt.Gantt;\r\n if (!ganttInstance) {\r\n console.error('ExportGanttPlugin: Gantt instance not provided to run method.');\r\n return;\r\n }\r\n this._gantt = ganttInstance;\r\n } \r\n /**\r\n * 执行甘特图导出操作\r\n * @async\r\n * @param {ExportOptions} [options={}] 导出配置选项\r\n * @returns {Promise<string | undefined>} 返回Base64格式的图片数据,或在未初始化时返回 undefined\r\n * @throws {Error} 导出过程中发生错误时抛出异常\r\n */\r\n public async exportToImage(options: ExportOptions = {}): Promise<string | undefined> {\r\n if (!this._gantt) {\r\n // 保留这个 error\r\n console.error('ExportGanttPlugin: Gantt instance not available.');\r\n return undefined;\r\n }\r\n\r\n const {\r\n fileName = 'gantt-export',\r\n type = 'png',\r\n quality = 1,\r\n backgroundColor = '#ffffff',\r\n scale = window.devicePixelRatio || 1,\r\n download = true // 默认执行下载\r\n } = options;\r\n\r\n try {\r\n const { tempContainer, clonedGantt } = this.createFullSizeContainer(scale);\r\n\r\n try {\r\n await new Promise(resolve => requestAnimationFrame(resolve));\r\n\r\n const totalWidth = (clonedGantt.taskListTableInstance.getAllColsWidth() + clonedGantt.getAllDateColsWidth()) * scale;\r\n const totalHeight = clonedGantt.getAllRowsHeight() * scale;\r\n\r\n const exportCanvas = document.createElement('canvas');\r\n exportCanvas.width = totalWidth;\r\n exportCanvas.height = totalHeight;\r\n const ctx = exportCanvas.getContext('2d')!;\r\n\r\n ctx.fillStyle = backgroundColor;\r\n ctx.fillRect(0, 0, totalWidth, totalHeight);\r\n\r\n if (clonedGantt.taskListTableInstance?.canvas) {\r\n ctx.drawImage(\r\n clonedGantt.taskListTableInstance.canvas,\r\n 0, 0,\r\n clonedGantt.taskListTableInstance.getAllColsWidth() * scale,\r\n totalHeight\r\n );\r\n }\r\n\r\n const splitLineWidth = 3 * scale;\r\n const splitLineX = clonedGantt.taskListTableInstance.getAllColsWidth() * scale;\r\n ctx.fillStyle = 'rgb(225, 228, 232)';\r\n ctx.fillRect(\r\n splitLineX - splitLineWidth / 2,\r\n 0,\r\n splitLineWidth,\r\n totalHeight\r\n );\r\n\r\n const sourceX = 4 * scale;\r\n const sourceWidth = clonedGantt.canvas.width - sourceX;\r\n\r\n if (clonedGantt.canvas) {\r\n ctx.drawImage(\r\n clonedGantt.canvas,\r\n sourceX, 0,\r\n sourceWidth, clonedGantt.canvas.height,\r\n (clonedGantt.taskListTableInstance.getAllColsWidth() + 1.5) * scale, 0,\r\n (clonedGantt.getAllDateColsWidth() - 1.5) * scale,\r\n totalHeight );\r\n }\r\n\r\n return this.finalizeExport(exportCanvas, fileName, type, quality, download);\r\n } finally {\r\n tempContainer.remove();\r\n // 确保克隆的甘特图实例被释放\r\n clonedGantt.release();\r\n }\r\n } catch (error) {\r\n console.error('[Gantt Export Plugin] Export failed:', error);\r\n throw new Error(`甘特图导出失败: ${error instanceof Error ? error.message : '未知错误'}`);\r\n }\r\n }\r\n\r\n /**\r\n * 获取甘特图的 Base64 图片数据,不触发下载\r\n * @async\r\n * @param {Omit<ExportOptions, 'download'>} [options={}] 导出配置选项(不包含 download 参数)\r\n * @returns {Promise<string | undefined>} 返回 Base64 格式的图片数据,或在未初始化时返回 undefined\r\n * @throws {Error} 导出过程中发生错误时抛出异常\r\n */\r\n public async exportToBase64(options: Omit<ExportOptions, 'download'> = {}): Promise<string | undefined> {\r\n // 调用 exportToImage 方法,但设置 download 为 false\r\n return this.exportToImage({\r\n ...options,\r\n download: false\r\n });\r\n }\r\n\r\n private createFullSizeContainer(scale: number) {\r\n if (!this._gantt) {\r\n // 保留这个 error\r\n throw new Error('ExportGanttPlugin: Gantt instance not available to create container.');\r\n }\r\n\r\n const tempContainer = document.createElement('div');\r\n tempContainer.style.position = 'fixed';\r\n tempContainer.style.left = '-9999px';\r\n tempContainer.style.overflow = 'hidden';\r\n tempContainer.style.width = `${window.innerWidth + 100}px`;\r\n tempContainer.style.height = `${window.innerHeight + 100}px`;\r\n document.body.appendChild(tempContainer);\r\n\r\n const clonedContainer = document.createElement('div');\r\n\r\n const totalWidth = this._gantt.taskListTableInstance.getAllColsWidth() + this._gantt.getAllDateColsWidth();\r\n const totalHeight = this._gantt.getAllRowsHeight();\r\n\r\n clonedContainer.style.width = `${totalWidth}px`;\r\n clonedContainer.style.height = `${totalHeight}px`;\r\n tempContainer.appendChild(clonedContainer);\r\n\r\n const clonedGantt = new VTableGantt.Gantt(clonedContainer, {\r\n ...this._gantt.options,\r\n records: JSON.parse(JSON.stringify(this._gantt.records)),\r\n taskListTable: {\r\n ...this._gantt.options.taskListTable,\r\n tableWidth: undefined as unknown as number,\r\n minTableWidth: undefined as unknown as number,\r\n maxTableWidth: undefined as unknown as number,\r\n },\r\n plugins: [] \r\n });\r\n\r\n clonedGantt.setPixelRatio(scale);\r\n\r\n // 禁用裁剪\r\n if ((clonedGantt as any).scenegraph?.ganttGroup) {\r\n (clonedGantt as any).scenegraph.ganttGroup.setAttribute('clip', false);\r\n }\r\n if ((clonedGantt.taskListTableInstance as any)?.scenegraph?.tableGroup) {\r\n (clonedGantt.taskListTableInstance as any).scenegraph.tableGroup.setAttribute('clip', false);\r\n }\r\n\r\n clonedGantt.scenegraph.stage.render();\r\n\r\n return { tempContainer, clonedGantt };\r\n } private finalizeExport(canvas: HTMLCanvasElement, fileName: string, type: string, quality: number, download: boolean = true): string {\r\n const base64 = canvas.toDataURL(`image/${type}`, quality);\r\n \r\n // 如果需要下载,则创建下载链接\r\n if (download) {\r\n const link = document.createElement('a');\r\n link.download = `${fileName}.${type}`;\r\n link.href = base64;\r\n document.body.appendChild(link);\r\n link.click();\r\n document.body.removeChild(link);\r\n }\r\n \r\n return base64;\r\n }\r\n \r\n release(): void {\r\n this._gantt = null;\r\n }\r\n}"]}
1
+ {"version":3,"sources":["gantt-export-image.ts"],"names":[],"mappings":"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","file":"gantt-export-image.js","sourcesContent":["import * as VTableGantt from '@visactor/vtable-gantt';\r\n\r\n// 甘特图导出配置项接口\r\nexport interface ExportOptions {\r\n fileName?: string;\r\n type?: 'png' | 'jpeg';\r\n quality?: number;\r\n backgroundColor?: string;\r\n scale?: number;\r\n download?: boolean;\r\n}\r\n\r\n/**\r\n * 甘特图导出插件\r\n * @description 提供完整的甘特图导出功能,支持高分辨率输出和精准布局保留\r\n */\r\nexport class ExportGanttPlugin implements VTableGantt.plugins.IGanttPlugin {\r\n id = 'gantt-export-helper';\r\n name = 'Gantt Export Helper';\r\n private _gantt: VTableGantt.Gantt | null = null;\r\n\r\n // run 方法,在插件初始化时由 PluginManager调用\r\n run(...args: any[]): void {\r\n const ganttInstance = args[0] as VTableGantt.Gantt;\r\n if (!ganttInstance) {\r\n console.error('ExportGanttPlugin: Gantt instance not provided to run method.');\r\n return;\r\n }\r\n this._gantt = ganttInstance;\r\n }\r\n /**\r\n * 执行甘特图导出操作\r\n * @async\r\n * @param {ExportOptions} [options={}] 导出配置选项\r\n * @returns {Promise<string | undefined>} 返回Base64格式的图片数据,或在未初始化时返回 undefined\r\n * @throws {Error} 导出过程中发生错误时抛出异常\r\n */\r\n async exportToImage(options: ExportOptions = {}): Promise<string | undefined> {\r\n if (!this._gantt) {\r\n // 保留这个 error\r\n console.error('ExportGanttPlugin: Gantt instance not available.');\r\n return undefined;\r\n }\r\n\r\n const {\r\n fileName = 'gantt-export',\r\n type = 'png',\r\n quality = 1,\r\n backgroundColor = '#ffffff',\r\n scale = window.devicePixelRatio || 1,\r\n download = true // 默认执行下载\r\n } = options;\r\n\r\n try {\r\n const { tempContainer, clonedGantt } = this.createFullSizeContainer(scale);\r\n\r\n try {\r\n await new Promise(resolve => requestAnimationFrame(resolve));\r\n\r\n const totalWidth =\r\n (clonedGantt.taskListTableInstance.getAllColsWidth() + clonedGantt.getAllDateColsWidth()) * scale;\r\n const totalHeight = clonedGantt.getAllRowsHeight() * scale;\r\n\r\n const exportCanvas = document.createElement('canvas');\r\n exportCanvas.width = totalWidth;\r\n exportCanvas.height = totalHeight;\r\n const ctx = exportCanvas.getContext('2d')!;\r\n\r\n ctx.fillStyle = backgroundColor;\r\n ctx.fillRect(0, 0, totalWidth, totalHeight);\r\n\r\n if (clonedGantt.taskListTableInstance?.canvas) {\r\n ctx.drawImage(\r\n clonedGantt.taskListTableInstance.canvas,\r\n 0,\r\n 0,\r\n clonedGantt.taskListTableInstance.getAllColsWidth() * scale,\r\n totalHeight\r\n );\r\n }\r\n\r\n const splitLineWidth = 3 * scale;\r\n const splitLineX = clonedGantt.taskListTableInstance.getAllColsWidth() * scale;\r\n ctx.fillStyle = 'rgb(225, 228, 232)';\r\n ctx.fillRect(splitLineX - splitLineWidth / 2, 0, splitLineWidth, totalHeight);\r\n\r\n const sourceX = 4 * scale;\r\n const sourceWidth = clonedGantt.canvas.width - sourceX;\r\n\r\n if (clonedGantt.canvas) {\r\n ctx.drawImage(\r\n clonedGantt.canvas,\r\n sourceX,\r\n 0,\r\n sourceWidth,\r\n clonedGantt.canvas.height,\r\n (clonedGantt.taskListTableInstance.getAllColsWidth() + 1.5) * scale,\r\n 0,\r\n (clonedGantt.getAllDateColsWidth() - 1.5) * scale,\r\n totalHeight\r\n );\r\n }\r\n\r\n return this.finalizeExport(exportCanvas, fileName, type, quality, download);\r\n } finally {\r\n tempContainer.remove();\r\n // 确保克隆的甘特图实例被释放\r\n clonedGantt.release();\r\n }\r\n } catch (error) {\r\n console.error('[Gantt Export Plugin] Export failed:', error);\r\n throw new Error(`甘特图导出失败: ${error instanceof Error ? error.message : '未知错误'}`);\r\n }\r\n }\r\n\r\n /**\r\n * 获取甘特图的 Base64 图片数据,不触发下载\r\n * @async\r\n * @param {Omit<ExportOptions, 'download'>} [options={}] 导出配置选项(不包含 download 参数)\r\n * @returns {Promise<string | undefined>} 返回 Base64 格式的图片数据,或在未初始化时返回 undefined\r\n * @throws {Error} 导出过程中发生错误时抛出异常\r\n */\r\n async exportToBase64(options: Omit<ExportOptions, 'download'> = {}): Promise<string | undefined> {\r\n // 调用 exportToImage 方法,但设置 download 为 false\r\n return this.exportToImage({\r\n ...options,\r\n download: false\r\n });\r\n }\r\n\r\n private createFullSizeContainer(scale: number) {\r\n if (!this._gantt) {\r\n // 保留这个 error\r\n throw new Error('ExportGanttPlugin: Gantt instance not available to create container.');\r\n }\r\n\r\n const tempContainer = document.createElement('div');\r\n tempContainer.style.position = 'fixed';\r\n tempContainer.style.left = '-9999px';\r\n tempContainer.style.overflow = 'hidden';\r\n tempContainer.style.width = `${window.innerWidth + 100}px`;\r\n tempContainer.style.height = `${window.innerHeight + 100}px`;\r\n document.body.appendChild(tempContainer);\r\n\r\n const clonedContainer = document.createElement('div');\r\n\r\n const totalWidth = this._gantt.taskListTableInstance.getAllColsWidth() + this._gantt.getAllDateColsWidth();\r\n const totalHeight = this._gantt.getAllRowsHeight();\r\n\r\n clonedContainer.style.width = `${totalWidth}px`;\r\n clonedContainer.style.height = `${totalHeight}px`;\r\n tempContainer.appendChild(clonedContainer);\r\n\r\n const clonedGantt = new VTableGantt.Gantt(clonedContainer, {\r\n ...this._gantt.options,\r\n records: JSON.parse(JSON.stringify(this._gantt.records)),\r\n taskListTable: {\r\n ...this._gantt.options.taskListTable,\r\n tableWidth: undefined as unknown as number,\r\n minTableWidth: undefined as unknown as number,\r\n maxTableWidth: undefined as unknown as number\r\n },\r\n plugins: []\r\n });\r\n\r\n clonedGantt.setPixelRatio(scale);\r\n\r\n // 禁用裁剪\r\n if ((clonedGantt as any).scenegraph?.ganttGroup) {\r\n (clonedGantt as any).scenegraph.ganttGroup.setAttribute('clip', false);\r\n }\r\n if ((clonedGantt.taskListTableInstance as any)?.scenegraph?.tableGroup) {\r\n (clonedGantt.taskListTableInstance as any).scenegraph.tableGroup.setAttribute('clip', false);\r\n }\r\n\r\n clonedGantt.scenegraph.stage.render();\r\n\r\n return { tempContainer, clonedGantt };\r\n }\r\n private finalizeExport(\r\n canvas: HTMLCanvasElement,\r\n fileName: string,\r\n type: string,\r\n quality: number,\r\n download: boolean = true\r\n ): string {\r\n const base64 = canvas.toDataURL(`image/${type}`, quality);\r\n\r\n // 如果需要下载,则创建下载链接\r\n if (download) {\r\n const link = document.createElement('a');\r\n link.download = `${fileName}.${type}`;\r\n link.href = base64;\r\n document.body.appendChild(link);\r\n link.click();\r\n document.body.removeChild(link);\r\n }\r\n\r\n return base64;\r\n }\r\n\r\n release(): void {\r\n this._gantt = null;\r\n }\r\n}\r\n"]}