<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]" v-bind="item" :upload-query="{ formId, patientId, prefix: item.prop }" :disabled="item.disabled" ></el-upload-self> <!-- 表单改文本 --> <template v-else-if="getVwForm.detail"> <form-item-text :item="item" :form="form"></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' : ''" :readonly="item.readonly" :disabled="item.disabled" :placeholder=" 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" @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'" 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> <!-- 多选框 --> <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" > <el-option v-for="(opt, optIndex) in item.dicData" :key="optIndex" :label="opt.label" :value="opt.value" ></el-option> </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" 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" clearable @change="handleChange" ></el-time-picker> <!-- 日期 --> <el-date-picker v-else-if="item.type === 'date'" v-model="form[item.prop]" :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 === '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 : '请选择'" clearable :disabled="item.disabled" :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 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: {}, 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, type: String, }, data() { return { pickerOptions, rangeOptions, } }, 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() }, mounted() { this.showFormItem() }, methods: { 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) }, // 获取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}`, function (val) { const columns = this.columns || [] const group = this.group || [] const dyMap = {} // 显示数据集合 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) { targetItem = group.find((_) => _.prop === key) } if (!targetItem) return const values = dyMap[key] let display = false if (Array.isArray(val)) { // 胃癌和进展性胃癌单独控制 if ( prop == "early_gastric_cancer" || prop == "period_gastric_cancer" ) { let flag = false 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(targetItem) display = flag if (display) { targetItem.rules[0] = { required: true, message: "请上传病理报告", } } else { if (targetItem.rules.length > 0) { targetItem.rules[0].required = false } } } else { display = values.filter((v) => val.includes(v)).length > 0 } } else { display = values.includes(val) } 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 { if (prop == "check_type" && Boolean(display)) { targetItem.rules[0] = { required: true, message: "请上传内镜报告", } } else if (prop == "check_type") { targetItem.rules = [] } this.$set(targetItem, "display", Boolean(display)) } }) }, { immediate: !noImmediate, } ) } }, // handleBlur() { this.handleAlgorithm() }, handleChange(val) { this.checkboxRepel(val) this.handleAlgorithm() // 该操作判断是否符合筛查条件 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 2px !important; } .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>