yxh
昨天 fce96ef468291fb9a0e6a4d34ab371315e9485d4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
package cn.lihu.jh.module.ecg.controller.admin.doctor;
 
import cn.lihu.jh.framework.common.exception.ErrorCode;
import cn.lihu.jh.framework.common.pojo.CommonResult;
import cn.lihu.jh.framework.common.util.object.BeanUtils;
import cn.lihu.jh.framework.security.core.util.SecurityFrameworkUtils;
import cn.lihu.jh.module.ecg.controller.admin.call.vo.CallSaveReqVO;
import cn.lihu.jh.module.ecg.controller.admin.queue.vo.PatientStatisticVO;
import cn.lihu.jh.module.ecg.controller.admin.queue.vo.QueueRespVO;
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;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
 
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
 
import static cn.lihu.jh.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
import static cn.lihu.jh.framework.common.pojo.CommonResult.error;
import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.*;
 
@Tag(name = "管理后台 - 医生叫号")
@RestController
@RequestMapping("/ecg/doctor")
@Validated
@Slf4j
public class DoctorController {
 
    @Resource
    private QueueService queueService;
 
    @Resource
    private CallService callService;
 
    @GetMapping("/bed-doctor-pause")
    @Operation(summary = "医生暂停")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:state')")
    public CommonResult<Integer> bedPause(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        String userNickname = SecurityFrameworkUtils.getLoginUserNickname();
 
        ErrorCode result = queueService.startBedDoctorPause(roomId, bedNo, userId, userNickname);
        if (result.equals(SUCCESS)) {
            queueService.updateStop(roomId, bedNo);
            return success(SUCCESS.getCode());
        }
 
        return error(result);
    }
 
    @GetMapping("/bed-doctor-resume")
    @Operation(summary = "医生恢复")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:state')")
    public CommonResult<Integer> bedResume(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        String userNickname = SecurityFrameworkUtils.getLoginUserNickname();
 
        ErrorCode result = queueService.startBedDoctorResume(roomId, bedNo, userId, userNickname);
        if (result.equals(SUCCESS))
            return success(SUCCESS.getCode());
 
        return error(result);
    }
 
    @GetMapping("/bed-doctor-on")
    @Operation(summary = "医生入座")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:state')")
    public CommonResult<Integer> bedDoctorOn(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        String userNickname = SecurityFrameworkUtils.getLoginUserNickname();
 
        ErrorCode result = queueService.startBedDoctorOn(roomId, bedNo, userId, userNickname);
        if (result.equals(SUCCESS))
            return success(0);
 
        return error(result);
    }
 
    @GetMapping("/bed-doctor-off")
    @Operation(summary = "医生离座")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:state')")
    public CommonResult<Integer> bedDoctorOff(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        String userNickname = SecurityFrameworkUtils.getLoginUserNickname();
 
        ErrorCode result = queueService.startBedDoctorOff(roomId, bedNo, userId, userNickname);
        if (result.equals(SUCCESS))
            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")
    @Operation(summary = "医生工位获取")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:state')")
    public CommonResult<RoomRespVO> bedDoctorGet(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
 
        CommonResult<RoomRespVO> result = queueService.getRoom(roomId, bedNo, userId);
        return result;
    }
 
    @GetMapping("/finish-next-patient")
    @Operation(summary = "常规叫号、下一位患者")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<List<QueueRespVO>> finishNextPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        queueService.finishNextPatient(roomId, bedNo);
 
        List<QueueDO> queueDOList = queueService.getCheckRelatedPatient(roomId, bedNo);
 
        // 过滤出  就诊中的,准备叫号
        QueueDO onStageItem = queueDOList.stream().filter(item ->
                item.getStatus() == QueueStatusEnum.ONSTAGE.getStatus() && item.getAffinityItem() == 0
        ).findFirst().orElse(null);
        if (null != onStageItem) {
            CallSaveReqVO callSaveReqVO = BeanUtils.toBean(onStageItem, CallSaveReqVO.class);
            callSaveReqVO.setId(null);
            callService.createCall(callSaveReqVO);
        }
 
        return success(BeanUtils.toBean(queueDOList, QueueRespVO.class));
    }
 
    @GetMapping("/finish-receive-next-patient")
    @Operation(summary = "领用叫号、下一位患者")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<List<QueueRespVO>> finishReceiveNextPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        queueService.finishReceiveNextPatient(roomId, bedNo);
 
        List<QueueDO> queueDOList = queueService.getCheckRelatedPatient(roomId, bedNo);
 
        // 过滤出  就诊中的,准备叫号
        QueueDO onStageItem = queueDOList.stream().filter(item ->
                item.getStatus() == QueueStatusEnum.ONSTAGE.getStatus() && item.getAffinityItem() == 0
        ).findFirst().orElse(null);
        if (null != onStageItem) {
            CallSaveReqVO callSaveReqVO = BeanUtils.toBean(onStageItem, CallSaveReqVO.class);
            callSaveReqVO.setId(null);
            callService.createCall(callSaveReqVO);
        }
 
