Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin
This commit is contained in:
commit
be54bfb2b7
@ -7,6 +7,7 @@ import {
|
|||||||
ElMessage,
|
ElMessage,
|
||||||
ElNotification,
|
ElNotification,
|
||||||
ElSpace,
|
ElSpace,
|
||||||
|
ElTable,
|
||||||
} from 'element-plus';
|
} from 'element-plus';
|
||||||
|
|
||||||
type NotificationType = 'error' | 'info' | 'success' | 'warning';
|
type NotificationType = 'error' | 'info' | 'success' | 'warning';
|
||||||
@ -38,6 +39,14 @@ function notify(type: NotificationType) {
|
|||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const tableData = [
|
||||||
|
{ prop1: '1', prop2: 'A' },
|
||||||
|
{ prop1: '2', prop2: 'B' },
|
||||||
|
{ prop1: '3', prop2: 'C' },
|
||||||
|
{ prop1: '4', prop2: 'D' },
|
||||||
|
{ prop1: '5', prop2: 'E' },
|
||||||
|
{ prop1: '6', prop2: 'F' },
|
||||||
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -74,5 +83,11 @@ function notify(type: NotificationType) {
|
|||||||
<ElButton type="success" @click="notify('success')"> 成功 </ElButton>
|
<ElButton type="success" @click="notify('success')"> 成功 </ElButton>
|
||||||
</ElSpace>
|
</ElSpace>
|
||||||
</ElCard>
|
</ElCard>
|
||||||
|
<ElCard class="mb-5">
|
||||||
|
<ElTable :data="tableData" stripe>
|
||||||
|
<ElTable.TableColumn label="测试列1" prop="prop1" />
|
||||||
|
<ElTable.TableColumn label="测试列2" prop="prop2" />
|
||||||
|
</ElTable>
|
||||||
|
</ElCard>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
@ -229,7 +229,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` |
|
| submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` |
|
||||||
| resetForm | 重置表单 | `()=>Promise<void>` |
|
| resetForm | 重置表单 | `()=>Promise<void>` |
|
||||||
| setValues | 设置表单值 | `()=>Promise<Record<string,any>>` |
|
| setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record<string, any>, filterFields?: boolean, shouldValidate?: boolean) => Promise<void>` |
|
||||||
| getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` |
|
| getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` |
|
||||||
| validate | 表单校验 | `()=>Promise<void>` |
|
| validate | 表单校验 | `()=>Promise<void>` |
|
||||||
| resetValidate | 重置表单校验 | `()=>Promise<void>` |
|
| resetValidate | 重置表单校验 | `()=>Promise<void>` |
|
||||||
|
@ -29,6 +29,7 @@ const shadcnUiColors = {
|
|||||||
DEFAULT: 'hsl(var(--accent))',
|
DEFAULT: 'hsl(var(--accent))',
|
||||||
foreground: 'hsl(var(--accent-foreground))',
|
foreground: 'hsl(var(--accent-foreground))',
|
||||||
hover: 'hsl(var(--accent-hover))',
|
hover: 'hsl(var(--accent-hover))',
|
||||||
|
lighter: 'has(val(--accent-lighter))',
|
||||||
},
|
},
|
||||||
background: {
|
background: {
|
||||||
deep: 'hsl(var(--background-deep))',
|
deep: 'hsl(var(--background-deep))',
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
|
|
||||||
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
||||||
--accent: 216 5% 19%;
|
--accent: 216 5% 19%;
|
||||||
|
--accent-lighter: 216 5% 11%;
|
||||||
--accent-hover: 216 5% 24%;
|
--accent-hover: 216 5% 24%;
|
||||||
--accent-foreground: 0 0% 98%;
|
--accent-foreground: 0 0% 98%;
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
|
|
||||||
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
||||||
--accent: 240 5% 96%;
|
--accent: 240 5% 96%;
|
||||||
|
--accent-lighter: 240 0% 98%;
|
||||||
--accent-hover: 200deg 10% 90%;
|
--accent-hover: 200deg 10% 90%;
|
||||||
--accent-foreground: 240 6% 10%;
|
--accent-foreground: 240 6% 10%;
|
||||||
|
|
||||||
|
@ -123,6 +123,47 @@ export class FormApi {
|
|||||||
return form.values;
|
return form.values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
merge(formApi: FormApi) {
|
||||||
|
const chain = [this, formApi];
|
||||||
|
const proxy = new Proxy(formApi, {
|
||||||
|
get(target: any, prop: any) {
|
||||||
|
if (prop === 'merge') {
|
||||||
|
return (nextFormApi: FormApi) => {
|
||||||
|
chain.push(nextFormApi);
|
||||||
|
return proxy;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (prop === 'submitAllForm') {
|
||||||
|
return async (needMerge: boolean = true) => {
|
||||||
|
try {
|
||||||
|
const results = await Promise.all(
|
||||||
|
chain.map(async (api) => {
|
||||||
|
const form = await api.getForm();
|
||||||
|
const validateResult = await api.validate();
|
||||||
|
if (!validateResult.valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rawValues = toRaw(form.values || {});
|
||||||
|
return rawValues;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
if (needMerge) {
|
||||||
|
const mergedResults = Object.assign({}, ...results);
|
||||||
|
return mergedResults;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Validation error:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return target[prop];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
mount(formActions: FormActions) {
|
mount(formActions: FormActions) {
|
||||||
if (!this.isMounted) {
|
if (!this.isMounted) {
|
||||||
Object.assign(this.form, formActions);
|
Object.assign(this.form, formActions);
|
||||||
|
@ -7,6 +7,7 @@ export function useCaptchaPoints() {
|
|||||||
function addPoint(point: CaptchaPoint) {
|
function addPoint(point: CaptchaPoint) {
|
||||||
points.push(point);
|
points.push(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearPoints() {
|
function clearPoints() {
|
||||||
points.splice(0, points.length);
|
points.splice(0, points.length);
|
||||||
}
|
}
|
||||||
|
@ -257,6 +257,7 @@ export function useElementPlusDesignTokens() {
|
|||||||
'--el-fill-color': getCssVariableValue('--accent'),
|
'--el-fill-color': getCssVariableValue('--accent'),
|
||||||
'--el-fill-color-blank': background,
|
'--el-fill-color-blank': background,
|
||||||
'--el-fill-color-light': getCssVariableValue('--accent'),
|
'--el-fill-color-light': getCssVariableValue('--accent'),
|
||||||
|
'--el-fill-color-lighter': getCssVariableValue('--accent-lighter'),
|
||||||
'--el-text-color-primary': getCssVariableValue('--foreground'),
|
'--el-text-color-primary': getCssVariableValue('--foreground'),
|
||||||
|
|
||||||
'--el-text-color-regular': getCssVariableValue('--foreground'),
|
'--el-text-color-regular': getCssVariableValue('--foreground'),
|
||||||
|
@ -79,7 +79,8 @@
|
|||||||
"rules": "Form Rules",
|
"rules": "Form Rules",
|
||||||
"dynamic": "Dynamic Form",
|
"dynamic": "Dynamic Form",
|
||||||
"custom": "Custom Component",
|
"custom": "Custom Component",
|
||||||
"api": "Api"
|
"api": "Api",
|
||||||
|
"merge": "Merge Form"
|
||||||
},
|
},
|
||||||
"captcha": {
|
"captcha": {
|
||||||
"title": "Captcha",
|
"title": "Captcha",
|
||||||
|
@ -79,7 +79,8 @@
|
|||||||
"rules": "表单校验",
|
"rules": "表单校验",
|
||||||
"dynamic": "动态表单",
|
"dynamic": "动态表单",
|
||||||
"custom": "自定义组件",
|
"custom": "自定义组件",
|
||||||
"api": "Api"
|
"api": "Api",
|
||||||
|
"merge": "合并表单"
|
||||||
},
|
},
|
||||||
"captcha": {
|
"captcha": {
|
||||||
"title": "验证码",
|
"title": "验证码",
|
||||||
|
@ -99,6 +99,14 @@ const routes: RouteRecordRaw[] = [
|
|||||||
title: $t('page.examples.form.api'),
|
title: $t('page.examples.form.api'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'FormMergeExample',
|
||||||
|
path: '/examples/form/merge',
|
||||||
|
component: () => import('#/views/examples/form/merge.vue'),
|
||||||
|
meta: {
|
||||||
|
title: $t('page.examples.form.merge'),
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
116
playground/src/views/examples/form/merge.vue
Normal file
116
playground/src/views/examples/form/merge.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import { Page } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { Button, Card, message, Step, Steps, Switch } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { useVbenForm } from '#/adapter';
|
||||||
|
|
||||||
|
const currentTab = ref(0);
|
||||||
|
function onFirstSubmit(values: Record<string, any>) {
|
||||||
|
message.success({
|
||||||
|
content: `form1 values: ${JSON.stringify(values)}`,
|
||||||
|
});
|
||||||
|
currentTab.value = 1;
|
||||||
|
}
|
||||||
|
function onSecondReset() {
|
||||||
|
currentTab.value = 0;
|
||||||
|
}
|
||||||
|
function onSecondSubmit(values: Record<string, any>) {
|
||||||
|
message.success({
|
||||||
|
content: `form2 values: ${JSON.stringify(values)}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const [FirstForm, firstFormApi] = useVbenForm({
|
||||||
|
commonConfig: {
|
||||||
|
componentProps: {
|
||||||
|
class: 'w-full',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handleSubmit: onFirstSubmit,
|
||||||
|
layout: 'horizontal',
|
||||||
|
resetButtonOptions: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入',
|
||||||
|
},
|
||||||
|
fieldName: 'formFirst',
|
||||||
|
label: '表单1字段',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
submitButtonOptions: {
|
||||||
|
text: '下一步',
|
||||||
|
},
|
||||||
|
wrapperClass: 'grid-cols-1 md:grid-cols-1 lg:grid-cols-1',
|
||||||
|
});
|
||||||
|
const [SecondForm, secondFormApi] = useVbenForm({
|
||||||
|
commonConfig: {
|
||||||
|
componentProps: {
|
||||||
|
class: 'w-full',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handleReset: onSecondReset,
|
||||||
|
handleSubmit: onSecondSubmit,
|
||||||
|
layout: 'horizontal',
|
||||||
|
resetButtonOptions: {
|
||||||
|
text: '上一步',
|
||||||
|
},
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入',
|
||||||
|
},
|
||||||
|
fieldName: 'formSecond',
|
||||||
|
label: '表单2字段',
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
wrapperClass: 'grid-cols-1 md:grid-cols-1 lg:grid-cols-1',
|
||||||
|
});
|
||||||
|
const needMerge = ref(true);
|
||||||
|
async function handleMergeSubmit() {
|
||||||
|
const values = await firstFormApi
|
||||||
|
.merge(secondFormApi)
|
||||||
|
.submitAllForm(needMerge.value);
|
||||||
|
message.success({
|
||||||
|
content: `merged form values: ${JSON.stringify(values)}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Page
|
||||||
|
description="表单组件合并示例:在某些场景下,例如分步表单,需要合并多个表单并统一提交。默认情况下,使用 Object.assign 规则合并表单。如果需要特殊处理数据,可以传入 false。"
|
||||||
|
title="表单组件"
|
||||||
|
>
|
||||||
|
<Card title="基础示例">
|
||||||
|
<template #extra>
|
||||||
|
<Switch
|
||||||
|
v-model:checked="needMerge"
|
||||||
|
checked-children="开启字段合并"
|
||||||
|
class="mr-4"
|
||||||
|
un-checked-children="关闭字段合并"
|
||||||
|
/>
|
||||||
|
<Button type="primary" @click="handleMergeSubmit">合并提交</Button>
|
||||||
|
</template>
|
||||||
|
<div class="mx-auto max-w-lg">
|
||||||
|
<Steps :current="currentTab" class="steps">
|
||||||
|
<Step title="表单1" />
|
||||||
|
<Step title="表单2" />
|
||||||
|
</Steps>
|
||||||
|
<div class="p-20">
|
||||||
|
<FirstForm v-show="currentTab === 0" />
|
||||||
|
<SecondForm v-show="currentTab === 1" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Page>
|
||||||
|
</template>
|
Loading…
Reference in New Issue
Block a user