Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(form): add merge form functionality #4495

Merged
merged 24 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4b460d4
feat: captcha example
Squall2017 Sep 6, 2024
1689c27
Merge pull request #1 from vbenjs/main
Squall2017 Sep 6, 2024
d973765
fix: fix lint errors
Squall2017 Sep 6, 2024
a2e56d8
chore: event handling and methods
Squall2017 Sep 7, 2024
185c623
chore: add accessibility features ARIA labels and roles
Squall2017 Sep 7, 2024
f6d4351
Merge branch 'main' into main
vince292007 Sep 7, 2024
04cde6a
Merge branch 'main' of github.com:vbenjs/vue-vben-admin into vbenjs-main
Squall2017 Sep 9, 2024
2d44bd8
Merge branch 'vbenjs-main'
Squall2017 Sep 9, 2024
18ee871
Merge pull request #3 from vbenjs/main
Squall2017 Sep 12, 2024
b06b57a
Merge pull request #4 from vbenjs/main
Squall2017 Sep 12, 2024
d95633a
refactor: refactor code structure and improve captcha demo page
Squall2017 Sep 13, 2024
c55375d
feat: add captcha internationalization
Squall2017 Sep 13, 2024
fe2080d
chore: 适配时间戳国际化展示
Squall2017 Sep 14, 2024
c202641
fix: 1. 添加点击位置边界校验,防止点击外部导致x,y误差。2. 演示页面宽度过长添加滚动条。3. 添加hooks
Squall2017 Sep 14, 2024
0ceabbe
Merge branch 'main' of github.com:vbenjs/vue-vben-admin
Squall2017 Sep 14, 2024
54e3d70
Merge branch 'main' into main
vince292007 Sep 14, 2024
a490762
Merge branch 'main' of github.com:vbenjs/vue-vben-admin into vbenjs-main
Squall2017 Sep 21, 2024
f956412
Merge branch 'vbenjs-main'
Squall2017 Sep 21, 2024
b281534
Merge branch 'vbenjs:main' into main
Squall2017 Sep 23, 2024
e5e5a10
Merge branch 'vbenjs:main' into main
Squall2017 Sep 23, 2024
14b12f2
feat: sync test
Squall2017 Sep 23, 2024
5c63056
feat: 代码合并
Squall2017 Sep 24, 2024
344eb5f
feat: 添加合并表单功能
Squall2017 Sep 24, 2024
87eeb79
fix: 修复上一步不展示问题
Squall2017 Sep 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions packages/@core/ui-kit/form-ui/src/form-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,47 @@ export class FormApi {
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;
}),
Squall2017 marked this conversation as resolved.
Show resolved Hide resolved
);
if (needMerge) {
const mergedResults = Object.assign({}, ...results);
return mergedResults;
Squall2017 marked this conversation as resolved.
Show resolved Hide resolved
}
return results;
} catch (error) {
console.error('Validation error:', error);
}
Squall2017 marked this conversation as resolved.
Show resolved Hide resolved
};
}
return target[prop];
},
});

return proxy;
}

mount(formActions: FormActions) {
if (!this.isMounted) {
Object.assign(this.form, formActions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export function useCaptchaPoints() {
function addPoint(point: CaptchaPoint) {
points.push(point);
}

function clearPoints() {
points.splice(0, points.length);
}
Expand Down
3 changes: 2 additions & 1 deletion playground/src/locales/langs/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
"rules": "Form Rules",
"dynamic": "Dynamic Form",
"custom": "Custom Component",
"api": "Api"
"api": "Api",
"merge": "Merge Form"
},
"captcha": {
"title": "Captcha",
Expand Down
3 changes: 2 additions & 1 deletion playground/src/locales/langs/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
"rules": "表单校验",
"dynamic": "动态表单",
"custom": "自定义组件",
"api": "Api"
"api": "Api",
"merge": "合并表单"
},
"captcha": {
"title": "验证码",
Expand Down
8 changes: 8 additions & 0 deletions playground/src/router/routes/modules/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ const routes: RouteRecordRaw[] = [
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'),
},
},
],
},
{
Expand Down
116 changes: 116 additions & 0 deletions playground/src/views/examples/form/merge.vue
Original file line number Diff line number Diff line change
@@ -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',
});
Squall2017 marked this conversation as resolved.
Show resolved Hide resolved
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)}`,
});
}
Squall2017 marked this conversation as resolved.
Show resolved Hide resolved
</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>