Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions packages/vtable-sheet/__tests__/multi-header-record-data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,49 @@ test('VTableSheet keeps record fields when top-level columns mix leaf and groupe
removeDom(container);
}
});

test('VTableSheet normalizes object record data with nested field paths for formulas', () => {
const container = createDiv() as HTMLDivElement;
container.style.position = 'relative';
container.style.width = '1000px';
container.style.height = '800px';

const sheet = new VTableSheet(container, {
showFormulaBar: false,
showSheetTab: false,
defaultRowHeight: 25,
defaultColWidth: 100,
sheets: [
{
sheetKey: 'nestedFieldSheet',
sheetTitle: '嵌套字段示例',
active: true,
columns: [
{ title: '名称', field: 'name', width: 120 },
{ title: '营业额', field: ['sales', 'amount'], width: 120 }
],
data: [
{
name: '商品A',
sales: {
amount: '125'
}
}
]
}
]
});

try {
const value = sheet.formulaManager.formulaEngine.getCellValue({
sheet: 'nestedFieldSheet',
row: 1,
col: 1
});

expect(value).toEqual({ value: 125, error: undefined });
} finally {
sheet.release();
removeDom(container);
}
});
4 changes: 4 additions & 0 deletions packages/vtable-sheet/examples/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ export const menus = [
{
path: 'sheet',
name: 'history'
},
{
path: 'sheet',
name: 'issue-5204-formula-manager'
}
];
66 changes: 66 additions & 0 deletions packages/vtable-sheet/examples/sheet/issue-5204-formula-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { VTableSheet } from '../../src/index';
import type { IColumnDefine, SheetData } from '../../src/ts-types';

const CONTAINER_ID = 'vTable';

const columns: IColumnDefine[] = [
{ title: '测试公式计算', field: 'test', width: 120 },
{
title: 'B商品营业额',
field: ['sales', 'Bmoney'],
width: 120
},
{
title: 'A商品营业额',
field: 'Amoney',
width: 120
}
];

const dataA: SheetData = Array.from({ length: 12 }, (_, index) => ({
test: `${index}-row`,
sales: {
Bmoney: `${(index + 1) * 50}`
},
Amoney: `${(index + 2) * 50}`
}));

const columnsB = [
{ title: '测试公式计算', width: 120 },
{
title: 'B商品营业额',
width: 120
},
{
title: 'A商品营业额',
width: 120
}
];

const dataB = [['1', 2, 3]];

