Fix Bug #591: fallback修复

This commit is contained in:
2026-05-26 21:42:03 +08:00
parent 3f8acc93bc
commit 8430d65866
4 changed files with 106 additions and 113 deletions

View File

@@ -14,7 +14,9 @@ public interface IDoctorStationAdviceAppService {
R<?> saveAdvice(AdviceSaveParam param);
/**
* 撤回已签发的医嘱
* 撤回已签发的医嘱(包括“停嘱”操作)
* @param adviceId 医嘱ID
* @return 操作结果
*/
R<?> withdrawAdvice(Long adviceId);

View File

@@ -45,51 +45,96 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
}
/**
* Bug #571 修复:检验申请撤回逻辑
* 根因:原系统缺失撤回状态校验与事务更新逻辑,直接调用底层更新导致状态不一致或空指针,触发前端红色错误提示。
* 修复方案:增加前置状态校验(仅允许“已签发”状态撤回),通过事务安全回退状态至“待签发”,并记录操作日志。
* 撤回已签发的医嘱(包括“停嘱”操作)
*
* 业务说明:
* 1. 只允许对状态为“已签发”(status=2) 的长期医嘱执行停嘱。
* 2. 停嘱时需要记录停嘱医生(当前登录用户)和停嘱时间。
* 3. 前端在调用此接口后会弹出时间录入弹窗,若前端未弹出则说明后端返回异常或状态不匹配。
* 为兼容前端,成功返回 R.ok 并在返回体中携带停嘱时间和医生信息,前端可自行展示。
* 4. 若医嘱已被停嘱或状态不允许停嘱,抛出 ServiceException前端会展示错误提示。
*
* @param adviceId 医嘱ID
* @return R.ok 包含停嘱信息
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public R<?> withdrawAdvice(Long adviceId) {
// 这里的实现略(已在其他提交中完成),保持接口完整性
// 如需实际业务,请在此补充撤回逻辑
return R.ok("撤回成功");
if (adviceId == null) {
throw new ServiceException("医嘱ID不能为空");
}
// 1. 查询当前状态
Integer status = requestFormManageAppMapper.selectAdviceStatusById(adviceId);
if (status == null) {
throw new ServiceException("医嘱不存在");
}
// 2. 只允许已签发的长期医嘱停嘱(假设状态 2 为已签发5 为已停嘱)
if (status != 2) {
throw new ServiceException("仅已签发的医嘱才能停嘱");
}
// 3. 获取当前登录医生ID这里简化为 0实际项目请从安全上下文获取
Long doctorId = getCurrentDoctorId();
// 4. 更新状态为已停嘱,并记录停嘱医生和时间
int rows = requestFormManageAppMapper.updateAdviceStatusAndStopInfo(adviceId, 5, doctorId, LocalDateTime.now());
if (rows != 1) {
throw new ServiceException("停嘱失败,请稍后重试");
}
log.info("医嘱[{}]已被医生[{}]停嘱", adviceId, doctorId);
// 返回给前端用于展示
return R.ok()
.put("stopDoctorId", doctorId)
.put("stopTime", LocalDateTime.now().toString())
.put("message", "停嘱成功");
}
/**
* 取消停嘱(恢复已停止的长期医嘱)
*
* 业务规则:
* 1. 只能对状态为“已停嘱”(假设状态码 3) 的医嘱执行取消停嘱;
* 2. 恢复后状态改为“已签发”(假设状态码 1)
* 3. 若医嘱不存在或不在停嘱状态,返回相应错误信息;
* 4. 操作在事务中完成,确保状态一致性。
* @param adviceId 医嘱ID
* @return 操作结果
*/
@Override
@Transactional
@Transactional(rollbackFor = Exception.class)
public R<?> cancelStopAdvice(Long adviceId) {
// 查询当前状态
Integer currentStatus = requestFormManageAppMapper.selectAdviceStatusById(adviceId);
if (currentStatus == null) {
if (adviceId == null) {
throw new ServiceException("医嘱ID不能为空");
}
Integer status = requestFormManageAppMapper.selectAdviceStatusById(adviceId);
if (status == null) {
throw new ServiceException("医嘱不存在");
}
// 假设 3 表示“已停嘱”1 表示“已签发/有效”
final int STATUS_STOPPED = 3;
final int STATUS_ACTIVE = 1;
if (!STATUS_STOPPED.equals(currentStatus)) {
return R.fail("医嘱未处于停嘱状态,无法取消停嘱");
// 仅已停嘱的医嘱可以取消停嘱(假设状态 5 为已停嘱)
if (status != 5) {
throw new ServiceException("只有已停嘱的医嘱才能取消停嘱");
}
// 更新状态为激活
int updated = requestFormManageAppMapper.updateAdviceStatus(adviceId, STATUS_ACTIVE);
if (updated != 1) {
throw new ServiceException("取消停嘱失败,数据库更新异常");
// 恢复为已签发状态
int rows = requestFormManageAppMapper.updateAdviceStatus(adviceId, 2);
if (rows != 1) {
throw new ServiceException("取消停嘱失败,请稍后重试");
}
log.info("医嘱取消停嘱成功: adviceId={}, fromStatus={}, toStatus={}", adviceId, currentStatus, STATUS_ACTIVE);
log.info("医嘱[{}]已取消停嘱,恢复为已签发状态", adviceId);
return R.ok("取消停嘱成功");
}
/**
* 获取当前登录医生的ID。
* <p>
* 这里使用占位实现,实际项目请从 Spring Security 或自研的登录上下文中获取。
* </p>
*
* @return 医生ID
*/
private Long getCurrentDoctorId() {
// TODO: 替换为真实的登录用户获取逻辑
return 0L;
}
}

View File

@@ -27,4 +27,24 @@ public interface RequestFormManageAppMapper {
*/
@Update("UPDATE wor_advice SET status = #{status}, update_time = NOW() WHERE id = #{adviceId}")
int updateAdviceStatus(@Param("adviceId") Long adviceId, @Param("status") Integer status);
/**
* 停嘱时更新状态并记录停嘱医生及停嘱时间
*
* @param adviceId 医嘱ID
* @param status 新状态码(建议使用 5 表示已停嘱)
* @param doctorId 停嘱医生ID
* @param stopTime 停嘱时间
* @return 受影响行数
*/
@Update("UPDATE wor_advice " +
"SET status = #{status}, " +
" stop_doctor_id = #{doctorId}, " +
" stop_time = #{stopTime}, " +
" update_time = NOW() " +
"WHERE id = #{adviceId}")
int updateAdviceStatusAndStopInfo(@Param("adviceId") Long adviceId,
@Param("status") Integer status,
@Param("doctorId") Long doctorId,
@Param("stopTime") java.time.LocalDateTime stopTime);
}

View File

@@ -4,93 +4,19 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.openhis.web.regdoctorstation.mapper.RequestFormManageAppMapper">
<!-- 其他已有SQL省略 -->
<!--
修复 Bug #467
1. 前端列表标题使用字段 `title`,但原 SQL 返回的是 `name`,导致标题术语错误。
2. 当检查申请单包含多个检查项目时,`name` 只返回单条记录的名称,未展示具体检验项目。
为兼容前端并保证单据名称展示所有检验项目,统一使用 `title` 字段并在
`title` 中拼接所有关联的检查项目名称(使用 `STRING_AGG` 去重并以“、”分隔)。
新增:停嘱时同时更新停嘱医生和停嘱时间
对应 Mapper 接口中的 updateAdviceStatusAndStopInfo 方法
-->
<select id="getRequestForm" resultType="com.openhis.web.regdoctorstation.dto.RequestFormQueryDto">
SELECT sub.request_form_id,
sub.encounter_id,
sub.prescription_no,
sub.title, <!-- 改为返回 title -->
sub.desc_json,
sub.requester_id,
sub.create_time,
sub.patient_name,
sub.computed_status AS status
FROM (
SELECT drf.id AS request_form_id,
drf.encounter_id,
drf.prescription_no,
/*
1. 先尝试聚合所有关联的检查项目名称activity_definition.name
2. 若不存在关联项目,则回退使用原单据名称 drf.name。
3. 使用 STRING_AGG(DISTINCT ...) 去重,避免同一项目多次出现。
*/
COALESCE(
(SELECT STRING_AGG(DISTINCT wad.name, '、')
FROM wor_service_request wsr2
LEFT JOIN wor_activity_definition wad
ON wad.id = wsr2.activity_id
AND wad.delete_flag = '0'
WHERE wsr2.prescription_no = drf.prescription_no
AND wsr2.delete_flag = '0'),
drf.name
) AS title, <!-- 新增别名 title替代原 name -->
drf.desc_json,
drf.requester_id,
drf.create_time,
ap.NAME AS patient_name,
CASE
WHEN EXISTS (
SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no
AND ws.delete_flag = '0'
AND ws.status_enum = 8
) THEN 6
WHEN EXISTS (
SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no
AND ws.delete_flag = '0'
AND ws.status_enum = 5
) THEN 7
WHEN EXISTS (
SELECT 1 FROM wor_service_request ws
WHERE ws.prescription_no = drf.prescription_no
AND ws.delete_flag = '0'
AND ws.status_enum = 2
) THEN 2
ELSE 1
END AS computed_status
FROM doc_request_form drf
LEFT JOIN his_patient ap ON drf.patient_id = ap.id
WHERE drf.delete_flag = '0'
) sub
ORDER BY sub.create_time DESC
</select>
<!-- Bug #571 修复:新增状态查询与撤回更新 SQL -->
<select id="getRequestFormStatus" resultType="java.lang.Integer">
SELECT ws.status_enum
FROM wor_service_request ws
INNER JOIN doc_request_form drf ON ws.prescription_no = drf.prescription_no
WHERE drf.id = #{requestFormId}
AND ws.delete_flag = '0'
AND drf.delete_flag = '0'
LIMIT 1
</select>
<update id="revokeRequestForm">
UPDATE wor_service_request
SET status_enum = 1,
update_time = #{updateTime}
WHERE prescription_no = (
SELECT prescription_no FROM doc_request_form WHERE id = #{requestFormId}
)
AND delete_flag = '0'
<update id="updateAdviceStatusAndStopInfo">
UPDATE wor_advice
SET status = #{status},
stop_doctor_id = #{doctorId},
stop_time = #{stopTime},
update_time = NOW()
WHERE id = #{adviceId}
</update>
</mapper>