diff --git a/common/changes/@visactor/vtable/feat-multiply-sheets-export_2025-12-15-09-04.json b/common/changes/@visactor/vtable/feat-multiply-sheets-export_2025-12-15-09-04.json new file mode 100644 index 0000000000..27c086ceb0 --- /dev/null +++ b/common/changes/@visactor/vtable/feat-multiply-sheets-export_2025-12-15-09-04.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "feat: excel export multiply sheets\n\n", + "type": "none", + "packageName": "@visactor/vtable" + } + ], + "packageName": "@visactor/vtable", + "email": "892739385@qq.com" +} \ No newline at end of file diff --git a/docs/assets/api/en/SheetAPI.md b/docs/assets/api/en/SheetAPI.md index 882e807e99..18a1768436 100644 --- a/docs/assets/api/en/SheetAPI.md +++ b/docs/assets/api/en/SheetAPI.md @@ -75,7 +75,7 @@ Save all data as a configuration Export the current sheet to a file ``` - exportSheetToFile: (fileType: 'csv' | 'xlsx') => void + exportSheetToFile: (fileType: 'csv' | 'xlsx', allSheets: boolean = true) => void ``` ### importFileToSheet(Function) diff --git a/docs/assets/api/zh/SheetAPI.md b/docs/assets/api/zh/SheetAPI.md index ccc798e344..39eb5abfea 100644 --- a/docs/assets/api/zh/SheetAPI.md +++ b/docs/assets/api/zh/SheetAPI.md @@ -75,7 +75,7 @@ VTableSheet组件支持的方法如下: 导出当前sheet到文件 ``` - exportSheetToFile: (fileType: 'csv' | 'xlsx') => void + exportSheetToFile: (fileType: 'csv' | 'xlsx', allSheets: boolean = true) => void ``` ### importFileToSheet(Function) diff --git a/docs/assets/guide/en/plugin/table-export.md b/docs/assets/guide/en/plugin/table-export.md index 3562ac4c84..70c1d9ae7e 100644 --- a/docs/assets/guide/en/plugin/table-export.md +++ b/docs/assets/guide/en/plugin/table-export.md @@ -170,4 +170,10 @@ By default, the exported file will not be automatically downloaded, and you need By default, the exported file name is `export`; if you need to customize the file name, you can set `fileName` to the file name ## Usage Example -Please refer to [table export](../../demo/export/table-export) \ No newline at end of file +Please refer to [table export](../../demo/export/table-export) + +## vtable-sheet usage + +In VTableSheet, you can refer to [VTableSheet export](../sheet/import_export). + +Because the electronic spreadsheet needs to support exporting multiple sheets, so this plugin extends the interface ability to export all sheets, and specifically adds the exportMultipleVTablesToExcel method. \ No newline at end of file diff --git a/docs/assets/guide/en/sheet/import_export.md b/docs/assets/guide/en/sheet/import_export.md index a63613dd5f..51b2043b8f 100644 --- a/docs/assets/guide/en/sheet/import_export.md +++ b/docs/assets/guide/en/sheet/import_export.md @@ -1,10 +1,70 @@ # Import and Export Capabilities -The import and export functionality in VTable-Sheet relies on export plugins from VTable's plugin package @visactor/vtable-plugins. +Import and export capabilities in VTable-Sheet rely on plugin packages from @visactor/vtable-plugins. -Export plugin: @visactor/vtable-plugins/table-export-plugin, refer to the tutorial documentation: [Table Export](../plugin/table-export) +Export plugin: @visactor/vtable-plugins/table-export-plugin, refer to the tutorial documentation: [table export](../plugin/table-export) -Import plugin: @visactor/vtable-plugins/excel-import-plugin, refer to the tutorial documentation: [Table Import](../plugin/excel-import) +Import plugin: @visactor/vtable-plugins/excel-import-plugin, refer to the tutorial documentation: [table import](../plugin/excel-import) -Since VTable plugins only work on a single table instance, VTableSheet's current import and export capabilities are limited. It can only export data from the current sheet or import external data files into the current sheet. The export and import capabilities of VTableSheet will be expanded and improved in the future. +If you want to modify the plugin configuration, you can configure the parameters of the import and export plugins through VTablePluginModules. -If you want to modify the plugin configuration options, you can configure various parameters for the import and export plugins through VTablePluginModules. \ No newline at end of file +Import and export capabilities usually need to be used together with menu functionality, so you need to configure menu functionality, which can be referred to [menu functionality](./menu.md). + +## Export sheet +Export the current sheet, you can configure menuKey as VTableSheet.TYPES.MenuKey.EXPORT_CURRENT_SHEET_CSV to export a csv file, or configure menuKey as VTableSheet.TYPES.MenuKey.EXPORT_CURRENT_SHEET_XLSX to export an excel file. + +Export excel file supports exporting all sheets, you can configure menuKey as VTableSheet.TYPES.MenuKey.EXPORT_ALL_SHEETS_XLSX to export an excel file. + +Example: + +```typescript + mainMenu: { + show: true, + items: [ + ...... + { + name: 'Export', + items: [ + { + name: 'Export CSV', + menuKey: TYPES.MainMenuItemKey.EXPORT_CURRENT_SHEET_CSV, + description: 'Export current sheet data to csv' + }, + { + name: 'Export XLSX', + menuKey: TYPES.MainMenuItemKey.EXPORT_CURRENT_SHEET_XLSX, + description: 'Export current sheet data to xlsx' + }, + { + name: 'Export All Sheets', + menuKey: TYPES.MainMenuItemKey.EXPORT_ALL_SHEETS_XLSX, + description: 'Export all sheets to xlsx' + } + ], + description: 'Export current sheet data' + } + ] + } +``` + +It also supports calling the export function through APIs, which can be referred to [API](../../api/SheetAPI#Methods.exportSheetToFile). + +## Import sheet + +Import sheet, you can configure menuKey as VTableSheet.TYPES.MenuKey.IMPORT to import a csv file or excel file. + +Example: + +```typescript +mainMenu: { + ...... + items: [ + { + name: 'Import', + menuKey: VTableSheet.TYPES.MenuKey.IMPORT, + description: 'Import data to current sheet' + } + ] +} +``` + +It also supports calling the import function through APIs, which can be referred to [API](../../api/SheetAPI#Methods.importFileToSheet). \ No newline at end of file diff --git a/docs/assets/guide/zh/plugin/table-export.md b/docs/assets/guide/zh/plugin/table-export.md index ddcda3560b..00e2fe045c 100644 --- a/docs/assets/guide/zh/plugin/table-export.md +++ b/docs/assets/guide/zh/plugin/table-export.md @@ -169,4 +169,10 @@ const tableExportPlugin = new VTablePlugins.TableExportPlugin({ 默认情况下,导出文件名称为`export`;如果需要自定义文件名,可以设置`fileName`为文件名 ## 用法示例 -可参考[表格导出](../../demo/export/table-export) \ No newline at end of file +可参考[表格导出](../../demo/export/table-export) + +## vtable-sheet中使用 + +在VTableSheet中使用时,可以参考[VTableSheet导出](../sheet/import_export)。 + +因为电子表格需要支持导出多个sheet,所以这个插件扩展导出所有sheet的接口能力,具体增加了exportMultipleVTablesToExcel方法。 \ No newline at end of file diff --git a/docs/assets/guide/zh/sheet/import_export.md b/docs/assets/guide/zh/sheet/import_export.md index 693002fe24..f120b79292 100644 --- a/docs/assets/guide/zh/sheet/import_export.md +++ b/docs/assets/guide/zh/sheet/import_export.md @@ -1,10 +1,70 @@ # 导入导出能力 -VTable-Sheet中导入导出依赖VTable的插件@visactor/vtable-plugins中的导出插件包来实现的。 +VTable-Sheet中导入导出依赖VTable的插件@visactor/vtable-plugins中的插件包来实现的。 导出插件:@visactor/vtable-plugins/table-export-plugin ,参考教程文档:[表格导出](../plugin/table-export) 导入插件:@visactor/vtable-plugins/excel-import-plugin, 参考教程文档:[表格导入](../plugin/excel-import) -因为VTable的插件只作用于单个表格实例,所以VTableSheet目前的导入导出能力不强,只能将当前sheet的数据导出,或将外部数据文件导入到当前sheet。后续会扩展完善 VTableSheet 的导出和导入能力。 +如果想要修改插件的配置项,可以通过VTablePluginModules配置导入和导出插件的各个参数。 -如果想要修改插件的配置项,可以通过VTablePluginModules配置导入和导出插件的各个参数。 \ No newline at end of file +导入导出能力一般要配合菜单功能一起使用,所以需要配置菜单功能,具体可以参考[菜单功能](./menu.md)。 + +## 导出sheet +导出当前sheet,可以在mainMenu配menuKey为VTableSheet.TYPES.MenuKey.EXPORT_CURRENT_SHEET_CSV来导出csv文件,或者配menuKey为VTableSheet.TYPES.MenuKey.EXPORT_CURRENT_SHEET_XLSX来导出excel文件。 + +导出excel文件支持全部sheet导出,可以在mainMenu配menuKey为VTableSheet.TYPES.MenuKey.EXPORT_ALL_SHEETS_XLSX来导出excel文件。 + +具体如: + +```typescript + mainMenu: { + show: true, + items: [ + ...... + { + name: '导出', + items: [ + { + name: '导出csv', + menuKey: TYPES.MainMenuItemKey.EXPORT_CURRENT_SHEET_CSV, + description: '导出当前sheet数据到csv' + }, + { + name: '导出xlsx', + menuKey: TYPES.MainMenuItemKey.EXPORT_CURRENT_SHEET_XLSX, + description: '导出当前sheet数据到xlsx' + }, + { + name: '导出全部xlsx', + menuKey: TYPES.MainMenuItemKey.EXPORT_ALL_SHEETS_XLSX, + description: '导出所有sheet到xlsx' + } + ], + description: '导出当前sheet数据' + } + ] + } +``` + +也支持通过API调用导出功能,具体可以参考[API](../../api/SheetAPI#Methods.exportSheetToFile)。 + +## 导入sheet + +导入sheet,可以在mainMenu配menuKey为VTableSheet.TYPES.MenuKey.IMPORT来导入csv文件或excel文件。 + +具体如: + +```typescript +mainMenu: { + ...... + items: [ + { + name: '导入', + menuKey: VTableSheet.TYPES.MenuKey.IMPORT, + description: '导入数据到当前sheet' + } + ] +} +``` + +也支持通过API调用导入功能,具体可以参考[API](../../api/SheetAPI#Methods.importFileToSheet)。 \ No newline at end of file diff --git a/packages/vtable-plugins/src/table-export.ts b/packages/vtable-plugins/src/table-export.ts index 0944ad2697..ea65380d40 100644 --- a/packages/vtable-plugins/src/table-export.ts +++ b/packages/vtable-plugins/src/table-export.ts @@ -1,7 +1,13 @@ import type { pluginsDefinition, ListTable } from '@visactor/vtable'; import { TABLE_EVENT_TYPE } from '@visactor/vtable'; import type { ExportVTableToCsvOptions, ExportVTableToExcelOptions } from './table-export/index'; -import { exportVTableToCsv, exportVTableToExcel, downloadCsv, downloadExcel } from './table-export/index'; +import { + exportVTableToCsv, + exportVTableToExcel, + downloadCsv, + downloadExcel, + exportMultipleVTablesToExcel +} from './table-export/index'; // // 扩展ListTable接口以包含导出方法 // declare module '@visactor/vtable' { @@ -65,6 +71,20 @@ export class TableExportPlugin implements pluginsDefinition.IVTablePlugin { } return exportVTableToExcel(this.table, options, this.pluginOptions.exportOnIdle); }; + if ((this.table as any).__vtableSheet) { + // 给VTableSheet实例添加导出所有sheet到Excel的方法 + if (!((this.table as any).__vtableSheet as any)._exportMutipleTablesToExcel) { + ((this.table as any).__vtableSheet as any)._exportMutipleTablesToExcel = async ( + tables: Array<{ table: any; name?: string }> + ) => { + const buffer = (await exportMultipleVTablesToExcel( + tables, + this.pluginOptions.exportExcelOptions + )) as ArrayBuffer; + await downloadExcel(buffer, this.pluginOptions.exportExcelOptions.fileName || 'vtable-sheet-export'); + }; + } + } } } diff --git a/packages/vtable-plugins/src/table-export/excel/index.ts b/packages/vtable-plugins/src/table-export/excel/index.ts index 690879b338..6faca30c09 100644 --- a/packages/vtable-plugins/src/table-export/excel/index.ts +++ b/packages/vtable-plugins/src/table-export/excel/index.ts @@ -58,22 +58,53 @@ export async function exportVTableToExcel( ) { const workbook = new ExcelJS.Workbook(); const worksheet = workbook.addWorksheet('sheet1'); + await renderTableToWorksheet(tableInstance, worksheet, workbook, options, optimization); + const buffer = await workbook.xlsx.writeBuffer(); + return buffer; +} + +export async function exportMultipleVTablesToExcel( + tables: Array<{ table: IVTable; name?: string }>, + options?: ExportVTableToExcelOptions, + optimization = false +) { + const workbook = new ExcelJS.Workbook(); + const usedWorksheetNames = new Set(); + for (let i = 0; i < tables.length; i++) { + const { table, name } = tables[i]; + const safeName = getUniqueWorksheetName(name || `sheet${i + 1}`, usedWorksheetNames); + usedWorksheetNames.add(safeName); + const worksheet = workbook.addWorksheet(safeName); + await renderTableToWorksheet(table, worksheet, workbook, options, optimization); + } + const buffer = await workbook.xlsx.writeBuffer(); + return buffer; +} + +async function renderTableToWorksheet( + tableInstance: IVTable, + worksheet: ExcelJS.Worksheet, + workbook: ExcelJS.Workbook, + options?: ExportVTableToExcelOptions, + optimization = false +): Promise { const exportAllData = !!options?.exportAllData; const { handleRowCount, reset } = handlePaginationExport(tableInstance, exportAllData); - const minRow = 0; - const maxRow = handleRowCount(); - const minCol = 0; - const maxCol = tableInstance.colCount - 1; - worksheet.properties.defaultRowHeight = 40; - const columns: { width: number }[] = []; - const mergeCells: CellRange[] = []; - const mergeCellSet = new Set(); + try { + const minRow = 0; + const maxRow = handleRowCount(); + const minCol = 0; + const maxCol = tableInstance.colCount - 1; + + worksheet.properties.defaultRowHeight = 40; + const columns: { width: number }[] = []; + const mergeCells: CellRange[] = []; + const mergeCellSet = new Set(); - const SLICE_SIZE = 100; - let currentRow = minRow; + const SLICE_SIZE = 100; + let currentRow = minRow; - function processSlice(deadline?: IdleDeadline) { - return new Promise(async resolve => { + const processSlice = async (deadline?: IdleDeadline): Promise => { while (currentRow <= maxRow && (!optimization || deadline?.timeRemaining() > 0)) { const endRow = Math.min(currentRow + SLICE_SIZE - 1, maxRow); for (let col = minCol; col <= maxCol; col++) { @@ -85,7 +116,6 @@ export async function exportVTableToExcel( if (col === minCol) { const rowHeight = tableInstance.getRowHeight(row); const worksheetRow = worksheet.getRow(row + 1); - // worksheetRow.height = rowHeight * 0.75; worksheetRow.height = rowHeight; } @@ -104,69 +134,89 @@ export async function exportVTableToExcel( currentRow = endRow + 1; } - if (currentRow > maxRow) { - resolve(); - } else { - let nextDeadline: IdleDeadline | undefined; - if (optimization) { - nextDeadline = await requestIdleCallbackPromise(); - } + if (currentRow <= maxRow) { + const nextDeadline = optimization ? await requestIdleCallbackPromise() : undefined; await processSlice(nextDeadline); - resolve(); } - }); - } + }; - await new Promise(async resolve => { - let deadline: IdleDeadline | undefined; if (optimization) { - deadline = await requestIdleCallbackPromise(); + const deadline = await requestIdleCallbackPromise(); + await processSlice(deadline); + } else { + await processSlice(); } - await processSlice(deadline); - resolve(); - }); - - worksheet.columns = columns; - mergeCells.forEach(mergeCell => { - worksheet.mergeCells( - mergeCell.start.row + 1, - mergeCell.start.col + 1, - mergeCell.end.row + 1, - mergeCell.end.col + 1 - ); - }); - // frozen - const frozenView: ExcelJS.WorksheetViewFrozen[] = []; - // top frozen - if (tableInstance.frozenRowCount > 0) { - frozenView.push({ - state: 'frozen', - ySplit: tableInstance.frozenRowCount, - // activeCell: 'A1', - topLeftCell: encodeCellAddress(0, tableInstance.frozenRowCount) - }); - } - // left frozen - if (tableInstance.frozenColCount > 0) { - frozenView.push({ - state: 'frozen', - xSplit: tableInstance.frozenColCount, - // activeCell: 'A1', - topLeftCell: encodeCellAddress(tableInstance.frozenColCount, 0) + worksheet.columns = columns; + mergeCells.forEach(mergeCell => { + worksheet.mergeCells( + mergeCell.start.row + 1, + mergeCell.start.col + 1, + mergeCell.end.row + 1, + mergeCell.end.col + 1 + ); }); + + const frozenView: ExcelJS.WorksheetViewFrozen[] = []; + if (tableInstance.frozenRowCount > 0) { + frozenView.push({ + state: 'frozen', + ySplit: tableInstance.frozenRowCount, + topLeftCell: encodeCellAddress(0, tableInstance.frozenRowCount) + }); + } + if (tableInstance.frozenColCount > 0) { + frozenView.push({ + state: 'frozen', + xSplit: tableInstance.frozenColCount, + topLeftCell: encodeCellAddress(tableInstance.frozenColCount, 0) + }); + } + worksheet.views = frozenView; + + if (options?.excelJSWorksheetCallback) { + options.excelJSWorksheetCallback(worksheet); + } + } finally { + // 恢复透视表的pagination配置 + reset(); } - // not support bottom&right frozen - worksheet.views = frozenView; +} - if (options?.excelJSWorksheetCallback) { - options.excelJSWorksheetCallback(worksheet); +function getUniqueWorksheetName(rawName: string, used: Set) { + // Excel sheet name constraints: + // - max 31 chars + // - cannot contain: : \ / ? * [ ] + // - cannot be empty + // ExcelJS will throw on invalid/duplicate names, so we guard here. + const cleanedBase = sanitizeWorksheetName(rawName) || 'sheet'; + if (!used.has(cleanedBase)) { + return cleanedBase; } + for (let n = 2; n < 10000; n++) { + const suffix = `-${n}`; + const baseMax = 31 - suffix.length; + const base = cleanedBase.length > baseMax ? cleanedBase.slice(0, baseMax) : cleanedBase; + const candidate = `${base}${suffix}`; + if (!used.has(candidate)) { + return candidate; + } + } + // Fallback: extremely unlikely; still ensure non-empty + <=31 + return `${cleanedBase.slice(0, 31 - 6)}-${Date.now().toString().slice(-5)}`; +} - const buffer = await workbook.xlsx.writeBuffer(); - // 恢复透视表的pagination配置 - reset(); - return buffer; +function sanitizeWorksheetName(name: string) { + const trimmed = (name ?? '').toString().trim(); + // Replace invalid characters with space, then collapse spaces. + const noInvalidChars = trimmed + .replace(/[:\\\/\?\*\[\]]/g, ' ') + .replace(/\s+/g, ' ') + .trim(); + // Excel doesn't allow empty names + const nonEmpty = noInvalidChars || 'sheet'; + // Excel max length is 31 + return nonEmpty.length > 31 ? nonEmpty.slice(0, 31) : nonEmpty; } async function addCell( diff --git a/packages/vtable-plugins/src/table-export/index.ts b/packages/vtable-plugins/src/table-export/index.ts index 1a550bce48..1d1906991c 100644 --- a/packages/vtable-plugins/src/table-export/index.ts +++ b/packages/vtable-plugins/src/table-export/index.ts @@ -1,8 +1,8 @@ import type { ExportVTableToExcelOptions } from './excel'; -import { exportVTableToExcel } from './excel'; +import { exportVTableToExcel, exportMultipleVTablesToExcel } from './excel'; import type { ExportVTableToCsvOptions } from './csv'; import { exportVTableToCsv } from './csv'; import { downloadCsv, downloadExcel } from './util/download'; -export { exportVTableToCsv, downloadCsv, exportVTableToExcel, downloadExcel }; +export { exportVTableToCsv, downloadCsv, exportVTableToExcel, exportMultipleVTablesToExcel, downloadExcel }; export type { ExportVTableToCsvOptions, ExportVTableToExcelOptions }; diff --git a/packages/vtable-plugins/src/table-series-number.ts b/packages/vtable-plugins/src/table-series-number.ts index 0147b5eb99..8ddcdcba77 100644 --- a/packages/vtable-plugins/src/table-series-number.ts +++ b/packages/vtable-plugins/src/table-series-number.ts @@ -489,6 +489,10 @@ export class TableSeriesNumber implements pluginsDefinition.IVTablePlugin { syncRowHeightToComponent() { // console.log('syncRowHeightToComponent adjust', adjustStartRowIndex, adjustEndRowIndex); + const rowRange = this.table.getBodyVisibleRowRange(); + if (!rowRange) { + return; + } const { rowStart, rowEnd } = this.table.getBodyVisibleRowRange(); const adjustStartRowIndex = Math.max(rowStart - 2, this.table.frozenRowCount); const adjustEndRowIndex = Math.min(rowEnd + 2, this.table.rowCount - 1); @@ -513,6 +517,10 @@ export class TableSeriesNumber implements pluginsDefinition.IVTablePlugin { } } syncColWidthToComponent() { + const colRange = this.table.getBodyVisibleColRange(); + if (!colRange) { + return; + } const { colStart, colEnd } = this.table.getBodyVisibleColRange(); const adjustStartColIndex = colStart; const adjustEndColIndex = Math.min(colEnd, this.table.scenegraph.proxy.colEnd); diff --git a/packages/vtable-sheet/examples/sheet/sheet.ts b/packages/vtable-sheet/examples/sheet/sheet.ts index 3ac14635b6..1702849315 100644 --- a/packages/vtable-sheet/examples/sheet/sheet.ts +++ b/packages/vtable-sheet/examples/sheet/sheet.ts @@ -784,6 +784,11 @@ export function createTable() { name: '导出xlsx', menuKey: TYPES.MainMenuItemKey.EXPORT_CURRENT_SHEET_XLSX, description: '导出当前sheet数据到xlsx' + }, + { + name: '导出全部xlsx', + menuKey: TYPES.MainMenuItemKey.EXPORT_ALL_SHEETS_XLSX, + description: '导出所有sheet到xlsx' } ], description: '导出当前sheet数据' diff --git a/packages/vtable-sheet/src/components/vtable-sheet.ts b/packages/vtable-sheet/src/components/vtable-sheet.ts index 6217b5d225..2cd2b21c5e 100644 --- a/packages/vtable-sheet/src/components/vtable-sheet.ts +++ b/packages/vtable-sheet/src/components/vtable-sheet.ts @@ -690,7 +690,7 @@ export default class VTableSheet { const columnWidthConfig = Array.from(instance.tableInstance.internalProps._widthResizedColMap).map(key => { return { key: key, - width: instance.tableInstance.getColWidth(key) + width: instance.tableInstance.getColWidth(key as number) }; }); //#endregion @@ -730,7 +730,7 @@ export default class VTableSheet { } /** 导出当前sheet到文件 */ - exportSheetToFile(fileType: 'csv' | 'xlsx'): void { + exportSheetToFile(fileType: 'csv' | 'xlsx', allSheets: boolean = true): void { const sheet = this.getActiveSheet(); if (!sheet) { return; @@ -742,13 +742,35 @@ export default class VTableSheet { console.warn('Please configure TableExportPlugin in VTablePluginModules'); } } else { - if ((sheet.tableInstance as any)?.exportToExcel) { - (sheet.tableInstance as any).exportToExcel(); + if (allSheets) { + this.exportAllSheetsToExcel(); } else { - console.warn('Please configure TableExportPlugin in VTablePluginModules'); + if ((sheet.tableInstance as any)?.exportToExcel) { + (sheet.tableInstance as any).exportToExcel(); + } else { + console.warn('Please configure TableExportPlugin in VTablePluginModules'); + } } } } + exportAllSheetsToExcel(): void { + this.initAllSheetInstances(); + const allDefines = this.sheetManager.getAllSheets(); + const tables = allDefines.map(def => { + const inst = this.workSheetInstances.get(def.sheetKey)!; + return { table: inst.tableInstance as any, name: def.sheetTitle || def.sheetKey }; + }); + (this as any)._exportMutipleTablesToExcel?.(tables); //这个方法是在vtable-plugins中添加的,table-export插件在VTableSheet实例上添加了导出所有sheet到Excel的方法 + } + initAllSheetInstances(): void { + const allDefines = this.sheetManager.getAllSheets(); + allDefines.forEach(def => { + if (!this.workSheetInstances.has(def.sheetKey)) { + const instance = this.createWorkSheetInstance(def); + this.workSheetInstances.set(def.sheetKey, instance); + } + }); + } /** 导入文件到当前sheet */ async importFileToSheet(): Promise { const sheet = this.getActiveSheet(); diff --git a/packages/vtable-sheet/src/core/WorkSheet.ts b/packages/vtable-sheet/src/core/WorkSheet.ts index 28100f1a75..5189ceea9d 100644 --- a/packages/vtable-sheet/src/core/WorkSheet.ts +++ b/packages/vtable-sheet/src/core/WorkSheet.ts @@ -151,6 +151,8 @@ export class WorkSheet extends EventTarget implements IWorkSheetAPI { this.element.classList.add('vtable-excel-cursor'); // 获取事件总线 this.eventBus = (this.tableInstance as any).eventBus; + // 在 tableInstance 上设置 VTableSheet 引用,方便插件访问 + (this.tableInstance as any).__vtableSheet = this.vtableSheet; } /** @@ -1002,7 +1004,7 @@ export class WorkSheet extends EventTarget implements IWorkSheetAPI { // 如果是公式,设置公式;否则设置普通值 if (FormulaPasteProcessor.needsFormulaAdjustment(value)) { - this.setCellFormula(targetRow, targetCol, value); + this.setCellFormula(targetRow, targetCol, value as string); } else { this.setCellValue(targetRow, targetCol, value); } diff --git a/packages/vtable-sheet/src/managers/menu-manager.ts b/packages/vtable-sheet/src/managers/menu-manager.ts index 2167a855ef..3099862fce 100644 --- a/packages/vtable-sheet/src/managers/menu-manager.ts +++ b/packages/vtable-sheet/src/managers/menu-manager.ts @@ -180,6 +180,10 @@ export class MenuManager { console.warn('Please configure TableExportPlugin in VTablePluginModules'); } break; + case MainMenuItemKey.EXPORT_ALL_SHEETS_XLSX: + // 多 sheet 导出走 vtable-plugins 的导出工具,不依赖向 tableInstance 注入 exportToExcel + this.sheet.exportAllSheetsToExcel?.(); + break; default: break; } diff --git a/packages/vtable-sheet/src/ts-types/base.ts b/packages/vtable-sheet/src/ts-types/base.ts index 1176fcbd17..99af581e66 100644 --- a/packages/vtable-sheet/src/ts-types/base.ts +++ b/packages/vtable-sheet/src/ts-types/base.ts @@ -54,7 +54,9 @@ export enum MainMenuItemKey { /** 需要插件支持,请在plugins中配置 TableExportPlugin */ EXPORT_CURRENT_SHEET_CSV = 'export-current-sheet-csv', /** 需要插件支持,请在plugins中配置 TableExportPlugin */ - EXPORT_CURRENT_SHEET_XLSX = 'export-current-sheet-xlsx' + EXPORT_CURRENT_SHEET_XLSX = 'export-current-sheet-xlsx', + /** 需要插件支持,请在plugins中配置 TableExportPlugin */ + EXPORT_ALL_SHEETS_XLSX = 'export-all-sheets-xlsx' } export interface MainMenuItem { /** 菜单项名称 */