<template> <el-row :ref="item.prop" class="custom-form-item" :style="item.styles" :class="{ isDefects: defectsSet.includes(item.prop) }" > <el-col :lg="item.width" :style="{ height: item.type === 'upload' ? '116px' : '53px' }" > <div v-if=" showIndex || (configForms && configForms.showIndex) || item.showIndex " :class="['formIndex', item.labelSuffix == '5' ? 'computeIndex' : '']" > {{ item.labelSuffix || columnIndex + 1 }} </div> <!-- <el-form-item :label=" !hiddenLabel && item.label ? `${item.label}${item.labelSuffix || ''}` : '' " :label-width="item.labelWidth ? `${item.labelWidth}px` : ''" :prop="item.prop" :rules="item.rules" :class="isEmpty" >--> <el-form-item :label="!hiddenLabel && item.label ? `${item.label}` : ''" :label-width="item.labelWidth ? `${item.labelWidth}px` : ''" :prop="item.prop" :rules="item.rules" :class="isEmpty" > <div class="flex"> <div> <el-upload-self v-if="item.type === 'upload'" v-model="form[item.prop]" :btn-type="'text'" v-bind="item" :list-type="item.listType" :upload-query="{ formId, patientId, prefix: item.prop }" :accept="item.accept" :limit="item.limit" :disabled="item.disabled" ></el-upload-self> <!-- 表单改文本 --> <template v-else-if="getVwForm.detail"> <form-item-text :item="item" :form="form" :union-list="unionList" ></form-item-text> </template> <!-- 可输入 --> <template v-else> <!-- 输入框 --> <el-input v-if="item.type === 'input'" v-model="form[item.prop]" :class=" item.prop == 'other_sickness' ? 'needlong' : item.readonly ? 'read-input' : '' " :readonly="item.readonly" :disabled="item.disabled" :placeholder=" item.disabled || item.readonly ? '' : item.placeholder || ` ${item.label ? '请输入' + item.label : ''}` " :clearable="item.notClearable ? false : true" :maxlength=" item.maxlength ? item.maxlength : item.fieldType === 'text' ? '' : item.fieldLength " @blur="handleBlur" > <!-- 牙位按钮 --> <el-button v-if="item.toothBit" slot="append" class="toothBit" @click="openToothBit" >{{ item.append || "牙位" }}</el-button > <template v-else-if="item.append" slot="append"> {{ item.append }} </template> <template v-if="item.prepend" slot="prepend"> {{ item.prepend }} </template> </el-input> <!-- 密码框 --> <el-input v-if="item.type === 'password'" v-model="form[item.prop]" type="password" :placeholder="item.placeholder || `请输入 ${item.label || ''}`" :readonly="item.readonly" :disabled="item.disabled" :show-password="item.showPassword" clearable :maxlength=" item.maxlength ? item.maxlength : item.fieldType === 'text' ? '' : item.fieldLength " @blur="handleBlur" > <template v-if="item.append" slot="append"> {{ item.append }} </template> <template v-if="item.prepend" slot="prepend"> {{ item.prepend }} </template> </el-input> <!-- 文本域 --> <template v-if="item.type === 'textarea'"> <el-input v-model="form[item.prop]" type="textarea" :placeholder=" item.placeholder || `请输入 ${item.label || ''}` " :autosize="{ minRows: item.minRows, maxRows: item.maxRows }" :minlength="item.minlength" :disabled="item.disabled" :maxlength=" item.maxlength ? item.maxlength : item.fieldType === 'text' ? '' : item.fieldLength " :show-word-limit="item.showWordLimit" @blur="handleBlur" ></el-input> </template> <!-- 计数器 --> <div v-if="item.type === 'number'" style="display: inline-table"> <el-input-number v-model="form[item.prop]" :readonly="item.readonly" :disabled="item.disabled" :controls="item.controls ? true : false" :controls-position="item.controlsPosition" :placeholder="item.placeholder || '请输入'" :step="item.step" :precision="item.precision" :min="item.minRows" :max="item.maxRows" style="display: table-cell; text-align: left" @blur="handleBlur" ></el-input-number> <span v-if="item.append" class="el-input-group__append" style="line-height: 28px" >{{ item.append }}</span > </div> <!-- 单选框 --> <el-radio-group v-if="item.type === 'radio' && !item.disabled" v-model="form[item.prop]" :disabled="item.disabled" @change="handleChange" > <el-radio v-for="(opt, optIndex) in item.dicData" :key="optIndex" :label="opt.value" >{{ opt.label }}</el-radio > </el-radio-group> <!-- 单选框只读 --> <div v-for="(opt, optIndex) in item.dicData" v-else-if="item.type === 'radio' && item.disabled" :key="optIndex" > <el-radio v-show="opt.value == form[item.prop]" v-model="form[item.prop]" :class=" item.class ? item.class : item.disabled ? 'read-radio' : '' " :label="opt.value" @change="item.func ? item.func($event) : {}" >{{ opt.label }}</el-radio > </div> <!-- 多选框 --> <template v-if="item.type === 'checkbox'"> <el-checkbox-group v-model="form[item.prop]" :disabled="item.disabled" @change="handleChange" > <el-checkbox v-for="(opt, optIndex) in item.dicData" :key="optIndex" :label="opt.value" >{{ opt.label }}</el-checkbox > </el-checkbox-group> </template> <!-- 下拉框 --> <template v-if="item.type === 'select'"> <el-select v-model="form[item.prop]" :clearable="item.clearable" :filterable="item.filterable" :disabled="item.disabled" :placeholder=" item.placeholder ? item.placeholder : `请选择 ${item.label || ''}` " default-first-option :multiple="item.multiple" :multiple-limit="item.limit" @change="handleChange" > <template v-if="item.prop == 'union_id'"> <el-option v-for="(opt, optIndex) in unionList" :key="optIndex" :label="opt.unionName" :value="opt.id" ></el-option> </template> <template v-else> <el-option v-for="(opt, optIndex) in item.dicData" :key="optIndex" :label="opt.label" :value="opt.value" ></el-option> </template> </el-select> </template> <!-- 级联 --> <el-cascader v-else-if="item.type === 'cascader'" v-model="form[item.prop]" :disabled="item.disabled" clearable :filterable="item.filterable" :props="{ multiple: item.multiple }" :options="item.dicData" :show-all-levels="item.showAllLevels" :separator="item.separator" style="width: 100%" @change="handleChange" ></el-cascader> <!-- 时间 --> <el-time-picker v-else-if="item.type === 'time'" v-model="form[item.prop]" :placeholder="item.placeholder ? item.placeholder : '请选择'" :value-format="item.valueFormat" :format="item.format" :disabled="item.disabled" :class="item.disabled ? 'read-time' : ''" style="width: 100%" clearable @change="handleChange" ></el-time-picker> <!-- 时间范围 --> <el-time-picker v-else-if="item.type === 'timerange'" v-model="form[item.prop]" is-range range-separator="至" :start-placeholder="item.startPlaceholder" :end-placeholder="item.endPlaceholder" :unlink-panels="item.unlinkPanels" :value-format="item.valueFormat" :format="item.format" :disabled="item.disabled" :class="item.disabled ? 'read-time' : ''" clearable @change="handleChange" ></el-time-picker> <!-- 日期 --> <div v-else-if="item.type === 'date'" class="flex" :class="item.disabled ? 'read-time' : ''" > <el-date-picker v-model="form[item.prop]" :placeholder=" item.placeholder ? item.placeholder : item.disabled ? '' : '请选择' " :value-format="item.valueFormat" :format="item.format" :disabled="item.disabled" clearable @change="handleChange" ></el-date-picker> <span v-if="item.prop == 'birthday'" style="margin-left: 12px" >{{ age + (age ? "岁" : "") }}</span > </div> <!-- 年 --> <el-date-picker v-else-if="item.type === 'year'" v-model="form[item.prop]" type="year" :placeholder="item.placeholder ? item.placeholder : '请选择'" :value-format="item.valueFormat" :format="item.format" :disabled="item.disabled" clearable @change="handleChange" ></el-date-picker> <!-- 月 --> <el-date-picker v-else-if="item.type === 'month'" v-model="form[item.prop]" type="month" :placeholder="item.placeholder ? item.placeholder : '请选择'" :value-format="item.valueFormat" :format="item.format" :disabled="item.disabled" clearable @change="handleChange" ></el-date-picker> <!-- 周 --> <el-date-picker v-else-if="item.type === 'week'" v-model="form[item.prop]" type="week" :placeholder="item.placeholder ? item.placeholder : '请选择'" :value-format="item.valueFormat || 'yyyy-ww'" :format="item.format || 'yyyy 第 WW 周'" :disabled="item.disabled" clearable @change="handleChange" ></el-date-picker> <!-- 日期范围 --> <el-date-picker v-else-if="item.type === 'daterange'" v-model="form[item.prop]" type="daterange" range-separator="至" :start-placeholder="item.startPlaceholder" :end-placeholder="item.endPlaceholder" :unlink-panels="item.unlinkPanels" :value-format="item.valueFormat" :format="item.format" :disabled="item.disabled" clearable @change="handleChange" ></el-date-picker> <!-- 日期时间 --> <el-date-picker v-else-if="item.type === 'datetime'" v-model="form[item.prop]" type="datetime" :placeholder=" item.placeholder ? item.placeholder : item.disabled ? '' : '请选择' " clearable :disabled="item.disabled" :class="item.disabled ? 'read-time' : ''" :picker-options="pickerOptions" :value-format="item.valueFormat" :format="item.format" @change="handleChange" ></el-date-picker> <!-- 日期时间范围 --> <el-date-picker v-else-if="item.type === 'datetimerange'" v-model="form[item.prop]" type="datetimerange" :picker-options="rangeOptions" range-separator="至" clearable :disabled="item.disabled" :start-placeholder="item.startPlaceholder" :end-placeholder="item.endPlaceholder" :value-format="item.valueFormat" :format="item.format" align="right" @change="handleChange" ></el-date-picker> </template> </div> <span v-if="item.importantField && !getVwForm.detail" class="important_field" >{{ item.importantFieldDesc || "*" }}</span > </div> </el-form-item> </el-col> <dialog-tooth-bit v-if="item.toothBit" ref="dialog" v-model="form[item.prop]" append-to-body title="牙位选择" ></dialog-tooth-bit> </el-row> </template> <script> /** * @description 自定义单组件 */ import { getMedicalunionList } from "@/api/medicalunion-management" import ElUploadSelf from "@/components/Upload" import FormItemText from "./FormItemText" import DialogToothBit from "./DialogToothBit" import { getTimePoor, getInfoByIdCard } from "@/utils/index" import { getChineseHeadLetter } from "@/utils/chinesePingyin.js" import { pickerOptions, rangeOptions } from "@/data/dateOption" export default { name: "FormItemSelf", components: { ElUploadSelf, FormItemText, DialogToothBit }, inject: { showIndex: { default: false, }, vwForm: {}, formId: { default: () => "", }, getPatientId: { type: Function, default: () => {}, }, getDefectsSet: { type: Function, default: () => {}, }, configForms: { type: Function, default: () => {}, }, }, props: { item: { type: Object, }, form: { type: Object | Array, }, hiddenLabel: { type: Boolean, default: false, }, columns: Array, columnIndex: Number, group: Array, }, data() { return { age: "", pickerOptions, rangeOptions, unionList: [], showChildren: false, // 用来控制不同表单 } }, computed: { getVwForm() { return this.vwForm() }, //重要字段空数据且填写表单时添加重点 isEmpty() { const { importantField, prop } = this.item if (!importantField || this.getVwForm.detail) return "" const value = this.form[prop] // [] let empty = !value if (value === 0) empty = false else if (value && typeof value !== "number") { empty = !(Object.keys(value) || value).length } return empty ? "empty-tip" : "" }, defectsSet() { return this.getDefectsSet ? this.getDefectsSet() : [] }, patientId() { return this.getPatientId ? this.getPatientId() : "" }, }, created() { this.timerangeReset() this.numberReset() this.checkboxReset() //! 处理医联体名称,新增直接请求,其他等union_id后再请求 if (this.item.prop == "union_id") { console.log("倒了") this.unionList = [] // this.getMedicalunionList() if ( this.$route.path == "/screening/add" || this.$route.path == "/screening/index" ) { this.getMedicalunionList() } else { this.$watch( () => this.form[this.item.prop], (newVal, oldVal) => { // console.log("----------有值----------") this.getMedicalunionList() // 做点什么 } ) } } }, mounted() { this.showFormItem() }, beforeDestroy() { this.$watch( () => this.form[this.item.prop], (newVal, oldVal) => {} ) }, methods: { // 获取医联体列表 getMedicalunionList() { getMedicalunionList().then((res) => { if (res.code == 1) { this.unionList = [...res.data] } else { this.unionList = [] } }) }, scrollToView() { if (this.$refs["JY_LCYY"]) { this.$refs["JY_LCYY"].$el.scrollIntoView({ behavior: "smooth" }) } }, openToothBit() { this.$refs.dialog.open() }, // 处理timerange 重置后不能选择的问题 timerangeReset() { if (this.item.type === "timerange") { this.$watch(`form.${this.item.prop}`, (val) => { if (val && val.length === 1) { this.form[this.item.prop] = null } }) } }, // 处理number 默认为0的问题 numberReset() { if (this.item.type === "number") { this.$watch( `form.${this.item.prop}`, (val) => { if (!val && val !== 0 && val !== undefined) { this.form[this.item.prop] = undefined } }, { immediate: true } ) } }, // 处理数组 默认值的问题 checkboxReset() { const { type, multiple, value } = this.item if ( type === "checkbox" || (type === "select" && multiple) || type === "cascader" ) { if (value && typeof value === "string") { this.form[this.item.prop] = value.split(",") } this.$watch( `form.${this.item.prop}`, (val) => { if (!Array.isArray(val)) { this.$set(this.form, this.item.prop, []) } }, { immediate: true } ) } }, // 处理复选框排斥 checkboxRepel(val) { const { repelValue, repel } = this.item if (repel && repelValue) { const len = val.length const lastValue = val[len - 1] if (!lastValue) return if (lastValue === repelValue) { this.form[this.item.prop].splice(0, len - 1) } else { let idx = val.findIndex((_) => _ === repelValue) if (idx > -1) { this.form[this.item.prop].splice(idx, 1) } } } }, // 处理运算规则 handleAlgorithm() { const { algorithm } = this.item if (algorithm) { const algorithmArr = algorithm.split(";") //多个规则数组集合 algorithmArr.forEach((item) => { if (item.includes("|")) { // 自定义方法规则: type|target|args const algorithmValue = item.split("|") this.handleSelfProcess(algorithmValue) } else { // 直接运算 target=process let target = this.getProp(algorithm.split("=")[0]) if (!this.form.hasOwnProperty(target)) return let process = this.getProcess(algorithm.split("=")[1]) if (process.includes("stop")) return try { this.$set(this.form, target, eval(process)) } catch {} } }) } }, // 自定义方法规则 handleSelfProcess(algorithmValue) { const type = algorithmValue[0] const ruleTarget = algorithmValue[1] const ruleArgs = algorithmValue[2] if (!ruleTarget || !ruleArgs || !this.form.hasOwnProperty(ruleTarget)) return const args = ruleArgs.split(",").map((v) => { if (v) { return this.form[v] } return null }) let val switch (type) { // 时间差 case "timepoor": val = getTimePoor(...args) break case "initials": //计算中文姓名缩写 val = getChineseHeadLetter(...args) break case "idcard_birthdate": val = getInfoByIdCard(...args) break case "idcard_age": val = getInfoByIdCard(...args, "age") break case "idcard_gender": val = getInfoByIdCard(...args, "gender") break default: break } val && this.$set(this.form, ruleTarget, val) }, // 根据生日设置年龄回显 getAge() { if (this.form.birthday) { var birthday = new Date(this.form.birthday.replace(/-/g, "/")) var d = new Date() var age = d.getFullYear() - birthday.getFullYear() - (d.getMonth() < birthday.getMonth() || (d.getMonth() == birthday.getMonth() && d.getDate() < birthday.getDate()) ? 1 : 0) this.age = age + "" } else { this.age = "" } }, // 获取prop prop 以{}包裹 getProp(value) { if (!value) return "" return value.replace(/[{][\w]*[}]/g, (word) => { return word.replace(/{|}/g, "") }) }, // 获取运算过程 getProcess(value) { return value.replace(/[{][\w]*[}]/g, (word) => { const actualValue = this.form[word.replace(/{|}/g, "")] return actualValue ? actualValue : "stop" }) }, // 表单子项控制显隐 showFormItem() { const { dynamicshSet, prop, noImmediate } = this.item if (dynamicshSet && dynamicshSet.length > 0) { this.$watch( `form.${prop}`, (val) => { //! val 表单的当前属性值 const columns = this.columns || [] const group = this.group || [] const dyMap = {} //! 显示数据集合 let filterArr = [ "early_esophagus_cancer", "period_esophagus_cancer", "early_gastric_cancer", "pathology_path", "esophagus_level", ] dynamicshSet.forEach((dy) => { if (dyMap[dy.target]) { dyMap[dy.target].push(dy.value) } else { dyMap[dy.target] = [dy.value] } }) Object.keys(dyMap).forEach((key) => { // !获取显隐目标 let targetItem = columns.find((_) => _.prop === key) if (!targetItem) { // !没有在表单子组件中找到,查找大表单id targetItem = group.find((_) => _.prop === key) } //没有找到再细化查找 if (!targetItem) { group.forEach((_) => { if (_.column) { _.column.find((item) => { if (item.prop === key) { targetItem = item return } else { if (item.children && item.children.column) { targetItem = item.children.column.find( (e) => e.prop === key ) } } }) } }) } if (!targetItem) return let display = false const values = dyMap[key] if (Array.isArray(val)) { display = values.filter((v) => val.includes(v)).length > 0 } else { display = values.includes(val + "") } //! 胃上皮瘤变(高级别)胃癌和进展性胃癌控制显隐+自定义规则 if ( prop == "early_gastric_cancer" || prop == "period_gastric_cancer" || prop == "inogm_level" ) { let flag = false this.form.inogm_level == "high" ? (flag = true) : (flag = false) if (!flag) { if (this.form.early_gastric_cancer) { this.form.early_gastric_cancer.length > 0 ? (flag = true) : (flag = false) } } if (!flag) { if (this.form.period_gastric_cancer) { this.form.period_gastric_cancer.length > 0 ? (flag = true) : (flag = false) } } // console.log(flag, targetItem) display = flag if (display) { targetItem.rules = [ { required: true, message: "请上传病理报告", }, ] } else { if (targetItem.rules.length > 0) { targetItem.rules[0].required = false } } } if (!display && targetItem) { // 清空数据 const newVal = Array.isArray(this.form[targetItem.prop]) ? [] : targetItem.type === "number" ? undefined : "" this.$set(this.form, targetItem.prop, newVal) } if (this.type === "form") { // 动态表格、表单处理 setTimeout(() => { this.$set(this.form, "$_hidden" + targetItem.prop, !display) }, 200) } else { // ! 设置每个表单中每项的rules if (!filterArr.includes(targetItem.prop)) { if (targetItem.rules && Boolean(display)) { if (targetItem.type == "checkbox") { targetItem.rules = [ { required: true, message: "请选择" + targetItem.label, }, ] } else if (targetItem.type == "upload") { targetItem.rules = [ { required: true, message: "请上传" + targetItem.label, }, ] } else { targetItem.rules = [ { required: true, message: "请输入" + targetItem.label, }, ] } } else if (targetItem.rules && !Boolean(display)) { targetItem.rules = [] } } // !设置大表单里的每个小表单rules if (targetItem.prop == "1669874397313_56690") { console.log(display) // !只能写死,当前情况下,定义一个字段用来缓存是否回显,根据val // if (val == 0) { // this.showChildren = false targetItem.column.forEach((e, index) => { // 去除esd报告 if (e.prop == "esd_path") { return } // console.log(e.label, ":", e.rules) if (e.rules && val == 0) { targetItem.column[index].rules = [] } else if (e.rules && val == 1) { if (filterArr.includes(targetItem.column[index].prop)) { return } if ( targetItem.column[index].type == "checkbox" || targetItem.column[index].type == "date" || targetItem.column[index].type == "radio" ) { targetItem.column[index].rules = [ { required: true, message: "请选择" + targetItem.column[index].label, }, ] } else if (targetItem.column[index].type == "upload") { targetItem.rules = [ { required: true, message: "请上传" + targetItem.column[index].label, }, ] } else { targetItem.column[index].rules = [ { required: true, message: "请输入" + targetItem.column[index].label, }, ] } } }) } this.$set(targetItem, "display", Boolean(display)) } }) }, { immediate: !noImmediate, } ) } }, // handleBlur() { this.handleAlgorithm() }, // 每个表单值改变的方法 handleChange(val) { this.checkboxRepel(val) this.handleAlgorithm() // !设置年龄 if (this.item.prop == "birthday") { this.getAge() } if (this.item.prop == "sex") { sessionStorage.setItem("addSex", this.form.sex) this.$emit("validateForm") } // 该操作判断是否符合筛查条件 this.$emit("formChange") // ['is_one_year','is_subtotal_history','is_ppi','is_symptom','is_subtotal_history','is_disease','is_tumour'] }, }, } </script> <style lang="scss" scoped> .custom-form-item { background: white; border-bottom: 1px solid #ccc; // margin: 3px; .el-col { height: 100%; display: flex; align-items: center; } .formIndex { min-width: 53px; height: 100%; background: #fafafa; border-right: 1px solid #ccc; font-size: 14px; justify-content: center; display: flex; align-items: center; // margin-right: 20px; } &.isDefects { border: 1px solid red; } ::v-deep .el-form-item { padding: 10px 0 10px 20px; margin-bottom: 0px; } .toothBit { ::v-deep .el-input-group__append { background-color: #1890ff; border-color: #1890ff; color: #fff; } } .el-input, .el-select, .el-cascader, .el-date-editor { width: 100%; } .el-input-number { width: 100%; } .flex { align-items: center; > div { flex: 1; } } .inline-block { > div { display: inline-block; } } .important_field { color: #ff4d4f; padding-left: 10px; display: inline-block; max-width: 150px; line-height: 1.2; } ::v-deep .el-input-number .el-input__inner { padding: 0 15px !important; text-align: left; } .el-radio { padding: 2px 0; } // 去除禁用样式 ::v-deep .is-disabled { input { background-color: #fff; color: #606266; } .el-textarea__inner, .el-input__inner { background-color: #fff; color: #606266; } .el-checkbox__inner, .el-radio__inner { background-color: #fff; } + span.el-checkbox__label, + span.el-radio__label { color: #606266; } &.is-checked { .el-radio__inner { border-color: #1890ff; background: #1890ff; &::after { background: #fff; } } + .el-radio__label { color: #1890ff; } .el-checkbox__inner { background-color: #1890ff; border-color: #1890ff; &::after { border-color: #fff; } } } } .empty-tip { ::v-deep .el-form-item__label { color: #333333; } } ::v-deep .el-form-item__label { font-weight: bolder; } // ::v-deep .el-form-item__label::after { // content: "☑"; // color: #ff4d4f; // margin-left: 4px; // } ::v-deep .el-checkbox-group { &::after, &::before { content: " "; display: table; } &::after { clear: both; visibility: hidden; font-size: 0; height: 0; } .el-checkbox { float: left; } } } ::v-deep .needlong { width: 260px !important; } </style>