yxh
昨天 fce96ef468291fb9a0e6a4d34ab371315e9485d4
jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/doctor/DoctorController.java
@@ -10,6 +10,7 @@
import cn.lihu.jh.module.ecg.controller.admin.queue.vo.QueueSaveReqVO;
import cn.lihu.jh.module.ecg.controller.admin.room.vo.RoomRespVO;
import cn.lihu.jh.module.ecg.dal.dataobject.queue.QueueDO;
import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomDO;
import cn.lihu.jh.module.ecg.enums.QueueStatusEnum;
import cn.lihu.jh.module.ecg.service.call.CallService;
import cn.lihu.jh.module.ecg.service.queue.QueueService;
@@ -112,6 +113,45 @@
            return success(SUCCESS.getCode());
        return error(result);
    }
    /**
     * 释放**当前登录用户**占用的全部诊疗床位(退出系统时自动离座)。
     *
     * <p>背景:医生在「诊室选择」页选好床位后即占用该床位({@code clinic_room.doc_id}),
     * 若一直不点「离座」就退出系统,床位会一直显示被占用,其他医生无法使用。
     *
     * <p>与 {@link #bedDoctorOff} 的区别:
     * <ul>
     *   <li>{@code /bed-doctor-off} 需要前端传 roomId + bedNo(离开某个**指定**床位);</li>
     *   <li>本接口**不需要任何参数**,按当前登录用户反查其占用的**所有**床位并逐一释放。</li>
     * </ul>
     * 之所以做成"无参":退出登录 / 空闲超时 / 令牌失效等场景下,前端可能已经拿不到
     * 床位的 roomId/bedNo(本地缓存已被清理),此时只能由服务端按 userId 反查。
     * 服务端反查也更可靠 —— 前端缓存的床位若被管理员改动过,就会出现"释放不掉"。
     *
     * <p>幂等:未占用任何床位时直接返回成功。
     */
    @PostMapping("/release-my-beds")
    @Operation(summary = "释放当前登录用户占用的全部床位(退出系统时自动离座)")
    public CommonResult<Boolean> releaseMyBeds() {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        if (userId == null) {
            // 未登录(或令牌已失效)时无床位可释放,按成功返回,避免前端报错
            return success(true);
        }
        String userNickname = SecurityFrameworkUtils.getLoginUserNickname();
        List<RoomDO> occupiedBeds = queueService.getDocRoomInfo(userId);
        if (occupiedBeds == null || occupiedBeds.isEmpty()) {
            return success(true);   // 未占用床位,无需处理
        }
        log.info("[releaseMyBeds] 退出系统自动离座. userId={} nickname={} 占用床位数={}",
                userId, userNickname, occupiedBeds.size());
        for (RoomDO bed : occupiedBeds) {
            // 逐个释放;单个失败不影响其它床位
            queueService.startBedDoctorOff(bed.getRoomId(), bed.getBedNo(), userId, userNickname);
        }
        return success(true);
    }
    @GetMapping("/bed-doctor-get")
@@ -460,4 +500,97 @@
        return success("操作成功");
    }
    // ==================== 需求2:撤销「叫号 / 检查完成」 ====================
    @GetMapping("/undo-finish-patient")
    @Operation(summary = "撤销检查完成:已就诊(40) → 候诊中(20)")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "A1")
    @Parameter(name = "patId", description = "患者编号", required = true, example = "913639423")
    @Parameter(name = "checkType", description = "检查类型", required = true, example = "100")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<String> undoFinishPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo,
            @RequestParam("patId") String patId,
            @RequestParam("checkType") Integer checkType) {
        // 说明:必须按 patId + checkType 精确定位,避免误撤销其他患者(既有缺陷见 DevRentServiceImpl)
        Integer result = queueService.undoFinishPatient(roomId, bedNo, patId, checkType);
        if (null == result || 0 == result) {
            return error(APPOINTMENT_NOT_EXISTS);
        }
        return success("已撤销检查完成,患者已返回候诊区");
    }
    @GetMapping("/undo-call-patient")
    @Operation(summary = "撤销叫号:就诊中(30) → 候诊中(20)")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "A1")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<String> undoCallPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo) {
        Integer result = queueService.undoCallPatient(roomId, bedNo);
        if (null == result || 0 == result) {
            return error(QUEUE_NOT_EXISTS);
        }
        return success("已撤销叫号,患者已返回候诊区");
    }
    @GetMapping("/last-finished-patient")
    @Operation(summary = "取本工位今日最近一位已完成患者(供撤销提示)")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "A1")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<QueueRespVO> lastFinishedPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo) {
        QueueDO queueDO = queueService.getBedLastFinishedQueueItem(roomId, bedNo);
        return success(BeanUtils.toBean(queueDO, QueueRespVO.class));
    }
    // ==================== 需求3:停止候诊开关 ====================
    @GetMapping("/stop-ready")
    @Operation(summary = "停止候诊:不再新增候诊患者(已有候诊仍可叫号)")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "A1")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<Boolean> stopReady(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo) {
        ErrorCode ec = queueService.setStopReady(roomId, bedNo, true);
        if (!SUCCESS.getCode().equals(ec.getCode())) {
            return error(ec);
        }
        return success(true);
    }
    @GetMapping("/resume-ready")
    @Operation(summary = "恢复候诊:重新开始接收候诊患者")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "A1")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<Boolean> resumeReady(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo) {
        ErrorCode ec = queueService.setStopReady(roomId, bedNo, false);
        if (!SUCCESS.getCode().equals(ec.getCode())) {
            return error(ec);
        }
        return success(true);
    }
    @GetMapping("/get-stop-ready")
    @Operation(summary = "查询停止候诊状态")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "A1")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<Boolean> getStopReady(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo) {
        Boolean stop = queueService.getStopReady(roomId, bedNo);
        return success(stop != null && stop);
    }
}