123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import { ElFormItem, ElTooltip } from 'element-plus'
- import { h, toRef, computed, ref, unref, onErrorCaptured } from 'vue'
- import { getInputComponent, getViewComponent, getH5InputComponent } from '../cip-form-input/util'
- import { isEmpty, isEmptyObject, isInputEmpty } from '@cip/utils/util'
- import { useWatchFieldDepend } from './hooks/use-field-depend'
- import { useFieldValue, useSteamUpdateValues } from './hooks/use-model-change'
- import { useRules } from './hooks/use-field-rules'
- import { isHideLabel, getLabelWidth, UpdateModelQueue } from './util'
- import './index.less'
- import { useFormInject, useElFormInject } from '../hooks/use-form'
- import { useCipConfig } from '@cip/components/hooks/use-cip-config'
- 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 cipConfig = useCipConfig()
- const elForm = useElFormInject()
- const cipForm = useFormInject()
- const equipment = computed(() => {
- return unref(cipForm.equipment) || 'pc'
- })
- // 一般处于cip-table直接使用的情况下
- const notInForm = computed(() => {
- return isEmptyObject(elForm)
- })
- const updateModel = (value) => {
- // console.log('updateModel', value)
- // if (!notInForm.value) {
- // // 因为延迟执行的问题,可能导致数据无法及时有效验证手动调用
- // elForm.validateField([formItemConfig.value.ruleKey || props.fieldKey])
- // }
- context.emit('update:model', value)
- }
- const updateModelQueue = new UpdateModelQueue(() => props.model, updateModel)
- // 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
- })
- // 3种数据更新方式并行
- // modelValue
- const [modelValue, updateModelValue] = useFieldValue(fieldKey, model, updateModelQueue, changeEffect)
- const otherKey = computed(() => formItemConfig.value?.otherKey)
- // otherValue
- const [otherValue, updateOtherValue] = useFieldValue(otherKey, model, updateModelQueue)
- const { values, streamUpdateModel, clearValues } = useSteamUpdateValues(fieldKey, otherKey, model, updateModel, changeEffect)
- // 监听依赖 触发响应事件
- const { changeCount, dependOnValues, outDependOnValues, runningConfig } = useWatchFieldDepend(props, context, { updateModelValue, updateOtherValue, clearValues })
- const readonly = toRef(props, 'readonly')
- // rules
- const { usingRules, rules } = useRules(formItemConfig, readonly, status, otherValue, dependOnValues, outDependOnValues)
- // 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 = (
- <ElTooltip effect={formItemConfig.value.descriptionEffect || 'light'} placement={'top'}>
- {{
- content: () => formItemConfig.value.description,
- default: () => <i class={'el-icon-question'} style={'margin-left:2px;line-height: inherit;'} />
- }}
- </ElTooltip>
- )
- result.push(descriptionComp)
- }
- // 仅在正在使用rules的input中且required为true时展示必填标记
- if (usingRules.value && formItemConfig.value.required) {
- const requiredAsterisk = (<span class={'cip-danger-color'}>*</span>)
- result.unshift(requiredAsterisk)
- }
- // 有标签后缀的增加标签后缀
- if (elForm.labelSuffix) {
- result.push(elForm.labelSuffix)
- }
- return h('div', { style: { color: '#333333', ...formItemConfig.value.labelStyle } }, result) // result
- }
- const inlineErrorMessage = computed(() => {
- return props.inTable || cipForm.equipment === 'mobile'
- })
- // FormItem ErrorMessage
- const errorMessageNode = ({ error }) => {
- if (!inlineErrorMessage.value) return null
- return (
- <ElTooltip content={error}>
- <i class={'el-icon-warning cip-danger-color '} style={{ outline: 'none', border: 'none' }} />
- </ElTooltip>
- )
- }
- const labelPosition = computed(() => {
- // 依赖elForm实例数据总是在变换、故修改为有父组件cip-form下发数据
- if (!isEmpty(formItemConfig.value.labelPosition)) {
- return formItemConfig.value.labelPosition === 'top'
- }
- return unref(cipForm.labelPosition) === 'top'
- })
- const renderItemInput = () => {
- if (props.customSlots) {
- return props.customSlots({
- fieldKey: props.fieldKey,
- modelValue: modelValue.value,
- updateModel: updateModelValue, // 即将废弃,此处名字与实际功能不符合
- updateModelValue
- })
- }
- const type = formItemConfig.value.type || 'default'
- const componentProps = {
- key: props.componentKey,
- id: props.fieldKey,
- fieldKey: props.fieldKey,
- modelValue: modelValue.value,
- otherValue: otherValue.value,
- values: values.value,
- // model: model.value, // 即将废弃
- changeCount: changeCount.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,
- class: 'cip-form-item__input',
- onStatusChange: (status) => { // 子组件触发事件控制父组件是否显示
- childStatus.value = status
- },
- onSearch: props.onSearch
- }
- if (status.value === 'read-write') {
- const inputComponentProps = {
- ...componentProps,
- // 'onUpdate:modelValue': updateModelValue,
- // 'onUpdate:otherValue': updateOtherValue,
- 'onStreamUpdate:model': streamUpdateModel
- }
- if (unref(cipForm.equipment) === 'mobile') {
- return h(getH5InputComponent(type), inputComponentProps)
- } else {
- return h(getInputComponent(type), inputComponentProps)
- }
- } else {
- // 根据cip-config配置给view的modelValue添加默认值
- if (isInputEmpty(componentProps.modelValue)) {
- if (props.inTable && cipConfig.table.defaultViewValue) {
- componentProps.modelValue = cipConfig.table.defaultViewValue
- }
- if (cipConfig.defaultViewValue) {
- componentProps.modelValue = cipConfig.defaultViewValue
- }
- }
- return h(getViewComponent(type), componentProps)
- }
- }
- // FormItem
- const formItem = () => {
- return h(ElFormItem, {
- 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: renderItemInput
- })
- }
- const cipFormStyle = computed(() => {
- if (props.grid) {
- return { gridColumn: `span ${formItemConfig.value.span || 1}`, ...formItemConfig.value.itemStyle }
- } else {
- return (elForm.inline && !props.inTable) ? formItemConfig.value.style : formItemConfig.value.itemStyle
- }
- })
- return () => {
- if (status.value === 'hidden') return null
- if (props.inTable && status.value === 'read') return renderItemInput()
- // 父组件不存在form状态下的渲染方式 目前经为cip-table下直接渲染使用
- if (notInForm.value) return renderItemInput()
- return (
- <div
- style={cipFormStyle.value}
- class={[
- 'cip-form-item',
- 'el-form-item__wrapper',
- 'ep-form-item__wrapper', // 支持namespace ep
- `cip-form-item--${equipment.value}`,
- {
- 'cip-form-item--label-position-top': labelPosition.value,
- 'cip-form-item--hidden': !childStatus.value || formItemConfig.value.hideItem,
- 'cip-form-item--in-table': props.inTable
- }
- ]}>
- {formItem()}
- </div>
- )
- }
- }
- }
|