359 lines
9.7 KiB
Plaintext
359 lines
9.7 KiB
Plaintext
<template>
|
|
<a-form v-bind="getBindValue" :model="formModel" ref="formElRef">
|
|
<a-row v-bind="getRow">
|
|
<a-col
|
|
v-bind="!schema.colProps ? getCol : schema.colProps"
|
|
v-for="schema in getSchema"
|
|
:key="schema.name"
|
|
>
|
|
<a-form-item
|
|
:label="schema.labelMessage ? null : schema.label"
|
|
:name="schema.name"
|
|
v-if="!getHidden(schema)"
|
|
>
|
|
<!--标签名右侧温馨提示-->
|
|
<template #label v-if="schema.labelMessage">
|
|
{{ schema.label }}
|
|
<a-tooltip trigger="hover" :style="schema.labelMessageStyle">
|
|
<span class="text-gray-400 cursor-pointer mx-1">
|
|
<QuestionCircleOutlined />
|
|
</span>
|
|
<template #title>{{ schema.labelMessage }}</template>
|
|
</a-tooltip>
|
|
</template>
|
|
<!--判断插槽-->
|
|
<template v-if="schema.slot">
|
|
<slot
|
|
:name="schema.slot"
|
|
:model="formModel"
|
|
:field="schema.name"
|
|
:value="formModel[schema.name]"
|
|
></slot>
|
|
</template>
|
|
|
|
<!--Checkbox-->
|
|
<template v-else-if="schema.component === 'Checkbox'">
|
|
<a-checkbox-group
|
|
v-bind="getSpecComponentProps(schema)"
|
|
v-model:value="formModel[schema.name]"
|
|
>
|
|
<a-space>
|
|
<a-checkbox
|
|
v-for="item in schema.componentProps?.options"
|
|
:key="item.value"
|
|
:value="item.value"
|
|
:label="item.label"
|
|
/>
|
|
</a-space>
|
|
</a-checkbox-group>
|
|
</template>
|
|
|
|
<!--RadioGroup-->
|
|
<template v-else-if="schema.component === 'RadioGroup'">
|
|
<a-radio-group
|
|
v-bind="getSpecComponentProps(schema)"
|
|
v-model:value="formModel[schema.name]"
|
|
>
|
|
<a-space>
|
|
<a-radio
|
|
v-for="item in schema.componentProps?.options"
|
|
:key="item.value"
|
|
:value="item.value"
|
|
>
|
|
{{ item.label }}
|
|
</a-radio>
|
|
</a-space>
|
|
</a-radio-group>
|
|
</template>
|
|
|
|
<!--BasicSelect-->
|
|
<template v-else-if="schema.component === 'BasicSelect'">
|
|
<BasicSelect v-model:value="formModel[schema.name]" v-bind="schema.componentProps" />
|
|
</template>
|
|
|
|
<!--动态渲染表单组件-->
|
|
<component
|
|
v-else
|
|
v-bind="getComponentProps(schema)"
|
|
:is="`a-${schema.component}`"
|
|
v-model:value="formModel[schema.name]"
|
|
:class="{ isFull: schema.isFull != false && getProps.isFull }"
|
|
/>
|
|
<!--组件后面的内容-->
|
|
<template v-if="schema.suffix">
|
|
<slot
|
|
:name="schema.suffix"
|
|
:model="formModel"
|
|
:field="schema.name"
|
|
:value="formModel[schema.name]"
|
|
></slot>
|
|
</template>
|
|
</a-form-item>
|
|
</a-col>
|
|
<!--提交 重置 展开收起 后期实现 -->
|
|
<a-col
|
|
v-bind="getActionCol"
|
|
:style="getProps.actionStyle"
|
|
v-if="getProps.showActionButtonGroup"
|
|
class="pl-0 pr-0"
|
|
>
|
|
<a-button
|
|
v-if="getProps.showSubmitButton"
|
|
v-bind="getSubmitBtnOptions"
|
|
@click="handleSubmit"
|
|
:loading="loadingSub"
|
|
class="mr-2"
|
|
>
|
|
<template #icon>
|
|
<SearchOutlined />
|
|
</template>
|
|
{{ getProps.submitButtonText }}</a-button
|
|
>
|
|
<a-button
|
|
v-if="getProps.showResetButton"
|
|
v-bind="getResetBtnOptions"
|
|
@click="resetFields"
|
|
>{{ getProps.resetButtonText }}</a-button
|
|
>
|
|
</a-col>
|
|
</a-row>
|
|
</a-form>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { reactive, ref, useAttrs, computed, unref, onMounted, watch } from 'vue';
|
|
import { createPlaceholderMessage } from './helper';
|
|
import { useFormEvents } from './hooks/useFormEvents';
|
|
import { useFormValues } from './hooks/useFormValues';
|
|
import { BasicSelect } from '@/components/Select';
|
|
|
|
import { basicProps } from './props';
|
|
import { QuestionCircleOutlined,SearchOutlined } from '@ant-design/icons-vue';
|
|
|
|
import type { Ref } from 'vue';
|
|
import type { FormSchema, FormProps, FormActionType } from './types/form';
|
|
|
|
import { isArray, isBoolean, isFunction } from '@/utils/is/index';
|
|
import { deepMerge } from '@/utils';
|
|
|
|
import { Form } from 'ant-design-vue';
|
|
|
|
const useForm = Form.useForm;
|
|
|
|
const props = defineProps({ ...basicProps });
|
|
const emit = defineEmits(['reset', 'submit', 'register', 'advanced']);
|
|
const attrs = useAttrs();
|
|
|
|
const defaultFormModel = ref<Recordable>({});
|
|
const formModel = reactive<Recordable>({});
|
|
const propsRef = ref<Partial<FormProps>>({});
|
|
const schemaRef = ref<Nullable<FormSchema[]>>(null);
|
|
const formElRef = ref<Nullable<FormActionType>>(null);
|
|
const loadingSub = ref(false);
|
|
const isUpdateDefaultRef = ref(false);
|
|
|
|
const getSubmitBtnOptions = computed(() => {
|
|
return Object.assign(
|
|
{
|
|
size: props.size,
|
|
type: 'primary',
|
|
},
|
|
props.submitButtonOptions,
|
|
);
|
|
});
|
|
|
|
const getResetBtnOptions = computed(() => {
|
|
return Object.assign(
|
|
{
|
|
size: props.size,
|
|
type: 'default',
|
|
},
|
|
props.resetButtonOptions,
|
|
);
|
|
});
|
|
|
|
function getComponentProps(schema) {
|
|
const compProps = schema.componentProps ?? {};
|
|
const component = schema.component;
|
|
return {
|
|
clearable: true,
|
|
placeholder: createPlaceholderMessage(unref(component)),
|
|
...compProps,
|
|
};
|
|
}
|
|
|
|
function getHidden(schema): boolean {
|
|
const hidden = schema.hidden;
|
|
const field = schema.field;
|
|
if (isBoolean(hidden)) return hidden;
|
|
|
|
if (isFunction(hidden)) {
|
|
const values = getFieldsValue();
|
|
const status = hidden({ schema, values, model: formModel, field });
|
|
return status;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function getSpecComponentProps(schema) {
|
|
const compProps = schema.componentProps ?? {};
|
|
return {
|
|
...compProps,
|
|
};
|
|
}
|
|
|
|
const getProps = computed((): FormProps => {
|
|
const formProps = { ...props, ...unref(propsRef) } as FormProps;
|
|
const rulesObj: any = {
|
|
rules: {},
|
|
};
|
|
const schemas: any = formProps.schemas || [];
|
|
schemas.forEach((item) => {
|
|
if (item.rules && isArray(item.rules)) {
|
|
rulesObj.rules[item.name] = item.rules;
|
|
}
|
|
});
|
|
return { ...formProps, ...unref(rulesObj) };
|
|
});
|
|
|
|
const isVertical = computed(() => {
|
|
const { layout } = unref(getProps);
|
|
return layout === 'vertical';
|
|
});
|
|
|
|
const getActionCol = computed(() => {
|
|
let colObj = {};
|
|
const { labelCol, actInheritLabelCol, colProps } = unref(getProps);
|
|
if (!actInheritLabelCol) {
|
|
colObj = {
|
|
...colProps,
|
|
};
|
|
} else {
|
|
if (labelCol && !unref(isVertical)) {
|
|
let leftSpan: any = labelCol?.span || 0;
|
|
colObj = {
|
|
span: 24 - leftSpan,
|
|
offset: labelCol?.span,
|
|
};
|
|
}
|
|
}
|
|
return colObj;
|
|
});
|
|
|
|
const getRow = computed(() => {
|
|
const { rowProps } = unref(getProps);
|
|
return {
|
|
...rowProps,
|
|
};
|
|
});
|
|
|
|
const getCol = computed(() => {
|
|
const { colProps } = unref(getProps);
|
|
return {
|
|
...colProps,
|
|
};
|
|
});
|
|
|
|
const getBindValue = computed(() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable));
|
|
|
|
const getSchema = computed((): FormSchema[] => {
|
|
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
|
for (const schema of schemas) {
|
|
const { defaultValue } = schema;
|
|
// handle date type
|
|
// dateItemType.includes(component as string)
|
|
if (defaultValue) {
|
|
schema.defaultValue = defaultValue;
|
|
}
|
|
}
|
|
return schemas as FormSchema[];
|
|
});
|
|
|
|
const getFormRules = computed(() => {
|
|
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
|
const rulesObj = {};
|
|
for (const schema of schemas) {
|
|
if (schema.rules) {
|
|
rulesObj[schema.name] = schema.rules;
|
|
}
|
|
}
|
|
return rulesObj;
|
|
});
|
|
|
|
const formRules = reactive<Recordable>(getFormRules.value);
|
|
|
|
const { handleFormValues, initDefault } = useFormValues({
|
|
defaultFormModel,
|
|
getSchema,
|
|
formModel,
|
|
});
|
|
|
|
const { handleSubmit, validate, resetFields, getFieldsValue, clearValidate, setFieldsValue } =
|
|
useFormEvents({
|
|
emit,
|
|
getProps,
|
|
formModel,
|
|
getSchema,
|
|
formElRef: formElRef as Ref<FormActionType>,
|
|
defaultFormModel,
|
|
loadingSub,
|
|
handleFormValues,
|
|
});
|
|
|
|
async function setProps(formProps: Partial<FormProps>): Promise<void> {
|
|
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
|
|
}
|
|
|
|
async function setSchema(schemaProps: FormSchema[]): Promise<void> {
|
|
schemaRef.value = schemaProps;
|
|
}
|
|
|
|
const { validateInfos, mergeValidateInfo } = useForm(formModel, formRules);
|
|
|
|
const formActionType: Partial<FormActionType> = {
|
|
validateInfos,
|
|
mergeValidateInfo,
|
|
getFieldsValue,
|
|
setFieldsValue,
|
|
resetFields,
|
|
validate,
|
|
clearValidate,
|
|
setProps,
|
|
setSchema,
|
|
submit: handleSubmit,
|
|
};
|
|
|
|
watch(
|
|
() => getSchema.value,
|
|
(schema) => {
|
|
if (unref(isUpdateDefaultRef)) {
|
|
return;
|
|
}
|
|
if (schema?.length) {
|
|
initDefault();
|
|
isUpdateDefaultRef.value = true;
|
|
}
|
|
},
|
|
);
|
|
|
|
defineExpose({
|
|
...formActionType,
|
|
});
|
|
|
|
onMounted(() => {
|
|
initDefault();
|
|
emit('register', formActionType);
|
|
});
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.isFull {
|
|
width: 100%;
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
.unfold-icon {
|
|
margin-left: 5px;
|
|
}
|
|
</style>
|