import _ from 'lodash' import { getuuid, isEqual, isValueEmpty } from '@/utils/index.js' import { isShowOtherByCheckboxTree } from '@/utils/formPackageCommon.js' export default { inject: ['getZdxgjl', 'updateZdxgjl'], watch: { formData: { immediate: true, deep: true, // 深度监听,以便检测嵌套对象变化 handler(v) { if (v) { this.handleFormField(true) } } }, fieldItemLabel: { immediate: true, deep: true, // 深度监听,以便检测嵌套对象变化 handler(v) { if (v) { console.log(v, 'fieldItemLabel') } } }, formConfig: { immediate: true, deep: true, // 深度监听,以便检测嵌套对象变化 handler(v) { this.handleFormField() } } }, data() { return { uuid: getuuid(), oldFormFields: {}, clickableKey: '' } }, mounted() { this.handleFormField() }, unmounted() { this.formFields = {} //清空当前填写的数据 }, methods: { onSelectChange(key, val, type) { // 获取对应的配制 const currentConfig = this.allFieldsConfig[key] if (currentConfig?.selectTo) { this.formFields[currentConfig?.selectTo] = val } this.onValueChangeCompareTo(key, val) this.formFields[key] = val this.$emit('select', { key, value: val, type, ...this.formFields }) // 清除该表单项的错误状态 if (this.errors[key]) { this.$set(this.errors, key, false) } }, //试剂/仪器等弹窗提交 onRegentSubmit(data, inputValue, key, item) { this.updateFormData(key, inputValue) this.$emit('onRegentSubmit', { selectInfo: data, inputValue, key, config: item }) }, getRegentItem(item, fieldCode = 'type') { const type = item[fieldCode] const fillType = fieldCode === 'type' ? item.fillType : item.subFillType || item.fillType return { label: '', type, fillType, parentLabel: item.label, filledCodes: item.filledCodes, qxbdType: item.qxbdType, checkType: item.checkType, regentFillType: item.regentFillType } }, handleClickButton(key) { this.$emit('clickButton', key) }, getFillType(type) { const typeObj = { actFill: 'orange-border', //实际填写的边框颜色 green: 'green-border', preFill: 'blue-border' //预填写的边框颜色 } return typeObj[type] || '' }, onInputNumberChange(key, val) { this.formFields[key] = val // 清除该表单项的错误状态 if (this.errors[key]) { this.$set(this.errors, key, false) } }, //批量更新表单数据 batchUpdateFormData(data) { const cloneFormFields = JSON.parse(JSON.stringify(this.formFields)) Object.keys(data).forEach((key) => { this.oldFormFields[key] = cloneFormFields[key] this.formFields[key] = data[key] // 清除该表单项的错误状态 if (this.errors[key]) { this.$set(this.errors, key, false) } }) }, //更新表单数据 updateFormData(key, value, data) { const { isUpdateRecord, signData } = data || {} // 深拷贝当前表单数据,避免直接修改原数据 const cloneFormFields = JSON.parse(JSON.stringify(this.formFields)) this.oldFormFields[key] = cloneFormFields[key] this.formFields[key] = value // 清除该表单项的错误状态 if (this.errors[key]) { this.$set(this.errors, key, false) } if (isUpdateRecord) { setTimeout(() => { this.$refs[key][0].handleUpdateRecord(signData, { oldValue: this.oldFormFields[key], inputValue: value }) }, 10) } }, handleClickable(sItem, key) { if (this.templateFillType !== 'actFill') { return } this.clickableKey = key this.$emit('clickable', sItem) }, //根据span判断一行显示几列 getSpanClass(sItem) { const spanArr = ['full-row', '', 'three-row'] if (sItem.span) { return spanArr[sItem.span - 1] } return '' }, //获取其他下拉框的配制 getOtherItem(sItem) { return { label: sItem.otherLabel ? this.$t(sItem.otherLabel) : this.$t('template.common.other'), fillType: sItem.fillType, maxlength: sItem.otherMaxlength || 50, parentLabel: sItem.label, options: sItem.otherOptions || [] } }, getRadioOtherItem(sItem) { return { // label: sItem.otherLabel ? this.$t(sItem.otherLabel) : this.$t("template.common.other"), fillType: sItem.fillType, maxlength: sItem.otherMaxlength || 50, parentLabel: sItem.label } }, getClickableItem(sItem) { return { label: '', type: 'clickable', fillType: sItem.subFillType || sItem.fillType, parentLabel: sItem.label } }, getSubItem(sItem) { const config = { label: '', options: sItem.subOptions || [], fillType: sItem.subFillType || sItem.fillType, parentLabel: sItem.label } if (sItem.subDisabled) { config.disabled = sItem.subDisabled } return config }, //获取第三个的配制 getThirdItem(sItem) { const config = { label: '', options: sItem.thirdOptions || [], fillType: sItem.thirdFillType, parentLabel: sItem.label, maxlength: sItem.thirdMaxlength || 50 } if (sItem.thirdDisabled) { config.disabled = sItem.thirdDisabled } return config }, // 根据formConfig回填form表单数据 handleFormField(update = false) { const result = {} let config = {} const { formConfig, formData, formFields } = this // 遍历配制 formConfig.forEach((item) => { if (item.config) { // 合并配制项 config = { ...config, ...item.config } // 处理每个配制项 Object.keys(item.config).forEach((key) => { const currentConfig = item.config[key] let value = formData[key] // 如果formFields中已经有值,保持原值(用户输入或之前设置的值) if ( formFields[key] !== null && formFields[key] !== undefined && formFields[key] !== '' // typeof formFields[key] !== 'object' ) { // 保留原值,不使用formData中的值 result[key] = formFields[key] } else { // 使用formData中的值 result[key] = value } // 处理特殊字段 - "其他"字段 if (currentConfig.otherCode) { const { otherCode, type } = currentConfig //如果是更新的话,优先使用formFields中的值 if (update) { result[otherCode] = formFields[otherCode] || formData[otherCode] || '' } else { result[otherCode] = formData[otherCode] || formFields[otherCode] || '' } config[otherCode] = { label: 'template.common.other', parentType: type, parentKey: key, type: 'input', fillType: currentConfig.fillType } } if (currentConfig.thirdOtherCode) { const { thirdOtherCode, type } = currentConfig //如果是更新的话,优先使用formFields中的值 if (update) { result[thirdOtherCode] = formFields[thirdOtherCode] || formData[thirdOtherCode] || '' } else { result[thirdOtherCode] = formData[thirdOtherCode] || formFields[thirdOtherCode] || '' } config[thirdOtherCode] = { label: 'template.common.other', parentType: type, parentKey: key, type: 'input', fillType: currentConfig.fillType } } if (currentConfig.subKey) { const { subKey } = currentConfig if (update) { result[subKey] = formFields[subKey] || formData[subKey] || '' } else { result[subKey] = formData[subKey] || formFields[subKey] || '' } config[subKey] = { label: currentConfig.label, subKey, type: currentConfig.subType, fillType: currentConfig.subFillType || currentConfig.fillType, selectTo: currentConfig.selectTo } } if (currentConfig.thirdKey) { const { thirdKey } = currentConfig if (update) { result[thirdKey] = formFields[thirdKey] || formData[thirdKey] || '' } else { result[thirdKey] = formFields[thirdKey] || formData[thirdKey] || '' } config[thirdKey] = { label: currentConfig.label, thirdKey, type: currentConfig.thirdType, fillType: currentConfig.thirdFillType, selectTo: currentConfig.selectTo } } if (currentConfig.fourthKey) { const { fourthKey } = currentConfig if (update) { result[fourthKey] = formFields[fourthKey] || formData[fourthKey] || '' } else { result[fourthKey] = formFields[fourthKey] || formData[fourthKey] || '' } config[fourthKey] = { label: currentConfig.label, fourthKey, type: currentConfig.fourthType, fillType: currentConfig.fourthFillType, selectTo: currentConfig.selectTo } } // 检查compareTo字段 if ( currentConfig.compareTo && formData[currentConfig.compareTo] && result[key] ) { const compareToValue = formData[currentConfig.compareTo] const currentValue = result[key] this.compareFieldsIsEqual(currentValue, compareToValue, key) } // 检查compareTo字段 if ( currentConfig.subCompareTo && formData[currentConfig.subCompareTo] && result[currentConfig.subKey] ) { const compareToValue = formData[currentConfig.subCompareTo] const currentValue = result[currentConfig.subKey] this.compareFieldsIsEqual( currentValue, compareToValue, currentConfig.subKey ) } if ( currentConfig.otherCodeCompareTo && formData[currentConfig.otherCodeCompareTo] && result[currentConfig.otherCode] ) { const compareToValue = formData[currentConfig.otherCodeCompareTo] const currentValue = result[currentConfig.otherCode] this.compareFieldsIsEqual( currentValue, compareToValue, currentConfig.otherCode ) } }) // 处理可能存在的直接otherCode字段 if (item.config?.otherCode) { config[item.config?.otherCode] = item.config?.otherCode } if (item.config?.thirdOtherCode) { config[item.config?.thirdOtherCode] = item.config?.thirdOtherCode } } }) // 处理selectInfo_开头的字段,步骤表单需要保留selectInfo_开头的字段 const selectInfoKeys = Object.keys(formData).filter((key) => key.startsWith('selectInfo_') ) selectInfoKeys.forEach((key) => { result[key] = formData[key] }) // 更新表单字段 this.formFields = { ...result } this.allFieldsConfig = config }, //比较值是否相等 compareFieldsIsEqual(currentValue, compareToValue, key) { if (!currentValue || !compareToValue) return // 如果当前值与compareTo字段的值不相等,则设置橙色背景 if (isEqual(currentValue, compareToValue)) { // 如果相等,移除橙色背景(如果之前设置了的话) this.$set(this.orangeBgFields, key, false) } else { this.$set(this.orangeBgFields, key, true) } }, //判断是否禁用 getDisabled() { const { item } = this const { fillType } = item if (item.hasOwnProperty('disabled')) { return item.disabled } else { if (fillType === 'actFill') { //当模板状态是实际填写时,只有当fillType是actFill时才能填写 return this.templateFillType !== 'actFill' } else if (fillType === 'preFill') { //当模板状态是预填写时,只有当fillType是preFill才能填写 return this.templateFillType !== 'preFill' } else { return true } } }, // 表单数据校验 validateFormData() { const { formFields, allFieldsConfig } = this const errors = [] // 清空之前的错误状态 this.errors = {} for (const key in allFieldsConfig) { const o = allFieldsConfig[key] if (o.otherCode) { // if (o.type === 'select') { const isSelectedOther = this.isShowOther(formFields[key], o) if (!isSelectedOther) { //如果其他选项没有被选择,清空其他字段 formFields[o.otherCode] = '' } } else if (o.subType === 'select') { const isSelectedOther = this.isShowOther(formFields[o.subKey], o) if (!isSelectedOther) { //如果其他选项没有被选择,清空其他字段 formFields[o.otherCode] = '' } } else if (o.type === 'radioAndOther') { const isSelectedOther = this.isShowOtherByRadioAndOther( formFields[key], o ) if (!isSelectedOther) { //如果其他选项没有被选择,清空其他字段 formFields[o.otherCode] = '' } } } if (o.type === 'attachment' && o.fillType === this.templateFillType) { const attValue = formFields[key] if (!attValue || attValue == '[]') { errors.push({ field: key, label: o.label, error: '请上传附件' }) this.$set(this.errors, key, true) } } else if (o.type === 'fqyq' && o.fillType === this.templateFillType) { const fqyqValue = formFields[key] || {} const { mainRadio, subRadio, inputValue } = fqyqValue if (!mainRadio) { errors.push({ field: key, label: o.label, error: '请选择是否在规定时间完成' }) this.$set(this.errors, key, true) } else { if (mainRadio === '是') { if (!subRadio) { errors.push({ field: key, label: o.label, error: '请选择是否在规定时间完成' }) this.$set(this.errors, key, true) } else if (!inputValue) { errors.push({ field: key, label: o.label, error: '请输入信息' }) this.$set(this.errors, key, true) } } } continue } else if ( o.type === 'checkboxTree' && o.fillType === this.templateFillType ) { const checkboxTreeValue = formFields[key] || {} const { checkedValues = [], otherValues = {} } = checkboxTreeValue const { options = [] } = o //需要校验第一层是否有选中项 const parentOptions = options.map((item) => item.label) const isChecked = checkedValues.some((option) => { return option.checked === true }) //获取所有选中的选项 const allCheckedOptions = checkedValues .filter((item) => item.checked) .map((item) => item.label) //再筛选出需要显示其他输入框的选项 const otherOptions = allCheckedOptions.filter((label) => isShowOtherByCheckboxTree(label) ) const isHasOtherInfo = otherOptions.every((item) => otherValues[item]) console.log(isChecked, isHasOtherInfo, 'isChecked') if (!isChecked || !isHasOtherInfo) { errors.push({ field: key, label: o.label, error: '请选择方法学验证' }) this.$set(this.errors, key, true) } continue } else if ( o.type === 'radioAndOther' && o.fillType === this.templateFillType ) { const radioValue = formFields[key] || {} const { otherCode } = o const otherValue = formFields[otherCode] || '' const isShow = this.isShowOtherByRadioAndOther(radioValue, o) if (isShow && !otherValue) { errors.push({ field: key, label: o.label, error: '请输入信息' }) this.$set(this.errors, key, true) } // if (!radioValue) { // errors.push({ // field: key, // label: o.label, // error: "请选择方法学验证" // }); // this.$set(this.errors, key, true); // } continue } if (isValueEmpty(formFields[key])) { // 其他字段需要判断是否显示再校验 if ( o.label === 'template.common.other' && !this.isShowOther(formFields[o.parentKey]) ) { continue } //span的字段不校验 if (o.type === 'span' || o.type === 'text' || o.type === 'button') { continue } if (o.fillType === this.templateFillType && !o.disabled) { let prefix = '' if ( o.type === 'input' || o.type === 'inputNumber' || o.type === 'textarea' ) { prefix = '填写' } else { prefix = '选择' } const errorItem = { field: key, label: o.label, error: `请${prefix}${o.label}` } errors.push(errorItem) this.$set(this.errors, key, true) } } } console.log(errors, 'errors') return { valid: errors.length === 0, errors: errors } }, getFormData() { // 同时执行数据校验和子组件校验 const validateResult = this.validateFormData() const subComponentValidateResult = this.validateSubComponents() // const subComponentValidateResult = {valid: true, error: ''}; return new Promise((resolve, reject) => { if (validateResult.valid && subComponentValidateResult.valid) { resolve(this.formFields) } else if (!validateResult.valid) { // this.$message.error("表单内容未填完,请填写后再提交"); reject(validateResult.errors[0].error) } else { reject(subComponentValidateResult.error) } }) }, // 子组件校验钩子方法,子组件可以重写此方法来添加额外的校验逻辑 validateSubComponents() { return { valid: true, error: '' } }, //直接获取表单数据,不做校验 getFilledFormData() { return this.formFields }, getFormDataByKey(key) { return this.formFields[key] }, onBlur(key, val) { // compareTo 功能:当fillType==="actFill"时,判断当前值是否与compareTo字段的值一样,如果不一样则将当前input框的背景色标记成橙色 this.onValueChangeCompareTo(key, val) if (this.errors[key]) { this.$set(this.errors, key, false) } this.$emit('blur', { key, value: val, ...this.formFields }) }, onValueChangeCompareTo(key, val, compKey) { // compareTo 功能:当fillType==="actFill"时,判断当前值是否与compareTo字段的值一样,如果不一样则将当前input框的背景色标记成橙色 const currentFieldConfig = this.allFieldsConfig[key] if (currentFieldConfig && currentFieldConfig.fillType === 'actFill') { if (currentFieldConfig.compareTo || compKey) { const compareToKey = compKey || currentFieldConfig.compareTo const compareToValue = this.formFields[compareToKey] this.compareFieldsIsEqual(val, compareToValue, key) } if ( currentFieldConfig.otherCodeCompareTo && this.formFields[currentFieldConfig.otherCodeCompareTo] && this.formFields[currentFieldConfig.otherCode] ) { const compareToValue = this.formFields[currentFieldConfig.otherCodeCompareTo] const currentValue = this.formFields[currentFieldConfig.otherCode] this.compareFieldsIsEqual( currentValue, compareToValue, currentFieldConfig.otherCode ) } if ( currentFieldConfig.subCompareTo && this.formFields[currentFieldConfig.subCompareTo] && this.formFields[currentFieldConfig.subKey] ) { const compareToValue = this.formFields[currentFieldConfig.subCompareTo] const currentValue = this.formFields[currentFieldConfig.subKey] this.compareFieldsIsEqual( currentValue, compareToValue, currentFieldConfig.subKey ) } } }, onAttachmentChange(key, val) { this.formFields[key] = val // 清除该表单项的错误状态 if (this.errors[key]) { this.$set(this.errors, key, false) } // 如果是checkboxList类型,需要处理otherValues if (val && typeof val === 'object' && val.otherValues) { // 将otherValues中的每个值也保存到formFields中 Object.keys(val.otherValues).forEach((otherCode) => { this.formFields[otherCode] = val.otherValues[otherCode] }) } }, //复制 onCopy(config, key) { const { formFields } = this if (config.copyFrom) { formFields[key] = formFields[config.copyFrom] this.onBlur(key, formFields[key]) } }, resetRecord(key) { this.formFields = { ...this.formFields, ...this.oldFormFields } this.oldFormFields = {} } } }