mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 16:46:19 +08:00
fix(form): form validate error
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
- form: 新增`suffix`属性,用于配置后缀内容
|
- form: 新增`suffix`属性,用于配置后缀内容
|
||||||
- form: 新增远程下拉`ApiSelect`及示例
|
- form: 新增远程下拉`ApiSelect`及示例
|
||||||
- form: 新增`autoFocusFirstItem`配置。用于配置是否聚焦表单第一个输入框
|
- form: 新增`autoFocusFirstItem`配置。用于配置是否聚焦表单第一个输入框
|
||||||
|
- useForm: 支持动态改变参数。可以传入`Ref`类型与`Computed`类型进行动态更改
|
||||||
|
|
||||||
### ⚡ Performance Improvements
|
### ⚡ Performance Improvements
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
|
|
||||||
### 🎫 Chores
|
### 🎫 Chores
|
||||||
|
|
||||||
- 升级`ant-design-vue`到`2.0.0-rc.6`
|
- 升级`ant-design-vue`到`2.0.0-rc.7`
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconify/iconify": "^2.0.0-rc.4",
|
"@iconify/iconify": "^2.0.0-rc.4",
|
||||||
"@vueuse/core": "^4.0.1",
|
"@vueuse/core": "^4.0.1",
|
||||||
"ant-design-vue": "^2.0.0-rc.6",
|
"ant-design-vue": "^2.0.0-rc.7",
|
||||||
"apexcharts": "^3.23.0",
|
"apexcharts": "^3.23.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"crypto-es": "^1.2.6",
|
"crypto-es": "^1.2.6",
|
||||||
|
@@ -31,14 +31,24 @@
|
|||||||
import type { AdvanceState } from './types/hooks';
|
import type { AdvanceState } from './types/hooks';
|
||||||
import type { CSSProperties, Ref, WatchStopHandle } from 'vue';
|
import type { CSSProperties, Ref, WatchStopHandle } from 'vue';
|
||||||
|
|
||||||
import { defineComponent, reactive, ref, computed, unref, onMounted, watch, toRefs } from 'vue';
|
import {
|
||||||
|
defineComponent,
|
||||||
|
reactive,
|
||||||
|
ref,
|
||||||
|
computed,
|
||||||
|
unref,
|
||||||
|
onMounted,
|
||||||
|
watch,
|
||||||
|
toRefs,
|
||||||
|
toRaw,
|
||||||
|
} from 'vue';
|
||||||
import { Form, Row } from 'ant-design-vue';
|
import { Form, Row } from 'ant-design-vue';
|
||||||
import FormItem from './components/FormItem';
|
import FormItem from './components/FormItem';
|
||||||
import FormAction from './components/FormAction.vue';
|
import FormAction from './components/FormAction.vue';
|
||||||
|
|
||||||
import { dateItemType } from './helper';
|
import { dateItemType } from './helper';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { cloneDeep } from 'lodash-es';
|
// import { cloneDeep } from 'lodash-es';
|
||||||
import { deepMerge } from '/@/utils';
|
import { deepMerge } from '/@/utils';
|
||||||
|
|
||||||
import { useFormValues } from './hooks/useFormValues';
|
import { useFormValues } from './hooks/useFormValues';
|
||||||
@@ -76,7 +86,7 @@
|
|||||||
// Get the basic configuration of the form
|
// Get the basic configuration of the form
|
||||||
const getProps = computed(
|
const getProps = computed(
|
||||||
(): FormProps => {
|
(): FormProps => {
|
||||||
return deepMerge(cloneDeep(props), unref(propsRef));
|
return { ...props, ...unref(propsRef) } as FormProps;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -38,7 +38,7 @@
|
|||||||
type: String as PropType<string>,
|
type: String as PropType<string>,
|
||||||
},
|
},
|
||||||
api: {
|
api: {
|
||||||
type: Function as PropType<(arg: Recordable) => Promise<OptionsItem[]>>,
|
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
|
@@ -1,15 +1,19 @@
|
|||||||
import { ref, onUnmounted, unref, nextTick } from 'vue';
|
import { ref, onUnmounted, unref, nextTick, watchEffect } from 'vue';
|
||||||
|
|
||||||
import { isInSetup } from '/@/utils/helper/vueHelper';
|
import { isInSetup } from '/@/utils/helper/vueHelper';
|
||||||
import { isProdMode } from '/@/utils/env';
|
import { isProdMode } from '/@/utils/env';
|
||||||
import { error } from '/@/utils/log';
|
import { error } from '/@/utils/log';
|
||||||
|
import { getDynamicProps } from '/@/utils';
|
||||||
|
|
||||||
import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
|
import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
|
||||||
import type { NamePath } from 'ant-design-vue/lib/form/interface';
|
import type { NamePath } from 'ant-design-vue/lib/form/interface';
|
||||||
|
import type { DynamicProps } from '/@/types/utils';
|
||||||
|
|
||||||
export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>;
|
export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>;
|
||||||
|
|
||||||
export function useForm(props?: Partial<FormProps>): UseFormReturnType {
|
type Props = Partial<DynamicProps<FormProps>>;
|
||||||
|
|
||||||
|
export function useForm(props?: Props): UseFormReturnType {
|
||||||
isInSetup();
|
isInSetup();
|
||||||
|
|
||||||
const formRef = ref<Nullable<FormActionType>>(null);
|
const formRef = ref<Nullable<FormActionType>>(null);
|
||||||
@@ -25,6 +29,7 @@ export function useForm(props?: Partial<FormProps>): UseFormReturnType {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
return form as FormActionType;
|
return form as FormActionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
function register(instance: FormActionType) {
|
function register(instance: FormActionType) {
|
||||||
isProdMode() &&
|
isProdMode() &&
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@@ -34,8 +39,12 @@ export function useForm(props?: Partial<FormProps>): UseFormReturnType {
|
|||||||
if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return;
|
if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return;
|
||||||
|
|
||||||
formRef.value = instance;
|
formRef.value = instance;
|
||||||
props && instance.setProps(props);
|
|
||||||
loadedRef.value = true;
|
loadedRef.value = true;
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
props && instance.setProps(getDynamicProps(props));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const methods: FormActionType = {
|
const methods: FormActionType = {
|
||||||
|
@@ -178,12 +178,10 @@ export function useFormEvents({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function validateFields(nameList?: NamePath[] | undefined) {
|
async function validateFields(nameList?: NamePath[] | undefined) {
|
||||||
const res = await unref(formElRef)?.validateFields(nameList || []);
|
return unref(formElRef)?.validateFields(nameList);
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validate(nameList?: NamePath[] | undefined) {
|
async function validate(nameList?: NamePath[] | undefined) {
|
||||||
return await unref(formElRef)?.validate(nameList || []);
|
return await unref(formElRef)?.validate(nameList);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clearValidate(name?: string | string[]) {
|
async function clearValidate(name?: string | string[]) {
|
||||||
|
@@ -18,6 +18,9 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
|
|||||||
|
|
||||||
// If labelWidth is set globally, all items setting
|
// If labelWidth is set globally, all items setting
|
||||||
if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) {
|
if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) {
|
||||||
|
labelCol.style = {
|
||||||
|
textAlign: 'left',
|
||||||
|
};
|
||||||
return { labelCol, wrapperCol };
|
return { labelCol, wrapperCol };
|
||||||
}
|
}
|
||||||
let width = labelWidth || globalLabelWidth;
|
let width = labelWidth || globalLabelWidth;
|
||||||
@@ -27,6 +30,7 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
|
|||||||
if (width) {
|
if (width) {
|
||||||
width = isNumber(width) ? `${width}px` : width;
|
width = isNumber(width) ? `${width}px` : width;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
labelCol: { style: { width }, ...col },
|
labelCol: { style: { width }, ...col },
|
||||||
wrapperCol: { style: { width: `calc(100% - ${width})` }, ...wrapCol },
|
wrapperCol: { style: { width: `calc(100% - ${width})` }, ...wrapCol },
|
||||||
|
@@ -68,8 +68,9 @@
|
|||||||
import { useEventListener } from '/@/hooks/event/useEventListener';
|
import { useEventListener } from '/@/hooks/event/useEventListener';
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
import { ROW_KEY } from './const';
|
import { ROW_KEY } from './const';
|
||||||
import './style/index.less';
|
|
||||||
import { useExpose } from '/@/hooks/core/useExpose';
|
import { useExpose } from '/@/hooks/core/useExpose';
|
||||||
|
|
||||||
|
import './style/index.less';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
components: { Table, BasicForm },
|
components: { Table, BasicForm },
|
||||||
@@ -87,6 +88,12 @@
|
|||||||
} as BasicTableProps;
|
} as BasicTableProps;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// const getProps = computed(
|
||||||
|
// (): FormProps => {
|
||||||
|
// return deepMerge(toRaw(props), unref(innerPropsRef));
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
const { loadingRef } = useLoading(getMergeProps);
|
const { loadingRef } = useLoading(getMergeProps);
|
||||||
const { getPaginationRef, setPagination } = usePagination(getMergeProps);
|
const { getPaginationRef, setPagination } = usePagination(getMergeProps);
|
||||||
const { getColumnsRef, setColumns } = useColumns(getMergeProps, getPaginationRef);
|
const { getColumnsRef, setColumns } = useColumns(getMergeProps, getPaginationRef);
|
||||||
@@ -299,8 +306,8 @@
|
|||||||
loadingRef.value = loading;
|
loadingRef.value = loading;
|
||||||
},
|
},
|
||||||
setProps,
|
setProps,
|
||||||
getSize: (): SizeType => {
|
getSize: () => {
|
||||||
return unref(getBindValues).size;
|
return unref(getBindValues).size as SizeType;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -16,6 +16,5 @@
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup() {},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -90,7 +90,6 @@
|
|||||||
SettingOutlined,
|
SettingOutlined,
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import { useFullscreen } from '/@/hooks/web/useFullScreen';
|
import { useFullscreen } from '/@/hooks/web/useFullScreen';
|
||||||
|
|
||||||
import type { SizeType, TableSetting } from '../types/table';
|
import type { SizeType, TableSetting } from '../types/table';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
|
||||||
@@ -150,6 +149,7 @@
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
let ret: Options[] = [];
|
let ret: Options[] = [];
|
||||||
table.getColumns({ ignoreIndex: true, ignoreAction: true }).forEach((item) => {
|
table.getColumns({ ignoreIndex: true, ignoreAction: true }).forEach((item) => {
|
||||||
|
@@ -13,10 +13,10 @@
|
|||||||
components: { BasicTitle },
|
components: { BasicTitle },
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
type: [Function, String] as PropType<string | ((data: any) => string)>,
|
type: [Function, String] as PropType<string | ((data: Recordable) => string)>,
|
||||||
},
|
},
|
||||||
getSelectRows: {
|
getSelectRows: {
|
||||||
type: Function as PropType<() => any[]>,
|
type: Function as PropType<() => Recordable[]>,
|
||||||
},
|
},
|
||||||
helpMessage: {
|
helpMessage: {
|
||||||
type: [String, Array] as PropType<string | string[]>,
|
type: [String, Array] as PropType<string | string[]>,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { BasicArrow } from '/@/components/Basic';
|
import { BasicArrow } from '/@/components/Basic';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return (props: any) => {
|
return (props: Recordable) => {
|
||||||
return (
|
return (
|
||||||
<BasicArrow
|
<BasicArrow
|
||||||
onClick={(e: Event) => {
|
onClick={(e: Event) => {
|
||||||
|
@@ -1,24 +1,24 @@
|
|||||||
import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table';
|
import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table';
|
||||||
import type { PaginationProps } from '../types/pagination';
|
import type { PaginationProps } from '../types/pagination';
|
||||||
|
|
||||||
import { ref, getCurrentInstance, onUnmounted, unref } from 'vue';
|
import { ref, onUnmounted, unref } from 'vue';
|
||||||
import { isProdMode } from '/@/utils/env';
|
import { isProdMode } from '/@/utils/env';
|
||||||
|
import { isInSetup } from '/@/utils/helper/vueHelper';
|
||||||
|
|
||||||
export function useTable(
|
export function useTable(
|
||||||
tableProps?: Partial<BasicTableProps>
|
tableProps?: Partial<BasicTableProps>
|
||||||
): [(instance: TableActionType) => void, TableActionType] {
|
): [(instance: TableActionType) => void, TableActionType] {
|
||||||
if (!getCurrentInstance()) {
|
isInSetup();
|
||||||
throw new Error('Please put useTable function in the setup function!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const tableRef = ref<TableActionType | null>(null);
|
const tableRef = ref<Nullable<TableActionType>>(null);
|
||||||
const loadedRef = ref<boolean | null>(false);
|
const loadedRef = ref<Nullable<boolean>>(false);
|
||||||
|
|
||||||
function register(instance: TableActionType) {
|
function register(instance: TableActionType) {
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
tableRef.value = null;
|
tableRef.value = null;
|
||||||
loadedRef.value = null;
|
loadedRef.value = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) {
|
if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -57,7 +57,7 @@ export default defineComponent({
|
|||||||
<p class={`${prefixCls}__header-name`}>{userStore.getUserInfoState.realName}</p>
|
<p class={`${prefixCls}__header-name`}>{userStore.getUserInfoState.realName}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BasicForm onRegister={registerForm} layout="vertical" />
|
<BasicForm onRegister={registerForm} />
|
||||||
|
|
||||||
<div class={`${prefixCls}__footer`}>
|
<div class={`${prefixCls}__footer`}>
|
||||||
<Button type="primary" block class="mt-2" onClick={lock}>
|
<Button type="primary" block class="mt-2" onClick={lock}>
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
<p :class="`${prefixCls}__header-name`">{{ getRealName }}</p>
|
<p :class="`${prefixCls}__header-name`">{{ getRealName }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BasicForm @register="registerForm" layout="vertical" />
|
<BasicForm @register="registerForm" />
|
||||||
|
|
||||||
<div :class="`${prefixCls}__footer`">
|
<div :class="`${prefixCls}__footer`">
|
||||||
<a-button type="primary" block class="mt-2" @click="handleLock">
|
<a-button type="primary" block class="mt-2" @click="handleLock">
|
||||||
|
5
src/types/utils.ts
Normal file
5
src/types/utils.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
|
|
||||||
|
export type DynamicProps<T> = {
|
||||||
|
[P in keyof T]: Ref<T[P]> | T[P] | ComputedRef<T[P]>;
|
||||||
|
};
|
@@ -1,4 +1,5 @@
|
|||||||
export const timestamp = () => +Date.now();
|
export const timestamp = () => +Date.now();
|
||||||
|
import { unref } from 'vue';
|
||||||
import { isObject } from '/@/utils/is';
|
import { isObject } from '/@/utils/is';
|
||||||
export const clamp = (n: number, min: number, max: number) => Math.min(max, Math.max(min, n));
|
export const clamp = (n: number, min: number, max: number) => Math.min(max, Math.max(min, n));
|
||||||
export const noop = () => {};
|
export const noop = () => {};
|
||||||
@@ -76,3 +77,14 @@ export function openWindow(
|
|||||||
|
|
||||||
window.open(url, target, feature.join(','));
|
window.open(url, target, feature.join(','));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dynamic use hook props
|
||||||
|
export function getDynamicProps<T, U>(props: T): Partial<U> {
|
||||||
|
const ret: Recordable = {};
|
||||||
|
|
||||||
|
Object.keys(props).map((key) => {
|
||||||
|
ret[key] = unref((props as Recordable)[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret as Partial<U>;
|
||||||
|
}
|
||||||
|
@@ -162,6 +162,7 @@
|
|||||||
components: { BasicForm, CollapseContainer },
|
components: { BasicForm, CollapseContainer },
|
||||||
setup() {
|
setup() {
|
||||||
const { createMessage } = useMessage();
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
const [register, { setProps }] = useForm({
|
const [register, { setProps }] = useForm({
|
||||||
labelWidth: 120,
|
labelWidth: 120,
|
||||||
schemas,
|
schemas,
|
||||||
@@ -172,7 +173,7 @@
|
|||||||
return {
|
return {
|
||||||
register,
|
register,
|
||||||
schemas,
|
schemas,
|
||||||
handleSubmit: (values: any) => {
|
handleSubmit: (values: Recordable) => {
|
||||||
createMessage.success('click search,values:' + JSON.stringify(values));
|
createMessage.success('click search,values:' + JSON.stringify(values));
|
||||||
},
|
},
|
||||||
setProps,
|
setProps,
|
||||||
|
@@ -6,10 +6,10 @@
|
|||||||
|
|
||||||
<div class="m-5">
|
<div class="m-5">
|
||||||
<a-card title="仓库管理" :bordered="false">
|
<a-card title="仓库管理" :bordered="false">
|
||||||
<BasicForm @register="register" layout="vertical" />
|
<BasicForm @register="register" />
|
||||||
</a-card>
|
</a-card>
|
||||||
<a-card title="任务管理" :bordered="false" class="mt-5">
|
<a-card title="任务管理" :bordered="false" class="mt-5">
|
||||||
<BasicForm @register="registerTask" layout="vertical" />
|
<BasicForm @register="registerTask" />
|
||||||
</a-card>
|
</a-card>
|
||||||
<a-card title="成员管理" :bordered="false" class="mt-5">
|
<a-card title="成员管理" :bordered="false" class="mt-5">
|
||||||
<PersonTable ref="tableRef" />
|
<PersonTable ref="tableRef" />
|
||||||
|
@@ -1956,10 +1956,10 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-convert "^2.0.1"
|
color-convert "^2.0.1"
|
||||||
|
|
||||||
ant-design-vue@^2.0.0-rc.6:
|
ant-design-vue@^2.0.0-rc.7:
|
||||||
version "2.0.0-rc.6"
|
version "2.0.0-rc.7"
|
||||||
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.0.0-rc.6.tgz#f25f61cde1c75c32a78b536751731c0b223b6590"
|
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.0.0-rc.7.tgz#5d83a7f13275574ec1fc1ea8c1fe8d9aa6de067c"
|
||||||
integrity sha512-NRxzIC4CSM56MXYHdg3K2oTc+pkcSJd6BJtIBCxUsbFfbBGp+F7ei7C1bQDdHHos3o/Oe2iqGwzfrZ7+Ot2Uew==
|
integrity sha512-QMStvwaLfV1Q3RaQ8D926aCkW6iqWBHXlNv7dBdTPvU8eeFXPaPKenLu1OTpSi+wpCncJqgumFOEcENPvh0nKw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ant-design-vue/use" "^0.0.1-0"
|
"@ant-design-vue/use" "^0.0.1-0"
|
||||||
"@ant-design/icons-vue" "^5.1.7"
|
"@ant-design/icons-vue" "^5.1.7"
|
||||||
|
Reference in New Issue
Block a user