Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin
This commit is contained in:
@@ -4,6 +4,7 @@ import type {
|
||||
VbenFormProps,
|
||||
} from '@vben/common-ui';
|
||||
|
||||
import type { Component, SetupContext } from 'vue';
|
||||
import { h } from 'vue';
|
||||
|
||||
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
||||
@@ -57,6 +58,16 @@ export type FormComponentType =
|
||||
| 'Upload'
|
||||
| BaseFormComponentType;
|
||||
|
||||
const withDefaultPlaceholder = <T extends Component>(
|
||||
component: T,
|
||||
type: 'input' | 'select',
|
||||
) => {
|
||||
return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
|
||||
const placeholder = props?.placeholder || $t(`placeholder.${type}`);
|
||||
return h(component, { ...props, ...attrs, placeholder }, slots);
|
||||
};
|
||||
};
|
||||
|
||||
// 初始化表单组件,并注册到form组件内部
|
||||
setupVbenForm<FormComponentType>({
|
||||
components: {
|
||||
@@ -73,20 +84,20 @@ setupVbenForm<FormComponentType>({
|
||||
return h(Button, { ...props, attrs, type: 'primary' }, slots);
|
||||
},
|
||||
Divider,
|
||||
Input,
|
||||
InputNumber,
|
||||
InputPassword,
|
||||
Mentions,
|
||||
Input: withDefaultPlaceholder(Input, 'input'),
|
||||
InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
|
||||
InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
|
||||
Mentions: withDefaultPlaceholder(Mentions, 'input'),
|
||||
Radio,
|
||||
RadioGroup,
|
||||
RangePicker,
|
||||
Rate,
|
||||
Select,
|
||||
Select: withDefaultPlaceholder(Select, 'select'),
|
||||
Space,
|
||||
Switch,
|
||||
Textarea,
|
||||
Textarea: withDefaultPlaceholder(Textarea, 'input'),
|
||||
TimePicker,
|
||||
TreeSelect,
|
||||
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
|
||||
Upload,
|
||||
},
|
||||
config: {
|
||||
|
@@ -223,6 +223,75 @@ const [BaseForm, baseFormApi] = useVbenForm({
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
||||
});
|
||||
|
||||
const [CustomLayoutForm] = useVbenForm({
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
// 所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{
|
||||
component: 'Select',
|
||||
fieldName: 'field1',
|
||||
label: '字符串',
|
||||
},
|
||||
{
|
||||
component: 'TreeSelect',
|
||||
fieldName: 'field2',
|
||||
label: '字符串',
|
||||
},
|
||||
{
|
||||
component: 'Mentions',
|
||||
fieldName: 'field3',
|
||||
label: '字符串',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'field4',
|
||||
label: '字符串',
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'field5',
|
||||
// 从第三列开始 相当于中间空了一列
|
||||
formItemClass: 'col-start-3',
|
||||
label: '前面空了一列',
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
fieldName: 'field6',
|
||||
// 占满三列空间 基线对齐
|
||||
formItemClass: 'col-span-3 items-baseline',
|
||||
label: '占满三列',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'field7',
|
||||
// 占满2列空间 从第二列开始 相当于前面空了一列
|
||||
formItemClass: 'col-span-2 col-start-2',
|
||||
label: '占满2列',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'field8',
|
||||
// 左右留空
|
||||
formItemClass: 'col-start-2',
|
||||
label: '左右留空',
|
||||
},
|
||||
{
|
||||
component: 'InputPassword',
|
||||
fieldName: 'field9',
|
||||
formItemClass: 'col-start-1',
|
||||
label: '字符串',
|
||||
},
|
||||
],
|
||||
// 一共三列
|
||||
wrapperClass: 'grid-cols-3',
|
||||
});
|
||||
|
||||
function onSubmit(values: Record<string, any>) {
|
||||
message.success({
|
||||
content: `form values: ${JSON.stringify(values)}`,
|
||||
@@ -256,6 +325,7 @@ function handleSetFormValue() {
|
||||
|
||||
<template>
|
||||
<Page
|
||||
content-class="flex flex-col gap-4"
|
||||
description="表单组件基础示例,请注意,该页面用到的参数代码会添加一些简单注释,方便理解,请仔细查看。"
|
||||
title="表单组件"
|
||||
>
|
||||
@@ -265,5 +335,8 @@ function handleSetFormValue() {
|
||||
</template>
|
||||
<BaseForm />
|
||||
</Card>
|
||||
<Card title="使用tailwind自定义布局">
|
||||
<CustomLayoutForm />
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
||||
|
@@ -175,6 +175,47 @@ const [Form, formApi] = useVbenForm({
|
||||
label: '密码',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'input-blur',
|
||||
formFieldProps: {
|
||||
validateOnChange: false,
|
||||
validateOnModelUpdate: false,
|
||||
},
|
||||
help: 'blur时才会触发校验',
|
||||
label: 'blur触发',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'input-async',
|
||||
label: '异步校验',
|
||||
rules: z
|
||||
.string()
|
||||
.min(3, '用户名至少需要3个字符')
|
||||
.refine(
|
||||
async (username) => {
|
||||
// 假设这是一个异步函数,模拟检查用户名是否已存在
|
||||
const checkUsernameExists = async (
|
||||
username: string,
|
||||
): Promise<boolean> => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return username === 'existingUser';
|
||||
};
|
||||
const exists = await checkUsernameExists(username);
|
||||
return !exists;
|
||||
},
|
||||
{
|
||||
message: '用户名已存在',
|
||||
},
|
||||
),
|
||||
},
|
||||
],
|
||||
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
||||
|
Reference in New Issue
Block a user