UNPKG

e-virt-table

Version:

A powerful data table based on canvas. You can use it as data grid、Microsoft Excel or Google sheets. It supports virtual scroll、cell edit etc.

1,240 lines 40.2 kB
import Schema from 'async-validator'; import { generateShortUUID } from './util'; import Cell from './Cell'; export default class Database { constructor(ctx, options) { Object.defineProperty(this, "loading", { enumerable: true, configurable: true, writable: true, value: false }); Object.defineProperty(this, "ctx", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "data", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "columns", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "footerData", { enumerable: true, configurable: true, writable: true, value: [] }); Object.defineProperty(this, "rowKeyMap", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "colIndexKeyMap", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "headerMap", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "rowIndexRowKeyMap", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "checkboxKeyMap", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "originalDataMap", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "changedDataMap", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "validationErrorMap", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "itemRowKeyMap", { enumerable: true, configurable: true, writable: true, value: new WeakMap() }); Object.defineProperty(this, "bufferData", { enumerable: true, configurable: true, writable: true, value: [] }); Object.defineProperty(this, "sumHeight", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "filterMethod", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "positions", { enumerable: true, configurable: true, writable: true, value: [] }); //虚拟滚动位置 this.ctx = ctx; const { data = [], columns = [], footerData = [] } = options; this.data = data; this.footerData = footerData; this.columns = columns; this.setLoading(true); this.init(); } init() { this.clearBufferData(); this.rowKeyMap.clear(); this.checkboxKeyMap.clear(); this.colIndexKeyMap.clear(); this.rowIndexRowKeyMap.clear(); this.originalDataMap.clear(); this.changedDataMap.clear(); this.validationErrorMap.clear(); this.itemRowKeyMap = new WeakMap(); this.initData(this.data); } /** * 清除缓存数据 */ clearBufferData() { this.bufferData = []; } /** * 初始化数据 * @param dataList * @param level */ initData(dataList, level = 0) { dataList.forEach((item, index) => { let hasChildren = item._hasChildren || false; if (Array.isArray(item.children) && item.children.length) { hasChildren = true; this.initData(item.children, level + 1); } const { ROW_KEY = '', DEFAULT_EXPAND_ALL, CELL_HEIGHT, SELECTABLE_METHOD, CHECKBOX_KEY } = this.ctx.config; const _rowKey = item[ROW_KEY]; // 行唯一标识,否则就rowKey const rowKey = _rowKey !== undefined && _rowKey !== null ? `${_rowKey}` : generateShortUUID(); this.itemRowKeyMap.set(item, rowKey); const height = item._height || CELL_HEIGHT; const readonly = item._readonly; let selectable = true; if (typeof SELECTABLE_METHOD === 'function') { const selectableMethod = SELECTABLE_METHOD; selectable = selectableMethod; } // 存储checkboxKey,处理合并单元格选中 if (CHECKBOX_KEY) { const checkboxKey = item[CHECKBOX_KEY]; if (this.checkboxKeyMap.has(checkboxKey)) { const checkboxKeys = this.checkboxKeyMap.get(checkboxKey) || []; checkboxKeys.push(rowKey); this.checkboxKeyMap.set(checkboxKey, checkboxKeys); } else { this.checkboxKeyMap.set(checkboxKey, [rowKey]); } } this.rowKeyMap.set(rowKey, { readonly, index, rowIndex: index, level, height, check: false, selectable, expand: DEFAULT_EXPAND_ALL, expandLazy: false, hasChildren, expandLoading: false, item, }); }); } /** * * @param rowKey 设置Row高度 * @param height */ setRowHeight(rowIndex, height) { const rowKey = this.rowIndexRowKeyMap.get(rowIndex); if (rowKey === undefined) { return; } const row = this.rowKeyMap.get(rowKey); row.height = height; row.item._height = height; this.clearBufferData(); // 清除缓存数据 } /** * * @returns 获取转化平铺数据 */ getAllRowsData() { let list = []; const recursiveData = (data) => { data.forEach((item) => { list.push(item); if (Array.isArray(item.children)) { recursiveData(item.children); } }); }; recursiveData(this.data); return list; } filterColumns(columns) { return columns.reduce((acc, column) => { // 检查当前列的 hide 属性 const shouldHide = typeof column.hide === 'function' ? column.hide() : column.hide; // 如果当前列不应该隐藏,则添加到结果中 if (!shouldHide) { const newColumn = { ...column }; // 复制当前列 // 递归处理子列 if (newColumn.children && Array.isArray(newColumn.children)) { newColumn.children = this.filterColumns(newColumn.children); } acc.push(newColumn); } return acc; }, []); } getColumns() { return this.filterColumns(this.columns); } setColumns(columns) { this.columns = columns; this.clearBufferData(); } setData(data) { this.data = data; if (this.columns.length) { this.init(); } } /** * 统一转化数据,给画body使用,包括过滤树状等,统一入口 * @returns */ getData() { if (this.bufferData.length > 0) { return { data: this.bufferData, sumHeight: this.sumHeight, positions: this.positions, }; } let list = []; let rowIndex = 0; this.sumHeight = 0; this.positions = []; const recursiveData = (data) => { data.forEach((item) => { list.push(item); const rowKey = this.itemRowKeyMap.get(item); const { expand, hasChildren, height } = this.rowKeyMap.get(rowKey); const top = this.sumHeight; this.sumHeight += height; this.rowIndexRowKeyMap.set(rowIndex, rowKey); this.positions.push({ top, height, bottom: this.sumHeight, }); rowIndex += 1; if (expand && hasChildren) { recursiveData(item.children); } }); }; this.rowIndexRowKeyMap.clear(); let _data = this.data; if (typeof this.filterMethod === 'function') { _data = this.filterMethod(_data); } recursiveData(_data); this.bufferData = list; return { data: list, sumHeight: this.sumHeight, positions: this.positions, }; } setFooterData(data) { this.footerData = data; } getFooterData() { return this.footerData; } /** * 设置过滤方法 */ setFilterMethod(filterMethod) { this.filterMethod = filterMethod; } /** * 清空过滤方法 */ clearFilterMethod() { this.filterMethod = undefined; } /** * 根据rowKey,控制指定展开行 * @param rowKey * @param expand */ expandItem(rowKey, expand = false) { const row = this.rowKeyMap.get(rowKey); row.expand = expand; this.clearBufferData(); // 清除缓存数据 this.ctx.emit('draw'); } setExpandRowKeys(rowKeys, expand = true) { rowKeys.forEach((rowkey) => { const row = this.rowKeyMap.get(rowkey); row.expand = expand; }); this.clearBufferData(); // 清除缓存数据 this.ctx.emit('draw'); } getExpandRowKeys() { let list = []; this.rowKeyMap.forEach((row, key) => { if (row.expand) { list.push(key); } }); return list; } expandAll(expand) { this.rowKeyMap.forEach((row) => { row.expand = expand; }); this.clearBufferData(); // 清除缓存数据 this.ctx.emit('draw'); } expandLoading(rowKey, loading = false) { const row = this.rowKeyMap.get(rowKey); row.expandLoading = loading; this.clearBufferData(); // 清除缓存数据 this.ctx.emit('draw'); } setExpandChildren(rowKey, children) { const row = this.rowKeyMap.get(rowKey); row.expand = true; row.expandLazy = true; row.item.children = children; this.initData(row.item.children, row.level + 1); this.clearBufferData(); // 清除缓存数据 } getIsExpandLoading(rowKey) { const row = this.rowKeyMap.get(rowKey); return row.expandLoading; } getIsExpandLazy(rowKey) { const row = this.rowKeyMap.get(rowKey); return row.expandLazy; } /** * 根据rowKey获取是否展开 * @param rowKey * @returns */ getIsExpand(rowKey) { const row = this.rowKeyMap.get(rowKey); return row.expand; } /** * 根据rowKey获取行数据 * @param rowKey * @returns */ getRowForRowKey(rowKey) { return this.rowKeyMap.get(rowKey); } getRowForRowIndex(rowIndex) { const rowKey = this.getRowKeyForRowIndex(rowIndex); return this.rowKeyMap.get(rowKey); } /** * 根据rowIndex获取rowKey * @param rowKey * @returns */ getRowKeyForRowIndex(rowIndex) { return this.rowIndexRowKeyMap.get(rowIndex) || ''; } getRowKeyByItem(item) { return this.itemRowKeyMap.get(item); } getRowIndexForRowKey(rowKey) { return this.rowKeyMap.get(rowKey).index; } /** * 根据rowIndex和colIndex获取单元格数据 * @param rowIndex * @param colIndex * @returns */ getItemValueForRowIndexAndColIndex(rowIndex, colIndex) { const has = this.rowIndexRowKeyMap.has(rowIndex) && this.colIndexKeyMap.get(colIndex); if (!has) { return null; } const rowKey = this.rowIndexRowKeyMap.get(rowIndex); const key = this.colIndexKeyMap.get(colIndex); if (rowKey === undefined || key === undefined) { return null; } return { rowKey, key, value: this.getItemValue(rowKey, key), }; } /** * 根据rowKey和key获取单元格数据 * @param rowKey * @param key * @returns */ getItemValue(rowKey, key) { const row = this.rowKeyMap.get(rowKey); if (row && row.item) { if (row.item[key] === undefined) { return null; } return row.item[key]; } return null; } /** * 批量设置数据 * @param list * @param history * @returns */ async batchSetItemValue(_list, history = false) { let changeList = []; const rowKeyList = new Set(); let list = _list; const { BEFORE_VALUE_CHANGE_METHOD } = this.ctx.config; if (typeof BEFORE_VALUE_CHANGE_METHOD === 'function') { const beforeCellValueChange = BEFORE_VALUE_CHANGE_METHOD; const changeList = _list.map((item) => ({ rowKey: item.rowKey, key: item.key, value: item.value, oldValue: this.getItemValue(item.rowKey, item.key), row: this.ctx.database.getRowDataItemForRowKey(item.rowKey), })); const values = await beforeCellValueChange(changeList); list = values; } list.forEach((data) => { const { value, rowKey, key } = data; const oldValue = this.getItemValue(rowKey, key); this.setItemValue(rowKey, key, value); rowKeyList.add(rowKey); changeList.push({ rowKey, key, oldValue, newValue: value, }); }); // 触发change事件 let rows = []; const _changeList = changeList.map((item) => { const row = this.ctx.database.getRowDataItemForRowKey(item.rowKey); return { rowKey: item.rowKey, key: item.key, value: item.newValue, row, }; }); rowKeyList.forEach((rowKey) => { rows.push(this.ctx.database.getRowDataItemForRowKey(rowKey)); }); const promsieValidators = _changeList.map(({ rowKey, key }) => this.getValidator(rowKey, key)); Promise.all(promsieValidators).then(() => { if (this.validationErrorMap.size === 0 && this.changedDataMap.size > 0) { this.ctx.emit('validateChangedData', this.getChangedData()); } }); this.ctx.emit('change', _changeList, rows); // 推历史记录 if (history) { this.ctx.history.pushState({ changeList, scrollX: this.ctx.scrollX, scrollY: this.ctx.scrollY, type: 'multiple', }); } this.ctx.emit('draw'); } /** *设置单一数据 * @param rowKey * @param key * @param value * @param history 是否添加历史记录 * @param reDraw 是否刷新重绘 * @param isEditor 是否是编辑器 * @returns */ async setItemValue(rowKey, key, _value, history = false, reDraw = false, isEditor = false) { // 异常情况 if (!this.rowKeyMap.has(rowKey)) { return {}; } const { item } = this.rowKeyMap.get(rowKey); let oldValue = item[key]; // 只读返回旧值 if (this.ctx.database.getReadonly(rowKey, key)) { return { oldValue, newValue: oldValue, }; } // 处理对象 if (item[key] !== null && typeof item[key] === 'object') { oldValue = JSON.parse(JSON.stringify(item[key])); } const changeKey = `${rowKey}\u200b_${key}`; // 设置原始值,只设置一次 if (!this.originalDataMap.has(changeKey)) { this.originalDataMap.set(changeKey, oldValue); } const originalValue = this.originalDataMap.get(changeKey); let value = _value; // 是否是否是编辑器进来的 if (isEditor) { const { BEFORE_VALUE_CHANGE_METHOD } = this.ctx.config; if (typeof BEFORE_VALUE_CHANGE_METHOD === 'function') { const beforeCellValueChange = BEFORE_VALUE_CHANGE_METHOD; const values = await beforeCellValueChange([ { rowKey, key, value: _value, oldValue: item[key], row: this.ctx.database.getRowDataItemForRowKey(rowKey), }, ]); if (values && values.length) { value = values[0].value; } } // 设置改变值 this.changedDataMap.set(changeKey, value); item[key] = value; const row = this.ctx.database.getRowDataItemForRowKey(rowKey); const changeItem = { rowKey, key, value, row, }; // 实时校验错误 this.getValidator(rowKey, key).then(() => { if (this.validationErrorMap.size === 0 && this.changedDataMap.size > 0) { this.ctx.emit('validateChangedData', this.getChangedData()); } }); this.ctx.emit('change', [changeItem], [row]); this.ctx.emit('editChange', { rowKey, key, oldValue, value, originalValue, row, }); } else { this.changedDataMap.set(changeKey, value); item[key] = value; } // 迭代改变值事件,有改变一次值就触发,包括批量的 if (this.ctx.hasEvent('iterationChange')) { this.ctx.emit('iterationChange', { rowKey, key, oldValue, value, originalValue: this.originalDataMap.get(changeKey), row: this.ctx.database.getRowDataItemForRowKey(rowKey), }); } // 添加历史记录 if (history) { this.ctx.history.pushState({ type: 'single', scrollX: this.ctx.scrollX, scrollY: this.ctx.scrollY, changeList: [ { rowKey, key, oldValue, newValue: value, }, ], }); } // 重绘 if (reDraw) { this.ctx.emit('draw'); } return { oldValue, newValue: value, }; } /** * 根据rowKey 获取行数据 * @param rowKey * @returns */ getRowDataItemForRowKey(rowKey) { if (!this.rowKeyMap.has(rowKey)) { return {}; } const { item } = this.rowKeyMap.get(rowKey); return item; } /** * * @param rowKey 设置选中状态ByCheckboxKey,用于合并Checkbox单元格时声明唯一key * @param check */ setRowSelectionByCheckboxKey(rowKey, check) { const { CHECKBOX_KEY } = this.ctx.config; if (CHECKBOX_KEY) { if (!this.rowKeyMap.has(rowKey)) { return false; } const { item } = this.rowKeyMap.get(rowKey); const checkboxKey = item[CHECKBOX_KEY]; if (this.checkboxKeyMap.has(checkboxKey)) { const rowKeys = this.checkboxKeyMap.get(checkboxKey) || []; rowKeys.forEach((rowKey) => { const row = this.rowKeyMap.get(rowKey); row.check = check; }); } } } /** * 根据rowKey 取反选中 * @param rowKey */ toggleRowSelection(rowKey) { const row = this.rowKeyMap.get(rowKey); row.check = !row.check; this.setRowSelectionByCheckboxKey(rowKey, row.check); this.ctx.emit('toggleRowSelection', row); const rows = this.getSelectionRows(); this.ctx.emit('selectionChange', rows); this.ctx.emit('draw'); } /** * 根据rowKey 设置选中状态 * @param rowKey */ setRowSelection(rowKey, check) { const row = this.rowKeyMap.get(rowKey); row.check = check; this.setRowSelectionByCheckboxKey(rowKey, row.check); const rows = this.getSelectionRows(); this.ctx.emit('setRowSelection', rows); this.ctx.emit('draw'); } getSelectionRows() { let rows = []; this.rowKeyMap.forEach((row) => { if (row.check) { rows.push(row.item); } }); return rows; } /** * 根据rowKey 获取选中状态 * @param rowKey */ getRowSelection(rowKey) { const { check } = this.rowKeyMap.get(rowKey); return check; } /** * 根据rowKey 获取选中状态 * @param rowKey */ getRowSelectable(rowKey) { const { selectable, item, rowIndex } = this.rowKeyMap.get(rowKey); if (typeof selectable === 'function') { return selectable({ row: item, rowIndex, }); } return selectable; } /** * 全选 * @param rowKey */ toggleAllSelection() { this.rowKeyMap.forEach((row) => { const _selectable = row.selectable; if (typeof _selectable === 'function') { const selectable = _selectable({ row: row.item, rowIndex: row.rowIndex, }); if (selectable) { row.check = true; } } else { if (_selectable) { row.check = true; } } }); const rows = this.getSelectionRows(); this.ctx.emit('toggleAllSelection', rows); this.ctx.emit('selectionChange', rows); this.ctx.emit('draw'); } /** * 清除选中 * @param rowKey */ clearSelection() { this.rowKeyMap.forEach((row) => { const _selectable = row.selectable; if (typeof _selectable === 'function') { const selectable = _selectable({ row: row.item, rowIndex: row.rowIndex, }); if (selectable) { row.check = false; } } else { if (_selectable) { row.check = false; } } }); const rows = this.getSelectionRows(); this.ctx.emit('clearSelection'); this.ctx.emit('selectionChange', rows); this.ctx.emit('draw'); } /** * 获取选中状态,表头用 * @param rowKey */ getCheckedState() { let total = 0; let totalChecked = 0; let totalSelectable = 0; this.rowKeyMap.forEach((row) => { total += 1; if (row.check) { totalChecked += 1; } const _selectable = row.selectable; if (typeof _selectable === 'function') { const selectable = _selectable({ row: row.item, rowIndex: row.rowIndex, }); if (selectable) { totalSelectable += 1; } } else { if (_selectable) { totalSelectable += 1; } } }); const indeterminate = totalSelectable && totalSelectable > totalChecked && totalChecked > 0; const selectable = totalSelectable !== 0; const check = totalSelectable && totalSelectable === totalChecked; return { check, indeterminate, selectable, }; } /** * 更新列索引 * @param list 表头末级列表 */ updateColIndexKeyMap(list = []) { this.colIndexKeyMap.clear(); list.forEach((column) => { this.colIndexKeyMap.set(column.colIndex, column.key); }); } getColumnByColIndex(colIndex) { const key = this.colIndexKeyMap.get(colIndex); if (key && this.headerMap.has(key)) { return this.headerMap.get(key)?.column; } return undefined; } getColIndexForKey(key) { if (key && this.headerMap.has(key)) { return this.headerMap.get(key)?.colIndex; } } getColHeaderByIndex(colIndex) { const key = this.colIndexKeyMap.get(colIndex); if (key && this.headerMap.has(key)) { return this.headerMap.get(key); } return undefined; } /** * 获取以改变数据 */ getChangedData() { let list = []; this.changedDataMap.forEach((value, key) => { const originalValue = this.originalDataMap.get(key); const rowKey = key.split('\u200b_')[0]; const colKey = key.split('\u200b_')[1]; if (originalValue !== value) { list.push({ rowKey, colKey, originalValue, row: this.ctx.database.getRowDataItemForRowKey(rowKey), value, }); } }); return list; } getChangedRows() { const rowKeyList = new Set(); this.changedDataMap.forEach((value, key) => { const originalValue = this.originalDataMap.get(key); const rowKey = key.split('\u200b_')[0]; if (originalValue !== value) { rowKeyList.add(rowKey); } }); let rows = []; rowKeyList.forEach((rowKey) => { rows.push(this.ctx.database.getRowDataItemForRowKey(rowKey)); }); return rows; } /** * 获取改变值是否已经改变 * @param rowKey * @param key * @returns */ isHasChangedData(rowKey, key) { const changedKey = `${rowKey}\u200b_${key}`; if (!this.changedDataMap.has(changedKey)) { return false; } const originalValue = this.originalDataMap.get(changedKey); const changedValue = this.changedDataMap.get(changedKey); return originalValue !== changedValue; } getPositionForRowIndex(rowIndex) { if (rowIndex < this.positions.length) { return this.positions[rowIndex]; } return { height: 0, top: 0, bottom: 0, }; } setHeader(key, cellHeader) { if (!key) { return false; } this.headerMap.set(key, cellHeader); return true; } getReadonly(rowKey, key) { const { DISABLED } = this.ctx.config; // 禁用编辑 if (DISABLED) { return true; } const row = this.rowKeyMap.get(rowKey); const colHeader = this.headerMap.get(key); const rowReadonly = row?.readonly; const colReadonly = colHeader?.readonly; const { BODY_CELL_READONLY_METHOD } = this.ctx.config; // 自定义只读 if (typeof BODY_CELL_READONLY_METHOD === 'function' && colHeader) { const cellReadonlyMethod = BODY_CELL_READONLY_METHOD; const readonly = cellReadonlyMethod({ row: row.item, rowIndex: row.rowIndex, colIndex: colHeader.colIndex, column: colHeader.column, value: this.getItemValue(rowKey, key), }); if (readonly !== undefined) { return readonly; } } return colReadonly || rowReadonly; } clearValidate() { this.validationErrorMap.clear(); } hasValidationError() { return this.validationErrorMap.size !== 0; } getValidator(rowKey, key) { return new Promise((resolve) => { const row = this.rowKeyMap.get(rowKey); const colHeader = this.headerMap.get(key); const { BODY_CELL_RULES_METHOD } = this.ctx.config; if (colHeader === undefined) { return resolve([]); } const column = colHeader.column; let rules = column.rules; // 自定义只读 if (typeof BODY_CELL_RULES_METHOD === 'function') { const cellRulesMethod = BODY_CELL_RULES_METHOD; const _rules = cellRulesMethod({ row: row.item, rowIndex: row.rowIndex, colIndex: colHeader.colIndex, column, value: this.getItemValue(rowKey, key), }); if (_rules) { rules = _rules; } } if (rules) { let descriptor = {}; let data = {}; data[key] = this.getItemValue(rowKey, key); if (Array.isArray(rules)) { const _rules = rules.map((item) => { return { ...item, row: row.item, column, rowIndex: row.rowIndex, colIndex: colHeader.colIndex, }; }); descriptor[key] = _rules; } else { descriptor[key] = { ...rules, row: row.item, column, rowIndex: row.rowIndex, colIndex: colHeader.colIndex, }; } const validator = new Schema(descriptor); validator .validate(data) .then(() => { this.clearValidationError(rowKey, key); resolve([]); }) .catch(({ errors }) => { const _errors = errors.map((error) => ({ ...error, column, key, row: row.item, rowKey, })); this.setValidationError(rowKey, key, _errors); resolve(_errors); }); } else { resolve([]); } }); } getHeightByRowIndexRowSpan(rowIndex, rowSpan) { let sumHeight = 0; for (let i = 0; i < rowSpan; i++) { const position = this.positions[rowIndex + i]; if (position) { sumHeight += position.height; } } return sumHeight; } getSpanInfo(cell) { const { rowIndex, key, rowKey, row, value, colIndex, relationRowKeys, relationColKeys, rowspan, height, width, colspan, mergeRow, mergeCol, } = cell; if (rowspan === 1 && colspan === 1) { return { xArr: [colIndex, colIndex], yArr: [rowIndex, rowIndex], rowspan, colspan, height, width, offsetTop: 0, offsetLeft: 0, dataList: [ { rowKey, key, row, value, }, ], }; } let topIndex = rowIndex; let bottomIndex = rowIndex; let leftIndex = colIndex; let rightIndex = colIndex; let dataList = []; let offsetTop = 0; let offsetLeft = 0; let mergeHeight = 0; let mergeWidth = 0; // 列合并的 if (rowspan !== 1 && mergeRow) { mergeWidth = width; const curValue = relationRowKeys.reduce((acc, key) => { const value = this.getItemValue(rowKey, key) ?? ''; return `${acc}${value}`; }, ''); // 先查找向上的相同值,根据关联值查询 for (let i = rowIndex - 1; i >= 0; i--) { const _rowKey = this.rowIndexRowKeyMap.get(i) || ''; const pValue = relationRowKeys.reduce((acc, key) => { const value = this.getItemValue(_rowKey, key) ?? ''; return `${acc}${value}`; }, ''); if (curValue === pValue) { topIndex = i; } else { break; } } // 再查找向下的相同值,根据关联值查询 for (let i = rowIndex; i <= this.ctx.maxRowIndex; i++) { const _rowKey = this.rowIndexRowKeyMap.get(i) || ''; const pValue = relationRowKeys.reduce((acc, key) => { const value = this.getItemValue(_rowKey, key) ?? ''; return `${acc}${value}`; }, ''); if (curValue === pValue) { bottomIndex = i; } else { break; } } for (let i = topIndex; i < rowIndex; i++) { const { height } = this.positions[i]; offsetTop += height; } for (let i = topIndex; i <= bottomIndex; i++) { const { height } = this.positions[i]; // 合并高度 mergeHeight += height; // 根据下标查找rowkey const _rowKey = this.rowIndexRowKeyMap.get(i) || ''; const { item } = this.rowKeyMap.get(_rowKey); const value = this.getItemValue(_rowKey, key); // 需要改变值 dataList.push({ rowKey: _rowKey, key, value, row: item, }); } } // 行合并的 if (colspan !== 1 && mergeCol) { mergeHeight = height; // 向左 for (let i = colIndex - 1; i >= 0; i--) { const column = this.getColumnByColIndex(i); if (!column) { break; } const curValue = this.getItemValue(rowKey, key); const pValue = this.getItemValue(rowKey, column.key); if (curValue === pValue && relationColKeys.includes(column.key)) { leftIndex = i; } else { break; } } // 向右 for (let i = colIndex; i <= this.ctx.maxColIndex; i++) { const column = this.getColumnByColIndex(i); if (!column) { break; } const curValue = this.getItemValue(rowKey, key); const pValue = this.getItemValue(rowKey, column.key); if (curValue === pValue && relationColKeys.includes(column.key)) { rightIndex = i; } else { break; } } for (let i = leftIndex; i < colIndex; i++) { const column = this.getColumnByColIndex(i); if (!column) { break; } // 合并宽度 offsetLeft += column.width || 100; } for (let i = leftIndex; i <= rightIndex; i++) { const column = this.getColumnByColIndex(i); if (!column) { break; } // 合并宽度 mergeWidth += column.width || 100; // 需要改变值 dataList.push({ rowKey, key: column.key, value: this.getItemValue(rowKey, column.key), row, }); } } return { xArr: [leftIndex, rightIndex], yArr: [topIndex, bottomIndex], rowspan, colspan, height: mergeHeight, width: mergeWidth, offsetTop, offsetLeft, dataList, }; } setLoading(loading) { this.loading = loading; this.ctx.emit('loadingChange', loading); } getLoading() { return this.loading; } setValidationErrorByRowIndex(rowIndex, key, message) { const rowKey = this.rowIndexRowKeyMap.get(rowIndex); const _key = `${rowKey}\u200b_${key}`; const errors = [ { message, }, ]; this.validationErrorMap.set(_key, errors); } setValidationError(rowKey, key, errors) { const _key = `${rowKey}\u200b_${key}`; this.validationErrorMap.set(_key, errors); } clearValidationError(rowKey, key) { const _key = `${rowKey}\u200b_${key}`; if (this.validationErrorMap.has(_key)) { this.validationErrorMap.delete(_key); } } getValidationError(rowKey, key) { const _key = `${rowKey}\u200b_${key}`; return this.validationErrorMap.get(_key) || []; } // 获取虚拟单元格 getVirtualBodyCell(rowIndex, colIndex) { const column = this.getColumnByColIndex(colIndex); const row = this.getRowForRowIndex(rowIndex); if (!column || !row) { return; } const cell = new Cell(this.ctx, rowIndex, colIndex, 0, 0, 0, 0, column, row, 'body'); return cell; } hasMergeCell(xArr, yArr) { let hasMergeCell = false; for (let i = yArr[0]; i <= yArr[1]; i++) { for (let j = xArr[0]; j <= xArr[1]; j++) { const cell = this.getVirtualBodyCell(i, j); if (cell && (cell.rowspan !== 1 || cell.colspan !== 1)) { hasMergeCell = true; break; } } } return hasMergeCell; } } //# sourceMappingURL=Database.js.map