From bb9cb64c6473536bcd48c65865d5dc682d8c20d7 Mon Sep 17 00:00:00 2001 From: xingyu4j Date: Tue, 21 Oct 2025 16:39:15 +0800 Subject: [PATCH] refactor: refactor naive desc comp --- .../components/description/description.vue | 248 +++++++++++++----- .../src/components/description/typing.ts | 54 ++-- .../components/description/use-description.ts | 80 ++---- 3 files changed, 237 insertions(+), 145 deletions(-) diff --git a/apps/web-naive/src/components/description/description.vue b/apps/web-naive/src/components/description/description.vue index ef0239933..51f0df4d3 100644 --- a/apps/web-naive/src/components/description/description.vue +++ b/apps/web-naive/src/components/description/description.vue @@ -1,80 +1,198 @@ diff --git a/apps/web-naive/src/components/description/typing.ts b/apps/web-naive/src/components/description/typing.ts index 7aadf72dd..9ee489678 100644 --- a/apps/web-naive/src/components/description/typing.ts +++ b/apps/web-naive/src/components/description/typing.ts @@ -1,27 +1,41 @@ -import type { DescriptionsProps } from 'naive-ui'; +import type { DescriptionsProps as NDescriptionsProps } from 'naive-ui'; +import type { JSX } from 'vue/jsx-runtime'; import type { CSSProperties, VNode } from 'vue'; -// TODO @xingyu:【content】这个纠结下;1)vben2.0 是 render;https://doc.vvbin.cn/components/desc.html#usage 2) -// TODO @xingyu:vben2.0 还有 sapn【done】、labelMinWidth、contentMinWidth -// TODO @xingyu:【hidden】这个纠结下;1)vben2.0 是 show; +import type { Recordable } from '@vben/types'; + export interface DescriptionItemSchema { - label: string | VNode; // 内容的描述 - field?: string; // 对应 data 中的字段名 - content?: ((data: any) => string | VNode) | string | VNode; // 自定义需要展示的内容,比如说 dict-tag - span?: number; // 包含列的数量 - labelStyle?: CSSProperties; // 自定义标签样式 - contentStyle?: CSSProperties; // 自定义内容样式 - hidden?: ((data: any) => boolean) | boolean; // 是否显示 + labelMinWidth?: number; + contentMinWidth?: number; + // 自定义标签样式 + labelStyle?: CSSProperties; + // 对应 data 中的字段名 + field: string; + // 内容的描述 + label: JSX.Element | string | VNode; + // 包含列的数量 + span?: number; + // 是否显示 + show?: (...arg: any) => boolean; + // 插槽名称 + slot?: string; + // 自定义需要展示的内容 + render?: ( + val: any, + data?: Recordable, + ) => Element | JSX.Element | number | string | undefined | VNode; } -// TODO @xingyu:vben2.0 还有 title【done】、bordered【done】d、useCollapse、collapseOptions -// TODO @xingyu:from 5.0:bordered 默认为 true -// TODO @xingyu:from 5.0:column 默认为 lg: 3, md: 3, sm: 2, xl: 3, xs: 1, xxl: 4 -// TODO @xingyu:from 5.0:size 默认为 small;有 'default', 'middle', 'small', undefined -// TODO @xingyu:from 5.0:useCollapse 默认为 true -export interface DescriptionsOptions { - data?: Record; // 数据 - schema?: DescriptionItemSchema[]; // 描述项配置 - componentProps?: DescriptionsProps; // antd Descriptions 组件参数 +export interface DescriptionProps extends NDescriptionsProps { + // 是否包含卡片组件 + useCard?: boolean; + // 描述项配置 + schema: DescriptionItemSchema[]; + // 数据 + data: Recordable; +} + +export interface DescInstance { + setDescProps(descProps: Partial): void; } diff --git a/apps/web-naive/src/components/description/use-description.ts b/apps/web-naive/src/components/description/use-description.ts index 7f99238bf..fd24920f0 100644 --- a/apps/web-naive/src/components/description/use-description.ts +++ b/apps/web-naive/src/components/description/use-description.ts @@ -1,71 +1,31 @@ -import type { DescriptionsOptions } from './typing'; +import type { Component } from 'vue'; -import { defineComponent, h, isReactive, reactive, watch } from 'vue'; +import type { DescInstance, DescriptionProps } from './typing'; + +import { h, reactive } from 'vue'; import Description from './description.vue'; -/** 描述列表 api 定义 */ -class DescriptionApi { - private state = reactive>({}); +export function useDescription(options?: Partial) { + const propsState = reactive>(options || {}); - constructor(options: DescriptionsOptions) { - this.state = { ...options }; - } + const api: DescInstance = { + setDescProps: (descProps: Partial): void => { + Object.assign(propsState, descProps); + }, + }; - getState(): DescriptionsOptions { - return this.state as DescriptionsOptions; - } - - // TODO @xingyu:【setState】纠结下:1)vben2.0 是 data https://doc.vvbin.cn/components/desc.html#usage; - setState(newState: Partial) { - this.state = { ...this.state, ...newState }; - } -} - -export type ExtendedDescriptionApi = DescriptionApi; - -export function useDescription(options: DescriptionsOptions) { - const IS_REACTIVE = isReactive(options); - const api = new DescriptionApi(options); - // 扩展 API - const extendedApi: ExtendedDescriptionApi = api as never; - const Desc = defineComponent({ + // 创建一个包装组件,将 propsState 合并到 props 中 + const DescriptionWrapper: Component = { name: 'UseDescription', inheritAttrs: false, - setup(_, { attrs, slots }) { - // 合并props和attrs到state - api.setState({ ...attrs }); - - return () => - h( - Description, - { - ...api.getState(), - ...attrs, - }, - slots, - ); + setup(_props, { attrs, slots }) { + return () => { + // @ts-ignore - 避免类型实例化过深 + return h(Description, { ...propsState, ...attrs }, slots); + }; }, - }); + }; - // 响应式支持 - if (IS_REACTIVE) { - watch( - () => options.schema, - (newSchema) => { - api.setState({ schema: newSchema }); - }, - { immediate: true, deep: true }, - ); - - watch( - () => options.data, - (newData) => { - api.setState({ data: newData }); - }, - { immediate: true, deep: true }, - ); - } - - return [Desc, extendedApi] as const; + return [DescriptionWrapper, api] as const; }