mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-02-02 18:28:40 +08:00
perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime (#4842)
* perf: formApi added validateAndSubmitForm & filedMapToTime renamed fieldMappingTime
This commit is contained in:
parent
632081e828
commit
8617d3dd1e
@ -280,6 +280,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单
|
|||||||
| 方法名 | 描述 | 类型 |
|
| 方法名 | 描述 | 类型 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` |
|
| submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` |
|
||||||
|
| validateAndSubmitForm | 提交并校验表单 | `(e:Event)=>Promise<Record<string,any>>` |
|
||||||
| resetForm | 重置表单 | `()=>Promise<void>` |
|
| resetForm | 重置表单 | `()=>Promise<void>` |
|
||||||
| setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record<string, any>, filterFields?: boolean, shouldValidate?: boolean) => Promise<void>` |
|
| 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>` |
|
||||||
@ -309,6 +310,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单
|
|||||||
| collapsed | 是否折叠,在`是否展开,在showCollapseButton=true`时生效 | `boolean` | `false` |
|
| collapsed | 是否折叠,在`是否展开,在showCollapseButton=true`时生效 | `boolean` | `false` |
|
||||||
| collapseTriggerResize | 折叠时,触发`resize`事件 | `boolean` | `false` |
|
| collapseTriggerResize | 折叠时,触发`resize`事件 | `boolean` | `false` |
|
||||||
| collapsedRows | 折叠时保持的行数 | `number` | `1` |
|
| collapsedRows | 折叠时保持的行数 | `number` | `1` |
|
||||||
|
| fieldMappingTime | 用于将表单内时间区域的应设成 2 个字段 | `[string, [string, string], string?][]` | - |
|
||||||
| commonConfig | 表单项的通用配置,每个配置都会传递到每个表单项,表单项可覆盖 | `FormCommonConfig` | - |
|
| commonConfig | 表单项的通用配置,每个配置都会传递到每个表单项,表单项可覆盖 | `FormCommonConfig` | - |
|
||||||
| schema | 表单项的每一项配置 | `FormSchema` | - |
|
| schema | 表单项的每一项配置 | `FormSchema` | - |
|
||||||
| submitOnEnter | 按下回车健时提交表单 | `boolean` | false |
|
| submitOnEnter | 按下回车健时提交表单 | `boolean` | false |
|
||||||
|
@ -84,6 +84,7 @@
|
|||||||
"@types/lodash.get": "catalog:",
|
"@types/lodash.get": "catalog:",
|
||||||
"@vue/shared": "catalog:",
|
"@vue/shared": "catalog:",
|
||||||
"clsx": "catalog:",
|
"clsx": "catalog:",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"defu": "catalog:",
|
"defu": "catalog:",
|
||||||
"lodash.clonedeep": "catalog:",
|
"lodash.clonedeep": "catalog:",
|
||||||
"lodash.get": "catalog:",
|
"lodash.get": "catalog:",
|
||||||
|
18
packages/@core/base/shared/src/utils/date.ts
Normal file
18
packages/@core/base/shared/src/utils/date.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
|
||||||
|
try {
|
||||||
|
const date = dayjs(time);
|
||||||
|
if (!date.isValid()) {
|
||||||
|
throw new Error('Invalid date');
|
||||||
|
}
|
||||||
|
return date.format(format);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error formatting date: ${error}`);
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatDateTime(time: number | string) {
|
||||||
|
return formatDate(time, 'YYYY-MM-DD HH:mm:ss');
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
export * from './cn';
|
export * from './cn';
|
||||||
|
export * from './date';
|
||||||
export * from './diff';
|
export * from './diff';
|
||||||
export * from './dom';
|
export * from './dom';
|
||||||
export * from './inference';
|
export * from './inference';
|
||||||
|
@ -3,7 +3,12 @@ import { computed, toRaw, unref, watch } from 'vue';
|
|||||||
|
|
||||||
import { useSimpleLocale } from '@vben-core/composables';
|
import { useSimpleLocale } from '@vben-core/composables';
|
||||||
import { VbenExpandableArrow } from '@vben-core/shadcn-ui';
|
import { VbenExpandableArrow } from '@vben-core/shadcn-ui';
|
||||||
import { cn, isFunction, triggerWindowResize } from '@vben-core/shared/utils';
|
import {
|
||||||
|
cn,
|
||||||
|
formatDate,
|
||||||
|
isFunction,
|
||||||
|
triggerWindowResize,
|
||||||
|
} from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { COMPONENT_MAP } from '../config';
|
import { COMPONENT_MAP } from '../config';
|
||||||
import { injectFormProps } from '../use-form-context';
|
import { injectFormProps } from '../use-form-context';
|
||||||
@ -64,8 +69,8 @@ async function handleReset(e: Event) {
|
|||||||
|
|
||||||
const values = toRaw(form.values);
|
const values = toRaw(form.values);
|
||||||
// 清理时间字段
|
// 清理时间字段
|
||||||
props.fieldMapToTime &&
|
props.fieldMappingTime &&
|
||||||
props.fieldMapToTime.forEach(([_, [startTimeKey, endTimeKey]]) => {
|
props.fieldMappingTime.forEach(([_, [startTimeKey, endTimeKey]]) => {
|
||||||
delete values[startTimeKey];
|
delete values[startTimeKey];
|
||||||
delete values[endTimeKey];
|
delete values[endTimeKey];
|
||||||
});
|
});
|
||||||
@ -78,15 +83,13 @@ async function handleReset(e: Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleRangeTimeValue(values: Record<string, any>) {
|
function handleRangeTimeValue(values: Record<string, any>) {
|
||||||
const fieldMapToTime = unref(rootProps).fieldMapToTime;
|
const fieldMappingTime = unref(rootProps).fieldMappingTime;
|
||||||
|
|
||||||
if (!fieldMapToTime) return values;
|
if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) {
|
||||||
|
|
||||||
if (!Array.isArray(fieldMapToTime)) {
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldMapToTime.forEach(
|
fieldMappingTime.forEach(
|
||||||
([field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD']) => {
|
([field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD']) => {
|
||||||
if (!values[field]) {
|
if (!values[field]) {
|
||||||
delete values[field];
|
delete values[field];
|
||||||
@ -99,10 +102,10 @@ function handleRangeTimeValue(values: Record<string, any>) {
|
|||||||
: [format, format];
|
: [format, format];
|
||||||
|
|
||||||
values[startTimeKey] = startTime
|
values[startTimeKey] = startTime
|
||||||
? formatTime(startTime, startTimeFormat)
|
? formatDate(startTime, startTimeFormat)
|
||||||
: undefined;
|
: undefined;
|
||||||
values[endTimeKey] = endTime
|
values[endTimeKey] = endTime
|
||||||
? formatTime(endTime, endTimeFormat)
|
? formatDate(endTime, endTimeFormat)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
delete values[field];
|
delete values[field];
|
||||||
@ -112,32 +115,6 @@ function handleRangeTimeValue(values: Record<string, any>) {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTime(time: string, format: string): number | string {
|
|
||||||
const date = new Date(time);
|
|
||||||
const timestamp = (date: Date) => Math.floor(date.getTime() / 1000);
|
|
||||||
|
|
||||||
if (format === 'timestamp') return timestamp(date);
|
|
||||||
if (format === 'timestampStartDay')
|
|
||||||
return timestamp(
|
|
||||||
new Date(date.getFullYear(), date.getMonth(), date.getDate()),
|
|
||||||
);
|
|
||||||
|
|
||||||
const padZero = (num: number) => num.toString().padStart(2, '0');
|
|
||||||
const replacements: Record<string, string> = {
|
|
||||||
DD: padZero(date.getDate()),
|
|
||||||
HH: padZero(date.getHours()),
|
|
||||||
MM: padZero(date.getMonth() + 1),
|
|
||||||
mm: padZero(date.getMinutes()),
|
|
||||||
ss: padZero(date.getSeconds()),
|
|
||||||
YYYY: date.getFullYear().toString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return format.replaceAll(
|
|
||||||
/YYYY|MM|DD|HH|mm|ss/g,
|
|
||||||
(match) => replacements[match] || match,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => collapsed.value,
|
() => collapsed.value,
|
||||||
() => {
|
() => {
|
||||||
|
@ -303,4 +303,13 @@ export class FormApi {
|
|||||||
}
|
}
|
||||||
return validateResult;
|
return validateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async validateAndSubmitForm() {
|
||||||
|
const form = await this.getForm();
|
||||||
|
const { valid } = await form.validate();
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return await this.submitForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ export type HandleResetFn = (
|
|||||||
values: Record<string, any>,
|
values: Record<string, any>,
|
||||||
) => Promise<void> | void;
|
) => Promise<void> | void;
|
||||||
|
|
||||||
export type FieldMapToTime = [
|
export type FieldMappingTime = [
|
||||||
string,
|
string,
|
||||||
[string, string],
|
[string, string],
|
||||||
([string, string] | string)?,
|
([string, string] | string)?,
|
||||||
@ -272,10 +272,6 @@ export interface FormRenderProps<
|
|||||||
* 组件集合
|
* 组件集合
|
||||||
*/
|
*/
|
||||||
componentMap: Record<BaseFormComponentType, Component>;
|
componentMap: Record<BaseFormComponentType, Component>;
|
||||||
/**
|
|
||||||
* 表单字段映射成时间格式
|
|
||||||
*/
|
|
||||||
fieldMapToTime?: FieldMapToTime;
|
|
||||||
/**
|
/**
|
||||||
* 表单实例
|
* 表单实例
|
||||||
*/
|
*/
|
||||||
@ -315,6 +311,10 @@ export interface VbenFormProps<
|
|||||||
* 表单操作区域class
|
* 表单操作区域class
|
||||||
*/
|
*/
|
||||||
actionWrapperClass?: ClassType;
|
actionWrapperClass?: ClassType;
|
||||||
|
/**
|
||||||
|
* 表单字段映射成时间格式
|
||||||
|
*/
|
||||||
|
fieldMappingTime?: FieldMappingTime;
|
||||||
/**
|
/**
|
||||||
* 表单重置回调
|
* 表单重置回调
|
||||||
*/
|
*/
|
||||||
|
@ -2,9 +2,7 @@ import type { VxeGridProps, VxeUIExport } from 'vxe-table';
|
|||||||
|
|
||||||
import type { VxeGridApi } from './api';
|
import type { VxeGridApi } from './api';
|
||||||
|
|
||||||
import { isFunction } from '@vben/utils';
|
import { formatDate, formatDateTime, isFunction } from '@vben/utils';
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
|
|
||||||
export function extendProxyOptions(
|
export function extendProxyOptions(
|
||||||
api: VxeGridApi,
|
api: VxeGridApi,
|
||||||
@ -54,13 +52,13 @@ function extendProxyOption(
|
|||||||
export function extendsDefaultFormatter(vxeUI: VxeUIExport) {
|
export function extendsDefaultFormatter(vxeUI: VxeUIExport) {
|
||||||
vxeUI.formats.add('formatDate', {
|
vxeUI.formats.add('formatDate', {
|
||||||
tableCellFormatMethod({ cellValue }) {
|
tableCellFormatMethod({ cellValue }) {
|
||||||
return dayjs(cellValue).format('YYYY-MM-DD');
|
return formatDate(cellValue);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
vxeUI.formats.add('formatDateTime', {
|
vxeUI.formats.add('formatDateTime', {
|
||||||
tableCellFormatMethod({ cellValue }) {
|
tableCellFormatMethod({ cellValue }) {
|
||||||
return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss');
|
return formatDateTime(cellValue);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,10 @@ const [BaseForm, baseFormApi] = useVbenForm({
|
|||||||
class: 'w-full',
|
class: 'w-full',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fieldMappingTime: [['rangePicker', ['startTime', 'endTime'], 'YYYY-MM-DD']],
|
||||||
// 提交函数
|
// 提交函数
|
||||||
handleSubmit: onSubmit,
|
handleSubmit: onSubmit,
|
||||||
|
|
||||||
// 垂直布局,label和input在不同行,值为vertical
|
// 垂直布局,label和input在不同行,值为vertical
|
||||||
// 水平布局,label和input在同一行
|
// 水平布局,label和input在同一行
|
||||||
layout: 'horizontal',
|
layout: 'horizontal',
|
||||||
|
@ -57,8 +57,8 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
modalApi.close();
|
modalApi.close();
|
||||||
},
|
},
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await formApi.submitForm();
|
await formApi.validateAndSubmitForm();
|
||||||
modalApi.close();
|
// modalApi.close();
|
||||||
},
|
},
|
||||||
onOpenChange(isOpen: boolean) {
|
onOpenChange(isOpen: boolean) {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
@ -8,7 +8,7 @@ import AutoHeightDemo from './auto-height-demo.vue';
|
|||||||
import BaseDemo from './base-demo.vue';
|
import BaseDemo from './base-demo.vue';
|
||||||
import DragDemo from './drag-demo.vue';
|
import DragDemo from './drag-demo.vue';
|
||||||
import DynamicDemo from './dynamic-demo.vue';
|
import DynamicDemo from './dynamic-demo.vue';
|
||||||
import FormModalDemo from './form-model-demo.vue';
|
import FormModalDemo from './form-modal-demo.vue';
|
||||||
import SharedDataDemo from './shared-data-demo.vue';
|
import SharedDataDemo from './shared-data-demo.vue';
|
||||||
|
|
||||||
const [BaseModal, baseModalApi] = useVbenModal({
|
const [BaseModal, baseModalApi] = useVbenModal({
|
||||||
|
@ -21,7 +21,6 @@ interface RowType {
|
|||||||
const formOptions: VbenFormProps = {
|
const formOptions: VbenFormProps = {
|
||||||
// 默认展开
|
// 默认展开
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
fieldMapToTime: [['dateRangePicker', ['startTime', 'endTime'], 'YYYY-MM']],
|
|
||||||
schema: [
|
schema: [
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
@ -63,11 +62,6 @@ const formOptions: VbenFormProps = {
|
|||||||
fieldName: 'datePicker',
|
fieldName: 'datePicker',
|
||||||
label: 'Date',
|
label: 'Date',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
component: 'RangePicker',
|
|
||||||
fieldName: 'dateRangePicker',
|
|
||||||
label: 'DateRange',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
// 控制表单是否显示折叠按钮
|
// 控制表单是否显示折叠按钮
|
||||||
showCollapseButton: true,
|
showCollapseButton: true,
|
||||||
|
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@ -1209,6 +1209,9 @@ importers:
|
|||||||
clsx:
|
clsx:
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 2.1.1
|
version: 2.1.1
|
||||||
|
dayjs:
|
||||||
|
specifier: ^1.11.13
|
||||||
|
version: 1.11.13
|
||||||
defu:
|
defu:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 6.1.4
|
version: 6.1.4
|
||||||
|
Loading…
Reference in New Issue
Block a user