@visactor/vtable-sheet 1.22.7 → 1.22.8-alpha.13
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/cjs/components/sheet-tab-event-handler.js +3 -2
- package/cjs/components/sheet-tab-event-handler.js.map +1 -1
- package/cjs/components/vtable-sheet.d.ts +2 -1
- package/cjs/components/vtable-sheet.js +9 -1
- package/cjs/components/vtable-sheet.js.map +1 -1
- package/cjs/core/WorkSheet.d.ts +1 -1
- package/cjs/core/WorkSheet.js.map +1 -1
- package/cjs/core/table-plugins.js +7 -5
- package/cjs/core/table-plugins.js.map +1 -1
- package/cjs/formula/cell-highlight-manager.d.ts +1 -0
- package/cjs/formula/cell-highlight-manager.js +27 -22
- package/cjs/formula/cell-highlight-manager.js.map +1 -1
- package/cjs/formula/cross-sheet-data-synchronizer.d.ts +48 -0
- package/cjs/formula/cross-sheet-data-synchronizer.js +159 -0
- package/cjs/formula/cross-sheet-data-synchronizer.js.map +1 -0
- package/cjs/formula/cross-sheet-formula-handler.d.ts +58 -0
- package/cjs/formula/cross-sheet-formula-handler.js +240 -0
- package/cjs/formula/cross-sheet-formula-handler.js.map +1 -0
- package/cjs/formula/cross-sheet-formula-manager.d.ts +52 -0
- package/cjs/formula/cross-sheet-formula-manager.js +235 -0
- package/cjs/formula/cross-sheet-formula-manager.js.map +1 -0
- package/cjs/formula/cross-sheet-formula-validator.d.ts +56 -0
- package/cjs/formula/cross-sheet-formula-validator.js +271 -0
- package/cjs/formula/cross-sheet-formula-validator.js.map +1 -0
- package/cjs/formula/formula-engine.d.ts +4 -1
- package/cjs/formula/formula-engine.js +132 -25
- package/cjs/formula/formula-engine.js.map +1 -1
- package/cjs/formula/formula-paste-processor.d.ts +3 -3
- package/cjs/formula/formula-paste-processor.js.map +1 -1
- package/cjs/formula/formula-reference-adjustor.d.ts +1 -1
- package/cjs/formula/formula-reference-adjustor.js.map +1 -1
- package/cjs/formula/index.d.ts +8 -0
- package/cjs/formula/index.js +40 -3
- package/cjs/formula/index.js.map +1 -1
- package/cjs/index.d.ts +1 -1
- package/cjs/index.js +1 -1
- package/cjs/index.js.map +1 -1
- package/cjs/managers/formula-manager.d.ts +17 -2
- package/cjs/managers/formula-manager.js +150 -12
- package/cjs/managers/formula-manager.js.map +1 -1
- package/cjs/styles/menu.js +2 -1
- package/cjs/styles/sheet-tab.js +1 -2
- package/cjs/tools/index.js +2 -1
- package/dist/vtable-sheet.js +11322 -331
- package/dist/vtable-sheet.min.js +1 -1
- package/es/components/sheet-tab-event-handler.js +3 -2
- package/es/components/sheet-tab-event-handler.js.map +1 -1
- package/es/components/vtable-sheet.d.ts +2 -1
- package/es/components/vtable-sheet.js +9 -1
- package/es/components/vtable-sheet.js.map +1 -1
- package/es/core/WorkSheet.d.ts +1 -1
- package/es/core/WorkSheet.js.map +1 -1
- package/es/core/table-plugins.js +7 -5
- package/es/core/table-plugins.js.map +1 -1
- package/es/formula/cell-highlight-manager.d.ts +1 -0
- package/es/formula/cell-highlight-manager.js +27 -22
- package/es/formula/cell-highlight-manager.js.map +1 -1
- package/es/formula/cross-sheet-data-synchronizer.d.ts +48 -0
- package/es/formula/cross-sheet-data-synchronizer.js +151 -0
- package/es/formula/cross-sheet-data-synchronizer.js.map +1 -0
- package/es/formula/cross-sheet-formula-handler.d.ts +58 -0
- package/es/formula/cross-sheet-formula-handler.js +236 -0
- package/es/formula/cross-sheet-formula-handler.js.map +1 -0
- package/es/formula/cross-sheet-formula-manager.d.ts +52 -0
- package/es/formula/cross-sheet-formula-manager.js +227 -0
- package/es/formula/cross-sheet-formula-manager.js.map +1 -0
- package/es/formula/cross-sheet-formula-validator.d.ts +56 -0
- package/es/formula/cross-sheet-formula-validator.js +263 -0
- package/es/formula/cross-sheet-formula-validator.js.map +1 -0
- package/es/formula/formula-engine.d.ts +4 -1
- package/es/formula/formula-engine.js +132 -25
- package/es/formula/formula-engine.js.map +1 -1
- package/es/formula/formula-paste-processor.d.ts +3 -3
- package/es/formula/formula-paste-processor.js.map +1 -1
- package/es/formula/formula-reference-adjustor.d.ts +1 -1
- package/es/formula/formula-reference-adjustor.js.map +1 -1
- package/es/formula/index.d.ts +8 -0
- package/es/formula/index.js +8 -0
- package/es/formula/index.js.map +1 -1
- package/es/index.d.ts +1 -1
- package/es/index.js +1 -1
- package/es/index.js.map +1 -1
- package/es/managers/formula-manager.d.ts +17 -2
- package/es/managers/formula-manager.js +152 -11
- package/es/managers/formula-manager.js.map +1 -1
- package/es/styles/menu.js +2 -1
- package/es/styles/sheet-tab.js +1 -2
- package/es/tools/index.js +2 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/formula/cell-highlight-manager.ts"],"names":[],"mappings":"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","file":"cell-highlight-manager.js","sourcesContent":["import type { WorkSheet } from '../core/WorkSheet';\nimport type VTableSheet from '../components/vtable-sheet';\nimport type { CellCoord } from '../ts-types';\n\ninterface HighlightedCell {\n row: number;\n col: number;\n color: string;\n}\n\nexport class CellHighlightManager {\n private sheet: VTableSheet;\n private highlightedCells: Map<string, HighlightedCell> = new Map();\n // /** 目前还没有自定义样式的功能 这个逻辑不需要 */\n // private originalBorderStyles: Map<string, any> = new Map(); // 保存原始边框样式\n private colors = [\n '#4A90E2', // 蓝色\n '#50C878', // 绿色\n '#FF6B6B', // 红色\n '#FFD93D', // 黄色\n '#6BCB77', // 浅绿\n '#9B59B6', // 紫色\n '#FF8C42', // 橙色\n '#00BCD4' // 青色\n ];\n private colorIndex = 0;\n\n constructor(sheet: VTableSheet) {\n this.sheet = sheet;\n }\n\n /**\n * 解析公式中的单元格引用(包括范围引用)\n */\n parseCellReferences(\n formula: string\n ): Array<{ address: string; coords: CellCoord[]; color: string; isRange: boolean }> {\n const references: Array<{ address: string; coords: CellCoord[]; color: string; isRange: boolean }> = [];\n\n // 匹配单元格引用的正则表达式(包括范围引用)\n const cellRefRegex = /(\\$?[A-Z]+\\$?\\d+(?::\\$?[A-Z]+\\$?\\d+)?)/gi;\n\n const matches = formula.match(cellRefRegex);\n if (!matches) {\n return references;\n }\n\n const activeSheet = this.sheet.getActiveSheet();\n if (!activeSheet) {\n return references;\n }\n\n const uniqueRefs = new Set<string>();\n this.colorIndex = 0;\n\n matches.forEach(match => {\n const normalizedRef = match.replace(/\\$/g, '').toUpperCase();\n\n if (!uniqueRefs.has(normalizedRef)) {\n uniqueRefs.add(normalizedRef);\n\n try {\n const isRange = normalizedRef.includes(':');\n let coords: CellCoord[] = [];\n\n if (isRange) {\n // 解析范围引用,如 A1:A4\n coords = this.parseRangeReference(normalizedRef, activeSheet);\n } else {\n // 解析单个单元格引用,如 A1\n const coord = activeSheet.coordFromAddress(normalizedRef);\n coords = [coord];\n }\n\n if (coords.length > 0) {\n const color = this.colors[this.colorIndex % this.colors.length];\n this.colorIndex++;\n\n references.push({\n address: normalizedRef,\n coords: coords,\n color: color,\n isRange: isRange\n });\n }\n } catch (e) {\n // 忽略无效的单元格引用\n console.warn(`Invalid cell reference: ${normalizedRef}`, e);\n }\n }\n });\n\n return references;\n }\n\n /**\n * 解析范围引用,如 A1:A4\n */\n private parseRangeReference(rangeRef: string, activeSheet: WorkSheet): CellCoord[] {\n const parts = rangeRef.split(':');\n if (parts.length !== 2) {\n throw new Error(`Invalid range reference: ${rangeRef}`);\n }\n\n const startCoord = activeSheet.coordFromAddress(parts[0]);\n const endCoord = activeSheet.coordFromAddress(parts[1]);\n\n const coords: CellCoord[] = [];\n\n // 生成范围内的所有单元格坐标\n const startRow = Math.min(startCoord.row, endCoord.row);\n const endRow = Math.max(startCoord.row, endCoord.row);\n const startCol = Math.min(startCoord.col, endCoord.col);\n const endCol = Math.max(startCoord.col, endCoord.col);\n\n for (let row = startRow; row <= endRow; row++) {\n for (let col = startCol; col <= endCol; col++) {\n coords.push({ row, col });\n }\n }\n\n return coords;\n }\n\n /**\n * 高亮公式中引用的单元格\n */\n highlightFormulaCells(formula: string): void {\n // 清除之前的高亮\n this.clearHighlights();\n\n const references = this.parseCellReferences(formula);\n\n if (references.length === 0) {\n return;\n }\n\n const activeSheet = this.sheet.getActiveSheet();\n if (!activeSheet) {\n return;\n }\n\n // 应用高亮\n references.forEach(ref => {\n ref.coords.forEach(coord => {\n const key = `${coord.row}-${coord.col}`;\n\n // 保存高亮信息\n this.highlightedCells.set(key, {\n row: coord.row,\n col: coord.col,\n color: ref.color\n });\n\n // 应用高亮样式\n this.applyCellHighlight(activeSheet, coord, ref.color);\n });\n });\n }\n\n /**\n * 应用单元格高亮\n * 通过修改单元格的边框样式实现\n */\n private applyCellHighlight(sheet: WorkSheet, coord: CellCoord, color: string): void {\n const table = (sheet as any).tableInstance;\n if (!table || !table.scenegraph) {\n return;\n }\n\n try {\n const key = `${coord.row}-${coord.col}`;\n\n // // 保存原始样式\n // if (!this.originalBorderStyles.has(key)) {\n // const originalStyle = table.getCellStyle(coord.col, coord.row);\n // this.originalBorderStyles.set(key, originalStyle);\n // }\n\n // 创建高亮样式\n const highlightStyle = {\n // ...table._getCellStyle(coord.col, coord.row),\n borderColor: [color, color, color, color],\n borderLineWidth: [4, 4, 4, 4],\n borderLineDash: [\n [4, 4],\n [4, 4],\n [4, 4],\n [4, 4]\n ],\n padding: [8, 8, 8, 8]\n };\n\n // 注册自定义样式\n const styleId = `highlight-${key}`;\n table.registerCustomCellStyle(styleId, highlightStyle);\n\n // 应用样式到单元格\n table.arrangeCustomCellStyle({ col: coord.col, row: coord.row }, styleId, false);\n } catch (e) {\n console.error('applyCellHighlight: 错误', e);\n }\n }\n\n /**\n * 清除所有高亮\n */\n clearHighlights(): void {\n const activeSheet = this.sheet.getActiveSheet();\n if (!activeSheet) {\n return;\n }\n\n const table = (activeSheet as any).tableInstance;\n if (!table || !table.scenegraph) {\n return;\n }\n\n this.highlightedCells.forEach(info => {\n try {\n const key = `${info.row}-${info.col}`;\n const styleId = `highlight-${key}`;\n\n // 移除高亮样式\n table.arrangeCustomCellStyle({ col: info.col, row: info.row }, null, false);\n\n // // 恢复原始样式\n // const originalStyle = this.originalBorderStyles.get(key);\n // if (originalStyle) {\n // table.registerCustomCellStyle(styleId, originalStyle);\n // table.arrangeCustomCellStyle({ col: info.col, row: info.row }, styleId, true);\n // }\n } catch (e) {\n console.warn(`Failed to clear highlight at ${info.row},${info.col}:`, e);\n }\n });\n\n this.highlightedCells.clear();\n // this.originalBorderStyles.clear();\n this.colorIndex = 0;\n }\n\n /**\n * 获取单元格的高亮颜色\n */\n getCellHighlightColor(coord: CellCoord): string | null {\n const key = `${coord.row}-${coord.col}`;\n const info = this.highlightedCells.get(key);\n return info ? info.color : null;\n }\n\n /**\n * 获取高亮的单元格列表\n */\n getHighlightedCells(): Array<{ coord: CellCoord; color: string }> {\n return Array.from(this.highlightedCells.values()).map(info => ({\n coord: { row: info.row, col: info.col },\n color: info.color\n }));\n }\n\n /**\n * 获取彩色公式文本\n */\n getColorizedFormula(formula: string): Array<{ text: string; color?: string }> {\n const references = this.parseCellReferences(formula);\n const parts: Array<{ text: string; color?: string }> = [];\n\n if (references.length === 0) {\n return [{ text: formula }];\n }\n\n let lastIndex = 0;\n const colorMap = new Map<string, string>();\n references.forEach(ref => {\n colorMap.set(ref.address.toUpperCase(), ref.color);\n });\n\n const regex = /(\\$?[A-Z]+\\$?\\d+)/gi;\n let match;\n\n while ((match = regex.exec(formula)) !== null) {\n if (match.index > lastIndex) {\n parts.push({ text: formula.substring(lastIndex, match.index) });\n }\n\n const normalizedRef = match[0].replace(/\\$/g, '').toUpperCase();\n const color = colorMap.get(normalizedRef);\n parts.push({\n text: match[0],\n color: color\n });\n\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < formula.length) {\n parts.push({ text: formula.substring(lastIndex) });\n }\n\n return parts;\n }\n\n /**\n * 销毁管理器\n */\n release(): void {\n this.clearHighlights();\n this.highlightedCells.clear();\n // this.originalBorderStyles.clear();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/formula/cell-highlight-manager.ts"],"names":[],"mappings":"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","file":"cell-highlight-manager.js","sourcesContent":["import type { WorkSheet } from '../core/WorkSheet';\nimport type VTableSheet from '../components/vtable-sheet';\nimport type { CellCoord } from '../ts-types';\n\ninterface HighlightedCell {\n row: number;\n col: number;\n color: string;\n}\n\nexport class CellHighlightManager {\n private sheet: VTableSheet;\n private highlightedCells: Map<string, HighlightedCell> = new Map();\n // /** 目前还没有自定义样式的功能 这个逻辑不需要 */\n // private originalBorderStyles: Map<string, any> = new Map(); // 保存原始边框样式\n private colors = [\n '#4A90E2', // 蓝色\n '#50C878', // 绿色\n '#FF6B6B', // 红色\n '#FFD93D', // 黄色\n '#6BCB77', // 浅绿\n '#9B59B6', // 紫色\n '#FF8C42', // 橙色\n '#00BCD4' // 青色\n ];\n private colorIndex = 0;\n\n constructor(sheet: VTableSheet) {\n this.sheet = sheet;\n }\n\n /**\n * 解析公式中的单元格引用(包括范围引用)\n */\n parseCellReferences(formula: string): Array<{\n address: string;\n coords: CellCoord[];\n color: string;\n isRange: boolean;\n sheetName?: string;\n }> {\n const references: Array<{\n address: string;\n coords: CellCoord[];\n color: string;\n isRange: boolean;\n sheetName?: string;\n }> = [];\n\n // 更简单的跨sheet引用匹配方法\n // 匹配模式:Sheet1!A1, 'Sheet Name'!A1, A1, A1:B2, Sheet1!A1:B2\n const cellRefRegex = /(?:([']?[^!'\\s]+[']?)!)?(\\$?[A-Z]+\\$?\\d+(?::\\$?[A-Z]+\\$?\\d+)?)/g;\n\n const uniqueRefs = new Map<string, { sheetName?: string; cellRef: string }>();\n this.colorIndex = 0;\n\n let match;\n while ((match = cellRefRegex.exec(formula)) !== null) {\n // 解析跨sheet引用\n const sheetNamePart = match[1];\n const cellRef = match[2];\n\n let sheetName: string | undefined;\n if (sheetNamePart) {\n sheetName = sheetNamePart.replace(/'/g, ''); // 移除可能的引号\n }\n\n const normalizedCellRef = cellRef.replace(/\\$/g, '').toUpperCase();\n const uniqueKey = sheetName ? `${sheetName}!${normalizedCellRef}` : normalizedCellRef;\n\n if (!uniqueRefs.has(uniqueKey)) {\n uniqueRefs.set(uniqueKey, { sheetName, cellRef: normalizedCellRef });\n\n try {\n const isRange = normalizedCellRef.includes(':');\n let coords: CellCoord[] = [];\n\n // 获取目标sheet\n const targetSheet = sheetName ? this.sheet.getSheetByName(sheetName) : this.sheet.getActiveSheet();\n if (!targetSheet) {\n console.warn(`Sheet not found: ${sheetName || 'active sheet'}`);\n continue;\n }\n\n if (isRange) {\n // 解析范围引用,如 A1:A4\n coords = this.parseRangeReference(normalizedCellRef, targetSheet);\n } else {\n // 解析单个单元格引用,如 A1\n const coord = targetSheet.coordFromAddress(normalizedCellRef);\n coords = [coord];\n }\n\n if (coords.length > 0) {\n const color = this.colors[this.colorIndex % this.colors.length];\n this.colorIndex++;\n\n references.push({\n address: uniqueKey,\n coords: coords,\n color: color,\n isRange: isRange,\n sheetName: sheetName\n });\n }\n } catch (e) {\n // 忽略无效的单元格引用\n console.warn(`Invalid cell reference: ${uniqueKey}`, e);\n }\n }\n }\n\n return references;\n }\n\n /**\n * 解析范围引用,如 A1:A4\n */\n private parseRangeReference(rangeRef: string, activeSheet: WorkSheet): CellCoord[] {\n const parts = rangeRef.split(':');\n if (parts.length !== 2) {\n throw new Error(`Invalid range reference: ${rangeRef}`);\n }\n\n const startCoord = activeSheet.coordFromAddress(parts[0]);\n const endCoord = activeSheet.coordFromAddress(parts[1]);\n\n const coords: CellCoord[] = [];\n\n // 生成范围内的所有单元格坐标\n const startRow = Math.min(startCoord.row, endCoord.row);\n const endRow = Math.max(startCoord.row, endCoord.row);\n const startCol = Math.min(startCoord.col, endCoord.col);\n const endCol = Math.max(startCoord.col, endCoord.col);\n\n for (let row = startRow; row <= endRow; row++) {\n for (let col = startCol; col <= endCol; col++) {\n coords.push({ row, col });\n }\n }\n\n return coords;\n }\n\n /**\n * 高亮公式中引用的单元格(支持跨sheet)\n */\n highlightFormulaCells(formula: string): void {\n // 清除之前的高亮\n this.clearHighlights();\n\n const references = this.parseCellReferences(formula);\n\n if (references.length === 0) {\n return;\n }\n\n // 应用高亮 - 支持跨sheet\n references.forEach(ref => {\n // 获取目标sheet\n const targetSheet = ref.sheetName ? this.sheet.getSheetByName(ref.sheetName) : this.sheet.getActiveSheet();\n\n if (!targetSheet) {\n console.warn(`Sheet not found for highlighting: ${ref.sheetName || 'active sheet'}`);\n return;\n }\n\n ref.coords.forEach(coord => {\n // 使用包含sheet名称的唯一key\n const sheetPrefix = ref.sheetName ? `${ref.sheetName}!` : '';\n const key = `${sheetPrefix}${coord.row}-${coord.col}`;\n\n // 保存高亮信息\n this.highlightedCells.set(key, {\n row: coord.row,\n col: coord.col,\n color: ref.color\n });\n\n // 应用高亮样式到正确的sheet\n this.applyCellHighlight(targetSheet, coord, ref.color);\n });\n });\n }\n\n /**\n * 应用单元格高亮\n * 通过修改单元格的边框样式实现\n */\n private applyCellHighlight(sheet: WorkSheet, coord: CellCoord, color: string): void {\n const table = (sheet as any).tableInstance;\n if (!table || !table.scenegraph) {\n return;\n }\n\n try {\n const key = `${coord.row}-${coord.col}`;\n\n // // 保存原始样式\n // if (!this.originalBorderStyles.has(key)) {\n // const originalStyle = table.getCellStyle(coord.col, coord.row);\n // this.originalBorderStyles.set(key, originalStyle);\n // }\n\n // 创建高亮样式\n const highlightStyle = {\n // ...table._getCellStyle(coord.col, coord.row),\n borderColor: [color, color, color, color],\n borderLineWidth: [4, 4, 4, 4],\n borderLineDash: [\n [4, 4],\n [4, 4],\n [4, 4],\n [4, 4]\n ],\n padding: [8, 8, 8, 8]\n };\n\n // 注册自定义样式\n const styleId = `highlight-${key}`;\n table.registerCustomCellStyle(styleId, highlightStyle);\n\n // 应用样式到单元格\n table.arrangeCustomCellStyle({ col: coord.col, row: coord.row }, styleId, false);\n } catch (e) {\n console.error('applyCellHighlight: 错误', e);\n }\n }\n\n /**\n * 清除所有高亮\n */\n clearHighlights(): void {\n const activeSheet = this.sheet.getActiveSheet();\n if (!activeSheet) {\n return;\n }\n\n const table = (activeSheet as any).tableInstance;\n if (!table || !table.scenegraph) {\n return;\n }\n\n this.highlightedCells.forEach(info => {\n try {\n // 移除高亮样式\n table.arrangeCustomCellStyle({ col: info.col, row: info.row }, null, false);\n\n // // 恢复原始样式\n // const originalStyle = this.originalBorderStyles.get(key);\n // if (originalStyle) {\n // table.registerCustomCellStyle(styleId, originalStyle);\n // table.arrangeCustomCellStyle({ col: info.col, row: info.row }, styleId, true);\n // }\n } catch (e) {\n console.warn(`Failed to clear highlight at ${info.row},${info.col}:`, e);\n }\n });\n\n this.highlightedCells.clear();\n // this.originalBorderStyles.clear();\n this.colorIndex = 0;\n }\n\n /**\n * 获取单元格的高亮颜色\n */\n getCellHighlightColor(coord: CellCoord): string | null {\n const key = `${coord.row}-${coord.col}`;\n const info = this.highlightedCells.get(key);\n return info ? info.color : null;\n }\n\n /**\n * 获取高亮的单元格列表\n */\n getHighlightedCells(): Array<{ coord: CellCoord; color: string }> {\n return Array.from(this.highlightedCells.values()).map(info => ({\n coord: { row: info.row, col: info.col },\n color: info.color\n }));\n }\n\n /**\n * 获取彩色公式文本\n */\n getColorizedFormula(formula: string): Array<{ text: string; color?: string }> {\n const references = this.parseCellReferences(formula);\n const parts: Array<{ text: string; color?: string }> = [];\n\n if (references.length === 0) {\n return [{ text: formula }];\n }\n\n let lastIndex = 0;\n const colorMap = new Map<string, string>();\n references.forEach(ref => {\n colorMap.set(ref.address.toUpperCase(), ref.color);\n });\n\n const regex = /(\\$?[A-Z]+\\$?\\d+)/gi;\n let match;\n\n while ((match = regex.exec(formula)) !== null) {\n if (match.index > lastIndex) {\n parts.push({ text: formula.substring(lastIndex, match.index) });\n }\n\n const normalizedRef = match[0].replace(/\\$/g, '').toUpperCase();\n const color = colorMap.get(normalizedRef);\n parts.push({\n text: match[0],\n color: color\n });\n\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < formula.length) {\n parts.push({ text: formula.substring(lastIndex) });\n }\n\n return parts;\n }\n\n /**\n * 销毁管理器\n */\n release(): void {\n this.clearHighlights();\n this.highlightedCells.clear();\n // this.originalBorderStyles.clear();\n }\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { FormulaCell } from '../ts-types/formula';
|
|
2
|
+
import type { FormulaEngine } from './formula-engine';
|
|
3
|
+
import type { CrossSheetFormulaManager } from './cross-sheet-formula-manager';
|
|
4
|
+
export interface DataChangeEvent {
|
|
5
|
+
sheet: string;
|
|
6
|
+
cells: FormulaCell[];
|
|
7
|
+
oldValues: any[];
|
|
8
|
+
newValues: any[];
|
|
9
|
+
timestamp: number;
|
|
10
|
+
}
|
|
11
|
+
export interface SyncOptions {
|
|
12
|
+
immediate: boolean;
|
|
13
|
+
batchSize: number;
|
|
14
|
+
timeout: number;
|
|
15
|
+
}
|
|
16
|
+
export declare class CrossSheetDataSynchronizer {
|
|
17
|
+
private formulaEngine;
|
|
18
|
+
private crossSheetManager;
|
|
19
|
+
private changeQueue;
|
|
20
|
+
private isSyncing;
|
|
21
|
+
private syncTimer;
|
|
22
|
+
private options;
|
|
23
|
+
private listeners;
|
|
24
|
+
constructor(formulaEngine: FormulaEngine, crossSheetManager: CrossSheetFormulaManager);
|
|
25
|
+
registerDataChange(sheet: string, cells: FormulaCell[], oldValues: any[], newValues: any[]): void;
|
|
26
|
+
private scheduleSync;
|
|
27
|
+
private processChanges;
|
|
28
|
+
private groupChangesBySheet;
|
|
29
|
+
private syncSheetChanges;
|
|
30
|
+
getCrossSheetDependencies(): Map<string, string[]>;
|
|
31
|
+
validateCrossSheetReferences(): {
|
|
32
|
+
valid: boolean;
|
|
33
|
+
errors: string[];
|
|
34
|
+
};
|
|
35
|
+
private detectCircularDependencies;
|
|
36
|
+
addDataChangeListener(sheet: string, listener: (event: DataChangeEvent) => void): void;
|
|
37
|
+
removeDataChangeListener(sheet: string, listener: (event: DataChangeEvent) => void): void;
|
|
38
|
+
private emitDataChange;
|
|
39
|
+
forceSync(): Promise<void>;
|
|
40
|
+
clearSyncQueue(): void;
|
|
41
|
+
getSyncStatus(): {
|
|
42
|
+
pendingChanges: number;
|
|
43
|
+
isSyncing: boolean;
|
|
44
|
+
lastSyncTime: number | null;
|
|
45
|
+
};
|
|
46
|
+
updateSyncOptions(options: Partial<SyncOptions>): void;
|
|
47
|
+
destroy(): void;
|
|
48
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
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
|
+
export class CrossSheetDataSynchronizer {
|
|
28
|
+
constructor(formulaEngine, crossSheetManager) {
|
|
29
|
+
this.changeQueue = [], this.isSyncing = !1, this.syncTimer = null, this.options = {
|
|
30
|
+
immediate: !1,
|
|
31
|
+
batchSize: 100,
|
|
32
|
+
timeout: 50
|
|
33
|
+
}, this.listeners = new Map, this.formulaEngine = formulaEngine, this.crossSheetManager = crossSheetManager;
|
|
34
|
+
}
|
|
35
|
+
registerDataChange(sheet, cells, oldValues, newValues) {
|
|
36
|
+
const event = {
|
|
37
|
+
sheet: sheet,
|
|
38
|
+
cells: cells,
|
|
39
|
+
oldValues: oldValues,
|
|
40
|
+
newValues: newValues,
|
|
41
|
+
timestamp: Date.now()
|
|
42
|
+
};
|
|
43
|
+
this.changeQueue.push(event), this.options.immediate ? this.processChanges() : this.scheduleSync();
|
|
44
|
+
}
|
|
45
|
+
scheduleSync() {
|
|
46
|
+
this.syncTimer && clearTimeout(this.syncTimer), this.syncTimer = setTimeout((() => {
|
|
47
|
+
this.processChanges();
|
|
48
|
+
}), this.options.timeout);
|
|
49
|
+
}
|
|
50
|
+
processChanges() {
|
|
51
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
52
|
+
if (!this.isSyncing && 0 !== this.changeQueue.length) {
|
|
53
|
+
this.isSyncing = !0;
|
|
54
|
+
try {
|
|
55
|
+
const batch = this.changeQueue.splice(0, this.options.batchSize), changesBySheet = this.groupChangesBySheet(batch);
|
|
56
|
+
for (const [targetSheet, changes] of changesBySheet.entries()) yield this.syncSheetChanges(targetSheet, changes);
|
|
57
|
+
for (const event of batch) this.emitDataChange(event);
|
|
58
|
+
} catch (error) {} finally {
|
|
59
|
+
this.isSyncing = !1, this.changeQueue.length > 0 && this.scheduleSync();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
groupChangesBySheet(events) {
|
|
65
|
+
const groups = new Map;
|
|
66
|
+
for (const event of events) {
|
|
67
|
+
const existing = groups.get(event.sheet) || [];
|
|
68
|
+
existing.push(event), groups.set(event.sheet, existing);
|
|
69
|
+
}
|
|
70
|
+
return groups;
|
|
71
|
+
}
|
|
72
|
+
syncSheetChanges(targetSheet, changes) {
|
|
73
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
74
|
+
const allChangedCells = [], allOldValues = [], allNewValues = [];
|
|
75
|
+
for (const change of changes) allChangedCells.push(...change.cells), allOldValues.push(...change.oldValues),
|
|
76
|
+
allNewValues.push(...change.newValues);
|
|
77
|
+
yield this.crossSheetManager.updateCrossSheetReferences(targetSheet, allChangedCells);
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
getCrossSheetDependencies() {
|
|
81
|
+
const dependencies = new Map, allSheets = this.formulaEngine.getAllSheets();
|
|
82
|
+
for (const sheetInfo of allSheets) {
|
|
83
|
+
const targetSheets = this.crossSheetManager.getCrossSheetDependencies(sheetInfo.key).map((dep => dep.precedentSheet));
|
|
84
|
+
dependencies.set(sheetInfo.key, targetSheets);
|
|
85
|
+
}
|
|
86
|
+
return dependencies;
|
|
87
|
+
}
|
|
88
|
+
validateCrossSheetReferences() {
|
|
89
|
+
const errors = [], allSheets = this.formulaEngine.getAllSheets();
|
|
90
|
+
for (const sheetInfo of allSheets) {
|
|
91
|
+
const validation = this.crossSheetManager.validateCrossSheetReferences(sheetInfo.key);
|
|
92
|
+
validation.valid || errors.push(...validation.errors);
|
|
93
|
+
const circularDeps = this.detectCircularDependencies(sheetInfo.key, new Set);
|
|
94
|
+
circularDeps.length > 0 && errors.push(`Circular dependency detected in sheet ${sheetInfo.key}: ${circularDeps.join(" -> ")}`);
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
valid: 0 === errors.length,
|
|
98
|
+
errors: errors
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
detectCircularDependencies(sheet, visited) {
|
|
102
|
+
if (visited.has(sheet)) return [ sheet ];
|
|
103
|
+
visited.add(sheet);
|
|
104
|
+
const dependencies = this.crossSheetManager.getCrossSheetDependencies(sheet);
|
|
105
|
+
for (const dep of dependencies) {
|
|
106
|
+
const cycle = this.detectCircularDependencies(dep.precedentSheet, new Set(visited));
|
|
107
|
+
if (cycle.length > 0) return [ sheet, ...cycle ];
|
|
108
|
+
}
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
addDataChangeListener(sheet, listener) {
|
|
112
|
+
this.listeners.has(sheet) || this.listeners.set(sheet, new Set), this.listeners.get(sheet).add(listener);
|
|
113
|
+
}
|
|
114
|
+
removeDataChangeListener(sheet, listener) {
|
|
115
|
+
const listeners = this.listeners.get(sheet);
|
|
116
|
+
listeners && (listeners.delete(listener), 0 === listeners.size && this.listeners.delete(sheet));
|
|
117
|
+
}
|
|
118
|
+
emitDataChange(event) {
|
|
119
|
+
const listeners = this.listeners.get(event.sheet);
|
|
120
|
+
if (listeners) for (const listener of listeners) try {
|
|
121
|
+
listener(event);
|
|
122
|
+
} catch (error) {}
|
|
123
|
+
const globalListeners = this.listeners.get("*");
|
|
124
|
+
if (globalListeners) for (const listener of globalListeners) try {
|
|
125
|
+
listener(event);
|
|
126
|
+
} catch (error) {}
|
|
127
|
+
}
|
|
128
|
+
forceSync() {
|
|
129
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
130
|
+
this.syncTimer && (clearTimeout(this.syncTimer), this.syncTimer = null), yield this.processChanges();
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
clearSyncQueue() {
|
|
134
|
+
this.changeQueue = [], this.syncTimer && (clearTimeout(this.syncTimer), this.syncTimer = null);
|
|
135
|
+
}
|
|
136
|
+
getSyncStatus() {
|
|
137
|
+
var _a;
|
|
138
|
+
return {
|
|
139
|
+
pendingChanges: this.changeQueue.length,
|
|
140
|
+
isSyncing: this.isSyncing,
|
|
141
|
+
lastSyncTime: this.changeQueue.length > 0 && (null === (_a = this.changeQueue[this.changeQueue.length - 1]) || void 0 === _a ? void 0 : _a.timestamp) || null
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
updateSyncOptions(options) {
|
|
145
|
+
this.options = Object.assign(Object.assign({}, this.options), options);
|
|
146
|
+
}
|
|
147
|
+
destroy() {
|
|
148
|
+
this.clearSyncQueue(), this.listeners.clear(), this.crossSheetManager.clearCache();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=cross-sheet-data-synchronizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/formula/cross-sheet-data-synchronizer.ts"],"names":[],"mappings":"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","file":"cross-sheet-data-synchronizer.js","sourcesContent":["/**\n * 跨sheet数据同步器\n * 处理不同sheet之间的数据同步和更新通知\n */\n\nimport type { FormulaCell } from '../ts-types/formula';\nimport type { FormulaEngine } from './formula-engine';\nimport type { CrossSheetFormulaManager } from './cross-sheet-formula-manager';\n\nexport interface DataChangeEvent {\n sheet: string;\n cells: FormulaCell[];\n oldValues: any[];\n newValues: any[];\n timestamp: number;\n}\n\nexport interface SyncOptions {\n immediate: boolean;\n batchSize: number;\n timeout: number;\n}\n\nexport class CrossSheetDataSynchronizer {\n private formulaEngine: FormulaEngine;\n private crossSheetManager: CrossSheetFormulaManager;\n\n // 数据变更队列\n private changeQueue: DataChangeEvent[] = [];\n\n // 同步状态\n private isSyncing = false;\n private syncTimer: NodeJS.Timeout | null = null;\n\n // 同步选项\n private options: SyncOptions = {\n immediate: false,\n batchSize: 100,\n timeout: 50 // 50ms批处理\n };\n\n // 事件监听器\n private listeners: Map<string, Set<(event: DataChangeEvent) => void>> = new Map();\n\n constructor(formulaEngine: FormulaEngine, crossSheetManager: CrossSheetFormulaManager) {\n this.formulaEngine = formulaEngine;\n this.crossSheetManager = crossSheetManager;\n }\n\n /**\n * 注册数据变更\n */\n registerDataChange(sheet: string, cells: FormulaCell[], oldValues: any[], newValues: any[]): void {\n const event: DataChangeEvent = {\n sheet,\n cells,\n oldValues,\n newValues,\n timestamp: Date.now()\n };\n\n this.changeQueue.push(event);\n\n if (this.options.immediate) {\n this.processChanges();\n } else {\n this.scheduleSync();\n }\n }\n\n /**\n * 调度同步\n */\n private scheduleSync(): void {\n if (this.syncTimer) {\n clearTimeout(this.syncTimer);\n }\n\n this.syncTimer = setTimeout(() => {\n this.processChanges();\n }, this.options.timeout);\n }\n\n /**\n * 处理数据变更\n */\n private async processChanges(): Promise<void> {\n if (this.isSyncing || this.changeQueue.length === 0) {\n return;\n }\n\n this.isSyncing = true;\n\n try {\n // 批量处理变更\n const batch = this.changeQueue.splice(0, this.options.batchSize);\n\n // 按sheet分组处理\n const changesBySheet = this.groupChangesBySheet(batch);\n\n for (const [targetSheet, changes] of changesBySheet.entries()) {\n await this.syncSheetChanges(targetSheet, changes);\n }\n\n // 触发事件\n for (const event of batch) {\n this.emitDataChange(event);\n }\n } catch (error) {\n console.error('Error processing cross-sheet data changes:', error);\n } finally {\n this.isSyncing = false;\n\n // 如果还有剩余的变更,继续处理\n if (this.changeQueue.length > 0) {\n this.scheduleSync();\n }\n }\n }\n\n /**\n * 按sheet分组变更\n */\n private groupChangesBySheet(events: DataChangeEvent[]): Map<string, DataChangeEvent[]> {\n const groups = new Map<string, DataChangeEvent[]>();\n\n for (const event of events) {\n const existing = groups.get(event.sheet) || [];\n existing.push(event);\n groups.set(event.sheet, existing);\n }\n\n return groups;\n }\n\n /**\n * 同步指定sheet的变更\n */\n private async syncSheetChanges(targetSheet: string, changes: DataChangeEvent[]): Promise<void> {\n // 收集所有变化的单元格\n const allChangedCells: FormulaCell[] = [];\n const allOldValues: any[] = [];\n const allNewValues: any[] = [];\n\n for (const change of changes) {\n allChangedCells.push(...change.cells);\n allOldValues.push(...change.oldValues);\n allNewValues.push(...change.newValues);\n }\n\n // 使用跨sheet管理器更新引用\n await this.crossSheetManager.updateCrossSheetReferences(targetSheet, allChangedCells);\n }\n\n /**\n * 获取跨sheet依赖关系\n */\n getCrossSheetDependencies(): Map<string, string[]> {\n const dependencies = new Map<string, string[]>();\n\n const allSheets = this.formulaEngine.getAllSheets();\n for (const sheetInfo of allSheets) {\n const deps = this.crossSheetManager.getCrossSheetDependencies(sheetInfo.key);\n const targetSheets = deps.map(dep => dep.precedentSheet);\n dependencies.set(sheetInfo.key, targetSheets);\n }\n\n return dependencies;\n }\n\n /**\n * 验证跨sheet引用的完整性\n */\n validateCrossSheetReferences(): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n const allSheets = this.formulaEngine.getAllSheets();\n\n for (const sheetInfo of allSheets) {\n const validation = this.crossSheetManager.validateCrossSheetReferences(sheetInfo.key);\n if (!validation.valid) {\n errors.push(...validation.errors);\n }\n\n // 检查循环依赖\n const circularDeps = this.detectCircularDependencies(sheetInfo.key, new Set());\n if (circularDeps.length > 0) {\n errors.push(`Circular dependency detected in sheet ${sheetInfo.key}: ${circularDeps.join(' -> ')}`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors\n };\n }\n\n /**\n * 检测循环依赖\n */\n private detectCircularDependencies(sheet: string, visited: Set<string>): string[] {\n if (visited.has(sheet)) {\n return [sheet];\n }\n\n visited.add(sheet);\n const dependencies = this.crossSheetManager.getCrossSheetDependencies(sheet);\n\n for (const dep of dependencies) {\n const cycle = this.detectCircularDependencies(dep.precedentSheet, new Set(visited));\n if (cycle.length > 0) {\n return [sheet, ...cycle];\n }\n }\n\n return [];\n }\n\n /**\n * 添加数据变更监听器\n */\n addDataChangeListener(sheet: string, listener: (event: DataChangeEvent) => void): void {\n if (!this.listeners.has(sheet)) {\n this.listeners.set(sheet, new Set());\n }\n this.listeners.get(sheet)!.add(listener);\n }\n\n /**\n * 移除数据变更监听器\n */\n removeDataChangeListener(sheet: string, listener: (event: DataChangeEvent) => void): void {\n const listeners = this.listeners.get(sheet);\n if (listeners) {\n listeners.delete(listener);\n if (listeners.size === 0) {\n this.listeners.delete(sheet);\n }\n }\n }\n\n /**\n * 触发数据变更事件\n */\n private emitDataChange(event: DataChangeEvent): void {\n const listeners = this.listeners.get(event.sheet);\n if (listeners) {\n for (const listener of listeners) {\n try {\n listener(event);\n } catch (error) {\n console.error('Error in data change listener:', error);\n }\n }\n }\n\n // 也触发全局监听器\n const globalListeners = this.listeners.get('*');\n if (globalListeners) {\n for (const listener of globalListeners) {\n try {\n listener(event);\n } catch (error) {\n console.error('Error in global data change listener:', error);\n }\n }\n }\n }\n\n /**\n * 强制立即同步\n */\n async forceSync(): Promise<void> {\n if (this.syncTimer) {\n clearTimeout(this.syncTimer);\n this.syncTimer = null;\n }\n\n await this.processChanges();\n }\n\n /**\n * 清除同步队列\n */\n clearSyncQueue(): void {\n this.changeQueue = [];\n if (this.syncTimer) {\n clearTimeout(this.syncTimer);\n this.syncTimer = null;\n }\n }\n\n /**\n * 获取同步状态\n */\n getSyncStatus(): {\n pendingChanges: number;\n isSyncing: boolean;\n lastSyncTime: number | null;\n } {\n return {\n pendingChanges: this.changeQueue.length,\n isSyncing: this.isSyncing,\n lastSyncTime:\n this.changeQueue.length > 0 ? this.changeQueue[this.changeQueue.length - 1]?.timestamp || null : null\n };\n }\n\n /**\n * 更新同步选项\n */\n updateSyncOptions(options: Partial<SyncOptions>): void {\n this.options = { ...this.options, ...options };\n }\n\n /**\n * 销毁同步器\n */\n destroy(): void {\n this.clearSyncQueue();\n this.listeners.clear();\n this.crossSheetManager.clearCache();\n }\n}\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { FormulaCell } from '../ts-types/formula';
|
|
2
|
+
import type { FormulaEngine } from './formula-engine';
|
|
3
|
+
import { type ValidationResult } from './cross-sheet-formula-validator';
|
|
4
|
+
export interface CrossSheetFormulaOptions {
|
|
5
|
+
enableCaching: boolean;
|
|
6
|
+
enableValidation: boolean;
|
|
7
|
+
syncTimeout: number;
|
|
8
|
+
maxRecursionDepth: number;
|
|
9
|
+
}
|
|
10
|
+
export interface FormulaCalculationResult {
|
|
11
|
+
value: any;
|
|
12
|
+
error?: string;
|
|
13
|
+
dependencies: FormulaCell[];
|
|
14
|
+
calculationTime: number;
|
|
15
|
+
}
|
|
16
|
+
export declare class CrossSheetFormulaHandler {
|
|
17
|
+
private formulaEngine;
|
|
18
|
+
private crossSheetManager;
|
|
19
|
+
private dataSynchronizer;
|
|
20
|
+
private validator;
|
|
21
|
+
private formulaManager?;
|
|
22
|
+
private options;
|
|
23
|
+
private isCalculating;
|
|
24
|
+
private calculationQueue;
|
|
25
|
+
private calculationResults;
|
|
26
|
+
constructor(formulaEngine: FormulaEngine, sheetManager?: {
|
|
27
|
+
getAllSheets: () => Array<{
|
|
28
|
+
sheetKey: string;
|
|
29
|
+
sheetTitle: string;
|
|
30
|
+
}>;
|
|
31
|
+
}, formulaManager?: any);
|
|
32
|
+
setCrossSheetFormula(cell: FormulaCell, formula: string): Promise<FormulaCalculationResult>;
|
|
33
|
+
getCrossSheetValue(cell: FormulaCell): Promise<FormulaCalculationResult>;
|
|
34
|
+
updateCrossSheetReferences(targetSheet: string, changedCells: FormulaCell[]): Promise<void>;
|
|
35
|
+
validateCrossSheetFormula(cell: FormulaCell): ValidationResult;
|
|
36
|
+
validateAllCrossSheetFormulas(): Map<string, ValidationResult>;
|
|
37
|
+
getCrossSheetDependencies(): Map<string, string[]>;
|
|
38
|
+
recalculateAllCrossSheetFormulas(): Promise<void>;
|
|
39
|
+
recalculateFormula(cell: FormulaCell): Promise<FormulaCalculationResult>;
|
|
40
|
+
private hasCrossSheetReference;
|
|
41
|
+
private cacheCalculationResult;
|
|
42
|
+
private getCachedResult;
|
|
43
|
+
private getCacheKey;
|
|
44
|
+
private parseA1Notation;
|
|
45
|
+
private getA1Notation;
|
|
46
|
+
updateOptions(options: Partial<CrossSheetFormulaOptions>): void;
|
|
47
|
+
getHandlerStatus(): {
|
|
48
|
+
isCalculating: boolean;
|
|
49
|
+
pendingCalculations: number;
|
|
50
|
+
cacheSize: number;
|
|
51
|
+
options: CrossSheetFormulaOptions;
|
|
52
|
+
};
|
|
53
|
+
clearCache(): void;
|
|
54
|
+
addDataChangeListener(sheet: string, listener: (event: any) => void): void;
|
|
55
|
+
removeDataChangeListener(sheet: string, listener: (event: any) => void): void;
|
|
56
|
+
forceSync(): Promise<void>;
|
|
57
|
+
destroy(): void;
|
|
58
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
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 { CrossSheetFormulaManager } from "./cross-sheet-formula-manager";
|
|
28
|
+
|
|
29
|
+
import { CrossSheetDataSynchronizer } from "./cross-sheet-data-synchronizer";
|
|
30
|
+
|
|
31
|
+
import { CrossSheetFormulaValidator } from "./cross-sheet-formula-validator";
|
|
32
|
+
|
|
33
|
+
export class CrossSheetFormulaHandler {
|
|
34
|
+
constructor(formulaEngine, sheetManager, formulaManager) {
|
|
35
|
+
this.options = {
|
|
36
|
+
enableCaching: !0,
|
|
37
|
+
enableValidation: !0,
|
|
38
|
+
syncTimeout: 50,
|
|
39
|
+
maxRecursionDepth: 100
|
|
40
|
+
}, this.isCalculating = !1, this.calculationQueue = [], this.calculationResults = new Map,
|
|
41
|
+
this.formulaEngine = formulaEngine, this.formulaManager = formulaManager, this.crossSheetManager = new CrossSheetFormulaManager(formulaEngine, sheetManager),
|
|
42
|
+
this.dataSynchronizer = new CrossSheetDataSynchronizer(formulaEngine, this.crossSheetManager),
|
|
43
|
+
this.validator = new CrossSheetFormulaValidator(formulaEngine, this.crossSheetManager, sheetManager);
|
|
44
|
+
}
|
|
45
|
+
setCrossSheetFormula(cell, formula) {
|
|
46
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
47
|
+
const startTime = performance.now();
|
|
48
|
+
try {
|
|
49
|
+
if (this.options.enableValidation) {
|
|
50
|
+
const validation = this.validator.validateFormulaSyntax(formula);
|
|
51
|
+
if (!validation.valid) return {
|
|
52
|
+
value: null,
|
|
53
|
+
error: validation.error,
|
|
54
|
+
dependencies: [],
|
|
55
|
+
calculationTime: performance.now() - startTime
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
let result;
|
|
59
|
+
this.crossSheetManager.registerCrossSheetReference(formula, cell), this.formulaEngine.setCellContent(cell, formula),
|
|
60
|
+
result = this.formulaManager ? this.formulaManager.getCellValue(cell) : this.formulaEngine.getCellValue(cell);
|
|
61
|
+
const dependencies = this.formulaEngine.getCellPrecedents(cell), calculationResult = {
|
|
62
|
+
value: result.value,
|
|
63
|
+
error: result.error,
|
|
64
|
+
dependencies: dependencies,
|
|
65
|
+
calculationTime: performance.now() - startTime
|
|
66
|
+
};
|
|
67
|
+
return this.options.enableCaching && this.cacheCalculationResult(cell, calculationResult),
|
|
68
|
+
calculationResult;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return {
|
|
71
|
+
value: null,
|
|
72
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
73
|
+
dependencies: [],
|
|
74
|
+
calculationTime: performance.now() - startTime
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
getCrossSheetValue(cell) {
|
|
80
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
81
|
+
const startTime = performance.now();
|
|
82
|
+
try {
|
|
83
|
+
if (this.options.enableCaching) {
|
|
84
|
+
const cached = this.getCachedResult(cell);
|
|
85
|
+
if (cached) return Object.assign(Object.assign({}, cached), {
|
|
86
|
+
calculationTime: performance.now() - startTime
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (!this.formulaEngine.getCellFormula(cell)) return {
|
|
90
|
+
value: null,
|
|
91
|
+
error: "No formula found",
|
|
92
|
+
dependencies: [],
|
|
93
|
+
calculationTime: performance.now() - startTime
|
|
94
|
+
};
|
|
95
|
+
let result;
|
|
96
|
+
result = this.formulaManager ? this.formulaManager.getCellValue(cell) : this.formulaEngine.getCellValue(cell);
|
|
97
|
+
const dependencies = this.formulaEngine.getCellPrecedents(cell), calculationResult = {
|
|
98
|
+
value: result.value,
|
|
99
|
+
error: result.error,
|
|
100
|
+
dependencies: dependencies,
|
|
101
|
+
calculationTime: performance.now() - startTime
|
|
102
|
+
};
|
|
103
|
+
return this.options.enableCaching && this.cacheCalculationResult(cell, calculationResult),
|
|
104
|
+
calculationResult;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return {
|
|
107
|
+
value: null,
|
|
108
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
109
|
+
dependencies: [],
|
|
110
|
+
calculationTime: performance.now() - startTime
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
updateCrossSheetReferences(targetSheet, changedCells) {
|
|
116
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
117
|
+
yield this.crossSheetManager.updateCrossSheetReferences(targetSheet, changedCells);
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
validateCrossSheetFormula(cell) {
|
|
121
|
+
const formula = this.formulaEngine.getCellFormula(cell);
|
|
122
|
+
if (!formula) return {
|
|
123
|
+
valid: !1,
|
|
124
|
+
errors: [ {
|
|
125
|
+
type: "MISSING_REFERENCE",
|
|
126
|
+
message: "No formula found",
|
|
127
|
+
sheet: cell.sheet,
|
|
128
|
+
cell: cell
|
|
129
|
+
} ],
|
|
130
|
+
warnings: []
|
|
131
|
+
};
|
|
132
|
+
const syntaxValidation = this.validator.validateFormulaSyntax(formula);
|
|
133
|
+
return {
|
|
134
|
+
valid: syntaxValidation.valid,
|
|
135
|
+
errors: syntaxValidation.error ? [ {
|
|
136
|
+
type: "MISSING_REFERENCE",
|
|
137
|
+
message: syntaxValidation.error,
|
|
138
|
+
sheet: cell.sheet,
|
|
139
|
+
cell: cell
|
|
140
|
+
} ] : [],
|
|
141
|
+
warnings: []
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
validateAllCrossSheetFormulas() {
|
|
145
|
+
return this.validator.validateAllSheets();
|
|
146
|
+
}
|
|
147
|
+
getCrossSheetDependencies() {
|
|
148
|
+
return this.dataSynchronizer.getCrossSheetDependencies();
|
|
149
|
+
}
|
|
150
|
+
recalculateAllCrossSheetFormulas() {
|
|
151
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
152
|
+
const allSheets = this.formulaEngine.getAllSheets();
|
|
153
|
+
for (const sheetInfo of allSheets) {
|
|
154
|
+
const formulas = this.formulaEngine.exportFormulas(sheetInfo.key);
|
|
155
|
+
for (const [cellRef, formula] of Object.entries(formulas)) if (this.hasCrossSheetReference(formula)) {
|
|
156
|
+
const cell = this.parseA1Notation(cellRef), cellWithSheet = {
|
|
157
|
+
sheet: sheetInfo.key,
|
|
158
|
+
row: cell.row,
|
|
159
|
+
col: cell.col
|
|
160
|
+
};
|
|
161
|
+
yield this.recalculateFormula(cellWithSheet);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
recalculateFormula(cell) {
|
|
167
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
168
|
+
return yield this.getCrossSheetValue(cell);
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
hasCrossSheetReference(formula) {
|
|
172
|
+
return formula.includes("!");
|
|
173
|
+
}
|
|
174
|
+
cacheCalculationResult(cell, result) {
|
|
175
|
+
const cacheKey = this.getCacheKey(cell);
|
|
176
|
+
this.calculationResults.set(cacheKey, result);
|
|
177
|
+
}
|
|
178
|
+
getCachedResult(cell) {
|
|
179
|
+
const cacheKey = this.getCacheKey(cell);
|
|
180
|
+
return this.calculationResults.get(cacheKey) || null;
|
|
181
|
+
}
|
|
182
|
+
getCacheKey(cell) {
|
|
183
|
+
return `${cell.sheet}!${this.getA1Notation(cell.row, cell.col)}`;
|
|
184
|
+
}
|
|
185
|
+
parseA1Notation(a1Notation) {
|
|
186
|
+
const match = a1Notation.match(/^([A-Z]+)([0-9]+)$/);
|
|
187
|
+
if (!match) throw new Error(`Invalid cell reference: ${a1Notation}`);
|
|
188
|
+
const colLetters = match[1], rowNumber = parseInt(match[2], 10);
|
|
189
|
+
let col = 0;
|
|
190
|
+
for (let i = 0; i < colLetters.length; i++) col = 26 * col + (colLetters.charCodeAt(i) - 65);
|
|
191
|
+
return {
|
|
192
|
+
row: rowNumber - 1,
|
|
193
|
+
col: col
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
getA1Notation(row, col) {
|
|
197
|
+
let colStr = "", tempCol = col;
|
|
198
|
+
do {
|
|
199
|
+
colStr = String.fromCharCode(65 + tempCol % 26) + colStr, tempCol = Math.floor(tempCol / 26) - 1;
|
|
200
|
+
} while (tempCol >= 0);
|
|
201
|
+
return `${colStr}${row + 1}`;
|
|
202
|
+
}
|
|
203
|
+
updateOptions(options) {
|
|
204
|
+
this.options = Object.assign(Object.assign({}, this.options), options), this.dataSynchronizer.updateSyncOptions({
|
|
205
|
+
immediate: this.options.enableCaching,
|
|
206
|
+
timeout: this.options.syncTimeout
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
getHandlerStatus() {
|
|
210
|
+
return {
|
|
211
|
+
isCalculating: this.isCalculating,
|
|
212
|
+
pendingCalculations: this.calculationQueue.length,
|
|
213
|
+
cacheSize: this.calculationResults.size,
|
|
214
|
+
options: Object.assign({}, this.options)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
clearCache() {
|
|
218
|
+
this.calculationResults.clear(), this.crossSheetManager.clearCache(), this.validator.clearCache();
|
|
219
|
+
}
|
|
220
|
+
addDataChangeListener(sheet, listener) {
|
|
221
|
+
this.dataSynchronizer.addDataChangeListener(sheet, listener);
|
|
222
|
+
}
|
|
223
|
+
removeDataChangeListener(sheet, listener) {
|
|
224
|
+
this.dataSynchronizer.removeDataChangeListener(sheet, listener);
|
|
225
|
+
}
|
|
226
|
+
forceSync() {
|
|
227
|
+
return __awaiter(this, void 0, void 0, (function*() {
|
|
228
|
+
yield this.dataSynchronizer.forceSync();
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
destroy() {
|
|
232
|
+
this.clearCache(), this.calculationResults.clear(), this.calculationQueue = [],
|
|
233
|
+
this.crossSheetManager.destroy(), this.dataSynchronizer.destroy(), this.validator.destroy();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=cross-sheet-formula-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/formula/cross-sheet-formula-handler.ts"],"names":[],"mappings":"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","file":"cross-sheet-formula-handler.js","sourcesContent":["/**\n * 跨sheet公式处理器\n * 处理跨sheet公式的计算、更新和同步\n */\n\nimport type { FormulaCell } from '../ts-types/formula';\nimport type { FormulaEngine } from './formula-engine';\nimport { CrossSheetFormulaManager } from './cross-sheet-formula-manager';\nimport { CrossSheetDataSynchronizer } from './cross-sheet-data-synchronizer';\nimport { CrossSheetFormulaValidator, type ValidationResult } from './cross-sheet-formula-validator';\n\nexport interface CrossSheetFormulaOptions {\n enableCaching: boolean;\n enableValidation: boolean;\n syncTimeout: number;\n maxRecursionDepth: number;\n}\n\nexport interface FormulaCalculationResult {\n value: any;\n error?: string;\n dependencies: FormulaCell[];\n calculationTime: number;\n}\n\nexport class CrossSheetFormulaHandler {\n private formulaEngine: FormulaEngine;\n private crossSheetManager: CrossSheetFormulaManager;\n private dataSynchronizer: CrossSheetDataSynchronizer;\n private validator: CrossSheetFormulaValidator;\n private formulaManager?: any; // FormulaManager reference for proper sheet registration\n\n private options: CrossSheetFormulaOptions = {\n enableCaching: true,\n enableValidation: true,\n syncTimeout: 50,\n maxRecursionDepth: 100\n };\n\n // 计算状态\n private isCalculating = false;\n private calculationQueue: FormulaCell[] = [];\n private calculationResults: Map<string, FormulaCalculationResult> = new Map();\n\n constructor(\n formulaEngine: FormulaEngine,\n sheetManager?: { getAllSheets: () => Array<{ sheetKey: string; sheetTitle: string }> },\n formulaManager?: any\n ) {\n this.formulaEngine = formulaEngine;\n this.formulaManager = formulaManager;\n this.crossSheetManager = new CrossSheetFormulaManager(formulaEngine, sheetManager);\n this.dataSynchronizer = new CrossSheetDataSynchronizer(formulaEngine, this.crossSheetManager);\n this.validator = new CrossSheetFormulaValidator(formulaEngine, this.crossSheetManager, sheetManager);\n }\n\n /**\n * 设置跨sheet公式\n */\n async setCrossSheetFormula(cell: FormulaCell, formula: string): Promise<FormulaCalculationResult> {\n const startTime = performance.now();\n\n try {\n // 验证公式(如果启用)\n if (this.options.enableValidation) {\n const validation = this.validator.validateFormulaSyntax(formula);\n if (!validation.valid) {\n return {\n value: null,\n error: validation.error,\n dependencies: [],\n calculationTime: performance.now() - startTime\n };\n }\n }\n\n // 注册跨sheet引用\n this.crossSheetManager.registerCrossSheetReference(formula, cell);\n\n // 设置公式到引擎\n this.formulaEngine.setCellContent(cell, formula);\n\n // 计算结果\n let result: { value: any; error?: string };\n if (this.formulaManager) {\n // 使用FormulaManager获取单元格值(支持未激活的sheet)\n result = this.formulaManager.getCellValue(cell);\n } else {\n // 回退到直接使用FormulaEngine\n result = this.formulaEngine.getCellValue(cell);\n }\n\n // 获取依赖关系\n const dependencies = this.formulaEngine.getCellPrecedents(cell);\n\n const calculationResult: FormulaCalculationResult = {\n value: result.value,\n error: result.error,\n dependencies,\n calculationTime: performance.now() - startTime\n };\n\n // 缓存结果\n if (this.options.enableCaching) {\n this.cacheCalculationResult(cell, calculationResult);\n }\n\n return calculationResult;\n } catch (error) {\n return {\n value: null,\n error: error instanceof Error ? error.message : 'Unknown error',\n dependencies: [],\n calculationTime: performance.now() - startTime\n };\n }\n }\n\n /**\n * 获取跨sheet公式的值\n */\n async getCrossSheetValue(cell: FormulaCell): Promise<FormulaCalculationResult> {\n const startTime = performance.now();\n\n try {\n // 检查缓存\n if (this.options.enableCaching) {\n const cached = this.getCachedResult(cell);\n if (cached) {\n return {\n ...cached,\n calculationTime: performance.now() - startTime\n };\n }\n }\n\n // 获取公式\n const formula = this.formulaEngine.getCellFormula(cell);\n if (!formula) {\n return {\n value: null,\n error: 'No formula found',\n dependencies: [],\n calculationTime: performance.now() - startTime\n };\n }\n\n // 计算结果\n let result: { value: any; error?: string };\n if (this.formulaManager) {\n // 使用FormulaManager获取单元格值(支持未激活的sheet)\n result = this.formulaManager.getCellValue(cell);\n } else {\n // 回退到直接使用FormulaEngine\n result = this.formulaEngine.getCellValue(cell);\n }\n const dependencies = this.formulaEngine.getCellPrecedents(cell);\n\n const calculationResult: FormulaCalculationResult = {\n value: result.value,\n error: result.error,\n dependencies,\n calculationTime: performance.now() - startTime\n };\n\n // 缓存结果\n if (this.options.enableCaching) {\n this.cacheCalculationResult(cell, calculationResult);\n }\n\n return calculationResult;\n } catch (error) {\n return {\n value: null,\n error: error instanceof Error ? error.message : 'Unknown error',\n dependencies: [],\n calculationTime: performance.now() - startTime\n };\n }\n }\n\n /**\n * 更新跨sheet引用\n */\n async updateCrossSheetReferences(targetSheet: string, changedCells: FormulaCell[]): Promise<void> {\n await this.crossSheetManager.updateCrossSheetReferences(targetSheet, changedCells);\n }\n\n /**\n * 验证跨sheet公式\n */\n validateCrossSheetFormula(cell: FormulaCell): ValidationResult {\n const formula = this.formulaEngine.getCellFormula(cell);\n if (!formula) {\n return {\n valid: false,\n errors: [\n {\n type: 'MISSING_REFERENCE',\n message: 'No formula found',\n sheet: cell.sheet,\n cell\n }\n ],\n warnings: []\n };\n }\n\n const syntaxValidation = this.validator.validateFormulaSyntax(formula);\n return {\n valid: syntaxValidation.valid,\n errors: syntaxValidation.error\n ? [\n {\n type: 'MISSING_REFERENCE',\n message: syntaxValidation.error,\n sheet: cell.sheet,\n cell\n }\n ]\n : [],\n warnings: []\n };\n }\n\n /**\n * 验证所有跨sheet公式\n */\n validateAllCrossSheetFormulas(): Map<string, ValidationResult> {\n return this.validator.validateAllSheets();\n }\n\n /**\n * 获取跨sheet依赖关系\n */\n getCrossSheetDependencies(): Map<string, string[]> {\n return this.dataSynchronizer.getCrossSheetDependencies();\n }\n\n /**\n * 强制重新计算所有跨sheet公式\n */\n async recalculateAllCrossSheetFormulas(): Promise<void> {\n const allSheets = this.formulaEngine.getAllSheets();\n\n for (const sheetInfo of allSheets) {\n const formulas = this.formulaEngine.exportFormulas(sheetInfo.key);\n\n for (const [cellRef, formula] of Object.entries(formulas)) {\n if (this.hasCrossSheetReference(formula)) {\n const cell = this.parseA1Notation(cellRef);\n const cellWithSheet: FormulaCell = { sheet: sheetInfo.key, row: cell.row, col: cell.col };\n\n await this.recalculateFormula(cellWithSheet);\n }\n }\n }\n }\n\n /**\n * 重新计算公式\n */\n async recalculateFormula(cell: FormulaCell): Promise<FormulaCalculationResult> {\n return await this.getCrossSheetValue(cell);\n }\n\n /**\n * 检查公式是否包含跨sheet引用\n */\n private hasCrossSheetReference(formula: string): boolean {\n return formula.includes('!');\n }\n\n /**\n * 缓存计算结果\n */\n private cacheCalculationResult(cell: FormulaCell, result: FormulaCalculationResult): void {\n const cacheKey = this.getCacheKey(cell);\n this.calculationResults.set(cacheKey, result);\n }\n\n /**\n * 获取缓存的计算结果\n */\n private getCachedResult(cell: FormulaCell): FormulaCalculationResult | null {\n const cacheKey = this.getCacheKey(cell);\n return this.calculationResults.get(cacheKey) || null;\n }\n\n /**\n * 获取缓存键\n */\n private getCacheKey(cell: FormulaCell): string {\n return `${cell.sheet}!${this.getA1Notation(cell.row, cell.col)}`;\n }\n\n /**\n * A1表示法解析\n */\n private parseA1Notation(a1Notation: string): { row: number; col: number } {\n const match = a1Notation.match(/^([A-Z]+)([0-9]+)$/);\n if (!match) {\n throw new Error(`Invalid cell reference: ${a1Notation}`);\n }\n\n const colLetters = match[1];\n const rowNumber = parseInt(match[2], 10);\n\n let col = 0;\n for (let i = 0; i < colLetters.length; i++) {\n col = col * 26 + (colLetters.charCodeAt(i) - 65);\n }\n\n return { row: rowNumber - 1, col };\n }\n\n /**\n * A1表示法生成\n */\n private getA1Notation(row: number, col: number): string {\n let colStr = '';\n let tempCol = col;\n\n do {\n colStr = String.fromCharCode(65 + (tempCol % 26)) + colStr;\n tempCol = Math.floor(tempCol / 26) - 1;\n } while (tempCol >= 0);\n\n return `${colStr}${row + 1}`;\n }\n\n /**\n * 更新处理选项\n */\n updateOptions(options: Partial<CrossSheetFormulaOptions>): void {\n this.options = { ...this.options, ...options };\n\n // 更新依赖组件的选项\n this.dataSynchronizer.updateSyncOptions({\n immediate: this.options.enableCaching,\n timeout: this.options.syncTimeout\n });\n }\n\n /**\n * 获取处理状态\n */\n getHandlerStatus(): {\n isCalculating: boolean;\n pendingCalculations: number;\n cacheSize: number;\n options: CrossSheetFormulaOptions;\n } {\n return {\n isCalculating: this.isCalculating,\n pendingCalculations: this.calculationQueue.length,\n cacheSize: this.calculationResults.size,\n options: { ...this.options }\n };\n }\n\n /**\n * 清除缓存\n */\n clearCache(): void {\n this.calculationResults.clear();\n this.crossSheetManager.clearCache();\n this.validator.clearCache();\n }\n\n /**\n * 添加数据变更监听器\n */\n addDataChangeListener(sheet: string, listener: (event: any) => void): void {\n this.dataSynchronizer.addDataChangeListener(sheet, listener);\n }\n\n /**\n * 移除数据变更监听器\n */\n removeDataChangeListener(sheet: string, listener: (event: any) => void): void {\n this.dataSynchronizer.removeDataChangeListener(sheet, listener);\n }\n\n /**\n * 强制同步\n */\n async forceSync(): Promise<void> {\n await this.dataSynchronizer.forceSync();\n }\n\n /**\n * 销毁处理器\n */\n destroy(): void {\n this.clearCache();\n this.calculationResults.clear();\n this.calculationQueue = [];\n this.crossSheetManager.destroy();\n this.dataSynchronizer.destroy();\n this.validator.destroy();\n }\n}\n"]}
|