挂号补单功能的完善
This commit is contained in:
@@ -29,6 +29,8 @@ import com.openhis.web.chargemanage.dto.PatientMetadata;
|
||||
import com.openhis.web.chargemanage.dto.PractitionerMetadata;
|
||||
import com.openhis.web.chargemanage.dto.ReprintRegistrationDto;
|
||||
import com.openhis.web.chargemanage.mapper.OutpatientRegistrationAppMapper;
|
||||
import com.openhis.triageandqueuemanage.domain.TriageCandidateExclusion;
|
||||
import com.openhis.triageandqueuemanage.service.TriageCandidateExclusionService;
|
||||
import com.openhis.web.paymentmanage.appservice.IPaymentRecService;
|
||||
import com.openhis.web.paymentmanage.dto.CancelPaymentDto;
|
||||
import com.openhis.web.paymentmanage.dto.CancelRegPaymentDto;
|
||||
@@ -38,12 +40,15 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 门诊挂号 应用实现类
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistrationAppService {
|
||||
|
||||
@@ -76,6 +81,9 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
||||
|
||||
@Resource
|
||||
IPatientIdentifierService patientIdentifierService;
|
||||
|
||||
@Resource
|
||||
TriageCandidateExclusionService triageCandidateExclusionService;
|
||||
|
||||
/**
|
||||
* 门诊挂号 - 查询患者信息
|
||||
@@ -308,6 +316,47 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
||||
new Page<>(pageNo, pageSize), EncounterClass.AMB.getValue(), EncounterStatus.IN_PROGRESS.getValue(),
|
||||
ParticipantType.ADMITTER.getCode(), ParticipantType.REGISTRATION_DOCTOR.getCode(), queryWrapper,
|
||||
ChargeItemContext.REGISTER.getValue(), PaymentStatus.SUCCESS.getValue());
|
||||
|
||||
// 过滤候选池排除列表(如果是从智能候选池查询,排除已加入队列的患者)
|
||||
// 检查请求参数 excludeFromCandidatePool,如果为 true 或未设置,则过滤排除列表
|
||||
String excludeParam = request.getParameter("excludeFromCandidatePool");
|
||||
boolean shouldExclude = excludeParam == null || "true".equalsIgnoreCase(excludeParam);
|
||||
if (shouldExclude && currentDayEncounter != null && !currentDayEncounter.getRecords().isEmpty()) {
|
||||
try {
|
||||
// 获取当前租户和日期
|
||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||
LocalDate today = LocalDate.now();
|
||||
|
||||
// 查询排除列表
|
||||
List<TriageCandidateExclusion> exclusions = triageCandidateExclusionService.list(
|
||||
new LambdaQueryWrapper<TriageCandidateExclusion>()
|
||||
.eq(TriageCandidateExclusion::getTenantId, tenantId)
|
||||
.eq(TriageCandidateExclusion::getExclusionDate, today)
|
||||
.eq(TriageCandidateExclusion::getDeleteFlag, "0")
|
||||
);
|
||||
|
||||
if (exclusions != null && !exclusions.isEmpty()) {
|
||||
// 构建排除的 encounterId 集合
|
||||
Set<Long> excludedEncounterIds = exclusions.stream()
|
||||
.map(TriageCandidateExclusion::getEncounterId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 过滤结果
|
||||
List<CurrentDayEncounterDto> filteredRecords = currentDayEncounter.getRecords().stream()
|
||||
.filter(e -> e.getEncounterId() == null || !excludedEncounterIds.contains(e.getEncounterId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 更新分页结果
|
||||
currentDayEncounter.setRecords(filteredRecords);
|
||||
currentDayEncounter.setTotal(filteredRecords.size());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果过滤失败,记录日志但不影响正常查询
|
||||
log.warn("过滤候选池排除列表失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
currentDayEncounter.getRecords().forEach(e -> {
|
||||
// 性别
|
||||
e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.openhis.web.triageandqueuemanage.appservice;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueActionReq;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueAddReq;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueAdjustReq;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public interface TriageQueueAppService {
|
||||
R<?> list(Long organizationId, LocalDate date);
|
||||
R<?> add(TriageQueueAddReq req);
|
||||
R<?> remove(Long id);
|
||||
R<?> adjust(TriageQueueAdjustReq req);
|
||||
/** 选呼:将之前叫号中置为完成,选中的置为叫号中 */
|
||||
R<?> call(TriageQueueActionReq req);
|
||||
/** 完成:叫号中 -> 完成(移出列表),并自动推进下一个等待为叫号中 */
|
||||
R<?> complete(TriageQueueActionReq req);
|
||||
/** 过号重排:叫号中 -> 跳过并移到末尾,并自动推进下一个等待为叫号中 */
|
||||
R<?> requeue(TriageQueueActionReq req);
|
||||
/** 跳过:兼容前端按钮(当前实现等同于过号重排) */
|
||||
R<?> skip(TriageQueueActionReq req);
|
||||
/** 下一患者:当前叫号中 -> 完成,下一位等待 -> 叫号中 */
|
||||
R<?> next(TriageQueueActionReq req);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,556 @@
|
||||
package com.openhis.web.triageandqueuemanage.appservice.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.core.common.core.domain.R;
|
||||
import com.core.common.utils.SecurityUtils;
|
||||
import com.openhis.triageandqueuemanage.domain.TriageQueueItem;
|
||||
import com.openhis.triageandqueuemanage.domain.TriageCandidateExclusion;
|
||||
import com.openhis.triageandqueuemanage.service.TriageQueueItemService;
|
||||
import com.openhis.triageandqueuemanage.service.TriageCandidateExclusionService;
|
||||
import com.openhis.web.triageandqueuemanage.appservice.TriageQueueAppService;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueActionReq;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueAddReq;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueAdjustReq;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueEncounterItem;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class TriageQueueAppServiceImpl implements TriageQueueAppService {
|
||||
|
||||
private static final String STATUS_WAITING = "WAITING";
|
||||
private static final String STATUS_CALLING = "CALLING";
|
||||
private static final String STATUS_SKIPPED = "SKIPPED";
|
||||
private static final String STATUS_COMPLETED = "COMPLETED";
|
||||
|
||||
@Resource
|
||||
private TriageQueueItemService triageQueueItemService;
|
||||
|
||||
@Resource
|
||||
private TriageCandidateExclusionService triageCandidateExclusionService;
|
||||
|
||||
@Override
|
||||
public R<?> list(Long organizationId, LocalDate date) {
|
||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||
// 只查询今天的患者
|
||||
LocalDate qd = date != null ? date : LocalDate.now();
|
||||
|
||||
LambdaQueryWrapper<TriageQueueItem> wrapper = new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getQueueDate, qd)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.ne(TriageQueueItem::getStatus, STATUS_COMPLETED)
|
||||
.orderByAsc(TriageQueueItem::getQueueOrder);
|
||||
|
||||
// 如果指定了科室,按科室过滤;否则查询所有科室(全科模式)
|
||||
if (organizationId != null) {
|
||||
wrapper.eq(TriageQueueItem::getOrganizationId, organizationId);
|
||||
}
|
||||
|
||||
List<TriageQueueItem> list = triageQueueItemService.list(wrapper);
|
||||
|
||||
// 双重保险:再次过滤掉 COMPLETED 状态的患者(防止数据库中有异常数据)
|
||||
if (list != null && !list.isEmpty()) {
|
||||
int beforeSize = list.size();
|
||||
list = list.stream()
|
||||
.filter(item -> !STATUS_COMPLETED.equals(item.getStatus()))
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
if (beforeSize != list.size()) {
|
||||
System.out.println(">>> [TriageQueue] list() 警告:过滤掉了 " + (beforeSize - list.size()) + " 条 COMPLETED 状态的记录");
|
||||
}
|
||||
}
|
||||
|
||||
// 调试日志:检查状态值
|
||||
if (list != null && !list.isEmpty()) {
|
||||
System.out.println(">>> [TriageQueue] list() 返回 " + list.size() + " 条记录(已排除 COMPLETED)");
|
||||
for (int i = 0; i < Math.min(3, list.size()); i++) {
|
||||
TriageQueueItem item = list.get(i);
|
||||
System.out.println(" [" + i + "] patientName=" + item.getPatientName()
|
||||
+ ", status=" + item.getStatus()
|
||||
+ ", organizationId=" + item.getOrganizationId());
|
||||
}
|
||||
}
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> add(TriageQueueAddReq req) {
|
||||
if (req == null || ObjectUtil.isNull(req.getOrganizationId())) {
|
||||
return R.fail("organizationId 不能为空");
|
||||
}
|
||||
if (CollUtil.isEmpty(req.getItems())) {
|
||||
return R.fail("items 不能为空");
|
||||
}
|
||||
|
||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||
LocalDate qd = LocalDate.now();
|
||||
Long orgId = req.getOrganizationId();
|
||||
|
||||
List<TriageQueueItem> existing = triageQueueItemService.list(new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getOrganizationId, orgId)
|
||||
.eq(TriageQueueItem::getQueueDate, qd)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.ne(TriageQueueItem::getStatus, STATUS_COMPLETED));
|
||||
|
||||
int maxOrder = existing.stream().map(TriageQueueItem::getQueueOrder).filter(Objects::nonNull).max(Integer::compareTo).orElse(0);
|
||||
|
||||
int added = 0;
|
||||
for (TriageQueueEncounterItem it : req.getItems()) {
|
||||
if (it == null || it.getEncounterId() == null) continue;
|
||||
boolean exists = existing.stream().anyMatch(e -> Objects.equals(e.getEncounterId(), it.getEncounterId()));
|
||||
if (exists) continue;
|
||||
|
||||
TriageQueueItem qi = new TriageQueueItem()
|
||||
.setTenantId(tenantId)
|
||||
.setQueueDate(qd)
|
||||
.setOrganizationId(orgId)
|
||||
.setOrganizationName(req.getOrganizationName())
|
||||
.setEncounterId(it.getEncounterId())
|
||||
.setPatientId(it.getPatientId())
|
||||
.setPatientName(it.getPatientName())
|
||||
.setHealthcareName(it.getHealthcareName())
|
||||
.setPractitionerName(it.getPractitionerName())
|
||||
.setStatus(STATUS_WAITING)
|
||||
.setQueueOrder(++maxOrder)
|
||||
.setDeleteFlag("0")
|
||||
.setCreateTime(LocalDateTime.now())
|
||||
.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
triageQueueItemService.save(qi);
|
||||
|
||||
// 记录到候选池排除列表(避免刷新后重新出现在候选池)
|
||||
TriageCandidateExclusion exclusion = triageCandidateExclusionService.getOne(
|
||||
new LambdaQueryWrapper<TriageCandidateExclusion>()
|
||||
.eq(TriageCandidateExclusion::getTenantId, tenantId)
|
||||
.eq(TriageCandidateExclusion::getExclusionDate, qd)
|
||||
.eq(TriageCandidateExclusion::getEncounterId, it.getEncounterId())
|
||||
.eq(TriageCandidateExclusion::getDeleteFlag, "0")
|
||||
);
|
||||
if (exclusion == null) {
|
||||
exclusion = new TriageCandidateExclusion()
|
||||
.setTenantId(tenantId)
|
||||
.setExclusionDate(qd)
|
||||
.setEncounterId(it.getEncounterId())
|
||||
.setPatientId(it.getPatientId())
|
||||
.setPatientName(it.getPatientName())
|
||||
.setOrganizationId(orgId)
|
||||
.setOrganizationName(req.getOrganizationName())
|
||||
.setReason("ADDED_TO_QUEUE")
|
||||
.setDeleteFlag("0")
|
||||
.setCreateTime(LocalDateTime.now())
|
||||
.setUpdateTime(LocalDateTime.now());
|
||||
triageCandidateExclusionService.save(exclusion);
|
||||
}
|
||||
|
||||
added++;
|
||||
}
|
||||
|
||||
return R.ok(added);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> remove(Long id) {
|
||||
if (id == null) return R.fail("id 不能为空");
|
||||
TriageQueueItem item = triageQueueItemService.getById(id);
|
||||
if (item == null) return R.fail("队列项不存在");
|
||||
|
||||
// 逻辑删除队列项
|
||||
item.setDeleteFlag("1").setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(item);
|
||||
|
||||
// 从排除列表中删除记录,使患者重新出现在候选池中
|
||||
Integer tenantId = item.getTenantId();
|
||||
LocalDate exclusionDate = item.getQueueDate();
|
||||
Long encounterId = item.getEncounterId();
|
||||
|
||||
if (tenantId != null && exclusionDate != null && encounterId != null) {
|
||||
TriageCandidateExclusion exclusion = triageCandidateExclusionService.getOne(
|
||||
new LambdaQueryWrapper<TriageCandidateExclusion>()
|
||||
.eq(TriageCandidateExclusion::getTenantId, tenantId)
|
||||
.eq(TriageCandidateExclusion::getExclusionDate, exclusionDate)
|
||||
.eq(TriageCandidateExclusion::getEncounterId, encounterId)
|
||||
.eq(TriageCandidateExclusion::getDeleteFlag, "0")
|
||||
);
|
||||
|
||||
if (exclusion != null) {
|
||||
// 逻辑删除排除记录
|
||||
exclusion.setDeleteFlag("1").setUpdateTime(LocalDateTime.now());
|
||||
triageCandidateExclusionService.updateById(exclusion);
|
||||
}
|
||||
}
|
||||
|
||||
recalcOrders(item.getOrganizationId(), item.getQueueDate());
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> adjust(TriageQueueAdjustReq req) {
|
||||
if (req == null || req.getId() == null) return R.fail("id 不能为空");
|
||||
if (!"up".equalsIgnoreCase(req.getDirection()) && !"down".equalsIgnoreCase(req.getDirection())) {
|
||||
return R.fail("direction 只能是 up/down");
|
||||
}
|
||||
TriageQueueItem cur = triageQueueItemService.getById(req.getId());
|
||||
if (cur == null) return R.fail("队列项不存在");
|
||||
|
||||
List<TriageQueueItem> list = listInternal(cur.getOrganizationId(), cur.getQueueDate());
|
||||
list.sort(Comparator.comparing(TriageQueueItem::getQueueOrder).thenComparing(TriageQueueItem::getId));
|
||||
int idx = -1;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (Objects.equals(list.get(i).getId(), cur.getId())) { idx = i; break; }
|
||||
}
|
||||
if (idx == -1) return R.fail("队列项不在当前队列");
|
||||
|
||||
int targetIdx = "up".equalsIgnoreCase(req.getDirection()) ? idx - 1 : idx + 1;
|
||||
if (targetIdx < 0 || targetIdx >= list.size()) return R.ok(false);
|
||||
|
||||
TriageQueueItem other = list.get(targetIdx);
|
||||
Integer tmp = cur.getQueueOrder();
|
||||
cur.setQueueOrder(other.getQueueOrder()).setUpdateTime(LocalDateTime.now());
|
||||
other.setQueueOrder(tmp).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(cur);
|
||||
triageQueueItemService.updateById(other);
|
||||
|
||||
recalcOrders(cur.getOrganizationId(), cur.getQueueDate());
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> call(TriageQueueActionReq req) {
|
||||
if (req == null || req.getId() == null) return R.fail("id 不能为空");
|
||||
TriageQueueItem selected = triageQueueItemService.getById(req.getId());
|
||||
if (selected == null) return R.fail("队列项不存在");
|
||||
|
||||
// 只将"等待"状态的患者转为"叫号中",允许有多个"叫号中"的患者
|
||||
if (STATUS_WAITING.equals(selected.getStatus())) {
|
||||
selected.setStatus(STATUS_CALLING).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(selected);
|
||||
return R.ok(true);
|
||||
} else if (STATUS_CALLING.equals(selected.getStatus())) {
|
||||
// 如果已经是"叫号中"状态,直接返回成功(不做任何操作)
|
||||
return R.ok(true);
|
||||
} else {
|
||||
// 其他状态(如 SKIPPED、COMPLETED)不能选呼
|
||||
return R.fail("只能选呼\"等待\"状态的患者,当前患者状态为:" + selected.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> complete(TriageQueueActionReq req) {
|
||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||
TriageQueueItem calling = null;
|
||||
|
||||
// 关键改进:如果提供了 id,直接通过ID获取(像 call 方法一样),不依赖查询条件
|
||||
if (req != null && req.getId() != null) {
|
||||
calling = triageQueueItemService.getById(req.getId());
|
||||
if (calling == null) {
|
||||
return R.fail("队列项不存在");
|
||||
}
|
||||
// 验证状态
|
||||
if (!STATUS_CALLING.equals(calling.getStatus())) {
|
||||
return R.fail("只能完成\"叫号中\"状态的患者,当前患者状态为:" + calling.getStatus());
|
||||
}
|
||||
} else {
|
||||
// 如果没有提供 id,通过查询条件查找(兼容旧逻辑)
|
||||
Long orgId = req != null && req.getOrganizationId() != null ? req.getOrganizationId() : null;
|
||||
System.out.println(">>> [TriageQueue] complete() 开始执行(不限制日期,通过查询条件), tenantId=" + tenantId + ", orgId=" + orgId);
|
||||
|
||||
LambdaQueryWrapper<TriageQueueItem> callingWrapper = new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.eq(TriageQueueItem::getStatus, STATUS_CALLING)
|
||||
.orderByAsc(TriageQueueItem::getQueueOrder)
|
||||
.last("LIMIT 1");
|
||||
|
||||
if (orgId != null) {
|
||||
callingWrapper.eq(TriageQueueItem::getOrganizationId, orgId);
|
||||
}
|
||||
|
||||
calling = triageQueueItemService.getOne(callingWrapper, false);
|
||||
|
||||
System.out.println(">>> [TriageQueue] complete() 查询叫号中患者(不限制日期): orgId=" + orgId + ", 结果=" + (calling != null ? calling.getPatientName() + "(status=" + calling.getStatus() + ", queueDate=" + calling.getQueueDate() + ")" : "null"));
|
||||
|
||||
if (calling == null) {
|
||||
return R.fail("当前没有叫号中的患者");
|
||||
}
|
||||
}
|
||||
|
||||
// 使用实际找到的科室ID
|
||||
Long actualOrgId = calling.getOrganizationId();
|
||||
|
||||
// 1) 叫号中 -> 完成(移出列表)
|
||||
calling.setStatus(STATUS_COMPLETED).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(calling);
|
||||
|
||||
// 2) 自动推进下一个等待为叫号中(同一科室,包含跳过状态,不限制日期)
|
||||
LambdaQueryWrapper<TriageQueueItem> nextWrapper = new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.and(w -> w.eq(TriageQueueItem::getStatus, STATUS_WAITING)
|
||||
.or()
|
||||
.eq(TriageQueueItem::getStatus, STATUS_SKIPPED))
|
||||
.orderByAsc(TriageQueueItem::getQueueOrder)
|
||||
.last("LIMIT 1");
|
||||
|
||||
// 如果指定了科室ID,则按科室过滤;否则查询所有科室(全科模式)
|
||||
if (actualOrgId != null) {
|
||||
nextWrapper.eq(TriageQueueItem::getOrganizationId, actualOrgId);
|
||||
}
|
||||
|
||||
TriageQueueItem next = triageQueueItemService.getOne(nextWrapper, false);
|
||||
|
||||
System.out.println(">>> [TriageQueue] complete() 查询等待患者(不限制日期): actualOrgId=" + actualOrgId + ", 结果=" + (next != null ? next.getPatientName() + "(status=" + next.getStatus() + ")" : "null"));
|
||||
|
||||
if (next != null) {
|
||||
next.setStatus(STATUS_CALLING).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(next);
|
||||
}
|
||||
|
||||
recalcOrders(actualOrgId, null);
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> requeue(TriageQueueActionReq req) {
|
||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||
TriageQueueItem calling = null;
|
||||
|
||||
|
||||
if (req != null && req.getId() != null) {
|
||||
calling = triageQueueItemService.getById(req.getId());
|
||||
if (calling == null) {
|
||||
return R.fail("队列项不存在");
|
||||
}
|
||||
// 验证状态
|
||||
if (!STATUS_CALLING.equals(calling.getStatus())) {
|
||||
return R.fail("只能对\"叫号中\"状态的患者进行过号重排,当前患者状态为:" + calling.getStatus());
|
||||
}
|
||||
} else {
|
||||
// 如果没有提供 id,通过查询条件查找(兼容旧逻辑)
|
||||
Long orgId = req != null && req.getOrganizationId() != null ? req.getOrganizationId() : null;
|
||||
|
||||
LambdaQueryWrapper<TriageQueueItem> callingWrapper = new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.eq(TriageQueueItem::getStatus, STATUS_CALLING)
|
||||
.orderByAsc(TriageQueueItem::getQueueOrder)
|
||||
.last("LIMIT 1");
|
||||
|
||||
if (orgId != null) {
|
||||
callingWrapper.eq(TriageQueueItem::getOrganizationId, orgId);
|
||||
}
|
||||
|
||||
calling = triageQueueItemService.getOne(callingWrapper, false);
|
||||
|
||||
if (calling == null) return R.fail("当前没有叫号中的患者");
|
||||
}
|
||||
|
||||
// 使用实际找到的科室ID
|
||||
Long actualOrgId = calling.getOrganizationId();
|
||||
|
||||
// 关键改进:在执行"跳过"操作之前,先检查是否有等待中的患者(判断队列状态)
|
||||
// 如果没有等待中的患者,就不应该执行"过号重排"操作
|
||||
LambdaQueryWrapper<TriageQueueItem> nextWrapper = new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.and(w -> w.eq(TriageQueueItem::getStatus, STATUS_WAITING)
|
||||
.or()
|
||||
.eq(TriageQueueItem::getStatus, STATUS_SKIPPED))
|
||||
.orderByAsc(TriageQueueItem::getQueueOrder)
|
||||
.last("LIMIT 1");
|
||||
|
||||
// 如果指定了科室ID,则按科室过滤;否则查询所有科室(全科模式)
|
||||
if (actualOrgId != null) {
|
||||
nextWrapper.eq(TriageQueueItem::getOrganizationId, actualOrgId);
|
||||
}
|
||||
|
||||
TriageQueueItem next = triageQueueItemService.getOne(nextWrapper, false);
|
||||
|
||||
// 调试日志:检查查询结果
|
||||
System.out.println(">>> [TriageQueue] requeue() 查询等待中的患者:");
|
||||
System.out.println(">>> - 科室ID: " + actualOrgId);
|
||||
System.out.println(">>> - 找到的等待患者: " + (next != null ? next.getPatientName() + " (状态: " + next.getStatus() + ")" : "null"));
|
||||
|
||||
// 如果找不到等待中的患者,直接返回失败(不执行跳过操作)
|
||||
if (next == null) {
|
||||
System.out.println(">>> [TriageQueue] requeue() 失败:没有等待中的患者");
|
||||
return R.fail("当前没有等待中的患者");
|
||||
}
|
||||
|
||||
// 找末尾序号(同一科室,不限制日期)
|
||||
Integer maxOrder = triageQueueItemService.list(new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getOrganizationId, actualOrgId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.ne(TriageQueueItem::getStatus, STATUS_COMPLETED))
|
||||
.stream()
|
||||
.map(TriageQueueItem::getQueueOrder)
|
||||
.filter(Objects::nonNull)
|
||||
.max(Integer::compareTo)
|
||||
.orElse(0);
|
||||
|
||||
// 1) 叫号中 -> 跳过,并移到末尾
|
||||
calling.setStatus(STATUS_SKIPPED).setQueueOrder(maxOrder + 1).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(calling);
|
||||
|
||||
// 2) 自动推进下一个等待为叫号中
|
||||
next.setStatus(STATUS_CALLING).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(next);
|
||||
|
||||
recalcOrders(actualOrgId, null);
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> skip(TriageQueueActionReq req) {
|
||||
// 当前业务“跳过”按“过号重排”处理:叫号中 -> 跳过并移到末尾,自动推进下一等待
|
||||
return requeue(req);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> next(TriageQueueActionReq req) {
|
||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||
TriageQueueItem calling = null;
|
||||
|
||||
System.out.println(">>> [TriageQueue] next() 开始执行(不限制日期), tenantId=" + tenantId);
|
||||
|
||||
// 关键改进:如果提供了 id,优先使用 id 直接查找(像 call 方法一样)
|
||||
if (req != null && req.getId() != null) {
|
||||
calling = triageQueueItemService.getById(req.getId());
|
||||
if (calling == null) {
|
||||
return R.fail("队列项不存在");
|
||||
}
|
||||
// 验证状态:必须是"叫号中"状态
|
||||
if (!STATUS_CALLING.equals(calling.getStatus())) {
|
||||
return R.fail("只能对\"叫号中\"状态的患者执行\"下一患者\"操作,当前患者状态为:" + calling.getStatus());
|
||||
}
|
||||
} else {
|
||||
// 如果没有提供 id,通过查询条件查找(兼容旧逻辑)
|
||||
Long orgId = req != null && req.getOrganizationId() != null ? req.getOrganizationId() : null;
|
||||
|
||||
LambdaQueryWrapper<TriageQueueItem> callingWrapper = new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.eq(TriageQueueItem::getStatus, STATUS_CALLING)
|
||||
.orderByAsc(TriageQueueItem::getQueueOrder)
|
||||
.last("LIMIT 1");
|
||||
|
||||
if (orgId != null) {
|
||||
callingWrapper.eq(TriageQueueItem::getOrganizationId, orgId);
|
||||
}
|
||||
|
||||
calling = triageQueueItemService.getOne(callingWrapper, false);
|
||||
}
|
||||
|
||||
Long actualOrgId = null;
|
||||
|
||||
// 当前叫号中 -> 完成(如果不存在,就当作从头找第一位等待)
|
||||
if (calling != null) {
|
||||
calling.setStatus(STATUS_COMPLETED).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(calling);
|
||||
actualOrgId = calling.getOrganizationId(); // 使用叫号中患者所在的科室
|
||||
} else {
|
||||
// 如果没有叫号中的患者,使用请求中的 organizationId(如果有)
|
||||
if (req != null && req.getOrganizationId() != null) {
|
||||
actualOrgId = req.getOrganizationId();
|
||||
}
|
||||
}
|
||||
|
||||
// 下一位等待 -> 叫号中(如果之前有叫号中的,就在同一科室找;否则在全科找)
|
||||
// 注意:也包含"跳过"状态的患者,因为跳过后的患者也可以重新叫号(不限制日期)
|
||||
LambdaQueryWrapper<TriageQueueItem> nextWrapper = new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.and(w -> w.eq(TriageQueueItem::getStatus, STATUS_WAITING)
|
||||
.or()
|
||||
.eq(TriageQueueItem::getStatus, STATUS_SKIPPED))
|
||||
.orderByAsc(TriageQueueItem::getQueueOrder)
|
||||
.last("LIMIT 1");
|
||||
|
||||
if (actualOrgId != null) {
|
||||
nextWrapper.eq(TriageQueueItem::getOrganizationId, actualOrgId);
|
||||
}
|
||||
|
||||
TriageQueueItem next = triageQueueItemService.getOne(nextWrapper, false);
|
||||
|
||||
// 调试日志:打印查询条件和结果
|
||||
System.out.println(">>> [TriageQueue] next() 查询条件(不限制日期): tenantId=" + tenantId
|
||||
+ ", actualOrgId=" + actualOrgId
|
||||
+ ", deleteFlag=0"
|
||||
+ ", status IN (WAITING, SKIPPED)");
|
||||
System.out.println(">>> [TriageQueue] next() 查询结果: calling=" + (calling != null ? calling.getPatientName() + "(status=" + calling.getStatus() + ", queueDate=" + calling.getQueueDate() + ")" : "null")
|
||||
+ ", next=" + (next != null ? next.getPatientName() + "(status=" + next.getStatus() + ", queueDate=" + next.getQueueDate() + ")" : "null"));
|
||||
|
||||
if (next == null) {
|
||||
if (actualOrgId != null) {
|
||||
recalcOrders(actualOrgId, null);
|
||||
}
|
||||
return R.fail("当前没有等待的患者");
|
||||
}
|
||||
|
||||
next.setStatus(STATUS_CALLING).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(next);
|
||||
|
||||
if (next.getOrganizationId() != null) {
|
||||
recalcOrders(next.getOrganizationId(), null);
|
||||
}
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
private List<TriageQueueItem> listInternal(Long orgId, LocalDate qd) {
|
||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||
LambdaQueryWrapper<TriageQueueItem> wrapper = new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getOrganizationId, orgId)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.ne(TriageQueueItem::getStatus, STATUS_COMPLETED);
|
||||
// 如果 qd 不为 null,才添加日期限制
|
||||
if (qd != null) {
|
||||
wrapper.eq(TriageQueueItem::getQueueDate, qd);
|
||||
}
|
||||
return triageQueueItemService.list(wrapper);
|
||||
}
|
||||
|
||||
private TriageQueueItem findCalling(Long orgId, LocalDate qd) {
|
||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||
return triageQueueItemService.getOne(new LambdaQueryWrapper<TriageQueueItem>()
|
||||
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||
.eq(TriageQueueItem::getOrganizationId, orgId)
|
||||
.eq(TriageQueueItem::getQueueDate, qd)
|
||||
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||
.eq(TriageQueueItem::getStatus, STATUS_CALLING)
|
||||
.last("LIMIT 1"), false);
|
||||
}
|
||||
|
||||
private void recalcOrders(Long orgId, LocalDate qd) {
|
||||
List<TriageQueueItem> list = listInternal(orgId, qd);
|
||||
list.sort(Comparator.comparing(TriageQueueItem::getQueueOrder).thenComparing(TriageQueueItem::getId));
|
||||
int i = 1;
|
||||
for (TriageQueueItem it : list) {
|
||||
if (!Objects.equals(it.getQueueOrder(), i)) {
|
||||
it.setQueueOrder(i).setUpdateTime(LocalDateTime.now());
|
||||
triageQueueItemService.updateById(it);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.openhis.web.triageandqueuemanage.controller;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import com.openhis.web.triageandqueuemanage.appservice.TriageQueueAppService;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueActionReq;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueAddReq;
|
||||
import com.openhis.web.triageandqueuemanage.dto.TriageQueueAdjustReq;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequestMapping("/triage/queue")
|
||||
public class TriageQueueController {
|
||||
|
||||
@Resource
|
||||
private TriageQueueAppService triageQueueAppService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public R<?> list(@RequestParam(value = "organizationId", required = false) Long organizationId,
|
||||
@RequestParam(value = "date", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
|
||||
return triageQueueAppService.list(organizationId, date);
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
public R<?> add(@RequestBody TriageQueueAddReq req) {
|
||||
return triageQueueAppService.add(req);
|
||||
}
|
||||
|
||||
@DeleteMapping("/remove/{id}")
|
||||
public R<?> remove(@PathVariable("id") Long id) {
|
||||
return triageQueueAppService.remove(id);
|
||||
}
|
||||
|
||||
@PutMapping("/adjust")
|
||||
public R<?> adjust(@RequestBody TriageQueueAdjustReq req) {
|
||||
return triageQueueAppService.adjust(req);
|
||||
}
|
||||
|
||||
@PostMapping("/call")
|
||||
public R<?> call(@RequestBody TriageQueueActionReq req) {
|
||||
return triageQueueAppService.call(req);
|
||||
}
|
||||
|
||||
@PostMapping("/complete")
|
||||
public R<?> complete(@RequestBody(required = false) TriageQueueActionReq req) {
|
||||
return triageQueueAppService.complete(req);
|
||||
}
|
||||
|
||||
@PostMapping("/requeue")
|
||||
public R<?> requeue(@RequestBody(required = false) TriageQueueActionReq req) {
|
||||
return triageQueueAppService.requeue(req);
|
||||
}
|
||||
|
||||
@PostMapping("/skip")
|
||||
public R<?> skip(@RequestBody(required = false) TriageQueueActionReq req) {
|
||||
return triageQueueAppService.skip(req);
|
||||
}
|
||||
|
||||
@PostMapping("/next")
|
||||
public R<?> next(@RequestBody(required = false) TriageQueueActionReq req) {
|
||||
return triageQueueAppService.next(req);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.openhis.web.triageandqueuemanage.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TriageQueueActionReq {
|
||||
/** 目标队列项ID(例如:选呼时选中的患者) */
|
||||
private Long id;
|
||||
/** 科室ID(可选:不传则用当前登录人orgId) */
|
||||
private Long organizationId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.openhis.web.triageandqueuemanage.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class TriageQueueAddReq {
|
||||
/** 科室ID(就诊科室) */
|
||||
private Long organizationId;
|
||||
/** 科室名称(冗余存储,便于展示) */
|
||||
private String organizationName;
|
||||
/** 要加入队列的就诊记录 */
|
||||
private List<TriageQueueEncounterItem> items;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.openhis.web.triageandqueuemanage.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TriageQueueAdjustReq {
|
||||
private Long id;
|
||||
/** up / down */
|
||||
private String direction;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.openhis.web.triageandqueuemanage.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TriageQueueEncounterItem {
|
||||
private Long encounterId;
|
||||
private Long patientId;
|
||||
private String patientName;
|
||||
private String healthcareName;
|
||||
private String practitionerName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user