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
25 changes: 19 additions & 6 deletions packages/vue-vtable/src/edit/editor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { isValid } from '@visactor/vutils';
import { isVNode, render } from 'vue';
import { VTable } from '..';
import type { IBasicColumnBodyDefine } from '@visactor/vtable/src/ts-types/list-table/define/basic-define';
import { TYPES } from '@visactor/vtable';

/** 渲染式编辑器参数 */
export interface DynamicRenderEditorParams {
Expand Down Expand Up @@ -43,7 +42,10 @@ export interface ValidateValueParams {
table?: any;
}

interface ColumnDefine extends IBasicColumnBodyDefine {
/** 必要列配置 */
interface ColumnDefine {
/** 列唯一标识 */
key?: string;
/** 渲染式编辑器配置 */
editConfig?: DynamicRenderEditorConfig;
}
Expand Down Expand Up @@ -118,8 +120,9 @@ export class DynamicRenderEditor {
return false;
}
const define = table.getBodyColumnDefine(col, row) as ColumnDefine;
const { key, editConfig } = define || {};
const { editConfig } = define || {};
const { id } = table;
const key = this.getColumnKeyField(define);
if (!isValid(key) || !isValid(id)) {
return false;
}
Expand All @@ -130,7 +133,7 @@ export class DynamicRenderEditor {
table.showTooltip(col, row, {
// TODO 多语言
content: editConfig.disablePrompt || 'This field is not allowed to be edited',
referencePosition: { rect: referencePosition?.rect, placement: VTable.TYPES.Placement.top },
referencePosition: { rect: referencePosition?.rect, placement: TYPES.Placement.top },
style: {
bgColor: 'black',
color: 'white',
Expand Down Expand Up @@ -172,6 +175,16 @@ export class DynamicRenderEditor {
}
return true;
}
/**
* @description: 获取渲染式编辑器的列配置主键
* @param {any} column
* @return {*}
*/
getColumnKeyField(column: any) {
const { field, key } = column || {};
// 兼容取 field
return isValid(key) ? key : field;
}

getValue() {
return this.currentValue;
Expand Down Expand Up @@ -208,7 +221,7 @@ export class DynamicRenderEditor {
const rect = table.getVisibleCellRangeRelativeRect({ col, row });
table.showTooltip(col, row, {
content: editConfig.invalidPrompt || 'invalid',
referencePosition: { rect, placement: VTable.TYPES.Placement.top },
referencePosition: { rect, placement: TYPES.Placement.top },
style: {
bgColor: 'red',
color: 'white',
Expand Down
63 changes: 17 additions & 46 deletions packages/vue-vtable/src/edit/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,22 @@
* @LastEditTime: 2025-03-03 20:17:33
* @Description: 集成编辑器工具方法
*/

import { VTable } from '..';
import { register } from '@visactor/vtable';
import { DynamicRenderEditor } from './editor';
import { isValid } from '@visactor/vutils';

/** 动态渲染编辑器名称 */
const DYNAMIC_RENDER_EDITOR = 'dynamic-render-editor';

/**
* @description: 动态渲染式编辑器
* @param {any} table
* @param {VTable} option
* @return {*}
*/
export function resolveRenderEditor(table: any, option: VTable.ListTableConstructorOptions) {
if (!isValid(table?.id) || !option?.columns?.length) {
return;
}
const { id } = table;
// 移除原本已存在的编辑器
const rawRenderEditor = getRenderEditor();
if (rawRenderEditor) {
rawRenderEditor.removeNode(id);
}
if (option.columns.some(x => checkRenderEditor(x))) {
// 需要注册编辑器
const renderEditor = rawRenderEditor || getRenderEditor(true);
option.columns.forEach((column: any) => {
if (!checkRenderEditor(column)) {
return;
}
const { key, getEditCustomNode } = column;
renderEditor.registerNode(id, key, getEditCustomNode);
delete column.editCustomNode;
});
}
}

/**
* @description: 校验动态渲染式编辑器
* @param {any} column
* @param {any} getEditCustomNode
* @return {*}
*/
export function checkRenderEditor(column: any, getEditCustomNode?: any) {
const { key, editor } = column || {};
const { editor } = column || {};
const key = getRenderEditorColumnKeyField(column);
if (!isValid(key) || editor !== DYNAMIC_RENDER_EDITOR) {
return false;
}
Expand All @@ -61,27 +31,28 @@ export function checkRenderEditor(column: any, getEditCustomNode?: any) {
return typeof column.getEditCustomNode === 'function';
}

/**
* @description: 获取渲染式编辑器的列配置主键
* @param {any} column
* @return {*}
*/
export function getRenderEditorColumnKeyField(column: any) {
const { field, key } = column || {};
// 兼容取 field
return isValid(key) ? key : field;
}

/**
* @description: 获取动态渲染式编辑器
* @param {boolean} create
* @return {*}
*/
function getRenderEditor(create?: boolean) {
let renderEditor = VTable.register.editor(DYNAMIC_RENDER_EDITOR) as DynamicRenderEditor;
export function getRenderEditor(create?: boolean) {
let renderEditor = register.editor(DYNAMIC_RENDER_EDITOR) as DynamicRenderEditor;
if (!renderEditor && !!create) {
// 注册自定义编辑器
renderEditor = new DynamicRenderEditor();
VTable.register.editor(DYNAMIC_RENDER_EDITOR, renderEditor);
register.editor(DYNAMIC_RENDER_EDITOR, renderEditor);
}
return renderEditor;
}

/**
* @description: 释放动态渲染式编辑器
* @param {number} tableId
* @return {*}
*/
export function releaseRenderEditor(tableId?: number | string) {
const renderEditor = getRenderEditor();
renderEditor?.release(tableId);
}
2 changes: 2 additions & 0 deletions packages/vue-vtable/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './useEditorRender';
export * from './useCellRender';
22 changes: 22 additions & 0 deletions packages/vue-vtable/src/hooks/useCellRender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Ref } from 'vue';
import { watchEffect } from 'vue';
import { VTableVueAttributePlugin } from '../components/custom/vtable-vue-attribute-plugin';

/**
* 自定义单元格渲染器
* @param props
* @param tableRef
*/
export function useCellRender(props: any, tableRef: Ref) {
watchEffect(() => {
if (!props?.customConfig?.createReactContainer) {
// 未开启自定义容器
return;
}
if (!tableRef.value) {
return;
}
// 注册 vtable-vue 自定义组件集成插件
tableRef.value.scenegraph.stage.pluginService.register(new VTableVueAttributePlugin());
});
}
69 changes: 69 additions & 0 deletions packages/vue-vtable/src/hooks/useEditorRender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { Ref } from 'vue';
import { computed, onBeforeUnmount, watchEffect } from 'vue';
import { isArray, isObject, isValid } from '@visactor/vutils';
import { checkRenderEditor, getRenderEditor, getRenderEditorColumnKeyField } from '../edit';

/**
* 编辑渲染器
* @param props
* @param tableRef
*/
export function useEditorRender(props: any, tableRef: Ref) {
/** 需要渲染编辑器的列 */
const validColumns = computed(() => {
const columns = props.options?.columns;
if (!isArray(columns)) {
return [];
}
return (columns as any[]).filter(col => !!isObject(col) && !!checkRenderEditor(col));
});
watchEffect(() => {
resolveRenderEditor();
});
onBeforeUnmount(() => {
releaseRenderEditor();
});
/**
* @description: 动态渲染式编辑器
* @return {*}
*/
function resolveRenderEditor() {
const id = getTableId();
if (!isValid(id)) {
return;
}
// 移除原本已存在的编辑器
let renderEditor = getRenderEditor();
if (renderEditor) {
renderEditor.removeNode(id);
} else if (validColumns.value.length > 0) {
// 注册编辑器
renderEditor = getRenderEditor(true);
}
validColumns.value.forEach(column => {
const { getEditCustomNode } = column;
const key = getRenderEditorColumnKeyField(column);
renderEditor.registerNode(id, key, getEditCustomNode);
delete column.editCustomNode;
});
}
/**
* @description: 释放动态渲染式编辑器
* @return {*}
*/
function releaseRenderEditor() {
const id = getTableId();
if (!isValid(id)) {
return;
}
const renderEditor = getRenderEditor();
renderEditor?.release(id);
}
/**
* @description: 获取表格 id
* @return {*}
*/
function getTableId() {
return tableRef.value?.id;
}
}
23 changes: 6 additions & 17 deletions packages/vue-vtable/src/tables/base-table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
<script setup lang="ts">
import { ref, shallowRef, watch, computed, onMounted, onBeforeUnmount } from 'vue';
import { ListTable, PivotTable, PivotChart } from '@visactor/vtable';
import { isEqual, isValid } from '@visactor/vutils';
import { TABLE_EVENTS, TABLE_EVENTS_KEYS } from '../eventsUtils';
import type * as VTable from '@visactor/vtable';
import type { EventsProps } from '../eventsUtils';
import type { TYPES } from '@visactor/vtable';
import { VTableVueAttributePlugin } from '../components/custom/vtable-vue-attribute-plugin';
import { releaseRenderEditor, resolveRenderEditor } from '../edit';
import { useCellRender, useEditorRender } from '../hooks';

// 定义表格实例和选项的类型
export type IVTable = VTable.ListTable | VTable.PivotTable | VTable.PivotChart;
Expand Down Expand Up @@ -47,6 +45,11 @@ const columnWidths = ref<Map<string, number>>(new Map());
const pivotColumnWidths = ref<{ dimensions: TYPES.IDimensionInfo[]; width: number }[]>([]);
const pivotHeaderColumnWidths = ref<number[]>([]);

// 自定义编辑渲染器
useEditorRender(props, vTableInstance);
// 自定义单元格渲染器
useCellRender(props, vTableInstance);

// 公开 vTableInstance,以便外部组件可以访问
defineExpose({ vTableInstance });

Expand All @@ -72,11 +75,6 @@ type Constructor<T> = new (dom: HTMLElement, options: IOption) => T;
const createTableInstance = (Type: any, options: IOption) => {
const vtable = new Type(vTableContainer.value!, options);
vTableInstance.value = vtable;
// 注册 vtable-vue 自定义组件集成插件
vtable.scenegraph.stage.pluginService.register(new VTableVueAttributePlugin());
// 校验并植入渲染式编辑器
resolveRenderEditor(vtable, options);

// for keepColumnWidthChange
columnWidths.value.clear();
pivotColumnWidths.value = [];
Expand Down Expand Up @@ -211,11 +209,6 @@ const updateVTable = (newOptions: IOption) => {
onMounted(createVTable);
onBeforeUnmount(() => {
vTableInstance.value?.release();
const { id } = vTableInstance.value || {};
if (isValid(id)) {
// 移除自定义编辑器
releaseRenderEditor(id);
}
});

// 监听 options 属性的变化
Expand All @@ -226,10 +219,6 @@ watch(
(newOptions, oldOptions) => {
if (vTableInstance.value) {
updateVTable(newOptions);
if (!isEqual(newOptions.columns, oldOptions?.columns)) {
// 更新编辑列
resolveRenderEditor(vTableInstance.value, newOptions);
}
} else {
createVTable();
}
Expand Down