fix(surgery): 解决手术申请中的数据绑定和字段映射问题

- 修复了手术申请组件中 userStore 初始化问题,确保 applyDoctorName 和 applyDeptName 正确赋值
- 添加了 surgeryApplication 组件的 saved 事件发射,用于通知父组件刷新医嘱列表
- 修复了手术项目选择变更时 surgeryName 的正确设置和空值处理
- 添加了手术名称和编码的验证逻辑,防止提交时出现空值错误
- 修复了手术排班页面中就诊卡号字段的属性映射(visitId 改为 patientCardNo)
- 在后端 DTO 中添加了 patientCardNo 字段支持
- 修复了数据库查询中就诊卡号的关联查询逻辑,通过患者标识表获取正确的就诊卡号
- 优化了手术医嘱的 contentJson 设置,确保手术名称和编码正确存储
This commit is contained in:
2026-04-02 17:54:07 +08:00
parent 09fdfa294a
commit b497eb853c
8 changed files with 132 additions and 9 deletions

View File

@@ -343,7 +343,24 @@ public class SurgeryAppServiceImpl implements ISurgeryAppService {
serviceRequest.setEncounterId(surgeryDto.getEncounterId()); // 就诊id
serviceRequest.setAuthoredTime(curDate); // 请求签发时间
serviceRequest.setOrgId(orgId); // 执行科室
// 🔧 BugFix#318: 设置 contentJson包含手术名称
Map<String, String> serviceContentMap = new HashMap<>();
String surgeryNameFromDto = surgeryDto.getSurgeryName();
String surgeryCodeFromDto = surgeryDto.getSurgeryCode();
log.info("【DEBUG】surgeryName from DTO: {}", surgeryNameFromDto);
log.info("【DEBUG】surgeryCode from DTO: {}", surgeryCodeFromDto);
serviceContentMap.put("surgeryName", surgeryNameFromDto != null ? surgeryNameFromDto : "");
serviceContentMap.put("surgeryCode", surgeryCodeFromDto != null ? surgeryCodeFromDto : "");
try {
String contentJson = new ObjectMapper().writeValueAsString(serviceContentMap);
log.info("【DEBUG】Setting contentJson: {}", contentJson);
serviceRequest.setContentJson(contentJson);
} catch (JsonProcessingException e) {
log.error("【DEBUG】设置手术医嘱 contentJson 失败", e);
}
serviceRequestService.save(serviceRequest);
log.info("【DEBUG】Saved serviceRequest with ID: {}, contentJson: {}",
serviceRequest.getId(), serviceRequest.getContentJson());
// 生成收费项目
ChargeItem chargeItem = new ChargeItem();

View File

@@ -43,6 +43,11 @@ public class OpScheduleDto extends OpSchedule {
*/
private Long encounterId;
/**
* 就诊卡号
*/
private String patientCardNo;
/**
* 性别
*/

View File

@@ -45,6 +45,9 @@ public class SurgeryDto {
/** 就诊流水号 */
private String encounterNo;
/** 就诊卡号 */
private String patientCardNo;
/** 申请医生ID */
@JsonSerialize(using = ToStringSerializer.class)
private Long applyDoctorId;

View File

@@ -13,6 +13,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="patientAge" column="patient_age" />
<result property="encounterId" column="encounter_id" />
<result property="encounterNo" column="encounter_no" />
<result property="patientCardNo" column="patient_card_no" />
<result property="applyDoctorId" column="apply_doctor_id" />
<result property="applyDoctorName" column="apply_doctor_name" />
<result property="applyDeptId" column="apply_dept_id" />
@@ -79,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
EXTRACT(YEAR FROM AGE(p.birth_date)) as patient_age,
s.encounter_id,
e.bus_no as encounter_no,
pi.identifier_no as patient_card_no,
s.apply_doctor_id,
COALESCE(s.apply_doctor_name, apply_doc.name) as apply_doctor_name,
s.apply_dept_id,
@@ -177,6 +179,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
FROM cli_surgery s
LEFT JOIN adm_patient p ON s.patient_id = p.id
LEFT JOIN adm_encounter e ON s.encounter_id = e.id
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON s.patient_id = pi.patient_id
LEFT JOIN adm_operating_room r ON s.operating_room_id = r.id
LEFT JOIN adm_organization ro ON r.organization_id = ro.id
LEFT JOIN adm_organization o ON s.org_id = o.id
@@ -248,6 +262,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
p.birth_date,
<!-- 就诊编号 -->
e.bus_no as encounter_no,
<!-- 就诊卡号 -->
pi.identifier_no as patient_card_no,
<!-- 字典文本使用CASE WHEN避免额外JOIN -->
CASE s.surgery_type_enum
WHEN 1 THEN '门诊手术'
@@ -302,6 +318,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<!-- 只JOIN必要的表患者和就诊 -->
LEFT JOIN adm_patient p ON s.patient_id = p.id
LEFT JOIN adm_encounter e ON s.encounter_id = e.id
<!-- 关联患者标识表获取就诊卡号 -->
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON s.patient_id = pi.patient_id
<where>
s.delete_flag = '0'
<if test="ew.sqlSegment != null and ew.sqlSegment != ''">

View File

@@ -30,13 +30,26 @@
cs.apply_dept_name,
cs.org_id,
o.name AS org_name,
cs.main_surgeon_name AS surgeon_name
cs.main_surgeon_name AS surgeon_name,
pi.identifier_no AS patient_card_no
FROM op_schedule os
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
LEFT JOIN adm_organization o ON cs.org_id = o.id
LEFT JOIN sys_tenant st ON st.id = os.tenant_id
LEFT JOIN sys_user su ON su.user_id = os.creator_id
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON os.patient_id = pi.patient_id
<where>
<if test="dto.tenantId != null">
AND os.tenant_id = #{dto.tenantId}
@@ -75,12 +88,25 @@
cs.main_surgeon_name AS surgeon_name,
cs.apply_doctor_name AS apply_doctor_name,
drf.create_time AS apply_time,
os.surgery_nature AS surgeryType
os.surgery_nature AS surgeryType,
pi.identifier_no AS patient_card_no
FROM op_schedule os
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
LEFT JOIN adm_organization o ON cs.org_id = o.id
LEFT JOIN doc_request_form drf ON drf.prescription_no=cs.surgery_no
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON os.patient_id = pi.patient_id
WHERE os.schedule_id = #{scheduleId}
LIMIT 1
</select>
@@ -123,13 +149,26 @@
cs.apply_dept_name,
cs.org_id,
o.name AS org_name,
cs.main_surgeon_name AS surgeon_name
cs.main_surgeon_name AS surgeon_name,
pi.identifier_no AS patient_card_no
FROM op_schedule os
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
LEFT JOIN adm_organization o ON cs.org_id = o.id
LEFT JOIN sys_tenant st ON st.id = os.tenant_id
LEFT JOIN sys_user su ON su.user_id = os.creator_id
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON os.patient_id = pi.patient_id
<where>
AND os.delete_flag = '0'
<if test="dto.patientId != null"> AND os.patient_id = #{dto.patientId}</if>

View File

@@ -505,7 +505,8 @@ import { useDict } from '@/utils/dict'
const { surgery_type, surgery_level, incision_level, anesthesia_type } = useDict('surgery_type', 'surgery_level', 'incision_level', 'anesthesia_type')
const { proxy } = getCurrentInstance()
const userStore = useUserStore()
const userStore = useUserStore() // 🔧 BugFix: 初始化 userStore否则 applyDoctorName 和 applyDeptName 会是 undefined
const emit = defineEmits(['saved'])
const props = defineProps({
patientInfo: {
type: Object,
@@ -963,9 +964,13 @@ function doSearchAnesthesia(query) {
// 手术项目选择变更
function handleSurgeryChange(val) {
// 🔧 BugFix#318: 确保 surgeryName 被正确设置
form.value.surgeryName = val
const selected = surgeryNameList.value.find(item => item.name === val)
if (selected) {
form.value.surgeryCode = selected.busNo
// 🔧 BugFix#318: 确保 surgeryName 从选中项获取(避免空值)
form.value.surgeryName = selected.name
// 设置手术费用 (增加对多种字段名和类型的兼容)
const price = selected.retailPrice ?? selected.retail_price ?? selected.price ?? selected.salePrice ?? 0
form.value.surgeryFee = parseFloat(price)
@@ -1050,6 +1055,27 @@ function submitForm() {
console.log('【提交表单】完整表单数据:', JSON.parse(JSON.stringify(form.value)))
console.log('【提交表单】手术指征字段值:', form.value.surgeryIndication)
console.log('【提交表单】手术指征字段类型:', typeof form.value.surgeryIndication)
// 🔧 BugFix#318: 验证 surgeryName 和 surgeryCode
if (!form.value.surgeryName) {
console.error('【提交表单】错误: surgeryName 为空!')
proxy.$modal.msgError('手术名称不能为空,请重新选择手术项目')
return
}
if (!form.value.surgeryCode) {
console.error('【提交表单】错误: surgeryCode 为空!')
// 尝试从 surgeryNameList 获取
const selected = surgeryNameList.value.find(item => item.name === form.value.surgeryName)
if (selected) {
form.value.surgeryCode = selected.busNo
console.log('【提交表单】自动填充 surgeryCode:', form.value.surgeryCode)
} else {
proxy.$modal.msgError('手术编码不能为空,请重新选择手术项目')
return
}
}
console.log('【提交表单】最终数据 - surgeryName:', form.value.surgeryName, 'surgeryCode:', form.value.surgeryCode)
if (form.value.id == undefined) {
// 新增手术
@@ -1060,6 +1086,7 @@ function submitForm() {
sessionStorage.setItem('anesthesiaType', form.value.anesthesiaTypeEnum)
open.value = false
getList()
emit('saved') // 🔧 触发保存事件,通知父组件刷新医嘱列表
} else {
proxy.$modal.msgError(res.msg || '新增手术失败,请检查表单信息')
}
@@ -1076,6 +1103,7 @@ function submitForm() {
sessionStorage.setItem('anesthesiaType', form.value.anesthesiaTypeEnum)
open.value = false
getList()
emit('saved') // 🔧 触发保存事件,通知父组件刷新医嘱列表
} else {
proxy.$modal.msgError(res.msg || '更新手术失败,请检查表单信息')
}

View File

@@ -150,7 +150,8 @@
@saved="() => prescriptionRef?.getListInfo()" />
</el-tab-pane>
<el-tab-pane label="手术申请" name="surgery">
<surgeryApplication :patientInfo="patientInfo" :activeTab="activeTab" ref="surgeryRef" />
<surgeryApplication :patientInfo="patientInfo" :activeTab="activeTab" ref="surgeryRef"
@saved="() => prescriptionRef?.getListInfo()" />
</el-tab-pane>
<el-tab-pane label="电子处方" name="eprescription">
<eprescriptionlist :patientInfo="patientInfo" ref="eprescriptionRef" />

View File

@@ -89,7 +89,7 @@
</el-table-column>
<el-table-column label="卫生机构" align="center" prop="orgName" width="120" show-overflow-tooltip />
<el-table-column label="姓名" align="center" prop="patientName" width="100" />
<el-table-column label="就诊卡号" align="center" prop="visitId" width="120" />
<el-table-column label="就诊卡号" align="center" prop="patientCardNo" width="120" />
<el-table-column label="手术名称" align="center" prop="operName" min-width="140" show-overflow-tooltip />
<el-table-column label="申请科室" align="center" prop="applyDeptName" width="100" show-overflow-tooltip>
<template #default="scope">
@@ -161,9 +161,9 @@
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="就诊卡号" prop="visitId">
<el-tooltip :content="form.visitId" placement="top" :disabled="!form.visitId">
<el-input v-model="form.visitId" :disabled="true" style="width: 100%" />
<el-form-item label="就诊卡号" prop="patientCardNo">
<el-tooltip :content="form.patientCardNo" placement="top" :disabled="!form.patientCardNo">
<el-input v-model="form.patientCardNo" :disabled="true" style="width: 100%" />
</el-tooltip>
</el-form-item>
</el-col>
@@ -1783,6 +1783,7 @@ function confirmApply() {
form.applyId=selectedRow.applyId// 手术申请id
form.patientId = selectedRow.patientId// 患者id
form.visitId = selectedRow.encounterId // id对应填入就诊id
form.patientCardNo = selectedRow.patientCardNo // 就诊卡号
form.operCode = selectedRow.surgeryNo // 手术单号作为手术编码
form.operName = selectedRow.descJson?.surgeryName//手术名称
form.preoperativeDiagnosis = selectedRow.preoperativeDiagnosis || selectedRow.descJson?.preoperativeDiagnosis