<!-- * @Author: ypt * @Date: 2021/11/19 * @Description: --> <template> <Col v-bind="colPropsComputed"> <FormItem v-bind="{ ...formItemProps }"> <template #label v-if="!formItemProps.hiddenLabel && schema.component !== 'Divider'"> <Tooltip> <span>{{ schema.label }}</span> <template #title v-if="schema.helpMessage" ><span>{{ schema.helpMessage }}</span></template > <Icon v-if="schema.helpMessage" class="ml-5" icon="ant-design:question-circle-outlined" /> </Tooltip> </template> <slot v-if="schema.componentProps && schema.componentProps?.slotName" :name="schema.componentProps.slotName" v-bind="schema" ></slot> <Divider v-else-if="schema.component == 'Divider' && schema.label && !formItemProps.hiddenLabel" >{{ schema.label }}</Divider > <!-- 部分控件需要一个空div --> <div ><component class="v-form-item-wrapper" :is="componentItem" v-bind="{ ...cmpProps, ...asyncProps }" :schema="schema" :style="schema.width ? { width: schema.width } : {}" @change="handleChange" @click="handleClick(schema)" /></div> <span v-if="['Button'].includes(schema.component)">{{ schema.label }}</span> </FormItem> </Col> </template> <script lang="ts"> import { defineComponent, reactive, toRefs, computed, PropType, unref } from 'vue'; import { componentMap } from '../../core/formItemConfig'; import { IVFormComponent, IFormConfig } from '../../typings/v-form-component'; import { asyncComputed } from '@vueuse/core'; import { handleAsyncOptions } from '../../utils'; import { omit } from 'lodash-es'; import { Tooltip, FormItem, Divider, Col } from 'ant-design-vue'; // import FormItem from '/@/components/Form/src/components/FormItem.vue'; import { Icon } from '/@/components/Icon'; import { useFormModelState } from '../../hooks/useFormDesignState'; export default defineComponent({ name: 'VFormItem', components: { Tooltip, Icon, FormItem, Divider, Col, }, props: { formData: { type: Object, default: () => ({}), }, schema: { type: Object as PropType<IVFormComponent>, required: true, }, formConfig: { type: Object as PropType<IFormConfig>, required: true, }, }, emits: ['update:form-data', 'change'], setup(props, { emit }) { const state = reactive({ componentMap, }); const { formModel: formData1, setFormModel } = useFormModelState(); const colPropsComputed = computed(() => { const { colProps = {} } = props.schema; return colProps; }); const formItemProps = computed(() => { const { formConfig } = unref(props); let { field, required, rules, labelCol, wrapperCol } = unref(props.schema); const { colon } = props.formConfig; const { itemProps } = unref(props.schema); //<editor-fold desc="布局属性"> labelCol = labelCol ? labelCol : formConfig.layout === 'horizontal' ? formConfig.labelLayout === 'flex' ? { style: `width:${formConfig.labelWidth}px` } : formConfig.labelCol : {}; wrapperCol = wrapperCol ? wrapperCol : formConfig.layout === 'horizontal' ? formConfig.labelLayout === 'flex' ? { style: 'width:auto;flex:1' } : formConfig.wrapperCol : {}; const style = formConfig.layout === 'horizontal' && formConfig.labelLayout === 'flex' ? { display: 'flex' } : {}; /** * 将字符串正则格式化成正则表达式 */ const newConfig = Object.assign( {}, { name: field, style: { ...style }, colon, required, rules, labelCol, wrapperCol, }, itemProps, ); if (!itemProps?.labelCol?.span) { newConfig.labelCol = labelCol; } if (!itemProps?.wrapperCol?.span) { newConfig.wrapperCol = wrapperCol; } if (!itemProps?.rules) { newConfig.rules = rules; } return newConfig; }) as Recordable; const componentItem = computed(() => componentMap.get(props.schema.component as string)); // console.log('component change:', props.schema.component, componentItem.value); const handleClick = (schema: IVFormComponent) => { if (schema.component === 'Button' && schema.componentProps?.handle) emit(schema.componentProps?.handle); }; /** * 处理异步属性,异步属性会导致一些属性渲染错误,如defaultValue异步加载会导致渲染不出来,故而此处只处理options,treeData,同步属性在cmpProps中处理 */ const asyncProps = asyncComputed(async () => { let { options, treeData } = props.schema.componentProps ?? {}; if (options) options = await handleAsyncOptions(options); if (treeData) treeData = await handleAsyncOptions(treeData); return { options, treeData, }; }); /** * 处理同步属性 */ const cmpProps = computed(() => { const isCheck = props.schema && ['Switch', 'Checkbox', 'Radio'].includes(props.schema.component); let { field } = props.schema; let { disabled, ...attrs } = omit(props.schema.componentProps, ['options', 'treeData']) ?? {}; disabled = props.formConfig.disabled || disabled; return { ...attrs, disabled, [isCheck ? 'checked' : 'value']: formData1.value[field!], }; }); const handleChange = function (e) { const isCheck = ['Switch', 'Checkbox', 'Radio'].includes(props.schema.component); const target = e ? e.target : null; const value = target ? (isCheck ? target.checked : target.value) : e; setFormModel(props.schema.field!, value); emit('change', value); }; return { ...toRefs(state), componentItem, formItemProps, handleClick, asyncProps, cmpProps, handleChange, colPropsComputed, }; }, }); </script> <style lang="less" scoped> .ml-5 { margin-left: 5px; } // form字段中的标签有ant-col,不能使用width:100% :deep(.ant-col) { width: auto; } .ant-form-item:not(.ant-form-item-with-help) { margin-bottom: 20px; } // .w-full { // width: 100% !important; // } </style>