export function createTable() {
const container = document.getElementById(CONTAINER_ID)!;
window.sheetInstance = new VTableSheet(container, {
showFormulaBar: false,
showSheetTab: true,
defaultRowHeight: 32,
defaultColWidth: 120,
sheets: [
{
sheetKey: 'Issue-5204-a',
sheetTitle: 'data是Array<Object>',
columns,
data: dataA,
active: true
},
{
sheetKey: 'Issue-5204-b',
sheetTitle: 'data是Array<Array<any>>',
columns: columnsB,
data: dataB,
active: true
}
]
});
}
7 changes: 4 additions & 3 deletions packages/vtable-sheet/src/components/vtable-sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import type {
IVTableSheetUpdateOptions,
ISheetDefine,
IWorkSheetOptions,
IColumnDefine
IColumnDefine,
SheetData
} from '../ts-types';
import type { MultiSheetImportResult } from '@visactor/vtable-plugins/src/excel-import/types';
import type { TableEventHandlersEventArgumentMap } from '@visactor/vtable/es/ts-types/events';
Expand Down Expand Up @@ -1356,7 +1357,7 @@ export default class VTableSheet {
* @param sheetKey sheet的key
* @returns 数据
*/
exportData(sheetKey: string): any[][] {
exportData(sheetKey: string): SheetData {
const sheet = this.workSheetInstances.get(sheetKey);
if (!sheet) {
return [];
Expand All @@ -1368,7 +1369,7 @@ export default class VTableSheet {
* 导出所有sheet的数据
* @returns 数据
*/
exportAllData(): any[][] {
exportAllData(): SheetData[] {
const sheets = Array.from(this.workSheetInstances.values());
return sheets.map(sheet => sheet.getData());
}
Expand Down
18 changes: 9 additions & 9 deletions packages/vtable-sheet/src/core/WorkSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type {
IThemeDefine,
IFilterConfig,
IFilterState,
ISheetDefine,
SheetData,
IVTableSheetUpdateOptions
} from '../ts-types';
import type { TYPES, VTableSheet } from '..';
Expand All @@ -27,7 +27,7 @@ import type { IWorksheetEventSource } from '../event/event-interfaces';
*/
export type WorkSheetConstructorOptions = {
/** 表格数据 */
data?: any[][];
data?: SheetData;
/** 公式计算选项 */
formula?: IFormulaManagerOptions;
/** Sheet 唯一标识 */
Expand Down Expand Up @@ -782,7 +782,7 @@ export class WorkSheet implements IWorkSheetAPI, IWorksheetEventSource {
/**
* 获取表格数据
*/
getData(): any[][] {
getData(): SheetData {
// 从表格实例获取数据
return this.options.data || [];
}
Expand All @@ -806,9 +806,9 @@ export class WorkSheet implements IWorkSheetAPI, IWorksheetEventSource {
}
}

const data = this.getData();
if (data && data[row] && data[row][col] !== undefined) {
return data[row][col];
const rowData = this.getData()[row];
if (Array.isArray(rowData) && rowData[col] !== undefined) {
return rowData[col];
}
return null;
}
Expand Down Expand Up @@ -848,9 +848,9 @@ export class WorkSheet implements IWorkSheetAPI, IWorksheetEventSource {
* @param value 新值
*/
setCellValue(col: number, row: number, value: any): void {
const data = this.getData();
if (data && data[row]) {
data[row][col] = value;
const rowData = this.getData()[row];
if (Array.isArray(rowData)) {
rowData[col] = value;

// 更新表格实例
if (this.tableInstance) {
Expand Down
27 changes: 23 additions & 4 deletions packages/vtable-sheet/src/managers/formula-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FormulaEngine } from '../formula/formula-engine';
import type VTableSheet from '../components/vtable-sheet';
import type { FormulaCell, FormulaResult, IFormulaManager } from '../ts-types/formula';
import { FormulaRangeSelector } from '../formula/formula-range-selector';
import type { CellRange, ISheetDefine } from '../ts-types';
import type { CellRange, ISheetDefine, SheetData } from '../ts-types';
import { CellHighlightManager } from '../formula';
import type * as VTable from '@visactor/vtable';
import { CrossSheetFormulaHandler } from '../formula/cross-sheet-formula-handler';
Expand Down Expand Up @@ -137,19 +137,39 @@ export class FormulaManager implements IFormulaManager {
* @param data 工作表数据
* @returns 标准化后的工作表数据
*/
normalizeSheetData(data: unknown[][], tableInstance: VTable.ListTable): unknown[][] {
normalizeSheetData(data: SheetData, tableInstance: VTable.ListTable): unknown[][] {
try {
//将columns中的title追加到data中
const headerRows: unknown[][] = [];
const headerKeyColMap = new Map();
for (let i = 0; i < tableInstance.columnHeaderLevelCount; i++) {
const headerRow: unknown[] = [];
for (let j = 0; j < tableInstance.colCount; j++) {
const cellValue = tableInstance.getCellValue(j, i);
const filedDefine = tableInstance.getHeaderDefine(j, i);
if (cellValue === filedDefine.title) {
headerKeyColMap.set(j, filedDefine.field);
}
headerRow.push(cellValue);
}
headerRows.push(headerRow);
}
const dataCopy = JSON.parse(JSON.stringify(data));
const colCount = tableInstance.colCount;
let dataCopy: unknown[][];
const firstRow = data[0];
if (firstRow && typeof firstRow === 'object' && !Array.isArray(firstRow)) {
dataCopy = data.map((_, rowIndex) => {
const bodyRow = tableInstance.columnHeaderLevelCount + rowIndex;
const rowTemp = new Array<unknown>(colCount);
for (let col = 0; col < colCount; col++) {
const field = tableInstance.getBodyField(col, bodyRow) ?? headerKeyColMap.get(col);
rowTemp[col] = field !== undefined ? tableInstance.getRawFieldData(field, col, bodyRow) ?? null : null;
}
return rowTemp;
});
} else {
dataCopy = JSON.parse(JSON.stringify(data));
}

const toNormalizeData = tableInstance.columnHeaderLevelCount > 0 ? [...headerRows].concat(dataCopy) : dataCopy;

Expand Down Expand Up @@ -1372,7 +1392,6 @@ export class FormulaManager implements IFormulaManager {
// 如果还没有对应的 WorkSheet 实例,跳过,后续按需再补充
return;
}

const normalizedData = this.normalizeSheetData(worksheetInstance.getData(), worksheetInstance.tableInstance);
this.addSheet(sheetKey, normalizedData, sheetDefine.sheetTitle);
});
Expand Down
6 changes: 4 additions & 2 deletions packages/vtable-sheet/src/ts-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ export interface IFilterConfig {
/** 扩展的列定义,添加筛选相关配置;field 可选,构建 ListTable 时由 WorkSheet 按列索引填充 */
export interface IColumnDefine extends Omit<ColumnDefine, 'field'> {
/** 列字段,可选;未指定时由 WorkSheet 按列索引填充 */
field?: string | number;
field?: ColumnDefine['field'];
/** 是否启用筛选功能 */
filter?: boolean;
}

export type SheetData = (CellValue[] | null)[] | Record<string, unknown>[];

/** Sheet定义 */
export interface ISheetDefine {
/** 标题 */
Expand All @@ -32,7 +34,7 @@ export interface ISheetDefine {
/** 表头定义 */
columns?: IColumnDefine[];
/** 数据 */
data?: (CellValue[] | null)[];
data?: SheetData;
/** 是否是当前活动sheet TODO 是不是放到外层更好*/
active?: boolean;
cellMerge?: VTableTypes.CustomMergeCellArray;
Expand Down
6 changes: 3 additions & 3 deletions packages/vtable-sheet/src/ts-types/sheet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IColumnDefine, IFilterConfig, IFilterState, ISheetDefine } from './index';
import type { IColumnDefine, IFilterConfig, IFilterState, ISheetDefine, SheetData } from './index';
import type { CellCoord, CellRange, CellValue } from './base';
import type { ListTableConstructorOptions } from '@visactor/vtable';

Expand All @@ -13,7 +13,7 @@ export interface IWorkSheetOptions extends Omit<ListTableConstructorOptions, 're
width?: number;
height?: number;
/** 数据 */
data?: any[][];
data?: SheetData;
/** 是否显示表头 */
showHeader?: boolean;
/** 是否将data中第一行作为表头。如果设置为true,则获取到的getData()将不包含data中的第一行 */
Expand Down Expand Up @@ -50,7 +50,7 @@ export interface IWorkSheetAPI {
getSelection: () => CellRange | null;

/** 获取数据 */
getData: () => CellValue[][];
getData: () => SheetData;

/** 获取行数 */
getRowCount: () => number;
Expand Down
Loading