|
|
@@ -1,42 +1,68 @@
|
|
|
<template>
|
|
|
- <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="800px" @close="handleClose" append-to-body>
|
|
|
- <el-form validate-on-rule-change :rules="rules" ref="form" :model="form" label-width="140px">
|
|
|
- <!-- 动态渲染问题区域 -->
|
|
|
- <div v-if="form.answers && form.answers.length > 0">
|
|
|
- <div style="margin-bottom: 20px;margin-top: 20px;" v-for="(answer, index) in form.answers" :key="index">
|
|
|
- <div style="margin-bottom: 20px;margin-top: 20px;">
|
|
|
- <span style="font-size: 15px;font-weight: bold; margin-left: 31px">{{ answer.title }}</span>
|
|
|
- </div>
|
|
|
- <div style="margin-left: 31px;">
|
|
|
- <el-checkbox-group
|
|
|
- v-model="answer.value"
|
|
|
- size="mini"
|
|
|
- @change="onCheckboxGroupChange(answer)">
|
|
|
- <div v-for="(option, optionIndex) in answer.options" :key="`${index}-${optionIndex}`" style="display: flex; align-items: center; margin-bottom: 10px;">
|
|
|
- <el-checkbox :label="option.value" style="margin-right: 10px; flex-shrink: 0;">
|
|
|
- {{ option.name }}
|
|
|
- </el-checkbox>
|
|
|
+ <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="1000px" @close="handleClose" append-to-body>
|
|
|
+ <div style="max-height: 60vh; overflow-y: auto; padding-right: 10px;">
|
|
|
+ <el-form validate-on-rule-change :rules="rules" ref="form" :model="form" label-width="140px">
|
|
|
+ <!-- 动态渲染问题区域 -->
|
|
|
+ <div v-if="form.answers && form.answers.length > 0">
|
|
|
+ <div style="margin-bottom: 20px;margin-top: 20px;" v-for="(answer, index) in form.answers" :key="index">
|
|
|
+ <div style="margin-bottom: 20px;margin-top: 20px;">
|
|
|
+ <span style="font-size: 15px;font-weight: bold; margin-left: 31px">{{ answer.title }}</span>
|
|
|
+ </div>
|
|
|
+ <div style="margin-left: 31px;">
|
|
|
+ <el-checkbox-group
|
|
|
+ v-model="answer.value"
|
|
|
+ size="mini"
|
|
|
+ @change="onCheckboxGroupChange(answer)">
|
|
|
+ <div v-for="(option, optionIndex) in answer.options" :key="`${index}-${optionIndex}`" style="display: flex; align-items: center; margin-bottom: 10px;">
|
|
|
+ <el-checkbox :label="option.value" style="margin-right: 10px; flex-shrink: 0;">
|
|
|
+ {{ option.name }}
|
|
|
+ </el-checkbox>
|
|
|
|
|
|
- <!-- 备注输入区域(含必填提示) -->
|
|
|
- <div v-if="option.open && isOptionSelected(answer, option)" style="display: inline-block;">
|
|
|
- <el-input
|
|
|
- v-model="option.remarkText"
|
|
|
- placeholder="请输入备注信息"
|
|
|
- size="mini"
|
|
|
- maxlength="20"
|
|
|
- show-word-limit
|
|
|
- style="width: 200px; margin-left: 5px;"
|
|
|
- :class="{ 'remark-required': !option.remarkText || option.remarkText.trim() === '' }"
|
|
|
- @blur="onRemarkBlur(option)"/>
|
|
|
- <div v-if="!option.remarkText || option.remarkText.trim() === ''" class="remark-error-tip">此项为必填</div>
|
|
|
+ <div v-if="option.open && isOptionSelected(answer, option)" style="display: inline-block;">
|
|
|
+ <el-input
|
|
|
+ v-model="option.remarkText"
|
|
|
+ placeholder="请输入备注信息"
|
|
|
+ size="mini"
|
|
|
+ maxlength="20"
|
|
|
+ show-word-limit
|
|
|
+ style="width: 200px; margin-left: 5px;"
|
|
|
+ :class="{ 'remark-required': !option.remarkText || option.remarkText.trim() === '' }"
|
|
|
+ @blur="onRemarkBlur(option)"/>
|
|
|
+ <div v-if="!option.remarkText || option.remarkText.trim() === ''" class="remark-error-tip">此项为必填</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </el-checkbox-group>
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- </el-form>
|
|
|
+ <!-- 选择默认患者(必填) -->
|
|
|
+ <el-form-item label="默认患者" prop="selectedPatientId" style="margin-top: 20px;">
|
|
|
+ <el-select
|
|
|
+ v-model="form.selectedPatientId"
|
|
|
+ placeholder="请选择患者"
|
|
|
+ clearable
|
|
|
+ size="small"
|
|
|
+ style="width: 300px;"
|
|
|
+ @change="onPatientChange"
|
|
|
+ @focus="loadPatientList"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="patient in patientList"
|
|
|
+ :key="patient.patientId"
|
|
|
+ :label="patient.patientName || patient.name || '患者' + patient.patientId"
|
|
|
+ :value="patient.patientId"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 患者详细信息区域(始终显示) -->
|
|
|
+ <div style="margin-top: 20px; border-top: 1px solid #EBEEF5; padding-top: 20px;">
|
|
|
+ <user-details ref="userDetails" />
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
|
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
|
|
@@ -46,36 +72,27 @@
|
|
|
|
|
|
<script>
|
|
|
import { getInfo, submitSalesInfo } from "@/api/qw/collectionPendingSales";
|
|
|
+import UserDetails from '@/views/store/components/userDetails1.vue';
|
|
|
+import { getUndeletedUserInfoByUserId } from "@/api/store/patient";
|
|
|
|
|
|
export default {
|
|
|
name: "CompleteCollectionInfoDialog",
|
|
|
+ components: {
|
|
|
+ UserDetails
|
|
|
+ },
|
|
|
props: {
|
|
|
- visible: {
|
|
|
- type: Boolean,
|
|
|
- default: false
|
|
|
- },
|
|
|
- id: {
|
|
|
- type: Number,
|
|
|
- required: true
|
|
|
- },
|
|
|
- userId: {
|
|
|
- type: Number,
|
|
|
- required: true
|
|
|
- },
|
|
|
- questionId: {
|
|
|
- type: Number,
|
|
|
- required: true
|
|
|
- }
|
|
|
+ visible: { type: Boolean, default: false },
|
|
|
+ id: { type: Number, required: true },
|
|
|
+ userId: { type: Number, required: true },
|
|
|
+ questionId: { type: Number, required: true }
|
|
|
},
|
|
|
data() {
|
|
|
- // 自定义验证规则:检查需要备注的选项是否填写了备注
|
|
|
const validateRequiredRemarks = (rule, value, callback) => {
|
|
|
if (!this.validateRequiredRemarks()) {
|
|
|
return callback(new Error('请填写必填的备注信息'));
|
|
|
}
|
|
|
callback();
|
|
|
};
|
|
|
-
|
|
|
return {
|
|
|
dialogVisible: false,
|
|
|
form: {
|
|
|
@@ -91,16 +108,16 @@ export default {
|
|
|
sex: null,
|
|
|
age: null,
|
|
|
allergy: '',
|
|
|
- remark: ''
|
|
|
+ remark: '',
|
|
|
+ selectedPatientId: null,
|
|
|
+ patientInfo: null //选中的患者完整信息对象
|
|
|
},
|
|
|
+ patientList: [],
|
|
|
privatePackageOptions: [],
|
|
|
- // 新增:加载状态
|
|
|
loading: false,
|
|
|
rules: {
|
|
|
- // 添加对备注的验证
|
|
|
- answers: [
|
|
|
- {required: true, validator: validateRequiredRemarks, trigger: 'blur'}
|
|
|
- ]
|
|
|
+ answers: [{ required: true, validator: validateRequiredRemarks, trigger: 'blur' }],
|
|
|
+ selectedPatientId: [{ required: true, message: '请选择默认患者', trigger: 'change' }]
|
|
|
}
|
|
|
};
|
|
|
},
|
|
|
@@ -120,10 +137,7 @@ export default {
|
|
|
immediate: true
|
|
|
}
|
|
|
},
|
|
|
- created() {
|
|
|
- },
|
|
|
methods: {
|
|
|
- // 验证需要备注的选项是否填写了备注
|
|
|
validateRequiredRemarks() {
|
|
|
for (const answer of this.form.answers) {
|
|
|
for (const option of answer.options) {
|
|
|
@@ -137,24 +151,56 @@ export default {
|
|
|
return true;
|
|
|
},
|
|
|
|
|
|
- // 监听复选框组的变化
|
|
|
+ // 患者切换时构建 patientInfo
|
|
|
+ onPatientChange(patientId) {
|
|
|
+ if (patientId) {
|
|
|
+ const patient = this.patientList.find(p => p.patientId === patientId);
|
|
|
+ if (patient) {
|
|
|
+ // 构建与后端 PatientInfo 结构一致的对象
|
|
|
+ this.form.patientInfo = {
|
|
|
+ patientId: patient.patientId,
|
|
|
+ patientName: patient.patientName || patient.name || '',
|
|
|
+ mobile: patient.mobile || patient.phone || patient.tel || '',
|
|
|
+ sex: String(patient.sex ?? ''),
|
|
|
+ birthday: patient.birthday || null
|
|
|
+ };
|
|
|
+
|
|
|
+ // 同时设置 selectedPatientId
|
|
|
+ this.form.selectedPatientId = patientId;
|
|
|
+
|
|
|
+ // 如果患者名称是"默认就诊人",提示完善信息并清空选择
|
|
|
+ if (patient.patientName === '默认就诊人') {
|
|
|
+ this.$confirm('当前选择的患者信息为默认值,请完善患者信息后再提交!', '提示', {
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ // 清空当前选择
|
|
|
+ this.form.selectedPatientId = null;
|
|
|
+ this.form.patientInfo = null;
|
|
|
+
|
|
|
+ }).catch(() => {
|
|
|
+ // 用户点击取消,清空选择
|
|
|
+ this.form.selectedPatientId = null;
|
|
|
+ this.form.patientInfo = null;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果清空了选择,也要清空 patientInfo
|
|
|
+ this.form.patientInfo = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
onCheckboxGroupChange(answer) {
|
|
|
- // 遍历所有选项,如果选项未被选中,则清除其备注文本
|
|
|
answer.options.forEach(option => {
|
|
|
if (!answer.value.includes(option.value)) {
|
|
|
option.remarkText = '';
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
-
|
|
|
- // 检查选项是否被选中
|
|
|
isOptionSelected(answer, option) {
|
|
|
return answer.value && answer.value.includes(option.value);
|
|
|
},
|
|
|
-
|
|
|
- // 备注输入框失去焦点时的处理
|
|
|
onRemarkBlur(option) {
|
|
|
- // 如果备注文本为空,则清空
|
|
|
if (!option.remarkText?.trim()) {
|
|
|
option.remarkText = '';
|
|
|
}
|
|
|
@@ -163,7 +209,9 @@ export default {
|
|
|
initDialog() {
|
|
|
this.resetFormData();
|
|
|
if (this.userId) {
|
|
|
+ this.loadPatientList();
|
|
|
this.loadUserData();
|
|
|
+ this.loadPatientInfo();
|
|
|
}
|
|
|
this.$nextTick(() => {
|
|
|
if (this.$refs.form) {
|
|
|
@@ -174,9 +222,10 @@ export default {
|
|
|
|
|
|
loadUserData() {
|
|
|
this.loading = true;
|
|
|
- getInfo({userId: this.userId, questionId: this.questionId}).then(response => {
|
|
|
+ getInfo({ userId: this.userId, questionId: this.questionId }).then(response => {
|
|
|
const data = response.data;
|
|
|
this.form = {
|
|
|
+ ...this.form,
|
|
|
id: data.id,
|
|
|
questionId: data.questionId,
|
|
|
packageId: data.packageId,
|
|
|
@@ -189,7 +238,9 @@ export default {
|
|
|
sex: data.sex,
|
|
|
age: data.age,
|
|
|
allergy: data.allergy,
|
|
|
- remark: data.remark
|
|
|
+ remark: data.remark,
|
|
|
+ selectedPatientId: this.form.selectedPatientId, // 避免覆盖可能回填的值
|
|
|
+ patientInfo: this.form.patientInfo
|
|
|
};
|
|
|
}).catch(error => {
|
|
|
this.$message.error('加载用户信息失败');
|
|
|
@@ -198,35 +249,22 @@ export default {
|
|
|
this.loading = false;
|
|
|
});
|
|
|
},
|
|
|
-
|
|
|
- // 处理答案数据,确保选项有备注相关的字段
|
|
|
processAnswers(answers) {
|
|
|
- if (!answers || !Array.isArray(answers)) {
|
|
|
- return [];
|
|
|
- }
|
|
|
-
|
|
|
+ if (!answers || !Array.isArray(answers)) return [];
|
|
|
return answers.map(answer => {
|
|
|
- // 建立 value -> text 的映射,用于快速回填备注
|
|
|
const remarksMap = {};
|
|
|
if (answer.remarksList && Array.isArray(answer.remarksList)) {
|
|
|
answer.remarksList.forEach(item => {
|
|
|
remarksMap[item.value] = item.text;
|
|
|
});
|
|
|
}
|
|
|
-
|
|
|
const processedOptions = (answer.options || []).map(option => ({
|
|
|
...option,
|
|
|
- remarkText: remarksMap[option.value] || '' // 有备注则填充,否则为空
|
|
|
+ remarkText: remarksMap[option.value] || ''
|
|
|
}));
|
|
|
-
|
|
|
- return {
|
|
|
- ...answer,
|
|
|
- options: processedOptions
|
|
|
- // 保留原始的 remarksList,但在组件内不再使用它,而是使用选项上的 remarkText
|
|
|
- };
|
|
|
+ return { ...answer, options: processedOptions };
|
|
|
});
|
|
|
},
|
|
|
-
|
|
|
resetFormData() {
|
|
|
this.form = {
|
|
|
id: null,
|
|
|
@@ -241,50 +279,55 @@ export default {
|
|
|
sex: null,
|
|
|
age: null,
|
|
|
allergy: '',
|
|
|
- remark: ''
|
|
|
+ remark: '',
|
|
|
+ selectedPatientId: null,
|
|
|
+ patientInfo: null
|
|
|
};
|
|
|
},
|
|
|
|
|
|
+ loadPatientList() {
|
|
|
+ getUndeletedUserInfoByUserId(this.userId).then(response => {
|
|
|
+ this.patientList = response.data || [];
|
|
|
+ }).catch(() => {
|
|
|
+ this.$message.error('获取患者列表失败');
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ loadPatientInfo() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (this.$refs.userDetails) {
|
|
|
+ this.$refs.userDetails.getDetails(this.userId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
submitForm() {
|
|
|
this.$refs["form"].validate(valid => {
|
|
|
if (valid) {
|
|
|
- // 验证必填备注
|
|
|
if (!this.validateRequiredRemarks()) {
|
|
|
this.$message.error('请填写必填的备注信息');
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- // 构建提交用的 answers 副本,组装 remarksList 并清理临时字段
|
|
|
const answersForSubmit = this.form.answers.map(answer => {
|
|
|
- // 构建 remarksList
|
|
|
const remarks = [];
|
|
|
answer.options.forEach(option => {
|
|
|
if (option.remarkText && option.remarkText.trim()) {
|
|
|
- remarks.push({
|
|
|
- value: option.value,
|
|
|
- text: option.remarkText.trim()
|
|
|
- });
|
|
|
+ remarks.push({ value: option.value, text: option.remarkText.trim() });
|
|
|
}
|
|
|
});
|
|
|
-
|
|
|
- // 清理 options,移除临时字段 remarkText
|
|
|
- const cleanOptions = answer.options.map(({remarkText, ...opt}) => opt);
|
|
|
-
|
|
|
- // 返回符合后端 AnswerVO 结构的对象
|
|
|
- return {
|
|
|
- ...answer,
|
|
|
- remarksList: remarks, // 标准备注字段
|
|
|
- options: cleanOptions // 纯净的选项列表
|
|
|
- };
|
|
|
+ const cleanOptions = answer.options.map(({ remarkText, ...opt }) => opt);
|
|
|
+ return { ...answer, remarksList: remarks, options: cleanOptions };
|
|
|
});
|
|
|
|
|
|
- // 构建提交数据,使用处理后的 answers
|
|
|
+ // 构建提交数据,去掉 selectedPatientId 和 patientInfo 中的临时字段,保证结构清晰
|
|
|
+ const { selectedPatientId, patientInfo, ...restForm } = this.form;
|
|
|
const submitData = {
|
|
|
- ...this.form,
|
|
|
+ ...restForm,
|
|
|
id: this.id,
|
|
|
- answers: answersForSubmit
|
|
|
+ answers: answersForSubmit,
|
|
|
+ patientInfo: patientInfo || null // 提交完整的患者信息对象
|
|
|
};
|
|
|
- // 提交请求
|
|
|
+
|
|
|
submitSalesInfo(submitData).then(res => {
|
|
|
this.$message.success("完善信息成功");
|
|
|
this.dialogVisible = false;
|
|
|
@@ -296,7 +339,6 @@ export default {
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
-
|
|
|
handleClose() {
|
|
|
this.dialogVisible = false;
|
|
|
this.$emit('update:visible', false);
|