        return success(BeanUtils.toBean(queueDOList, QueueRespVO.class));
    }
 
    @GetMapping("/finish-install-next-patient")
    @Operation(summary = "装机叫号、下一位患者")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<List<QueueRespVO>> finishInstallNextPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        queueService.finishInstallNextPatient(roomId, bedNo);
 
        List<QueueDO> queueDOList = queueService.getInstallRelatedPatient(roomId, bedNo); // 待安装的患者
 
        List<QueueDO> installingQueueDOList = queueDOList.stream().filter(queueDO ->
                queueDO.getStatus() == QueueStatusEnum.INSTALLING.getStatus() && queueDO.getAffinityItem() == 0
        ).toList();
        // 过滤出  [安装中] 的,准备叫号   该工位应该 最多只有一个 [安装中]
        if (installingQueueDOList.size() > 0) {
            QueueDO onStageItem = installingQueueDOList.get(0);
            CallSaveReqVO callSaveReqVO = BeanUtils.toBean(onStageItem, CallSaveReqVO.class);
            callSaveReqVO.setId(null);
            callSaveReqVO.setCallType(1); // 装机叫号
            callService.createCall(callSaveReqVO);
        }
 
        return success(BeanUtils.toBean(queueDOList, QueueRespVO.class));
    }
 
    // 常规检查过号、领用过号
    @GetMapping("/pass-waiting-patient")
    @Operation(summary = "过号排队中患者")
    @Parameter(name = "patId", description = "患者编号", required = true, example = "20247845")
    @Parameter(name = "checkType", description = "预约检查类型", required = true, example = "100")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<Integer> passWaitingPatient(
            @RequestParam("patId") String patId,
            @RequestParam("checkType") Integer checkType)
    {
        queueService.passWaitingPatient( patId, checkType );
        return success(0);
    }
 
    // 常规检查过号、领用过号
    @GetMapping("/pass-next-patient")
    @Operation(summary = "过号、下一位患者")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<List<QueueRespVO>> passNextPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        queueService.passNextPatient(roomId, bedNo);
 
        List<QueueDO> queueDOList = queueService.getCheckRelatedPatient(roomId, bedNo);
 
        // 过滤出  就诊中的,准备叫号
        QueueDO onStageItem = queueDOList.stream().filter(item -> Objects.equals(item.getStatus(), QueueStatusEnum.ONSTAGE.getStatus())).findFirst().orElse(null);
        if (null != onStageItem) {
            CallSaveReqVO callSaveReqVO = BeanUtils.toBean(onStageItem, CallSaveReqVO.class);
            callSaveReqVO.setId(null);
            callService.createCall(callSaveReqVO);
        }
 
        return success(BeanUtils.toBean(queueDOList, QueueRespVO.class));
    }
 
    @GetMapping("/pass-install-next-patient")
    @Operation(summary = "安装过号、下一位患者")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<List<QueueRespVO>> passInstallNextPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        queueService.passInstallNextPatient(roomId, bedNo);
 
        List<QueueDO> queueDOList = queueService.getInstallRelatedPatient(roomId, bedNo);
 
        List<QueueDO> installingQueueDOList = queueDOList.stream().filter(queueDO -> queueDO.getStatus() == QueueStatusEnum.INSTALLING.getStatus()).toList();
        // 过滤出  [安装中] 的,准备叫号   该工位应该 最多只有一个 [安装中]
        if (installingQueueDOList.size() > 0) {
            QueueDO onStageItem = installingQueueDOList.get(0);
            CallSaveReqVO callSaveReqVO = BeanUtils.toBean(onStageItem, CallSaveReqVO.class);
            callSaveReqVO.setId(null);
            callSaveReqVO.setCallType(1); // 装机叫号
            callService.createCall(callSaveReqVO);
        }
 
        return success(BeanUtils.toBean(queueDOList, QueueRespVO.class));
    }
 
    @GetMapping("/call-again")
    @Operation(summary = "[常规检查]或[领用] 重叫、患者")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<String> callPatientAgain(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        List<Integer> queueStatusList = new ArrayList<>();
        queueStatusList.add(QueueStatusEnum.ONSTAGE.getStatus());
        List<QueueDO> queueDOList = queueService.getBedQueueByStatus(roomId, bedNo, queueStatusList);
 
        if (queueDOList.isEmpty())
            return success("无就诊中患者");
 
        if (queueDOList.size() > 1) {
            log.error("room {} bed {} have {} 就诊中患者", roomId, bedNo, queueDOList.size());
            return error(ECG_INNER_ERROR);
        }
 
        QueueDO onStageItem = queueDOList.get(0);
        CallSaveReqVO callSaveReqVO = BeanUtils.toBean(onStageItem, CallSaveReqVO.class);
        callSaveReqVO.setId(null);
        callService.callAgain(callSaveReqVO);
 
        return success("操作成功");
    }
 
 
    @GetMapping("/call-install-again")
    @Operation(summary = "重叫、患者")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<String> callInstallingPatientAgain(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        List<Integer> queueStatusList = new ArrayList<>();
        queueStatusList.add(QueueStatusEnum.INSTALLING.getStatus());
        List<QueueDO> queueDOList = queueService.getBedQueueByStatus(roomId, bedNo, queueStatusList);
 
        if (queueDOList.isEmpty())
            return success("无安装中的患者");
 
        if (queueDOList.size() > 1) {
            log.error("room {} bed {} have {} 安装中的患者", roomId, bedNo, queueDOList.size());
            return error(ECG_INNER_ERROR);
        }
 
        QueueDO onStageItem = queueDOList.get(0);
        CallSaveReqVO callSaveReqVO = BeanUtils.toBean(onStageItem, CallSaveReqVO.class);
        callSaveReqVO.setId(null);
        callSaveReqVO.setCallType(1); // 装机叫号
        callService.callAgain(callSaveReqVO);
 
        return success("操作成功");
    }
 
    @GetMapping("/get-to-be-checked-list")
    @Operation(summary = "取 [常规检查] 或 [待领用] 患者列表")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<List<QueueRespVO>> getToBeCheckedPatientList(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        List<QueueDO> queueDOList = queueService.getCheckRelatedPatient(roomId, bedNo);
        return success(BeanUtils.toBean(queueDOList, QueueRespVO.class));
    }
 
    @GetMapping("/get-to-be-installed-list")
    @Operation(summary = "取 [待安装] 患者列表")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<List<QueueRespVO>> getToBeInstalledPatientList(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        List<QueueDO> queueDOList = queueService.getInstallRelatedPatient(roomId, bedNo);
        return success(BeanUtils.toBean(queueDOList, QueueRespVO.class));
    }
 
    @GetMapping("/get-patient-statistic")
    @Operation(summary = "取患者统计")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<PatientStatisticVO> getPatientStatistic(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        PatientStatisticVO patientStatisticVO = queueService.getPatientStatistic(roomId, bedNo);
        return success(patientStatisticVO);
    }
 
    @GetMapping("/get-dev-ready-statistic")
    @Operation(summary = "设备领用统计")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<PatientStatisticVO> getDevReadyStatistic(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        PatientStatisticVO patientStatisticVO = queueService.getBedDevReadyStatistic(roomId, bedNo);
        return success(patientStatisticVO);
    }
 
 
    @GetMapping("/get-dev-install-statistic")
    @Operation(summary = "设备装机统计")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<PatientStatisticVO> getDevInstallStatistic(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo)
    {
        PatientStatisticVO patientStatisticVO = queueService.getBedDevInstallStatistic(roomId, bedNo);
        return success(patientStatisticVO);
    }
 
    @GetMapping("/recall-pass-waiting-patient")
    @Operation(summary = "过号-排队中 患者召回")
    @Parameter(name = "patId", description = "患者编号", required = true, example = "B2")
    @Parameter(name = "checkType", description = "预约检查类型", required = true, example = "100")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<String> recallPatient(
            @RequestParam("patId") String patId,
            @RequestParam("checkType") Integer checkType)
    {
        Integer result = queueService.recallPassWaitingPatient(patId, checkType);
        if (null == result || 0 == result)
            return error(PATIENT_NOT_EXISTS);
 
        return success("操作成功");
    }
 
    @GetMapping("/recall-patient")
    @Operation(summary = "过号病人召回")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @Parameter(name = "patId", description = "患者编号", required = true, example = "B2")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<String> recallPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo,
            @RequestParam("patId") String patId,
            @RequestParam("checkType") Integer checkType,
            @RequestParam("roomId_operator") Long roomId_operator,
            @RequestParam("bedNo_operator") String bedNo_operator )
    {
        Integer result = queueService.recallPatient(roomId, bedNo, patId, checkType);
        if (null == result || 0 == result)
            return error(PATIENT_NOT_EXISTS);
 
        return success("操作成功");
    }
 
    @GetMapping("/recall-install-patient")
    @Operation(summary = "过号安装病人召回")
    @Parameter(name = "roomId", description = "诊室编号", required = true, example = "116")
    @Parameter(name = "bedNo", description = "工位编号", required = true, example = "B2")
    @Parameter(name = "patId", description = "患者编号", required = true, example = "B2")
    @Parameter(name = "checkType", description = "检查类型", required = true, example = "100")
    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
    public CommonResult<String> recallInstallPatient(
            @RequestParam("roomId") Long roomId,
            @RequestParam("bedNo") String bedNo,
            @RequestParam("patId") String patId,
            @RequestParam("checkType") Integer checkType,
            @RequestParam("roomId_operator") Long roomId_operator,
            @RequestParam("bedNo_operator") String bedNo_operator )
    {
        if (roomId != roomId_operator)
            return error(QUEUE_RECALL_INSTALL_NOT_CUR_ROOM);
 
        Integer result = queueService.recallInstallPatient(roomId, bedNo, patId, checkType, roomId_operator, bedNo_operator);
        if (null == result || 0 == result)
            return error(PATIENT_NOT_EXISTS);
 
        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);
    }
 
}