From 6f18718c879a56a619719ee3ed81885500935994 Mon Sep 17 00:00:00 2001 From: allen <495141992@qq.com> Date: Mon, 13 Apr 2026 19:20:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20add=20collapsible=20=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=EF=BC=8Cform=E8=A1=A8=E5=8D=95=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E9=A1=B9=E5=8F=AF=E6=8A=98=E5=8F=A0=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?schema=E9=85=8D=E7=BD=AE=E9=BB=98=E8=AE=A4=E5=85=B3=E9=97=AD/?= =?UTF-8?q?=E5=BC=80=E5=90=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: add collapsible 组件,form表单增加单项可折叠,支持schema配置默认关闭/开启 - shadcn-ui 增加 collapsible组件,collapsible-params组件 - form新增支持单项折叠 - collapsible-params组件在Form表单应用 --- apps/web-naive/package.json | 1 + apps/web-naive/src/views/demos/form/basic.vue | 169 ++++++++++++- packages/@core/base/icons/src/lucide.ts | 1 + .../form-ui/src/components/form-actions.vue | 4 - .../form-ui/src/form-render/form-field.vue | 160 +++++++----- .../form-ui/src/form-render/form-label.vue | 1 + packages/@core/ui-kit/form-ui/src/types.ts | 9 + .../collapsible/collapsible-params-item.vue | 98 ++++++++ .../collapsible/collapsible-params.vue | 230 ++++++++++++++++++ .../components/collapsible/collapsible.vue | 77 ++++++ .../src/components/collapsible/index.ts | 4 + .../src/components/collapsible/type.ts | 15 ++ .../ui-kit/shadcn-ui/src/components/index.ts | 1 + .../src/locales/langs/en-US/examples.json | 3 +- .../src/locales/langs/zh-CN/examples.json | 3 +- .../src/router/routes/modules/examples.ts | 8 + .../src/views/examples/form/collapsible.vue | 210 ++++++++++++++++ pnpm-lock.yaml | 3 + 18 files changed, 929 insertions(+), 68 deletions(-) create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue create mode 100755 packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue create mode 100755 packages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts create mode 100644 playground/src/views/examples/form/collapsible.vue diff --git a/apps/web-naive/package.json b/apps/web-naive/package.json index e7ab20bab..d8940c0d1 100644 --- a/apps/web-naive/package.json +++ b/apps/web-naive/package.json @@ -26,6 +26,7 @@ "#/*": "./src/*" }, "dependencies": { + "@vben-core/shadcn-ui": "workspace:*", "@vben/access": "workspace:*", "@vben/common-ui": "workspace:*", "@vben/constants": "workspace:*", diff --git a/apps/web-naive/src/views/demos/form/basic.vue b/apps/web-naive/src/views/demos/form/basic.vue index 60702a11e..0dcf9bc30 100644 --- a/apps/web-naive/src/views/demos/form/basic.vue +++ b/apps/web-naive/src/views/demos/form/basic.vue @@ -1,7 +1,19 @@ - + + + + 设置表单值 打开弹窗 diff --git a/packages/@core/base/icons/src/lucide.ts b/packages/@core/base/icons/src/lucide.ts index ce7e930e6..9aa0ad4f7 100644 --- a/packages/@core/base/icons/src/lucide.ts +++ b/packages/@core/base/icons/src/lucide.ts @@ -16,6 +16,7 @@ export { ChevronDown, ChevronLeft, ChevronRight, + ChevronsDown, ChevronsLeft, ChevronsRight, Circle, diff --git a/packages/@core/ui-kit/form-ui/src/components/form-actions.vue b/packages/@core/ui-kit/form-ui/src/components/form-actions.vue index 36b1caa0c..d09e1a606 100644 --- a/packages/@core/ui-kit/form-ui/src/components/form-actions.vue +++ b/packages/@core/ui-kit/form-ui/src/components/form-actions.vue @@ -30,10 +30,6 @@ const submitButtonOptions = computed(() => { }; }); -// const isQueryForm = computed(() => { -// return !!unref(rootProps).showCollapseButton; -// }); - async function handleSubmit(e: Event) { e?.preventDefault(); e?.stopPropagation(); diff --git a/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue b/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue index e630b7996..89efd08b9 100644 --- a/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue +++ b/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue @@ -7,15 +7,24 @@ import type { MaybeComponentProps, } from '../types'; -import { computed, nextTick, onUnmounted, useTemplateRef, watch } from 'vue'; - -import { CircleAlert } from '@vben-core/icons'; import { + computed, + nextTick, + onUnmounted, + ref, + useTemplateRef, + watch, +} from 'vue'; + +import { ChevronsDown, CircleAlert } from '@vben-core/icons'; +import { + Button, FormControl, FormDescription, FormField, FormItem, FormMessage, + VbenCollapsible, VbenRenderContent, VbenTooltip, } from '@vben-core/shadcn-ui'; @@ -53,6 +62,8 @@ const { renderComponentContent, rules, help, + collapsible, + defaultCollapsed = false, } = defineProps< Props & { commonComponentProps: MaybeComponentProps; @@ -67,6 +78,7 @@ const fieldComponentRef = useTemplateRef('fieldComponentRef'); const formApi = formRenderProps.form; const compact = computed(() => formRenderProps.compact); const isInValid = computed(() => errors.value?.length > 0); +const collapseOpen = ref(!defaultCollapsed); function getFormApi(): FormActions { if (!formApi) { @@ -296,6 +308,15 @@ function autofocus() { fieldComponentRef.value?.focus?.(); } } + +const shouldCollapsible = computed(() => { + return collapsible; /* && isVertical.value; */ +}); + +function toggleCollapsed() { + collapseOpen.value = !collapseOpen.value; +} + const componentRefMap = injectComponentRefMap(); watch(fieldComponentRef, (componentRef) => { componentRefMap?.set(fieldName, componentRef); @@ -335,6 +356,7 @@ onUnmounted(() => { { 'mr-2 shrink-0 justify-end': !isVertical, 'mb-1 flex-row': isVertical, + 'self-start': shouldCollapsible && !isVertical, }, labelClass, ) @@ -348,65 +370,87 @@ onUnmounted(() => { + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue b/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue index c206717f2..71a3d8c58 100644 --- a/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue +++ b/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue @@ -26,6 +26,7 @@ const props = defineProps(); + : diff --git a/packages/@core/ui-kit/form-ui/src/types.ts b/packages/@core/ui-kit/form-ui/src/types.ts index 78114ee30..754aa3f60 100644 --- a/packages/@core/ui-kit/form-ui/src/types.ts +++ b/packages/@core/ui-kit/form-ui/src/types.ts @@ -145,6 +145,10 @@ type ComponentProps = | MaybeComponentProps; export interface FormCommonConfig { + /** + * 是否可折叠的 + */ + collapsible?: boolean; /** * 在Label后显示一个冒号 */ @@ -157,6 +161,11 @@ export interface FormCommonConfig { * 所有表单项的控件样式 */ controlClass?: string; + /** + * 默认折叠 + * @default false + */ + defaultCollapsed?: boolean; /** * 所有表单项的禁用状态 * @default false diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue new file mode 100644 index 000000000..e1ba939f1 --- /dev/null +++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue @@ -0,0 +1,98 @@ + + + + + {{ data.key }} + + + + + + + [{{ data.option.min }},{{ data.option.max }}] + + + step:{{ data.option.step }} + + + + + + {{ data.description }} + + + + + diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue new file mode 100644 index 000000000..9417369a3 --- /dev/null +++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue @@ -0,0 +1,230 @@ + + + + + + + + 参数名称 + 配置 + 说明 + + + + onParamValueChange(v, row.key)" + /> + + onParamValueChange(v, row.key)" + /> + + + + + + + + + {{ open ? '收起' : '展开' }} + + + + + diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue new file mode 100755 index 000000000..1ac1d7f78 --- /dev/null +++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.ts b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.ts new file mode 100755 index 000000000..8563a7e59 --- /dev/null +++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.ts @@ -0,0 +1,4 @@ +export { default as VbenCollapsibleParams } from './collapsible-params.vue'; +export { default as VbenCollapsible } from './collapsible.vue'; + +export * from './type'; diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts new file mode 100644 index 000000000..a89edf765 --- /dev/null +++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts @@ -0,0 +1,15 @@ +export interface CollapsibleParamOption { + [key: string]: any; + max?: number; + min?: number; + precision?: number; + step?: number; + type: 'exponential' | 'number' | 'select' | 'string'; +} + +export interface CollapsibleParamSchema { + defaultValue: number | number[] | string | string[]; + description: string; + key: string; + option: CollapsibleParamOption; +} diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/index.ts b/packages/@core/ui-kit/shadcn-ui/src/components/index.ts index 6b2c7fc17..be157b887 100644 --- a/packages/@core/ui-kit/shadcn-ui/src/components/index.ts +++ b/packages/@core/ui-kit/shadcn-ui/src/components/index.ts @@ -3,6 +3,7 @@ export * from './back-top'; export * from './breadcrumb'; export * from './button'; export * from './checkbox'; +export * from './collapsible'; export * from './context-menu'; export * from './count-to-animator'; export * from './dropdown-menu'; diff --git a/playground/src/locales/langs/en-US/examples.json b/playground/src/locales/langs/en-US/examples.json index d60062174..00ff67ab9 100644 --- a/playground/src/locales/langs/en-US/examples.json +++ b/playground/src/locales/langs/en-US/examples.json @@ -25,7 +25,8 @@ "upload-urls": "Urls after file upload", "file": "file", "crop-image": "Crop image", - "upload-image": "Click to upload image" + "upload-image": "Click to upload image", + "collapsible": "Collapsible FormItem Content" }, "vxeTable": { "title": "Vxe Table", diff --git a/playground/src/locales/langs/zh-CN/examples.json b/playground/src/locales/langs/zh-CN/examples.json index 6a5be2358..e260016ec 100644 --- a/playground/src/locales/langs/zh-CN/examples.json +++ b/playground/src/locales/langs/zh-CN/examples.json @@ -28,7 +28,8 @@ "upload-urls": "文件上传后的网址", "file": "文件", "crop-image": "裁剪图片", - "upload-image": "点击上传图片" + "upload-image": "点击上传图片", + "collapsible": "单项表单折叠" }, "vxeTable": { "title": "Vxe 表格", diff --git a/playground/src/router/routes/modules/examples.ts b/playground/src/router/routes/modules/examples.ts index 5bac90ac3..38f25e2d3 100644 --- a/playground/src/router/routes/modules/examples.ts +++ b/playground/src/router/routes/modules/examples.ts @@ -102,6 +102,14 @@ const routes: RouteRecordRaw[] = [ title: $t('examples.form.scrollToError'), }, }, + { + name: 'FormCollapsibleExample', + path: '/examples/form/collapsible-test', + component: () => import('#/views/examples/form/collapsible.vue'), + meta: { + title: $t('examples.form.collapsible'), + }, + }, ], }, { diff --git a/playground/src/views/examples/form/collapsible.vue b/playground/src/views/examples/form/collapsible.vue new file mode 100644 index 000000000..caaf82390 --- /dev/null +++ b/playground/src/views/examples/form/collapsible.vue @@ -0,0 +1,210 @@ + + + + + + + 可折叠表单项、以及可折叠参数配置组件示例 + + + + + + + + + + 设置表单值 + + 设置表单值 + + + + + + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6cddeb9f7..e432a6623 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -848,6 +848,9 @@ importers: apps/web-naive: dependencies: + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../../packages/@core/ui-kit/shadcn-ui '@vben/access': specifier: workspace:* version: link:../../packages/effects/access
+ {{ data.description }} +
可折叠表单项、以及可折叠参数配置组件示例