feat: add collapsible 组件,form表单增加单项可折叠,支持schema配置默认关闭/开启

feat: add collapsible 组件,form表单增加单项可折叠,支持schema配置默认关闭/开启
- shadcn-ui 增加 collapsible组件,collapsible-params组件
- form新增支持单项折叠
- collapsible-params组件在Form表单应用
This commit is contained in:
allen
2026-04-13 19:20:01 +08:00
parent 2a32715c99
commit 6f18718c87
18 changed files with 929 additions and 68 deletions

View File

@@ -1,7 +1,19 @@
<script lang="ts" setup>
import { Page, useVbenModal } from '@vben/common-ui';
import type { CollapsibleParamSchema } from '@vben-core/shadcn-ui';
import { NButton, NCard, useMessage } from 'naive-ui';
import { ref } from 'vue';
import { Page, useVbenModal, z } from '@vben/common-ui';
import { VbenCollapsibleParams } from '@vben-core/shadcn-ui';
import {
NButton,
NCard,
NRadioButton,
NRadioGroup,
useMessage,
} from 'naive-ui';
import { useVbenForm } from '#/adapter/form';
import { getAllMenusApi } from '#/api';
@@ -9,6 +21,111 @@ import { getAllMenusApi } from '#/api';
import modalDemo from './modal.vue';
const message = useMessage();
const layouts = [
{ label: 'Vertical', value: 'vertical' },
{ label: 'Horizontal', value: 'horizontal' },
{ label: 'Inline', value: 'inline' },
];
const layout = ref(layouts[0].value);
function getNumberValidator(key: string, limit?: [number, number]) {
const validator = z.number({
required_error: `${key} 值不能为空`,
invalid_type_error: `${key} 值只能为数字`,
});
if (limit) {
validator.min(limit[0], { message: `${key} 值不在区间范围内` });
validator.max(limit[1], { message: `${key} 值不在区间范围内` });
}
return validator;
}
const paramsSchema = [
{
key: 'micro_batch_size',
description: `批次大小,代表模型训练过程中,模型更新模型参数的数据步长,可理解为模型每看多少数据即更新一次模型参数,
一般建议的批次大小为16/32表示模型每看16或32条数据即更新一次参数`,
// defaultValue: 8,
option: {
min: 8,
max: 1024,
step: 8,
},
},
{
key: 'learning_rate',
description:
'学习率,代表每次更新数据的增量参数权重,学习率数值越大参数变化越大,对模型影响越大',
// defaultValue: 1e-5,
option: {
step: 1e-4,
type: 'exponential',
},
},
{
key: 'eval_steps',
description:
'验证步数,训练阶段针模型的验证间隔步长,用于阶段性评估模型训练准确率、训练损失',
// defaultValue: 50,
option: {
min: 1,
max: 2_147_483_647,
},
},
{
key: 'num_train_epochs',
description:
'循环次数代表模型训练过程中模型学习数据集的次数可理解为看几遍数据一般建议的范围是1-3遍即可可依据需求进行调整',
// defaultValue: 3,
option: {
min: 1,
max: 200,
},
},
{
key: 'max_length',
description: `序列长度,单个训练数据样本的最大长度,超出配置长度将丢弃`,
// defaultValue: 32_768,
option: {
min: 500,
max: 131_072,
},
},
{
key: 'warmup_ratio',
description: '学习率预热比例,学习率预热阶段占总训练步数的比例',
// defaultValue: 0.05,
option: {
min: 0,
max: 1,
precision: 2,
step: 0.01,
},
},
{
key: 'save_steps',
description: 'Checkpoint保存间隔',
// defaultValue: 50,
option: {
min: 1,
max: 2_147_483_647,
},
},
] as CollapsibleParamSchema[];
const paramsValidator = z.object({
micro_batch_size: getNumberValidator('micro_batch_size', [8, 1024]),
learning_rate: getNumberValidator('learning_rate'),
eval_steps: getNumberValidator('eval_steps', [1, 2_147_483_647]),
num_train_epochs: getNumberValidator('num_train_epochs', [1, 200]),
max_length: getNumberValidator('max_length', [1, 131_072]),
warmup_ratio: getNumberValidator('warmup_ratio', [0, 1]),
save_steps: getNumberValidator('save_steps', [1, 2_147_483_647]),
});
const [Form, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
@@ -16,7 +133,7 @@ const [Form, formApi] = useVbenForm({
class: 'w-full',
},
},
layout: 'horizontal',
layout: 'vertical',
// 大屏一行显示3个中屏一行显示2个小屏一行显示1个
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
handleSubmit: (values) => {
@@ -133,8 +250,29 @@ const [Form, formApi] = useVbenForm({
},
rules: 'required',
},
{
component: 'Input',
fieldName: 'collapsibleTextArea',
label: 'vertical时可折叠',
componentProps: {
type: 'textarea',
},
collapsible: true,
},
{
component: VbenCollapsibleParams,
componentProps: {
params: paramsSchema,
},
modelPropName: 'value',
fieldName: 'params',
label: '参数配置',
formItemClass: 'col-span-2',
rules: paramsValidator,
},
],
});
function setFormValues() {
formApi.setValues({
string: 'string',
@@ -143,20 +281,43 @@ function setFormValues() {
radioButton: 'C',
checkbox: ['A', 'C'],
date: Date.now(),
params: {
micro_batch_size: 8,
learning_rate: 1e-5,
eval_steps: 50,
num_train_epochs: 3,
max_length: 32_768,
warmup_ratio: 0.05,
save_steps: 50,
},
});
}
const [Modal, modalApi] = useVbenModal({
connectedComponent: modalDemo,
});
function onLayoutChange(layout: string) {
formApi.setState({
layout,
});
}
</script>
<template>
<Page
description="表单适配器重新包装了CheckboxGroup和RadioGroup可以通过options属性传递选项数据选项数据将作为子组件的属性"
title="表单演示"
>
<NCard title="基础表单">
<NCard title="基础表单" header-extra-class="gap-4">
<template #header-extra>
<NRadioGroup v-model:value="layout" @update:value="onLayoutChange">
<NRadioButton
v-for="layoutItem in layouts"
:key="layoutItem.value"
:value="layoutItem.value"
:label="layoutItem.label"
/>
</NRadioGroup>
<NButton type="primary" @click="setFormValues">设置表单值</NButton>
<NButton type="primary" @click="modalApi.open()" class="ml-2">
打开弹窗