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