mirror of
https://github.com/VisActor/VTable
synced 2024-11-21 17:40:10 +00:00
feat: refactor utils to optimize functionality
This commit is contained in:
parent
3baf2f32cb
commit
ada47b984c
@ -57,6 +57,10 @@ const bindEvents = (instance: IVTable) => {
|
||||
};
|
||||
|
||||
// 创建表格实例
|
||||
const createTableInstance = (Type: new (container: HTMLElement, options: IOption) => IVTable, options: IOption) => {
|
||||
vTableInstance.value = new Type(vTableContainer.value!, options);
|
||||
};
|
||||
|
||||
const createVTable = () => {
|
||||
if (!vTableContainer.value) return;
|
||||
|
||||
@ -68,10 +72,6 @@ const createVTable = () => {
|
||||
return props.records !== undefined && props.records !== null && props.records.length > 0 ? props.records : props.options.records;
|
||||
};
|
||||
|
||||
const createTableInstance = (Type: any, options: any) => {
|
||||
vTableInstance.value = new Type(vTableContainer.value, options);
|
||||
};
|
||||
|
||||
try {
|
||||
switch (props.type) {
|
||||
case 'list':
|
||||
@ -96,8 +96,8 @@ const createVTable = () => {
|
||||
bindEvents(vTableInstance.value);
|
||||
props.onReady?.(vTableInstance.value, true);
|
||||
} catch (err) {
|
||||
// props.onError?.(err as Error);
|
||||
console.error(err);
|
||||
console.error('Error creating table instance:', err);
|
||||
props.onError?.(err as Error);
|
||||
}
|
||||
};
|
||||
|
||||
@ -134,6 +134,7 @@ onBeforeUnmount(() => vTableInstance.value?.release());
|
||||
|
||||
// 监听 options 属性的变化
|
||||
// 需要去做细颗粒度的比较
|
||||
// deep 选中会导致tree失效
|
||||
watch(
|
||||
() => props.options,
|
||||
(newOptions) => {
|
||||
@ -143,7 +144,7 @@ watch(
|
||||
createVTable();
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
// { deep: true },
|
||||
);
|
||||
|
||||
// 监听 records 属性的变化并更新表格
|
||||
|
@ -14,11 +14,9 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, defineProps, useSlots, defineExpose } from 'vue';
|
||||
import { flattenVNodes, createCustomLayout , convertPropsToCamelCase } from './utils';
|
||||
import { flattenVNodes, extractListSlotOptions } from '../utils';
|
||||
import BaseTable from './base-table.vue';
|
||||
import type { ColumnDefine } from '@visactor/vtable';
|
||||
import type { TooltipProps } from '../components/component/tooltip';
|
||||
import type { MenuProps } from '../components/component/menu';
|
||||
|
||||
|
||||
// 定义属性接口
|
||||
interface Props {
|
||||
@ -38,7 +36,7 @@ const slots = useSlots();
|
||||
// 合并插槽配置
|
||||
const computedOptions = computed(() => {
|
||||
const flattenedSlots = flattenVNodes(slots.default?.() || []);
|
||||
const slotOptions = extractSlotOptions(flattenedSlots);
|
||||
const slotOptions = extractListSlotOptions(flattenedSlots);
|
||||
|
||||
return {
|
||||
...props.options,
|
||||
@ -48,58 +46,6 @@ const computedOptions = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
// 从插槽中提取配置
|
||||
function extractSlotOptions(vnodes: any[]) {
|
||||
const options = {
|
||||
columns: [] as ColumnDefine[],
|
||||
tooltip: {} as TooltipProps,
|
||||
menu: {} as MenuProps,
|
||||
};
|
||||
|
||||
const typeMapping: Record<string, keyof typeof options> = {
|
||||
ListColumn: 'columns',
|
||||
Tooltip: 'tooltip',
|
||||
Menu: 'menu',
|
||||
};
|
||||
|
||||
vnodes.forEach(vnode => {
|
||||
vnode.props = convertPropsToCamelCase(vnode.props);
|
||||
const typeName = vnode.type?.symbol || vnode.type?.name;
|
||||
const optionKey = typeMapping[typeName];
|
||||
|
||||
if (optionKey) {
|
||||
if (optionKey === 'columns' && vnode.children) {
|
||||
vnode.props.customLayout = createCustomLayoutHandler(vnode.children);
|
||||
}
|
||||
|
||||
if (Array.isArray(options[optionKey])) {
|
||||
(options[optionKey] as any[]).push(vnode.props);
|
||||
} else {
|
||||
options[optionKey] = vnode.props;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
// 创建自定义布局处理器
|
||||
function createCustomLayoutHandler(children: any) {
|
||||
return (args: any) => {
|
||||
const { table, row, col, rect } = args;
|
||||
const record = table.getCellOriginRecord(col, row);
|
||||
const { height, width } = rect ?? table.getCellRect(col, row);
|
||||
|
||||
const rootContainer = children.customLayout({ table, row, col, rect, record, height, width })[0];
|
||||
const { rootComponent } = createCustomLayout(rootContainer);
|
||||
|
||||
return {
|
||||
rootContainer: rootComponent,
|
||||
renderDefault: false,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// 暴露实例
|
||||
defineExpose({
|
||||
vTableInstance: computed(() => baseTableRef.value?.vTableInstance || null),
|
||||
|
@ -13,11 +13,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { shallowRef, computed, defineProps, useSlots } from 'vue';
|
||||
import { flattenVNodes , convertPropsToCamelCase } from './utils';
|
||||
import { flattenVNodes, extractPivotSlotOptions } from '../utils';
|
||||
import BaseTable from './base-table.vue';
|
||||
import type { ICornerDefine as PivotCornerProps, IIndicator as PivotIndicatorsProps, IDimension as PivotColumnDimensionProps, IDimension as PivotRowDimensionProps, ITitleDefine } from '@visactor/vtable';
|
||||
import type { TooltipProps } from '../components/component/tooltip';
|
||||
import type { MenuProps } from '../components/component/menu';
|
||||
|
||||
interface Props {
|
||||
options: Record<string, unknown>;
|
||||
@ -33,57 +30,18 @@ const slots = useSlots();
|
||||
|
||||
const computedOptions = computed(() => {
|
||||
const flattenedSlots = flattenVNodes(slots.default?.() || []);
|
||||
|
||||
const options = {
|
||||
columns: [] as PivotColumnDimensionProps[],
|
||||
columnHeaderTitle: [] as ITitleDefine[],
|
||||
rows: [] as PivotRowDimensionProps[],
|
||||
rowHeaderTitle: [] as ITitleDefine[],
|
||||
indicators: [] as PivotIndicatorsProps[],
|
||||
corner: Object as PivotCornerProps | null,
|
||||
tooltip: Object as TooltipProps | null,
|
||||
menu: Object as MenuProps | null,
|
||||
};
|
||||
|
||||
const typeMapping: Record<string, keyof typeof options> = {
|
||||
'PivotColumnDimension': 'columns',
|
||||
'PivotColumnHeaderTitle': 'columnHeaderTitle',
|
||||
'PivotRowDimension': 'rows',
|
||||
'PivotRowHeaderTitle': 'rowHeaderTitle',
|
||||
'PivotCorner': 'corner',
|
||||
'PivotIndicator': 'indicators',
|
||||
'Tooltip': 'tooltip',
|
||||
'Menu': 'menu',
|
||||
};
|
||||
|
||||
flattenedSlots.forEach(vnode => {
|
||||
vnode.props = convertPropsToCamelCase(vnode.props);
|
||||
const typeName = vnode.type?.symbol || vnode.type?.name ;
|
||||
const optionKey = typeMapping[typeName];
|
||||
|
||||
if (optionKey) {
|
||||
if (Array.isArray(options[optionKey])) {
|
||||
if (vnode.props.hasOwnProperty('objectHandler')) {
|
||||
(options[optionKey] as any[]).push(vnode.props.objectHandler);
|
||||
} else {
|
||||
(options[optionKey] as any[]).push(vnode.props);
|
||||
}
|
||||
}else {
|
||||
options[optionKey] = vnode.props;
|
||||
}
|
||||
}
|
||||
});
|
||||
const slotOptions = extractPivotSlotOptions(flattenedSlots);
|
||||
|
||||
return {
|
||||
...props.options,
|
||||
columns: options.columns.length ? options.columns : props.options.columns,
|
||||
columnHeaderTitle: options.columnHeaderTitle.length ? options.columnHeaderTitle : props.options.columnHeaderTitle,
|
||||
rows: options.rows.length ? options.rows : props.options.rows,
|
||||
rowHeaderTitle: options.rowHeaderTitle.length ? options.rowHeaderTitle : props.options.rowHeaderTitle,
|
||||
indicators: options.indicators.length ? options.indicators : props.options.indicators,
|
||||
corner: options.corner || props.options.corner,
|
||||
tooltip: options.tooltip || props.options.tooltip,
|
||||
menu: options.menu || props.options.menu,
|
||||
columns: slotOptions.columns.length ? slotOptions.columns : props.options.columns,
|
||||
columnHeaderTitle: slotOptions.columnHeaderTitle.length ? slotOptions.columnHeaderTitle : props.options.columnHeaderTitle,
|
||||
rows: slotOptions.rows.length ? slotOptions.rows : props.options.rows,
|
||||
rowHeaderTitle: slotOptions.rowHeaderTitle.length ? slotOptions.rowHeaderTitle : props.options.rowHeaderTitle,
|
||||
indicators: slotOptions.indicators.length ? slotOptions.indicators : props.options.indicators,
|
||||
corner: props.options.corner || slotOptions.corner,
|
||||
tooltip: props.options.tooltip || slotOptions.tooltip,
|
||||
menu: props.options.menu || slotOptions.menu,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -13,11 +13,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { shallowRef, computed, defineProps, useSlots } from 'vue';
|
||||
import { flattenVNodes , convertPropsToCamelCase } from './utils';
|
||||
import { flattenVNodes, extractPivotSlotOptions } from '../utils';
|
||||
import BaseTable from './base-table.vue';
|
||||
import type { ICornerDefine as PivotCornerProps, IIndicator as PivotIndicatorsProps, IDimension as PivotColumnDimensionProps, IDimension as PivotRowDimensionProps, ITitleDefine } from '@visactor/vtable';
|
||||
import type { TooltipProps } from '../components/component/tooltip';
|
||||
import type { MenuProps } from '../components/component/menu';
|
||||
|
||||
interface Props {
|
||||
options: Record<string, unknown>;
|
||||
@ -33,53 +30,18 @@ const slots = useSlots();
|
||||
|
||||
const computedOptions = computed(() => {
|
||||
const flattenedSlots = flattenVNodes(slots.default?.() || []);
|
||||
const slotOptions = extractPivotSlotOptions(flattenedSlots);
|
||||
|
||||
const options = {
|
||||
columns: [] as PivotColumnDimensionProps[],
|
||||
columnHeaderTitle: [] as ITitleDefine[],
|
||||
rows: [] as PivotRowDimensionProps[],
|
||||
rowHeaderTitle: [] as ITitleDefine[],
|
||||
indicators: [] as PivotIndicatorsProps[],
|
||||
corner: Object as PivotCornerProps | null,
|
||||
tooltip: Object as TooltipProps | null,
|
||||
menu: Object as MenuProps | null,
|
||||
};
|
||||
|
||||
const typeMapping: Record<string, keyof typeof options> = {
|
||||
'PivotColumnDimension': 'columns',
|
||||
'PivotColumnHeaderTitle': 'columnHeaderTitle',
|
||||
'PivotRowDimension': 'rows',
|
||||
'PivotRowHeaderTitle': 'rowHeaderTitle',
|
||||
'PivotCorner': 'corner',
|
||||
'PivotIndicator': 'indicators',
|
||||
'Tooltip': 'tooltip',
|
||||
'Menu': 'menu',
|
||||
};
|
||||
|
||||
flattenedSlots.forEach(vnode => {
|
||||
vnode.props = convertPropsToCamelCase(vnode.props);
|
||||
const typeName = vnode.type?.symbol || vnode.type?.name ;
|
||||
const optionKey = typeMapping[typeName];
|
||||
|
||||
if (optionKey) {
|
||||
if (Array.isArray(options[optionKey])) {
|
||||
(options[optionKey] as any[]).push(vnode.props);
|
||||
} else {
|
||||
options[optionKey] = vnode.props;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
...props.options,
|
||||
columns: options.columns.length ? options.columns : props.options.columns,
|
||||
columnHeaderTitle: options.columnHeaderTitle.length ? options.columnHeaderTitle : props.options.columnHeaderTitle,
|
||||
rows: options.rows.length ? options.rows : props.options.rows,
|
||||
rowHeaderTitle: options.rowHeaderTitle.length ? options.rowHeaderTitle : props.options.rowHeaderTitle,
|
||||
indicators: options.indicators.length ? options.indicators : props.options.indicators,
|
||||
corner: props.options.corner || options.corner,
|
||||
tooltip: props.options.tooltip || options.tooltip,
|
||||
menu: props.options.menu|| options.menu,
|
||||
columns: slotOptions.columns.length ? slotOptions.columns : props.options.columns,
|
||||
columnHeaderTitle: slotOptions.columnHeaderTitle.length ? slotOptions.columnHeaderTitle : props.options.columnHeaderTitle,
|
||||
rows: slotOptions.rows.length ? slotOptions.rows : props.options.rows,
|
||||
rowHeaderTitle: slotOptions.rowHeaderTitle.length ? slotOptions.rowHeaderTitle : props.options.rowHeaderTitle,
|
||||
indicators: slotOptions.indicators.length ? slotOptions.indicators : props.options.indicators,
|
||||
corner: props.options.corner || slotOptions.corner,
|
||||
tooltip: props.options.tooltip || slotOptions.tooltip,
|
||||
menu: props.options.menu || slotOptions.menu,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -1,9 +1,19 @@
|
||||
// 已经被废弃,不再使用,后续会删除 :)
|
||||
// was deprecated, no longer used, will be deleted later
|
||||
|
||||
// 已经被废弃,不再使用,后续会删除 :)
|
||||
// was deprecated, no longer used, will be deleted later
|
||||
|
||||
import * as VTable from '@visactor/vtable';
|
||||
import { isFunction, merge } from '@visactor/vutils';
|
||||
import { application, REACT_TO_CANOPUS_EVENTS } from '@visactor/vtable/es/vrender';
|
||||
import type { Graphic, IGraphic, IGraphicCreator } from '@visactor/vtable/es/vrender';
|
||||
import { CheckBox, Radio, Tag } from '@visactor/vtable/es/vrender';
|
||||
import { reactive, watch } from 'vue';
|
||||
import type { ColumnDefine, ICornerDefine, IIndicator, IDimension, ITitleDefine } from '@visactor/vtable';
|
||||
import type { TooltipProps } from '../components/component/tooltip';
|
||||
import type { MenuProps } from '../components/component/menu';
|
||||
|
||||
// import { application, REACT_TO_CANOPUS_EVENTS } from '@visactor/vtable/es/vrender';
|
||||
// import type { Graphic, IGraphic, IGraphicCreator } from '@visactor/vtable/es/vrender';
|
||||
// import { CheckBox, Radio, Tag } from '@visactor/vtable/es/vrender';
|
||||
// import { reactive, watch } from 'vue';
|
||||
|
||||
// 展平嵌套的虚拟节点
|
||||
export function flattenVNodes(vnodes: any[]): any[] {
|
||||
@ -108,3 +118,97 @@ export function createCustomLayout(children: any): any {
|
||||
// 返回root组件和refs
|
||||
return { rootComponent: createComponent(children) };
|
||||
}
|
||||
|
||||
// 创建自定义布局
|
||||
export function extractPivotSlotOptions(vnodes: any[]) {
|
||||
const options = {
|
||||
columns: [] as ColumnDefine[],
|
||||
columnHeaderTitle: [] as ITitleDefine[],
|
||||
rows: [] as IDimension[],
|
||||
rowHeaderTitle: [] as ITitleDefine[],
|
||||
indicators: [] as IIndicator[],
|
||||
corner: {} as ICornerDefine | null,
|
||||
tooltip: {} as TooltipProps | null,
|
||||
menu: {} as MenuProps | null
|
||||
};
|
||||
|
||||
const typeMapping: Record<string, keyof typeof options> = {
|
||||
PivotColumnDimension: 'columns',
|
||||
PivotColumnHeaderTitle: 'columnHeaderTitle',
|
||||
PivotRowDimension: 'rows',
|
||||
PivotRowHeaderTitle: 'rowHeaderTitle',
|
||||
PivotCorner: 'corner',
|
||||
PivotIndicator: 'indicators',
|
||||
Tooltip: 'tooltip',
|
||||
Menu: 'menu'
|
||||
};
|
||||
|
||||
vnodes.forEach(vnode => {
|
||||
vnode.props = convertPropsToCamelCase(vnode.props);
|
||||
const typeName = vnode.type?.symbol || vnode.type?.name;
|
||||
const optionKey = typeMapping[typeName];
|
||||
|
||||
if (optionKey) {
|
||||
if (Array.isArray(options[optionKey])) {
|
||||
if (vnode.props.hasOwnProperty('objectHandler')) {
|
||||
(options[optionKey] as any[]).push(vnode.props.objectHandler);
|
||||
} else {
|
||||
(options[optionKey] as any[]).push(vnode.props);
|
||||
}
|
||||
} else {
|
||||
options[optionKey] = vnode.props;
|
||||
}
|
||||
}
|
||||
});
|
||||
return options;
|
||||
}
|
||||
|
||||
function createCustomLayoutHandler(children: any) {
|
||||
return (args: any) => {
|
||||
const { table, row, col, rect } = args;
|
||||
const record = table.getCellOriginRecord(col, row);
|
||||
const { height, width } = rect ?? table.getCellRect(col, row);
|
||||
|
||||
const rootContainer = children.customLayout({ table, row, col, rect, record, height, width })[0];
|
||||
const { rootComponent } = createCustomLayout(rootContainer);
|
||||
|
||||
return {
|
||||
rootContainer: rootComponent,
|
||||
renderDefault: false
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function extractListSlotOptions(vnodes: any[]) {
|
||||
const options = {
|
||||
columns: [] as ColumnDefine[],
|
||||
tooltip: {} as TooltipProps,
|
||||
menu: {} as MenuProps
|
||||
};
|
||||
|
||||
const typeMapping: Record<string, keyof typeof options> = {
|
||||
ListColumn: 'columns',
|
||||
Tooltip: 'tooltip',
|
||||
Menu: 'menu'
|
||||
};
|
||||
|
||||
vnodes.forEach(vnode => {
|
||||
vnode.props = convertPropsToCamelCase(vnode.props);
|
||||
const typeName = vnode.type?.symbol || vnode.type?.name;
|
||||
const optionKey = typeMapping[typeName];
|
||||
|
||||
if (optionKey) {
|
||||
if (optionKey === 'columns' && vnode.children) {
|
||||
vnode.props.customLayout = createCustomLayoutHandler(vnode.children);
|
||||
}
|
||||
|
||||
if (Array.isArray(options[optionKey])) {
|
||||
(options[optionKey] as any[]).push(vnode.props);
|
||||
} else {
|
||||
options[optionKey] = vnode.props;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
4
packages/vue-vtable/src/utils.ts
Normal file
4
packages/vue-vtable/src/utils.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './utils/stringUtils';
|
||||
export * from './utils/vnodeUtils';
|
||||
export * from './utils/customLayoutUtils';
|
||||
export * from './utils/slotUtils';
|
100
packages/vue-vtable/src/utils/customLayoutUtils.ts
Normal file
100
packages/vue-vtable/src/utils/customLayoutUtils.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import * as VTable from '@visactor/vtable';
|
||||
import { convertPropsToCamelCase, toCamelCase } from './stringUtils';
|
||||
import { isFunction } from '@visactor/vutils';
|
||||
|
||||
// 检查属性是否为事件
|
||||
function isEventProp(key: string, props: any) {
|
||||
return key.startsWith('on') && isFunction(props[key]);
|
||||
}
|
||||
|
||||
// 创建自定义布局
|
||||
export function createCustomLayout(children: any): any {
|
||||
// 组件映射
|
||||
const componentMap: Record<string, any> = {
|
||||
Group: VTable.CustomLayout.Group,
|
||||
Image: VTable.CustomLayout.Image,
|
||||
Text: VTable.CustomLayout.Text,
|
||||
Tag: VTable.CustomLayout.Tag,
|
||||
Radio: VTable.CustomLayout.Radio,
|
||||
CheckBox: VTable.CustomLayout.CheckBox
|
||||
};
|
||||
|
||||
// 创建组件的函数
|
||||
function createComponent(child: any): any {
|
||||
if (!child) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { type, children: childChildren } = child;
|
||||
const props = convertPropsToCamelCase(child.props);
|
||||
const componentName = type?.symbol || type?.name;
|
||||
const ComponentClass = componentMap[componentName];
|
||||
|
||||
if (!ComponentClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 创建组件实例
|
||||
const component = new ComponentClass({ ...props });
|
||||
|
||||
// 绑定组件事件
|
||||
bindComponentEvents(component, props);
|
||||
|
||||
// 递归创建子组件
|
||||
const subChildren = resolveChildren(childChildren);
|
||||
subChildren.forEach((subChild: any) => {
|
||||
const subComponent = createComponent(subChild);
|
||||
if (subComponent) {
|
||||
component.add(subComponent);
|
||||
} else if (subChild.type === Symbol.for('v-fgt')) {
|
||||
subChild.children.forEach((nestedChild: any) => {
|
||||
const nestedComponent = createComponent(nestedChild);
|
||||
if (nestedComponent) {
|
||||
component.add(nestedComponent);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
// 处理子节点
|
||||
function resolveChildren(childChildren: any): any[] {
|
||||
return childChildren?.default?.() || childChildren || [];
|
||||
}
|
||||
|
||||
// 绑定组件事件
|
||||
function bindComponentEvents(component: any, props: any): void {
|
||||
Object.keys(props).forEach(key => {
|
||||
if (isEventProp(key, props)) {
|
||||
let eventName: string;
|
||||
if (key.startsWith('on')) {
|
||||
eventName = key.slice(2).toLowerCase(); // 去掉'on'前缀并转换为小写
|
||||
} else {
|
||||
eventName = toCamelCase(key.slice(2)).toLowerCase(); // 转换为camelCase
|
||||
}
|
||||
component.addEventListener(eventName, props[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 返回root组件和refs
|
||||
return { rootComponent: createComponent(children) };
|
||||
}
|
||||
|
||||
export function createCustomLayoutHandler(children: any) {
|
||||
return (args: any) => {
|
||||
const { table, row, col, rect } = args;
|
||||
const record = table.getCellOriginRecord(col, row);
|
||||
const { height, width } = rect ?? table.getCellRect(col, row);
|
||||
|
||||
const rootContainer = children.customLayout({ table, row, col, rect, record, height, width })[0];
|
||||
const { rootComponent } = createCustomLayout(rootContainer);
|
||||
|
||||
return {
|
||||
rootContainer: rootComponent,
|
||||
renderDefault: false
|
||||
};
|
||||
};
|
||||
}
|
82
packages/vue-vtable/src/utils/slotUtils.ts
Normal file
82
packages/vue-vtable/src/utils/slotUtils.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { convertPropsToCamelCase } from './stringUtils';
|
||||
import { createCustomLayoutHandler } from './customLayoutUtils';
|
||||
import type { ColumnDefine, ICornerDefine, IIndicator, IDimension, ITitleDefine } from '@visactor/vtable';
|
||||
import type { TooltipProps } from '../components/component/tooltip';
|
||||
import type { MenuProps } from '../components/component/menu';
|
||||
|
||||
export function extractPivotSlotOptions(vnodes: any[]) {
|
||||
const options = {
|
||||
columns: [] as ColumnDefine[],
|
||||
columnHeaderTitle: [] as ITitleDefine[],
|
||||
rows: [] as IDimension[],
|
||||
rowHeaderTitle: [] as ITitleDefine[],
|
||||
indicators: [] as IIndicator[],
|
||||
corner: {} as ICornerDefine | null,
|
||||
tooltip: {} as TooltipProps | null,
|
||||
menu: {} as MenuProps | null
|
||||
};
|
||||
|
||||
const typeMapping: Record<string, keyof typeof options> = {
|
||||
PivotColumnDimension: 'columns',
|
||||
PivotColumnHeaderTitle: 'columnHeaderTitle',
|
||||
PivotRowDimension: 'rows',
|
||||
PivotRowHeaderTitle: 'rowHeaderTitle',
|
||||
PivotCorner: 'corner',
|
||||
PivotIndicator: 'indicators',
|
||||
Tooltip: 'tooltip',
|
||||
Menu: 'menu'
|
||||
};
|
||||
|
||||
vnodes.forEach(vnode => {
|
||||
vnode.props = convertPropsToCamelCase(vnode.props);
|
||||
const typeName = vnode.type?.symbol || vnode.type?.name;
|
||||
const optionKey = typeMapping[typeName];
|
||||
|
||||
if (optionKey) {
|
||||
if (Array.isArray(options[optionKey])) {
|
||||
if (vnode.props.hasOwnProperty('objectHandler')) {
|
||||
(options[optionKey] as any[]).push(vnode.props.objectHandler);
|
||||
} else {
|
||||
(options[optionKey] as any[]).push(vnode.props);
|
||||
}
|
||||
} else {
|
||||
options[optionKey] = vnode.props;
|
||||
}
|
||||
}
|
||||
});
|
||||
return options;
|
||||
}
|
||||
|
||||
export function extractListSlotOptions(vnodes: any[]) {
|
||||
const options = {
|
||||
columns: [] as ColumnDefine[],
|
||||
tooltip: {} as TooltipProps,
|
||||
menu: {} as MenuProps
|
||||
};
|
||||
|
||||
const typeMapping: Record<string, keyof typeof options> = {
|
||||
ListColumn: 'columns',
|
||||
Tooltip: 'tooltip',
|
||||
Menu: 'menu'
|
||||
};
|
||||
|
||||
vnodes.forEach(vnode => {
|
||||
vnode.props = convertPropsToCamelCase(vnode.props);
|
||||
const typeName = vnode.type?.symbol || vnode.type?.name;
|
||||
const optionKey = typeMapping[typeName];
|
||||
|
||||
if (optionKey) {
|
||||
if (optionKey === 'columns' && vnode.children) {
|
||||
vnode.props.customLayout = createCustomLayoutHandler(vnode.children);
|
||||
}
|
||||
|
||||
if (Array.isArray(options[optionKey])) {
|
||||
(options[optionKey] as any[]).push(vnode.props);
|
||||
} else {
|
||||
options[optionKey] = vnode.props;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
16
packages/vue-vtable/src/utils/stringUtils.ts
Normal file
16
packages/vue-vtable/src/utils/stringUtils.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// 将连字符形式的字符串转换为驼峰形式
|
||||
export function toCamelCase(str: string): string {
|
||||
return str.replace(/-([a-z])/g, g => g[1].toUpperCase());
|
||||
}
|
||||
|
||||
// 将 vnode.props 中的所有属性名转换为驼峰形式
|
||||
export function convertPropsToCamelCase(props: Record<string, any>): Record<string, any> {
|
||||
const newProps: Record<string, any> = {};
|
||||
for (const key in props) {
|
||||
if (props.hasOwnProperty(key)) {
|
||||
const camelCaseKey = toCamelCase(key);
|
||||
newProps[camelCaseKey] = props[key];
|
||||
}
|
||||
}
|
||||
return newProps;
|
||||
}
|
4
packages/vue-vtable/src/utils/vnodeUtils.ts
Normal file
4
packages/vue-vtable/src/utils/vnodeUtils.ts
Normal file
@ -0,0 +1,4 @@
|
||||
// 展平嵌套的虚拟节点
|
||||
export function flattenVNodes(vnodes: any[]): any[] {
|
||||
return vnodes.flatMap(vnode => (Array.isArray(vnode.children) ? flattenVNodes(vnode.children) : vnode));
|
||||
}
|
Loading…
Reference in New Issue
Block a user