import { ElFormItem, ElTooltip } from 'element-plus' import { h, toRef, inject, computed, ref, unref, onErrorCaptured } from 'vue' import { getInputComponent, getViewComponent, getH5InputComponent } from '../cip-form-input/util' // import { handleFormConfig } from '../helper/d-render' import { isEmpty, debounce, isEmptyObject } from '@cip/utils/util' import { useWatchFieldDepend, useFieldValue, useRules } from './form-item-hooks' import { isHideLabel, getLabelWidth } from './util' import './index.less' import { useFormInject } from '../hooks/use-form' export default { name: 'CipFormItem', props: { config: Object, // 字段配置信息 fieldKey: String, // 字段名 model: { // 字段所属model type: Object, default: () => ({}) }, readonly: Boolean, // 是否只读-即查看模式 customSlots: Function, showTemplate: { // 是否展示模版值[注:表单设计中使用] type: Boolean, default: false }, tableDependOnValues: Object, inTable: { type: Boolean, default: false }, componentKey: String, grid: [Number, Boolean], tableData: Array, onSearch: Function // 供CipSearchForm使用 }, emits: ['update:model'], setup (props, context) { onErrorCaptured((e) => { // el-form-item 在onBeforeUnmount会访问el.value.firstElementChild 由于切换较快的原因会抱错 process.env.NODE_ENV === 'development' && console.log(e) return false }) // elForm组件实例 const elForm = inject('elForm', {}) const { cipForm } = useFormInject() const equipment = computed(() => { return unref(cipForm.equipment) || 'pc' }) const NoFormItem = (props, { slots }) => { return
{slots.default?.()}
} const FormItemComponent = computed(() => { return isEmptyObject(elForm) ? NoFormItem : ElFormItem }) const updateModel = debounce((value) => { context.emit('update:model', value) }, 50, false) // FormItem及Input组件渲染模式 ['hidden','read','read-write'] const status = computed(() => { // 为设置则默认开始可读可写模式 const config = formItemConfig.value if (props.readonly) { if (config.readable === false) return 'hidden' return 'read' } if (isEmpty(config.readable) && isEmpty(config.writable)) { return 'read-write' } if (config.writable) { return 'read-write' } else if (config.readable) { return 'read' } else { return 'hidden' } }) // Input组件实际使用的配置 const formItemConfig = computed(() => { return runningConfig.value || props.config // handleFormConfig() }) const model = toRef(props, 'model') const fieldKey = toRef(props, 'fieldKey') // 仅正对modelValue生效 const changeEffect = computed(() => { return formItemConfig.value.changeEffect }) // modelValue const [modelValue, updateModelValue] = useFieldValue(fieldKey, model, updateModel, changeEffect) const otherKey = computed(() => formItemConfig.value?.otherKey) // otherValue const [otherValue, updateOtherValue] = useFieldValue(otherKey, model, updateModel) // 监听依赖 触发响应事件 const { dependOnValues, outDependOnValues, runningConfig } = useWatchFieldDepend(props, context, { updateModelValue, updateOtherValue }) const readonly = toRef(props, 'readonly') // rules const { usingRules, rules } = useRules(formItemConfig, readonly, status, otherValue, dependOnValues) // Input组件是否展示标记(需要控制form-item内置的margin-bottom) const childStatus = ref(true) // FormItem label const formItemLabel = () => { // 隐藏label或者label为空时直接返回空字符串 if (formItemConfig.value.hideLabel === true || isEmpty(formItemConfig.value.label)) return '' // 表单为只读模式下展示样式控制 const labelId = formItemConfig.value.directory ? props.fieldKey : undefined const result = [h('span', { class: { 'is-readonly': props.readonly }, id: labelId }, [formItemConfig.value.label])] // 存在说明 if (formItemConfig.value.description) { const descriptionComp = ( {{ content: () => formItemConfig.value.description, default: () => }} ) result.push(descriptionComp) } // 仅在正在使用rules的input中且required为true时展示必填标记 if (usingRules.value && formItemConfig.value.required) { const requiredAsterisk = (*) result.unshift(requiredAsterisk) } // 有标签后缀的增加标签后缀 if (elForm.labelSuffix) { result.push(elForm.labelSuffix) } return result } const inlineErrorMessage = computed(() => { return props.inTable || cipForm.equipment === 'mobile' }) // FormItem ErrorMessage const errorMessageNode = ({ error }) => { if (!inlineErrorMessage.value) return null return ( ) } const labelPosition = computed(() => { // 依赖elForm实例数据总是在变换、故修改为有父组件cip-form下发数据 if (!isEmpty(formItemConfig.value.labelPosition)) { return formItemConfig.value.labelPosition === 'top' } return unref(cipForm.labelPosition) === 'top' }) // FormItem const formItem = () => { return h(FormItemComponent.value, { class: { 'pos-top': labelPosition.value, // 'pos-top--padding': labelPositionTopPadding, 暂时关闭position === top时内容的缩进 'hide-label': isHideLabel(formItemConfig.value), 'content--end': formItemConfig.value.contentEnd }, prop: formItemConfig.value.ruleKey || props.fieldKey, // 子表单内的输入框会生成一个ruleKey rules: rules.value, labelWidth: getLabelWidth(formItemConfig.value), inlineMessage: inlineErrorMessage.value }, { label: formItemLabel, error: errorMessageNode, default: () => { if (props.customSlots) { return props.customSlots({ fieldKey: props.fieldKey, updateModel: updateModelValue }) } const type = formItemConfig.value.type || 'default' const componentProps = { key: props.componentKey, id: props.fieldKey, fieldKey: props.fieldKey, modelValue: modelValue.value, otherValue: otherValue.value, model: model.value, // 即将废弃 config: formItemConfig.value, usingRules: usingRules.value, rules: rules.value, dependOnValues: dependOnValues.value, outDependOnValues: outDependOnValues.value, disabled: formItemConfig.value.importantDisabled !== undefined ? formItemConfig.value.importantDisabled : formItemConfig.value.disabled, showTemplate: props.showTemplate, tableData: props.tableData, onStatusChange: (status) => { // 子组件触发事件控制父组件是否显示 childStatus.value = status }, onSearch: props.onSearch } if (status.value === 'read-write') { const inputComponentProps = { ...componentProps, 'onUpdate:modelValue': updateModelValue, 'onUpdate:otherValue': updateOtherValue } if (unref(cipForm.equipment) === 'mobile') { return h(getH5InputComponent(type), inputComponentProps) } else { return h(getInputComponent(type), inputComponentProps) } } else { return h(getViewComponent(type), componentProps) } } }) } const cipFormStyle = computed(() => { if (props.grid) { return { gridColumn: `span ${formItemConfig.value.span || 1}` } } else { return (elForm.inline && !props.inTable) ? formItemConfig.value.style : '' } }) return () => { if (status.value === 'hidden') return null return (
{formItem()}
) } } }