diff --git a/common/changes/feat-support_cell_values_change-1767100301.json b/common/changes/feat-support_cell_values_change-1767100301.json new file mode 100644 index 000000000..b1edd14fa --- /dev/null +++ b/common/changes/feat-support_cell_values_change-1767100301.json @@ -0,0 +1,12 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "support cell values change event and improve delete/update records handling", + "type": "patch" + } + ], + "packageName": "@visactor/vtable", + "email": "", + "commit": "f14b40ee1" +} \ No newline at end of file diff --git a/packages/vtable/examples/editor/custom-date-editor.ts b/packages/vtable/examples/editor/custom-date-editor.ts index ba3d302d6..1f3e338db 100644 --- a/packages/vtable/examples/editor/custom-date-editor.ts +++ b/packages/vtable/examples/editor/custom-date-editor.ts @@ -381,6 +381,12 @@ export function createTable() { tableInstance.on('change_cell_value', arg => { console.log(arg); }); + tableInstance.on('change_cell_values', arg => { + console.log(arg); + }); + tableInstance.on('delete_record', arg => { + console.log(arg); + }); window.tableInstance = tableInstance; tableInstance.on('dropdown_menu_click', args => { console.log('dropdown_menu_click', args); diff --git a/packages/vtable/src/ListTable.ts b/packages/vtable/src/ListTable.ts index ec3816e2d..0fa8bdfcb 100644 --- a/packages/vtable/src/ListTable.ts +++ b/packages/vtable/src/ListTable.ts @@ -49,6 +49,7 @@ import { listTableAddRecords, listTableChangeCellValue, listTableChangeCellValues, + listTableChangeCellValuesByIds, listTableDeleteRecords, listTableUpdateRecords, sortRecords @@ -1594,9 +1595,18 @@ export class ListTable extends BaseTable implements ListTableAPI { row: number, value: string | number | null, workOnEditableCell = false, - triggerEvent = true + triggerEvent = true, + silentChangeCellValuesEvent?: boolean ) { - return listTableChangeCellValue(col, row, value, workOnEditableCell, triggerEvent, this); + return listTableChangeCellValue( + col, + row, + value, + workOnEditableCell, + triggerEvent, + this, + silentChangeCellValuesEvent + ); } /** * 批量更新多个单元格的数据 @@ -1611,9 +1621,31 @@ export class ListTable extends BaseTable implements ListTableAPI { startRow: number, values: (string | number)[][], workOnEditableCell = false, - triggerEvent = true + triggerEvent = true, + silentChangeCellValuesEvent?: boolean + ) { + return listTableChangeCellValues( + startCol, + startRow, + values, + workOnEditableCell, + triggerEvent, + this, + silentChangeCellValuesEvent + ); + } + + changeCellValuesByIds( + changeValues: { + col: number; + row: number; + value: string | number | null; + }[], + triggerEvent = true, + silentChangeCellValuesEvent?: boolean ) { - return listTableChangeCellValues(startCol, startRow, values, workOnEditableCell, triggerEvent, this); + // @ts-ignore + return listTableChangeCellValuesByIds(changeValues, triggerEvent, this, silentChangeCellValuesEvent); } /** * 添加数据 单条数据 @@ -1666,6 +1698,22 @@ export class ListTable extends BaseTable implements ListTableAPI { * @param recordIndexs 要删除数据的索引(显示在body中的索引,即要修改的是body部分的第几行数据) */ deleteRecords(recordIndexs: number[] | number[][]) { + const deletedRecords: any[] = []; + // 收集被删除的记录 + if (recordIndexs?.length > 0) { + recordIndexs.forEach(index => { + let record = null; + if (typeof index === 'number') { + record = this.dataSource.get(index); + } else { + // 目前无法正确处理嵌套情况 + record = []; + } + + deletedRecords.push(record); + }); + } + listTableDeleteRecords(recordIndexs, this); adjustHeightResizedRowMapWithDeleteRecordIndex(this as ListTable, recordIndexs as number[]); this.internalProps.emptyTip?.resetVisible(); @@ -1676,6 +1724,7 @@ export class ListTable extends BaseTable implements ListTableAPI { // 触发删除数据记录事件 - 假设操作成功 this.fireListeners(TABLE_EVENT_TYPE.DELETE_RECORD, { recordIndexs, + records: deletedRecords, rowIndexs, deletedCount: Array.isArray(recordIndexs[0]) ? (recordIndexs as number[][]).length diff --git a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts index b105d7b82..89499ab63 100644 --- a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts +++ b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts @@ -190,6 +190,8 @@ export interface TableEvents { /** 编辑单元格 */ CHANGE_CELL_VALUE: 'change_cell_value'; + /** 批量编辑单元格 */ + CHANGE_CELL_VALUES: 'change_cell_values'; /** * 鼠标按下填充柄事件 @@ -330,6 +332,7 @@ export const TABLE_EVENT_TYPE: TableEvents = { AFTER_UPDATE_CELL_CONTENT_WIDTH: 'after_update_cell_content_width', AFTER_UPDATE_SELECT_BORDER_HEIGHT: 'after_update_select_border_height', CHANGE_CELL_VALUE: 'change_cell_value', + CHANGE_CELL_VALUES: 'change_cell_values', DRAG_FILL_HANDLE_END: 'drag_fill_handle_end', MOUSEDOWN_FILL_HANDLE: 'mousedown_fill_handle', DBLCLICK_FILL_HANDLE: 'dblclick_fill_handle', diff --git a/packages/vtable/src/core/index.ts b/packages/vtable/src/core/index.ts new file mode 100644 index 000000000..223cf51ae --- /dev/null +++ b/packages/vtable/src/core/index.ts @@ -0,0 +1,6 @@ +export { + listTableChangeCellValue, + listTableChangeCellValues, + listTableChangeCellValuesByIds, + listTableDeleteRecords +} from './record-helper'; diff --git a/packages/vtable/src/core/record-helper.ts b/packages/vtable/src/core/record-helper.ts index 763ea99eb..14a50860e 100644 --- a/packages/vtable/src/core/record-helper.ts +++ b/packages/vtable/src/core/record-helper.ts @@ -23,7 +23,8 @@ export function listTableChangeCellValue( value: string | number | null, workOnEditableCell: boolean, triggerEvent: boolean, - table: ListTable + table: ListTable, + silentChangeCellValuesEvent?: boolean ) { if ((workOnEditableCell && table.isHasEditorDefine(col, row)) || workOnEditableCell === false) { const recordIndex = table.getRecordShowIndexByCell(col, row); @@ -95,13 +96,17 @@ export function listTableChangeCellValue( } const changedValue = table.getCellOriginValue(col, row); if (oldValue !== changedValue && triggerEvent) { - table.fireListeners(TABLE_EVENT_TYPE.CHANGE_CELL_VALUE, { + const changeValue = { col, row, rawValue: beforeChangeValue, currentValue: oldValue, changedValue - }); + }; + table.fireListeners(TABLE_EVENT_TYPE.CHANGE_CELL_VALUE, changeValue); + if (!silentChangeCellValuesEvent) { + table.fireListeners(TABLE_EVENT_TYPE.CHANGE_CELL_VALUES, { values: [changeValue] }); + } } table.scenegraph.updateNextFrame(); } @@ -120,7 +125,8 @@ export async function listTableChangeCellValues( values: (string | number)[][], workOnEditableCell: boolean, triggerEvent: boolean, - table: ListTable + table: ListTable, + silentChangeCellValuesEvent?: boolean ): Promise { const changedCellResults: boolean[][] = []; let pasteColEnd = startCol; @@ -151,6 +157,15 @@ export async function listTableChangeCellValues( oldRowValues.push(oldValue); } } + + const resultChangeValues: { + col: number; + row: number; + rawValue: string | number; + currentValue: string | number; + changedValue: string | number; + }[] = []; + //#endregion for (let i = 0; i < values.length; i++) { if (startRow + i > table.rowCount - 1) { @@ -204,13 +219,15 @@ export async function listTableChangeCellValues( } const changedValue = table.getCellOriginValue(startCol + j, startRow + i); if (oldValue !== changedValue && triggerEvent) { - table.fireListeners(TABLE_EVENT_TYPE.CHANGE_CELL_VALUE, { + const changeValue = { col: startCol + j, row: startRow + i, rawValue: beforeChangeValue, currentValue: oldValue, changedValue - }); + }; + table.fireListeners(TABLE_EVENT_TYPE.CHANGE_CELL_VALUE, changeValue); + resultChangeValues.push(changeValue); } } else { changedCellResults[i][j] = false; @@ -218,6 +235,9 @@ export async function listTableChangeCellValues( } pasteColEnd = Math.max(pasteColEnd, thisRowPasteColEnd); } + if (!silentChangeCellValuesEvent) { + table.fireListeners(TABLE_EVENT_TYPE.CHANGE_CELL_VALUES, { values: resultChangeValues }); + } // const cell_value = table.getCellValue(col, row); const startRange = table.getCellRange(startCol, startRow); @@ -314,6 +334,42 @@ export async function listTableChangeCellValues( return changedCellResults; } +export async function listTableChangeCellValuesByIds( + changeValues: { + col: number; + row: number; + value: string | number | null; + }[], + triggerEvent: boolean, + table: ListTable, + silentChangeCellValuesEvent?: boolean +) { + const resultChangeValues: { + col: number; + row: number; + rawValue: string | number; + currentValue: string | number; + changedValue: string | number; + }[] = []; + for (let i = 0; i < changeValues.length; i++) { + const { col, row, value } = changeValues[i]; + const oldValue = table.getCellOriginValue(col, row); + listTableChangeCellValue(col, row, value, false, triggerEvent, table, true); + if (oldValue !== value && triggerEvent) { + resultChangeValues.push({ + col, + row, + rawValue: oldValue, // Assuming origin value as raw value for simplicity in this discrete update, or fetch raw if needed + currentValue: oldValue, + changedValue: value as string | number + }); + } + } + if (!silentChangeCellValuesEvent) { + table.fireListeners(TABLE_EVENT_TYPE.CHANGE_CELL_VALUES, { values: resultChangeValues }); + } +} + type CellUpdateType = 'normal' | 'sort' | 'group'; function getCellUpdateType( col: number, diff --git a/packages/vtable/src/event/event.ts b/packages/vtable/src/event/event.ts index 13126cca1..252e49f5c 100644 --- a/packages/vtable/src/event/event.ts +++ b/packages/vtable/src/event/event.ts @@ -284,7 +284,7 @@ export class EventManager { eventArgs.event.shiftKey && shiftMultiSelect, (eventArgs.event.ctrlKey || eventArgs.event.metaKey) && ctrlMultiSelect, false, - isSelectMoving ? false : (this.table.options.select?.makeSelectCellVisible ?? true) + isSelectMoving ? false : this.table.options.select?.makeSelectCellVisible ?? true ); return true; @@ -1122,13 +1122,23 @@ export class EventManager { return; } + const changeValues: { + col: number; + row: number; + value: string | number | null; + }[] = []; for (let i = 0; i < selectCells.length; i++) { for (let j = 0; j < selectCells[i].length; j++) { if (selectCells[i][j]) { - table.changeCellValue(selectCells[i][j].col, selectCells[i][j].row, undefined); + changeValues.push({ + col: selectCells[i][j].col, + row: selectCells[i][j].row, + value: undefined + }); } } } + table.changeCellValuesByIds(changeValues); } catch (error) { console.error('清空单元格内容失败', error); } diff --git a/packages/vtable/src/ts-types/events.ts b/packages/vtable/src/ts-types/events.ts index eca14ff89..e13634f53 100644 --- a/packages/vtable/src/ts-types/events.ts +++ b/packages/vtable/src/ts-types/events.ts @@ -284,6 +284,15 @@ export interface TableEventHandlersEventArgumentMap { currentValue: string | number; changedValue: string | number; }; + change_cell_values: { + values: { + col: number; + row: number; + rawValue: string | number; + currentValue: string | number; + changedValue: string | number; + }[]; + }; mousedown_fill_handle: {}; drag_fill_handle_end: { direction?: 'top' | 'bottom' | 'left' | 'right' }; @@ -318,6 +327,7 @@ export interface TableEventHandlersEventArgumentMap { delete_record: { recordIndexs: number[] | number[][]; + records: any[]; rowIndexs: number[]; deletedCount: number; }; @@ -426,6 +436,7 @@ export interface TableEventHandlersReturnMap { after_update_select_border_height: void; change_cell_value: void; + change_cell_values: void; mousedown_fill_handle: void; drag_fill_handle_end: void; dblclick_fill_handle: void; diff --git a/packages/vtable/src/ts-types/table-engine.ts b/packages/vtable/src/ts-types/table-engine.ts index 74ddfa13f..b9c44b66c 100644 --- a/packages/vtable/src/ts-types/table-engine.ts +++ b/packages/vtable/src/ts-types/table-engine.ts @@ -359,7 +359,27 @@ export interface ListTableAPI extends BaseTableAPI { isListTable: () => true; isPivotTable: () => false; /** 设置单元格的value值,注意对应的是源数据的原始值,vtable实例records会做对应修改 */ - changeCellValue: (col: number, row: number, value: string | number | null, workOnEditableCell?: boolean) => void; + changeCellValue: ( + col: number, + row: number, + value: string | number | null, + workOnEditableCell?: boolean, + triggerEvent?: boolean, + silentChangeCellValuesEvent?: boolean + ) => void; + /** + * 批量更新多个单元格的数据(根据col, row坐标, 支持离散数据) + * @param changeValues + */ + changeCellValuesByIds: ( + changeValues: { + col: number; + row: number; + value: string | number | null; + }[], + triggerEvent?: boolean, + silentChangeCellValuesEvent?: boolean + ) => void; /** * 批量更新多个单元格的数据 * @param col 粘贴数据的起始列号 @@ -371,7 +391,9 @@ export interface ListTableAPI extends BaseTableAPI { col: number, row: number, values: (string | number)[][], - workOnEditableCell?: boolean + workOnEditableCell?: boolean, + triggerEvent?: boolean, + silentChangeCellValuesEvent?: boolean ) => Promise | boolean[][]; getFieldData: (field: FieldDef | FieldFormat | undefined, col: number, row: number) => FieldData; //#region 编辑器相关demo