mirror of
https://github.com/imdap/ruoyi-plus-vben5.git
synced 2026-05-11 05:02:10 +08:00
feat: add collapsible 组件,form表单增加单项可折叠,支持schema配置默认关闭/开启
feat: add collapsible 组件,form表单增加单项可折叠,支持schema配置默认关闭/开启 - shadcn-ui 增加 collapsible组件,collapsible-params组件 - form新增支持单项折叠 - collapsible-params组件在Form表单应用
This commit is contained in:
@@ -30,10 +30,6 @@ const submitButtonOptions = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
// const isQueryForm = computed(() => {
|
||||
// return !!unref(rootProps).showCollapseButton;
|
||||
// });
|
||||
|
||||
async function handleSubmit(e: Event) {
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
|
||||
@@ -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<HTMLInputElement>('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(() => {
|
||||
<template v-if="label">
|
||||
<VbenRenderContent :content="label" />
|
||||
</template>
|
||||
<template #extra>
|
||||
<Button
|
||||
class="ml-0.5"
|
||||
variant="icon"
|
||||
size="icon"
|
||||
@click.prevent="toggleCollapsed"
|
||||
v-if="shouldCollapsible"
|
||||
>
|
||||
<ChevronsDown
|
||||
:size="16"
|
||||
class="transition-transform"
|
||||
:class="{
|
||||
'rotate-180': !collapseOpen,
|
||||
}"
|
||||
/>
|
||||
</Button>
|
||||
</template>
|
||||
</FormLabel>
|
||||
<div class="flex-auto overflow-hidden p-px">
|
||||
<div :class="cn('relative flex w-full items-center', wrapperClass)">
|
||||
<FormControl :class="cn(controlClass)">
|
||||
<slot
|
||||
v-bind="{
|
||||
...slotProps,
|
||||
...createComponentProps(slotProps),
|
||||
disabled: shouldDisabled,
|
||||
isInValid,
|
||||
}"
|
||||
>
|
||||
<component
|
||||
:is="FieldComponent"
|
||||
ref="fieldComponentRef"
|
||||
:class="{
|
||||
'border-destructive hover:border-destructive/80 focus:border-destructive focus:shadow-[0_0_0_2px_rgba(255,38,5,0.06)]':
|
||||
<VbenCollapsible :show-trigger="false" v-model:open="collapseOpen">
|
||||
<template #collapsibleContent>
|
||||
<div :class="cn('relative flex w-full items-center', wrapperClass)">
|
||||
<FormControl :class="cn(controlClass)">
|
||||
<slot
|
||||
v-bind="{
|
||||
...slotProps,
|
||||
...createComponentProps(slotProps),
|
||||
disabled: shouldDisabled,
|
||||
isInValid,
|
||||
}"
|
||||
v-bind="createComponentProps(slotProps)"
|
||||
:disabled="shouldDisabled"
|
||||
>
|
||||
<template
|
||||
v-for="name in renderContentKey"
|
||||
:key="name"
|
||||
#[name]="renderSlotProps"
|
||||
}"
|
||||
>
|
||||
<VbenRenderContent
|
||||
:content="customContentRender[name]"
|
||||
v-bind="{ ...renderSlotProps, formContext: slotProps }"
|
||||
/>
|
||||
</template>
|
||||
<!-- <slot></slot> -->
|
||||
</component>
|
||||
<VbenTooltip
|
||||
v-if="compact && isInValid"
|
||||
:delay-duration="300"
|
||||
side="left"
|
||||
>
|
||||
<template #trigger>
|
||||
<slot name="trigger">
|
||||
<CircleAlert
|
||||
:class="
|
||||
cn(
|
||||
'inline-flex size-5 cursor-pointer text-foreground/80 hover:text-foreground',
|
||||
)
|
||||
"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
<FormMessage />
|
||||
</VbenTooltip>
|
||||
</slot>
|
||||
</FormControl>
|
||||
<!-- 自定义后缀 -->
|
||||
<div v-if="suffix" class="ml-1">
|
||||
<VbenRenderContent :content="suffix" />
|
||||
</div>
|
||||
</div>
|
||||
<component
|
||||
:is="FieldComponent"
|
||||
ref="fieldComponentRef"
|
||||
:class="{
|
||||
'border-destructive hover:border-destructive/80 focus:border-destructive focus:shadow-[0_0_0_2px_rgba(255,38,5,0.06)]':
|
||||
isInValid,
|
||||
}"
|
||||
v-bind="createComponentProps(slotProps)"
|
||||
:disabled="shouldDisabled"
|
||||
>
|
||||
<template
|
||||
v-for="name in renderContentKey"
|
||||
:key="name"
|
||||
#[name]="renderSlotProps"
|
||||
>
|
||||
<VbenRenderContent
|
||||
:content="customContentRender[name]"
|
||||
v-bind="{ ...renderSlotProps, formContext: slotProps }"
|
||||
/>
|
||||
</template>
|
||||
<!-- <slot></slot> -->
|
||||
</component>
|
||||
<VbenTooltip
|
||||
v-if="compact && isInValid"
|
||||
:delay-duration="300"
|
||||
side="left"
|
||||
>
|
||||
<template #trigger>
|
||||
<slot name="trigger">
|
||||
<CircleAlert
|
||||
:class="
|
||||
cn(
|
||||
'inline-flex size-5 cursor-pointer text-foreground/80 hover:text-foreground',
|
||||
)
|
||||
"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
<FormMessage />
|
||||
</VbenTooltip>
|
||||
</slot>
|
||||
</FormControl>
|
||||
<!-- 自定义后缀 -->
|
||||
<div v-if="suffix" class="ml-1">
|
||||
<VbenRenderContent :content="suffix" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</VbenCollapsible>
|
||||
|
||||
<FormDescription v-if="description" class="text-xs">
|
||||
<VbenRenderContent :content="description" />
|
||||
</FormDescription>
|
||||
|
||||
@@ -26,6 +26,7 @@ const props = defineProps<Props>();
|
||||
<VbenHelpTooltip v-if="help" trigger-class="size-3.5 ml-1">
|
||||
<VbenRenderContent :content="help" />
|
||||
</VbenHelpTooltip>
|
||||
<slot name="extra"></slot>
|
||||
<span v-if="colon && label" class="ml-0.5">:</span>
|
||||
</FormLabel>
|
||||
</template>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user