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()}
)
}
}
}