Merge remote-tracking branch 'origin/develop' into guanyu
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# HealthLink-HIS 代码模块索引
|
||||
|
||||
> 供 LLM 快速定位代码。每个模块列出 Controller → Service → Mapper 关键文件。
|
||||
> 最后更新: 2026-06-18 12:00 (309 个 Controller)
|
||||
> 最后更新: 2026-06-18 18:00 (334 个 Controller)
|
||||
|
||||
## 关键词 → 模块速查
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.healthlink.his.web.cdss.appservice;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
|
||||
public interface ICdssAppService {
|
||||
|
||||
R<?> evaluateRules(Long encounterId, Long patientId, String triggerType, Long departmentId);
|
||||
|
||||
R<?> getAlerts(Long encounterId, Integer acknowledged);
|
||||
|
||||
R<?> acknowledgeAlert(Long id, String remark);
|
||||
|
||||
R<?> getRules(String ruleType, String severity, String keyword);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.healthlink.his.web.cdss.appservice.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.cdss.domain.CdssAlert;
|
||||
import com.healthlink.his.cdss.domain.CdssRule;
|
||||
import com.healthlink.his.cdss.service.ICdssAlertService;
|
||||
import com.healthlink.his.cdss.service.ICdssRuleService;
|
||||
import com.healthlink.his.web.cdss.appservice.ICdssAppService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class CdssAppServiceImpl implements ICdssAppService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CdssAppServiceImpl.class);
|
||||
|
||||
private final ICdssRuleService cdssRuleService;
|
||||
private final ICdssAlertService cdssAlertService;
|
||||
|
||||
public CdssAppServiceImpl(ICdssRuleService cdssRuleService, ICdssAlertService cdssAlertService) {
|
||||
this.cdssRuleService = cdssRuleService;
|
||||
this.cdssAlertService = cdssAlertService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<?> evaluateRules(Long encounterId, Long patientId, String triggerType, Long departmentId) {
|
||||
if (encounterId == null || patientId == null) {
|
||||
return R.fail(400, "就诊ID和患者ID不能为空");
|
||||
}
|
||||
List<CdssRule> activeRules = cdssRuleService.findActiveRules(triggerType, departmentId);
|
||||
List<CdssAlert> triggeredAlerts = new ArrayList<>();
|
||||
|
||||
for (CdssRule rule : activeRules) {
|
||||
if (matchRule(rule, encounterId, patientId)) {
|
||||
CdssAlert alert = buildAlert(rule, encounterId, patientId);
|
||||
cdssAlertService.save(alert);
|
||||
triggeredAlerts.add(alert);
|
||||
log.info("CDSS rule triggered: ruleCode={}, encounterId={}", rule.getRuleCode(), encounterId);
|
||||
}
|
||||
}
|
||||
|
||||
return R.ok(Map.of(
|
||||
"totalRules", activeRules.size(),
|
||||
"triggeredAlerts", triggeredAlerts.size(),
|
||||
"alerts", triggeredAlerts
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<?> getAlerts(Long encounterId, Integer acknowledged) {
|
||||
if (encounterId == null) {
|
||||
return R.fail(400, "就诊ID不能为空");
|
||||
}
|
||||
List<CdssAlert> alerts = cdssAlertService.findByEncounterId(encounterId);
|
||||
if (acknowledged != null) {
|
||||
alerts = alerts.stream()
|
||||
.filter(a -> Integer.valueOf(acknowledged).equals(a.getAcknowledged()))
|
||||
.toList();
|
||||
}
|
||||
return R.ok(alerts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<?> acknowledgeAlert(Long id, String remark) {
|
||||
if (id == null) {
|
||||
return R.fail(400, "告警ID不能为空");
|
||||
}
|
||||
boolean updated = cdssAlertService.acknowledgeAlert(id, null, remark);
|
||||
if (!updated) {
|
||||
return R.fail(404, "告警不存在或已确认");
|
||||
}
|
||||
return R.ok(null, "确认成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<?> getRules(String ruleType, String severity, String keyword) {
|
||||
List<CdssRule> rules = cdssRuleService.findActiveRules(ruleType, null);
|
||||
if (severity != null && !severity.isEmpty()) {
|
||||
rules = rules.stream()
|
||||
.filter(r -> severity.equals(r.getSeverity()))
|
||||
.toList();
|
||||
}
|
||||
if (keyword != null && !keyword.isEmpty()) {
|
||||
rules = rules.stream()
|
||||
.filter(r -> r.getRuleName().contains(keyword) ||
|
||||
(r.getRuleCode() != null && r.getRuleCode().contains(keyword)))
|
||||
.toList();
|
||||
}
|
||||
return R.ok(rules);
|
||||
}
|
||||
|
||||
private boolean matchRule(CdssRule rule, Long encounterId, Long patientId) {
|
||||
try {
|
||||
String conditionExpr = rule.getConditionExpr();
|
||||
if (ObjectUtil.isEmpty(conditionExpr)) {
|
||||
return false;
|
||||
}
|
||||
return evaluateCondition(conditionExpr, encounterId, patientId);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to evaluate rule {}: {}", rule.getRuleCode(), e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean evaluateCondition(String conditionExpr, Long encounterId, Long patientId) {
|
||||
return conditionExpr.contains("encounterId") || conditionExpr.contains("patientId");
|
||||
}
|
||||
|
||||
private CdssAlert buildAlert(CdssRule rule, Long encounterId, Long patientId) {
|
||||
CdssAlert alert = new CdssAlert();
|
||||
alert.setEncounterId(encounterId);
|
||||
alert.setPatientId(patientId);
|
||||
alert.setRuleId(rule.getId());
|
||||
alert.setRuleCode(rule.getRuleCode());
|
||||
alert.setRuleName(rule.getRuleName());
|
||||
alert.setSeverity(rule.getSeverity());
|
||||
alert.setAlertTitle("[" + rule.getSeverity() + "] " + rule.getRuleName());
|
||||
alert.setAlertMessage(rule.getDescription() != null ? rule.getDescription() : rule.getRuleName());
|
||||
alert.setSuggestion(rule.getActionExpr());
|
||||
alert.setAcknowledged(0);
|
||||
alert.setCreateTime(new Date());
|
||||
return alert;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.healthlink.his.web.cdss.controller;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.web.cdss.appservice.ICdssAppService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
@Tag(name = "CDSS临床决策支持")
|
||||
@RestController
|
||||
@RequestMapping("/infection/cdss")
|
||||
public class CdssController {
|
||||
|
||||
@Resource
|
||||
private ICdssAppService cdssAppService;
|
||||
|
||||
@Operation(summary = "评估规则生成告警")
|
||||
@PreAuthorize("@ss.hasPermi('infection:cdss:edit')")
|
||||
@PostMapping("/evaluate")
|
||||
public R<?> evaluateRules(@RequestParam Long encounterId,
|
||||
@RequestParam Long patientId,
|
||||
@RequestParam(required = false) String triggerType,
|
||||
@RequestParam(required = false) Long departmentId) {
|
||||
return cdssAppService.evaluateRules(encounterId, patientId, triggerType, departmentId);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取告警列表")
|
||||
@PreAuthorize("@ss.hasPermi('infection:cdss:list')")
|
||||
@GetMapping("/alerts/{encounterId}")
|
||||
public R<?> getAlerts(@PathVariable Long encounterId,
|
||||
@RequestParam(required = false) Integer acknowledged) {
|
||||
return cdssAppService.getAlerts(encounterId, acknowledged);
|
||||
}
|
||||
|
||||
@Operation(summary = "确认告警")
|
||||
@PreAuthorize("@ss.hasPermi('infection:cdss:edit')")
|
||||
@PostMapping("/alerts/{id}/acknowledge")
|
||||
public R<?> acknowledgeAlert(@PathVariable Long id,
|
||||
@RequestBody(required = false) Map<String, String> body) {
|
||||
String remark = body != null ? body.get("remark") : null;
|
||||
return cdssAppService.acknowledgeAlert(id, remark);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询规则列表")
|
||||
@PreAuthorize("@ss.hasPermi('infection:cdss:list')")
|
||||
@GetMapping("/rules")
|
||||
public R<?> getRules(
|
||||
@RequestParam(value = "ruleType", required = false) String ruleType,
|
||||
@RequestParam(value = "severity", required = false) String severity,
|
||||
@RequestParam(value = "keyword", required = false) String keyword) {
|
||||
return cdssAppService.getRules(ruleType, severity, keyword);
|
||||
}
|
||||
}
|
||||
@@ -152,6 +152,9 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
||||
InspectionLabApply inspectionLabApply = new InspectionLabApply();
|
||||
//将 dto 数据复制到 InspectionLabApply 对象中
|
||||
BeanUtils.copyProperties(doctorStationLabApplyDto, inspectionLabApply);
|
||||
// 修复:applicationId 与 id 字段名不一致,BeanUtils 不会自动拷贝,需手动设置
|
||||
// 否则 saveOrUpdate 永远走 INSERT,导致编辑保存时主键冲突
|
||||
inspectionLabApply.setId(doctorStationLabApplyDto.getApplicationId());
|
||||
//设置租户 ID
|
||||
inspectionLabApply.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||
//获取当前登陆用户名称
|
||||
@@ -337,8 +340,11 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
||||
}
|
||||
adviceSaveDto.setAccountId(accountId);
|
||||
|
||||
// 将申请单号作为业务关联标识(请求内容 json)
|
||||
adviceSaveDto.setContentJson("{\"applyNo\":\"" + doctorStationLabApplyDto.getApplyNo() + "\"}");
|
||||
// 将申请单号和项目名称作为业务关联标识(请求内容 json)
|
||||
// 项目名称用于读取时 COALESCE 回退显示(检验项目存的是 lab_activity_definition 的 ID,
|
||||
// 读取 SQL JOIN 的是 wor_activity_definition,会匹配不上,所以需要在 contentJson 中冗余存储名称)
|
||||
String escapedItemName = itemName.replace("\"", "\\\"");
|
||||
adviceSaveDto.setContentJson("{\"applyNo\":\"" + doctorStationLabApplyDto.getApplyNo() + "\",\"adviceName\":\"" + escapedItemName + "\"}");
|
||||
|
||||
// 设置其他必要字段
|
||||
// 请求数量
|
||||
|
||||
@@ -40,7 +40,9 @@ import com.healthlink.his.web.document.dto.DocStatisticsDto;
|
||||
import com.healthlink.his.web.inhospitalnursestation.appservice.IATDManageAppService;
|
||||
import com.healthlink.his.web.inhospitalnursestation.dto.*;
|
||||
import com.healthlink.his.web.inhospitalnursestation.mapper.ATDManageAppMapper;
|
||||
import com.healthlink.his.workflow.domain.DeviceRequest;
|
||||
import com.healthlink.his.workflow.domain.ServiceRequest;
|
||||
import com.healthlink.his.workflow.service.IDeviceRequestService;
|
||||
import com.healthlink.his.workflow.service.IServiceRequestService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -98,6 +100,9 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
@Resource
|
||||
private IServiceRequestService serviceRequestService;
|
||||
|
||||
@Resource
|
||||
private IDeviceRequestService deviceRequestService;
|
||||
|
||||
@Resource
|
||||
private IPractitionerService practitionerService;
|
||||
|
||||
@@ -402,7 +407,8 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
ChargeItemStatus.BILLABLE.getValue(), ChargeItemStatus.BILLED.getValue(),
|
||||
ChargeItemStatus.REFUNDED.getValue(), EncounterClass.IMP.getValue(),
|
||||
GenerateSource.DOCTOR_PRESCRIPTION.getValue(), ActivityDefCategory.TRANSFER.getCode(),
|
||||
ActivityDefCategory.DISCHARGE.getCode(), ActivityDefCategory.NURSING.getCode());
|
||||
ActivityDefCategory.DISCHARGE.getCode(), ActivityDefCategory.NURSING.getCode(),
|
||||
RequestStatus.DISPENSE_COMPLETED.getValue());
|
||||
inpatientAdvicePage.getRecords().forEach(e -> {
|
||||
// 是否皮试
|
||||
e.setSkinTestFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getSkinTestFlag()));
|
||||
@@ -622,20 +628,10 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
if (encounterId == null) {
|
||||
return R.fail("转科失败,请选择有效的患者");
|
||||
}
|
||||
// 获取是否还有待执行医嘱
|
||||
List<MedicationRequest> medicationRequestList = medicationRequestService
|
||||
.list(new LambdaQueryWrapper<MedicationRequest>().eq(MedicationRequest::getEncounterId, encounterId)
|
||||
.ne(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
|
||||
.eq(MedicationRequest::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
List<ServiceRequest> serviceRequestList = serviceRequestService
|
||||
.list(new LambdaQueryWrapper<ServiceRequest>().eq(ServiceRequest::getEncounterId, encounterId)
|
||||
.ne(ServiceRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.TRANSFER.getValue())
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.DISCHARGE.getValue())
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.NURSING.getValue())
|
||||
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
if (!medicationRequestList.isEmpty() || !serviceRequestList.isEmpty()) {
|
||||
return R.fail("有待执行的医嘱,请执行完后再转科");
|
||||
// 校验是否有未处理完的医嘱(药品/诊疗/耗材)
|
||||
String blockingMsg = checkBlockingOrders(encounterId);
|
||||
if (blockingMsg != null) {
|
||||
return R.fail(blockingMsg);
|
||||
}
|
||||
// 查询患者待取的药品
|
||||
List<MedicationDispense> medicationDispenseList = medicationDispenseService
|
||||
@@ -686,25 +682,15 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> hospitalDischarge(Long encounterId) {
|
||||
if (encounterId == null) {
|
||||
return R.fail("出院失败,请选择有效的患者");
|
||||
}
|
||||
// 获取是否还有待执行医嘱
|
||||
List<MedicationRequest> medicationRequestList = medicationRequestService
|
||||
.list(new LambdaQueryWrapper<MedicationRequest>().eq(MedicationRequest::getEncounterId, encounterId)
|
||||
.ne(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
|
||||
.eq(MedicationRequest::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
List<ServiceRequest> serviceRequestList = serviceRequestService
|
||||
.list(new LambdaQueryWrapper<ServiceRequest>().eq(ServiceRequest::getEncounterId, encounterId)
|
||||
.ne(ServiceRequest::getStatusEnum, RequestStatus.STOPPED.getValue())
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.TRANSFER.getValue())
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.DISCHARGE.getValue())
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.NURSING.getValue())
|
||||
.eq(ServiceRequest::getParentId, null)
|
||||
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
if (!medicationRequestList.isEmpty() || !serviceRequestList.isEmpty()) {
|
||||
return R.fail("有待执行的医嘱,请执行完后再出院");
|
||||
// 校验是否有未处理完的医嘱(药品/诊疗/耗材)
|
||||
String blockingMsg = checkBlockingOrders(encounterId);
|
||||
if (blockingMsg != null) {
|
||||
return R.fail(blockingMsg);
|
||||
}
|
||||
// 查询患者待取的药品
|
||||
List<MedicationDispense> medicationDispenseList = medicationDispenseService
|
||||
@@ -737,6 +723,15 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
|| EncounterZyStatus.REGISTERED.getValue().equals(encounter.getStatusEnum())) {
|
||||
return R.fail("请等待出院结算完成后再清床");
|
||||
}
|
||||
// 待转科患者应使用转科功能,不允许直接清床
|
||||
if (EncounterZyStatus.PENDING_TRANSFER.getValue().equals(encounter.getStatusEnum())) {
|
||||
return R.fail("患者处于待转科状态,请使用转科功能");
|
||||
}
|
||||
// 校验是否有未处理完的医嘱(药品/诊疗/耗材)
|
||||
String blockingMsg = checkBlockingOrders(encounterId);
|
||||
if (blockingMsg != null) {
|
||||
return R.fail(blockingMsg);
|
||||
}
|
||||
// 更新患者位置状态:已完成
|
||||
encounterLocationService.updateEncounterLocationStatus(encounterId, true);
|
||||
// 更新患者相关医生状态:已完成
|
||||
@@ -751,6 +746,73 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
return R.ok("清床完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查患者是否有未处理完的医嘱(药品/诊疗/耗材),用于转科/出院/清床前的统一校验。
|
||||
* <p>
|
||||
* 使用正向白名单方式,仅查询处于"阻塞状态"的医嘱:
|
||||
* - DRAFT(1) 待发送 —— 医生已开嘱尚未提交
|
||||
* - ACTIVE(2) 已发送 —— 待护士校对
|
||||
* - COMPLETED(3) 已校对 —— 护士校对通过但尚未执行完
|
||||
* - CHECK_VERIFIED(10) 检查已校对 —— 检查类医嘱校对通过,待执行
|
||||
* - PENDING_STOP(13) 停嘱待核对 —— 医生已停嘱,待护士核对
|
||||
* <p>
|
||||
* 以下状态不会阻塞(已走完流程或已取消):
|
||||
* - STOPPED(6) 停嘱
|
||||
* - CANCELLED(5) 取消/待退
|
||||
* - PENDING_RECEIVE(11) 待接收 —— 检查已送检
|
||||
* - CHECK_RECEIVED(12) 已接收 —— 医技已接单
|
||||
* - DISPENSE_COMPLETED(20) 发药完成
|
||||
*
|
||||
* @param encounterId 住院患者id
|
||||
* @return 错误提示消息,null 表示无阻塞
|
||||
*/
|
||||
private String checkBlockingOrders(Long encounterId) {
|
||||
// 阻塞状态白名单:仅这些状态的医嘱会阻止转科/出院/清床
|
||||
List<Integer> blockingStatuses = List.of(
|
||||
RequestStatus.DRAFT.getValue(),
|
||||
RequestStatus.ACTIVE.getValue(),
|
||||
RequestStatus.COMPLETED.getValue(),
|
||||
RequestStatus.CHECK_VERIFIED.getValue(),
|
||||
RequestStatus.PENDING_STOP.getValue()
|
||||
);
|
||||
|
||||
// 1. 检查药品医嘱(MedicationRequest)
|
||||
long medCount = medicationRequestService.count(
|
||||
new LambdaQueryWrapper<MedicationRequest>()
|
||||
.eq(MedicationRequest::getEncounterId, encounterId)
|
||||
.in(MedicationRequest::getStatusEnum, blockingStatuses)
|
||||
.eq(MedicationRequest::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
if (medCount > 0) {
|
||||
return "有未处理完的医嘱,请先处理完再操作";
|
||||
}
|
||||
|
||||
// 2. 检查诊疗医嘱(ServiceRequest),排除转科/出院/护理级别类医嘱,只查父级医嘱
|
||||
long svcCount = serviceRequestService.count(
|
||||
new LambdaQueryWrapper<ServiceRequest>()
|
||||
.eq(ServiceRequest::getEncounterId, encounterId)
|
||||
.in(ServiceRequest::getStatusEnum, blockingStatuses)
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.TRANSFER.getValue())
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.DISCHARGE.getValue())
|
||||
.ne(ServiceRequest::getCategoryEnum, ActivityDefCategory.NURSING.getValue())
|
||||
.eq(ServiceRequest::getParentId, null)
|
||||
.eq(ServiceRequest::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
if (svcCount > 0) {
|
||||
return "有未处理完的医嘱,请先处理完再操作";
|
||||
}
|
||||
|
||||
// 3. 检查耗材医嘱(DeviceRequest)
|
||||
long devCount = deviceRequestService.count(
|
||||
new LambdaQueryWrapper<DeviceRequest>()
|
||||
.eq(DeviceRequest::getEncounterId, encounterId)
|
||||
.in(DeviceRequest::getStatusEnum, blockingStatuses)
|
||||
.eq(DeviceRequest::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
if (devCount > 0) {
|
||||
return "有未处理完的医嘱,请先处理完再操作";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 诊断个人账户金额信息获取
|
||||
*
|
||||
|
||||
@@ -461,15 +461,17 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
}
|
||||
// 处理转科/出院等特殊医嘱
|
||||
for (ServiceRequest serviceRequest : allServiceRequests) {
|
||||
// Bug #718: 延迟状态变更时机。核对通过时不立即变更患者就诊状态,
|
||||
// 而是等到护士在【入出转管理】中手动点击“转科”或“清床”时再处理。
|
||||
// 这样可以确保护士在真正转出前,依然能在在科列表中选中患者并处理遗留医嘱。
|
||||
// 核对通过后更新就诊状态,使患者出现在对应的管理列表中:
|
||||
// - 转科医嘱 → 状态6(待转科),患者出现在【入出转管理→转出】列表
|
||||
// - 出院医嘱 → 状态3(待出院),患者出现在【入出转管理→出院】列表
|
||||
// 注意:此处仅更新 adm_encounter.status_enum,不释放床位。
|
||||
// 床位释放发生在护士手动点击”转科”/”出院”时的 transferDepartment()/hospitalDischarge() 中。
|
||||
if (ActivityDefCategory.TRANSFER.getValue().equals(serviceRequest.getCategoryEnum())) {
|
||||
// encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
|
||||
// EncounterZyStatus.PENDING_TRANSFER.getValue());
|
||||
encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
|
||||
EncounterZyStatus.PENDING_TRANSFER.getValue());
|
||||
} else if (ActivityDefCategory.DISCHARGE.getValue().equals(serviceRequest.getCategoryEnum())) {
|
||||
// encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
|
||||
// EncounterZyStatus.AWAITING_DISCHARGE.getValue());
|
||||
encounterService.updateEncounterStatus(serviceRequest.getEncounterId(),
|
||||
EncounterZyStatus.AWAITING_DISCHARGE.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class MedicineSummaryAppServiceImpl implements IMedicineSummaryAppService
|
||||
|
||||
// 汇总单分页列表
|
||||
Page<MedicineSummaryFormDto> medicineSummaryFormPage = medicineSummaryAppMapper.selectMedicineSummaryFormPage(
|
||||
new Page<>(pageNo, pageSize), queryWrapper, DispenseStatus.PREPARATION.getValue(),
|
||||
new Page<>(pageNo, pageSize), queryWrapper,
|
||||
SupplyType.SUMMARY_DISPENSE.getValue());
|
||||
medicineSummaryFormPage.getRecords().forEach(e -> {
|
||||
// 发药状态(汇总单展示文案)
|
||||
|
||||
@@ -144,7 +144,8 @@ public interface ATDManageAppMapper {
|
||||
@Param("admittingDoctor") String admittingDoctor, @Param("personalCashAccount") String personalCashAccount,
|
||||
@Param("billable") Integer billable, @Param("billed") Integer billed, @Param("refunded") Integer refunded,
|
||||
@Param("imp") Integer imp, @Param("doctorPrescription") Integer doctorPrescription,
|
||||
@Param("transfer") String transfer, @Param("discharge") String discharge, @Param("nursing") String nursing);
|
||||
@Param("transfer") String transfer, @Param("discharge") String discharge, @Param("nursing") String nursing,
|
||||
@Param("dispenseCompleted") Integer dispenseCompleted);
|
||||
|
||||
/**
|
||||
* 查询执行记录
|
||||
|
||||
@@ -46,13 +46,11 @@ public interface MedicineSummaryAppMapper {
|
||||
*
|
||||
* @param page 分页信息
|
||||
* @param queryWrapper 查询条件
|
||||
* @param preparation 发药状态:待配药
|
||||
* @param summaryDispense 单据类型:汇总发药
|
||||
* @return 汇总单列表
|
||||
*/
|
||||
Page<MedicineSummaryFormDto> selectMedicineSummaryFormPage(@Param("page") Page<MedicineSummaryFormDto> page,
|
||||
@Param(Constants.WRAPPER) QueryWrapper<DispenseFormSearchParam> queryWrapper,
|
||||
@Param("preparation") Integer preparation,
|
||||
@Param("summaryDispense") Integer summaryDispense);
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.ArrayNode;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.core.common.core.domain.R;
|
||||
@@ -351,6 +352,30 @@ public class InHospitalReturnMedicineAppServiceImpl implements IInHospitalReturn
|
||||
}
|
||||
// 退药更新
|
||||
medicationDispenseService.updateBatchById(refundMedList);
|
||||
|
||||
// 退药完成后,检查医嘱关联的发药记录是否全部退完,如果是则回写医嘱状态为已停止
|
||||
// 解决:医嘱取消(status=5)后退药完成,医嘱状态未变更,导致护士站"待处理执行单"仍显示已退完的医嘱
|
||||
Set<Long> distinctMedReqIds = refundMedList.stream()
|
||||
.map(MedicationDispense::getMedReqId).collect(Collectors.toSet());
|
||||
for (Long medReqId : distinctMedReqIds) {
|
||||
// 查询该医嘱下所有发药记录
|
||||
List<MedicationDispense> allDispenses = medicationDispenseService.list(
|
||||
new LambdaQueryWrapper<MedicationDispense>()
|
||||
.eq(MedicationDispense::getMedReqId, medReqId)
|
||||
.eq(MedicationDispense::getDeleteFlag, "0"));
|
||||
// 判断是否全部已退药
|
||||
boolean allRefunded = allDispenses.stream()
|
||||
.allMatch(d -> DispenseStatus.REFUNDED.getValue().equals(d.getStatusEnum()));
|
||||
if (allRefunded) {
|
||||
// 回写医嘱状态:取消/待退(5) → 已停止(6)
|
||||
// STOPPED(6)会被护士站查询排除,不再出现在"待处理执行单"中
|
||||
medicationRequestService.update(
|
||||
new LambdaUpdateWrapper<MedicationRequest>()
|
||||
.eq(MedicationRequest::getId, medReqId)
|
||||
.eq(MedicationRequest::getStatusEnum, RequestStatus.CANCELLED.getValue())
|
||||
.set(MedicationRequest::getStatusEnum, RequestStatus.STOPPED.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理退耗材
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.web.reportmanage.appservice;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IReportDimensionAppService {
|
||||
|
||||
Map<String, Object> getReportByDimension(String dimension, Map<String, String> filters);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.healthlink.his.web.reportmanage.appservice.impl;
|
||||
|
||||
import com.healthlink.his.mrhomepage.domain.MrHomepage;
|
||||
import com.healthlink.his.mrhomepage.service.IMrHomepageService;
|
||||
import com.healthlink.his.web.reportmanage.appservice.IReportDimensionAppService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class ReportDimensionAppServiceImpl implements IReportDimensionAppService {
|
||||
|
||||
private final IMrHomepageService mrHomepageService;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getReportByDimension(String dimension, Map<String, String> filters) {
|
||||
List<MrHomepage> allData = mrHomepageService.list();
|
||||
|
||||
String startDate = filters != null ? filters.get("startDate") : null;
|
||||
String endDate = filters != null ? filters.get("endDate") : null;
|
||||
|
||||
if (StringUtils.hasText(startDate)) {
|
||||
allData = allData.stream()
|
||||
.filter(h -> h.getDischargeDate() != null &&
|
||||
h.getDischargeDate().toString().compareTo(startDate) >= 0)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
if (StringUtils.hasText(endDate)) {
|
||||
allData = allData.stream()
|
||||
.filter(h -> h.getDischargeDate() != null &&
|
||||
h.getDischargeDate().toString().compareTo(endDate) <= 0)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("totalCount", allData.size());
|
||||
|
||||
BigDecimal totalCost = allData.stream()
|
||||
.map(MrHomepage::getTotalCost)
|
||||
.filter(Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
result.put("totalCost", totalCost);
|
||||
result.put("avgCost", allData.isEmpty() ? BigDecimal.ZERO :
|
||||
totalCost.divide(BigDecimal.valueOf(allData.size()), 2, RoundingMode.HALF_UP));
|
||||
|
||||
Map<String, List<MrHomepage>> grouped;
|
||||
switch (dimension != null ? dimension : "status") {
|
||||
case "drg":
|
||||
grouped = allData.stream()
|
||||
.filter(h -> h.getDrgGroup() != null)
|
||||
.collect(Collectors.groupingBy(MrHomepage::getDrgGroup));
|
||||
break;
|
||||
case "diagnosis":
|
||||
grouped = allData.stream()
|
||||
.filter(h -> h.getPrimaryDiagnosisName() != null)
|
||||
.collect(Collectors.groupingBy(MrHomepage::getPrimaryDiagnosisName));
|
||||
break;
|
||||
case "status":
|
||||
default:
|
||||
grouped = allData.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
h -> h.getQualityStatus() != null ? h.getQualityStatus() : "UNKNOWN"));
|
||||
break;
|
||||
}
|
||||
|
||||
List<Map<String, Object>> dimensionData = new ArrayList<>();
|
||||
grouped.forEach((key, items) -> {
|
||||
Map<String, Object> entry = new HashMap<>();
|
||||
entry.put("dimension", key);
|
||||
entry.put("count", items.size());
|
||||
BigDecimal cost = items.stream()
|
||||
.map(MrHomepage::getTotalCost)
|
||||
.filter(Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
entry.put("totalCost", cost);
|
||||
entry.put("avgCost", items.isEmpty() ? BigDecimal.ZERO :
|
||||
cost.divide(BigDecimal.valueOf(items.size()), 2, RoundingMode.HALF_UP));
|
||||
long totalLos = items.stream()
|
||||
.mapToInt(h -> h.getLosDays() != null ? h.getLosDays() : 0)
|
||||
.sum();
|
||||
entry.put("avgLosDays", items.isEmpty() ? 0 :
|
||||
Math.round(totalLos * 10.0 / items.size()) / 10.0);
|
||||
dimensionData.add(entry);
|
||||
});
|
||||
|
||||
result.put("dimension", dimension);
|
||||
result.put("data", dimensionData);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RestController("reportBusinessAnalyticsController")
|
||||
@RequestMapping("/report/analytics")
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RestController("reportDrgAnalysisController")
|
||||
@RequestMapping("/report/drg")
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.healthlink.his.web.reportmanage.controller;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.web.reportmanage.appservice.IReportDimensionAppService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Tag(name = "多维度报表")
|
||||
@RestController
|
||||
@RequestMapping("/report-manage/report-dimension")
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class ReportDimensionController {
|
||||
|
||||
private final IReportDimensionAppService reportDimensionAppService;
|
||||
|
||||
@Operation(summary = "多维度报表查询")
|
||||
@PreAuthorize("@ss.hasPermi('reportmanage:report:list')")
|
||||
@GetMapping("/query")
|
||||
public R<Map<String, Object>> getReportByDimension(
|
||||
@RequestParam(value = "dimension", defaultValue = "status") String dimension,
|
||||
@RequestParam(value = "startDate", required = false) String startDate,
|
||||
@RequestParam(value = "endDate", required = false) String endDate) {
|
||||
Map<String, String> filters = new HashMap<>();
|
||||
if (startDate != null) filters.put("startDate", startDate);
|
||||
if (endDate != null) filters.put("endDate", endDate);
|
||||
return R.ok(reportDimensionAppService.getReportByDimension(dimension, filters));
|
||||
}
|
||||
}
|
||||
@@ -1,338 +0,0 @@
|
||||
-- V66__update_menu_icons.sql
|
||||
-- 更新菜单图标 - 根据菜单功能名称匹配合适的图标
|
||||
-- 仅使用 src/assets/icons/svg/ 目录下实际存在的图标
|
||||
|
||||
SET search_path TO healthlink_his;
|
||||
|
||||
-- ========== 一级菜单(顶级目录)==========
|
||||
UPDATE sys_menu SET icon = 'system' WHERE menu_id = 1; -- 系统管理
|
||||
UPDATE sys_menu SET icon = 'monitor' WHERE menu_id = 2; -- 系统监控
|
||||
UPDATE sys_menu SET icon = 'tool' WHERE menu_id = 3; -- 系统工具
|
||||
UPDATE sys_menu SET icon = 'log' WHERE menu_id = 108; -- 日志管理
|
||||
UPDATE sys_menu SET icon = 'inpatient' WHERE menu_id = 235; -- 住院管理
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 268; -- 药库管理
|
||||
UPDATE sys_menu SET icon = 'outpatient' WHERE menu_id = 270; -- 门诊管理
|
||||
UPDATE sys_menu SET icon = 'inventory' WHERE menu_id = 313; -- 库房管理
|
||||
UPDATE sys_menu SET icon = 'drug-dispensing' WHERE menu_id = 342; -- 发药管理
|
||||
UPDATE sys_menu SET icon = 'finance' WHERE menu_id = 350; -- 财务管理
|
||||
UPDATE sys_menu SET icon = 'report' WHERE menu_id = 360; -- 报表管理
|
||||
UPDATE sys_menu SET icon = 'insurance' WHERE menu_id = 386; -- 医保管理
|
||||
UPDATE sys_menu SET icon = 'connection' WHERE menu_id = 418; -- 接口管理
|
||||
UPDATE sys_menu SET icon = 'workflow' WHERE menu_id = 2020; -- 流程管理
|
||||
UPDATE sys_menu SET icon = 'task' WHERE menu_id = 2023; -- 任务管理
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 2078; -- 收费工作站
|
||||
UPDATE sys_menu SET icon = 'pharmacy' WHERE menu_id = 2079; -- 药房管理
|
||||
UPDATE sys_menu SET icon = 'tool' WHERE menu_id = 2083; -- 维护系统
|
||||
UPDATE sys_menu SET icon = 'doctor' WHERE menu_id = 2084; -- 门诊医生工作站
|
||||
UPDATE sys_menu SET icon = 'appointment' WHERE menu_id = 2092; -- 预约管理
|
||||
UPDATE sys_menu SET icon = 'triage' WHERE menu_id = 2110; -- 分诊排队管理
|
||||
UPDATE sys_menu SET icon = 'surgery' WHERE menu_id = 2119; -- 手术管理
|
||||
UPDATE sys_menu SET icon = 'user' WHERE menu_id = 2140; -- 患者管理
|
||||
UPDATE sys_menu SET icon = 'consultation' WHERE menu_id = 2147; -- 会诊管理
|
||||
UPDATE sys_menu SET icon = 'report' WHERE menu_id = 2159; -- 疾病报告管理
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10001; -- 院感管理
|
||||
UPDATE sys_menu SET icon = 'log' WHERE menu_id = 10011; -- 药品追溯管理
|
||||
UPDATE sys_menu SET icon = 'edit' WHERE menu_id = 10021; -- 电子签名管理
|
||||
UPDATE sys_menu SET icon = 'alert' WHERE menu_id = 10031; -- 危急值管理
|
||||
UPDATE sys_menu SET icon = 'peoples' WHERE menu_id = 10041; -- 患者主索引(EMPI)
|
||||
UPDATE sys_menu SET icon = 'peoples' WHERE menu_id = 10051; -- 质量管理
|
||||
UPDATE sys_menu SET icon = 'shopping' WHERE menu_id = 10061; -- 手术安全核查
|
||||
UPDATE sys_menu SET icon = 'guide' WHERE menu_id = 10071; -- 临床路径
|
||||
UPDATE sys_menu SET icon = 'anesthesia' WHERE menu_id = 20001; -- 麻醉管理
|
||||
UPDATE sys_menu SET icon = 'medication' WHERE menu_id = 20011; -- 合理用药
|
||||
UPDATE sys_menu SET icon = 'emergency' WHERE menu_id = 20021; -- 急诊管理
|
||||
UPDATE sys_menu SET icon = 'nursing' WHERE menu_id = 20031; -- 护理管理
|
||||
UPDATE sys_menu SET icon = 'pathology' WHERE menu_id = 20041; -- 病理管理
|
||||
UPDATE sys_menu SET icon = 'medical-record' WHERE menu_id = 20051; -- 病案管理
|
||||
UPDATE sys_menu SET icon = 'radiology' WHERE menu_id = 20061; -- 影像管理
|
||||
UPDATE sys_menu SET icon = 'follow-up' WHERE menu_id = 20071; -- 随访管理
|
||||
UPDATE sys_menu SET icon = 'monitor' WHERE menu_id = 20081; -- ESB管理
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20091; -- 检查检验
|
||||
UPDATE sys_menu SET icon = 'consent' WHERE menu_id = 20101; -- 知情同意管理
|
||||
UPDATE sys_menu SET icon = 'order' WHERE menu_id = 20111; -- 医嘱闭环
|
||||
UPDATE sys_menu SET icon = 'audit' WHERE menu_id = 20131; -- 审核管理
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20141; -- 跨模块协同
|
||||
UPDATE sys_menu SET icon = 'sample' WHERE menu_id = 20151; -- 标本管理
|
||||
UPDATE sys_menu SET icon = 'standard' WHERE menu_id = 20161; -- FHIR/CDA标准
|
||||
UPDATE sys_menu SET icon = 'emr' WHERE menu_id = 20201; -- 电子病历管理
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20211; -- 检验增强
|
||||
|
||||
-- ========== 二级菜单图标更新 ==========
|
||||
-- 系统管理子菜单
|
||||
UPDATE sys_menu SET icon = 'user' WHERE menu_id = 100; -- 用户管理
|
||||
UPDATE sys_menu SET icon = 'peoples' WHERE menu_id = 101; -- 角色管理
|
||||
UPDATE sys_menu SET icon = 'post' WHERE menu_id = 104; -- 岗位管理
|
||||
UPDATE sys_menu SET icon = 'system' WHERE menu_id = 102; -- 菜单管理
|
||||
UPDATE sys_menu SET icon = 'tree-table' WHERE menu_id = 103; -- 部门管理
|
||||
UPDATE sys_menu SET icon = 'dict' WHERE menu_id = 105; -- 字典管理
|
||||
UPDATE sys_menu SET icon = 'edit' WHERE menu_id = 106; -- 参数设置
|
||||
UPDATE sys_menu SET icon = 'message' WHERE menu_id = 107; -- 通知公告
|
||||
|
||||
-- 系统监控子菜单
|
||||
UPDATE sys_menu SET icon = 'online' WHERE menu_id = 109; -- 在线用户
|
||||
UPDATE sys_menu SET icon = 'job' WHERE menu_id = 110; -- 定时任务
|
||||
UPDATE sys_menu SET icon = 'druid' WHERE menu_id = 111; -- 数据监控
|
||||
UPDATE sys_menu SET icon = 'server' WHERE menu_id = 112; -- 服务监控
|
||||
UPDATE sys_menu SET icon = 'monitor' WHERE menu_id = 113; -- 缓存监控
|
||||
UPDATE sys_menu SET icon = 'log' WHERE menu_id = 2104; -- 监控日志
|
||||
|
||||
-- 系统工具子菜单
|
||||
UPDATE sys_menu SET icon = 'form' WHERE menu_id = 115; -- 表单构建
|
||||
UPDATE sys_menu SET icon = 'code' WHERE menu_id = 116; -- 代码生成
|
||||
UPDATE sys_menu SET icon = 'swagger' WHERE menu_id = 117; -- 系统接口
|
||||
|
||||
-- 日志管理子菜单
|
||||
UPDATE sys_menu SET icon = 'log' WHERE menu_id = 500; -- 操作日志
|
||||
UPDATE sys_menu SET icon = 'log' WHERE menu_id = 501; -- 登录日志
|
||||
|
||||
-- 住院管理子菜单
|
||||
UPDATE sys_menu SET icon = 'doctor' WHERE menu_id = 288; -- 住院医生工作站
|
||||
UPDATE sys_menu SET icon = 'nurse' WHERE menu_id = 295; -- 住院护士站
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 307; -- 住院收费工作站
|
||||
UPDATE sys_menu SET icon = 'doctor' WHERE menu_id = 20171; -- 住院医生增强
|
||||
UPDATE sys_menu SET icon = 'nurse' WHERE menu_id = 20181; -- 住院护士增强
|
||||
UPDATE sys_menu SET icon = 'hospital' WHERE menu_id = 20221; -- 住院辅助
|
||||
|
||||
-- 药库管理子菜单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2049; -- 药库订货单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2050; -- 药库退货单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2051; -- 药库进货单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2053; -- 药库出库单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2054; -- 药库退库单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2055; -- 药库损益单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2056; -- 药库盘点单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2058; -- 库房单据管理
|
||||
|
||||
-- 门诊管理子菜单
|
||||
UPDATE sys_menu SET icon = 'doctor' WHERE menu_id = 269; -- 门诊工作站
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 277; -- 医技工作站
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 282; -- 门诊收费工作站
|
||||
|
||||
-- 门诊工作站子菜单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 272; -- 门诊退药
|
||||
UPDATE sys_menu SET icon = 'registration' WHERE menu_id = 274; -- 门诊退号
|
||||
|
||||
-- 门诊收费工作站子菜单
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 283; -- 门诊收费
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 284; -- 门诊退费
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 285; -- 门诊划价
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 287; -- 收费详情查询
|
||||
|
||||
-- 药房管理子菜单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 343; -- 门诊发药
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 344; -- 门诊退药
|
||||
|
||||
-- 住院护士站子菜单
|
||||
UPDATE sys_menu SET icon = 'nurse' WHERE menu_id = 296; -- 门户
|
||||
UPDATE sys_menu SET icon = 'admission' WHERE menu_id = 297; -- 入出转管理
|
||||
UPDATE sys_menu SET icon = 'nursing' WHERE menu_id = 298; -- 护理记录
|
||||
UPDATE sys_menu SET icon = 'vital-signs' WHERE menu_id = 299; -- 三测单
|
||||
UPDATE sys_menu SET icon = 'order' WHERE menu_id = 2061; -- 医嘱执行
|
||||
UPDATE sys_menu SET icon = 'order' WHERE menu_id = 2064; -- 医嘱校对
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 301; -- 汇总发药申请
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 302; -- 住院记账
|
||||
UPDATE sys_menu SET icon = 'allergy' WHERE menu_id = 303; -- 皮试管理
|
||||
UPDATE sys_menu SET icon = 'order' WHERE menu_id = 276; -- 医嘱查看与打印
|
||||
UPDATE sys_menu SET icon = 'discharge' WHERE menu_id = 304; -- 出院管理
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 305; -- 退药管理
|
||||
UPDATE sys_menu SET icon = 'surgery' WHERE menu_id = 306; -- 手术记录
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 2062; -- 住院领药
|
||||
|
||||
-- 住院收费工作站子菜单
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 308; -- 费用管理
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 309; -- 住院费用结算
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 311; -- 住院收费详情
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 312; -- 中途结算
|
||||
|
||||
-- 财务管理子菜单
|
||||
UPDATE sys_menu SET icon = 'finance' WHERE menu_id = 354; -- 日结结算单管理
|
||||
UPDATE sys_menu SET icon = 'finance' WHERE menu_id = 356; -- 药房对账
|
||||
UPDATE sys_menu SET icon = 'finance' WHERE menu_id = 357; -- 库房审批
|
||||
UPDATE sys_menu SET icon = 'insurance' WHERE menu_id = 358; -- 医保结算
|
||||
UPDATE sys_menu SET icon = 'insurance' WHERE menu_id = 359; -- 医保对账
|
||||
|
||||
-- 报表管理子菜单
|
||||
UPDATE sys_menu SET icon = 'report' WHERE menu_id = 213; -- 门诊就诊记录
|
||||
UPDATE sys_menu SET icon = 'report' WHERE menu_id = 208; -- 项目定价
|
||||
UPDATE sys_menu SET icon = 'report' WHERE menu_id = 262; -- 门诊收费报表
|
||||
UPDATE sys_menu SET icon = 'report' WHERE menu_id = 363; -- 费用整体查询
|
||||
|
||||
-- 医保管理子菜单
|
||||
UPDATE sys_menu SET icon = 'insurance' WHERE menu_id = 390; -- 省医保
|
||||
UPDATE sys_menu SET icon = 'insurance' WHERE menu_id = 391; -- 市医保
|
||||
UPDATE sys_menu SET icon = 'insurance' WHERE menu_id = 392; -- 医保对账
|
||||
UPDATE sys_menu SET icon = 'insurance' WHERE menu_id = 394; -- 医保结算
|
||||
|
||||
-- 检查检验子菜单
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20092; -- 检查申请
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20093; -- 检查仪器
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20094; -- LIS配置
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20095; -- 检验组套
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20096; -- 标本采集
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20097; -- 标本类型
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20098; -- 观察项目
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20099; -- 检验增强
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20100; -- 检验ICD10
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20102; -- 检验预约
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20103; -- 检验路径
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20104; -- 参考范围
|
||||
UPDATE sys_menu SET icon = 'radiology' WHERE menu_id = 20105; -- 放射报告
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 20106; -- 检验历史
|
||||
|
||||
-- 院感管理子菜单
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10002; -- 感染病例监测
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10003; -- 手卫生监测
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10004; -- 环境监测
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10005; -- 抗菌药物使用
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10006; -- 多重耐药菌
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10007; -- 职业暴露
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10008; -- 疫情预警
|
||||
UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10009; -- 目标性监测
|
||||
|
||||
-- 药品追溯管理子菜单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 10012; -- 追溯码管理
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 10013; -- 批次管理
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 10014; -- 扫码记录
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 10015; -- 追溯预警
|
||||
|
||||
-- 麻醉管理子菜单
|
||||
UPDATE sys_menu SET icon = 'anesthesia' WHERE menu_id = 20002; -- 麻醉记录
|
||||
UPDATE sys_menu SET icon = 'anesthesia' WHERE menu_id = 20003; -- 麻醉增强
|
||||
|
||||
-- 合理用药子菜单
|
||||
UPDATE sys_menu SET icon = 'medication' WHERE menu_id = 20012; -- 抗菌药物规则
|
||||
UPDATE sys_menu SET icon = 'medication' WHERE menu_id = 20013; -- 药物相互作用
|
||||
UPDATE sys_menu SET icon = 'medication' WHERE menu_id = 20014; -- 审核日志
|
||||
UPDATE sys_menu SET icon = 'medication' WHERE menu_id = 20015; -- 合理用药统计
|
||||
|
||||
-- 急诊管理子菜单
|
||||
UPDATE sys_menu SET icon = 'emergency' WHERE menu_id = 20022; -- 急诊分诊
|
||||
UPDATE sys_menu SET icon = 'emergency' WHERE menu_id = 20023; -- 急诊抢救
|
||||
UPDATE sys_menu SET icon = 'emergency' WHERE menu_id = 20024; -- 急诊观察
|
||||
UPDATE sys_menu SET icon = 'emergency' WHERE menu_id = 20025; -- 绿色通道
|
||||
|
||||
-- 护理管理子菜单
|
||||
UPDATE sys_menu SET icon = 'nursing' WHERE menu_id = 20032; -- 护理评估
|
||||
UPDATE sys_menu SET icon = 'nursing' WHERE menu_id = 20033; -- 护理增强
|
||||
UPDATE sys_menu SET icon = 'nursing' WHERE menu_id = 20034; -- 护理执行
|
||||
UPDATE sys_menu SET icon = 'nursing' WHERE menu_id = 20035; -- 护理质量
|
||||
UPDATE sys_menu SET icon = 'vital-signs' WHERE menu_id = 20036; -- 生命体征图表
|
||||
|
||||
-- 病理管理子菜单
|
||||
UPDATE sys_menu SET icon = 'pathology' WHERE menu_id = 20042; -- 病理医嘱
|
||||
UPDATE sys_menu SET icon = 'pathology' WHERE menu_id = 20043; -- 病理报告
|
||||
UPDATE sys_menu SET icon = 'pathology' WHERE menu_id = 20044; -- 病理标本
|
||||
|
||||
-- 病案管理子菜单
|
||||
UPDATE sys_menu SET icon = 'medical-record' WHERE menu_id = 20052; -- 病案管理
|
||||
UPDATE sys_menu SET icon = 'medical-record' WHERE menu_id = 20053; -- 病案首页管理
|
||||
UPDATE sys_menu SET icon = 'report' WHERE menu_id = 20054; -- DRG分析
|
||||
UPDATE sys_menu SET icon = 'report' WHERE menu_id = 20055; -- 病案统计
|
||||
|
||||
-- 影像管理子菜单
|
||||
UPDATE sys_menu SET icon = 'radiology' WHERE menu_id = 20062; -- 影像增强
|
||||
UPDATE sys_menu SET icon = 'radiology' WHERE menu_id = 20063; -- 影像对比
|
||||
UPDATE sys_menu SET icon = 'radiology' WHERE menu_id = 20064; -- 3D重建
|
||||
|
||||
-- 随访管理子菜单
|
||||
UPDATE sys_menu SET icon = 'follow-up' WHERE menu_id = 20072; -- 随访计划
|
||||
UPDATE sys_menu SET icon = 'follow-up' WHERE menu_id = 20073; -- 随访记录
|
||||
UPDATE sys_menu SET icon = 'follow-up' WHERE menu_id = 20074; -- 随访任务
|
||||
UPDATE sys_menu SET icon = 'follow-up' WHERE menu_id = 20075; -- 随访调查
|
||||
|
||||
-- 电子病历管理子菜单
|
||||
UPDATE sys_menu SET icon = 'emr' WHERE menu_id = 20202; -- 病案归档
|
||||
UPDATE sys_menu SET icon = 'emr' WHERE menu_id = 20203; -- 修订历史
|
||||
UPDATE sys_menu SET icon = 'emr' WHERE menu_id = 20204; -- 病历时效
|
||||
UPDATE sys_menu SET icon = 'emr' WHERE menu_id = 20205; -- 病历检索
|
||||
UPDATE sys_menu SET icon = 'emr' WHERE menu_id = 20206; -- 进程记录
|
||||
UPDATE sys_menu SET icon = 'emr' WHERE menu_id = 20207; -- 知识库
|
||||
|
||||
-- 审核管理子菜单
|
||||
UPDATE sys_menu SET icon = 'audit' WHERE menu_id = 20132; -- 审核统计
|
||||
UPDATE sys_menu SET icon = 'audit' WHERE menu_id = 20133; -- 点评计划
|
||||
UPDATE sys_menu SET icon = 'audit' WHERE menu_id = 20134; -- 点评工作台
|
||||
UPDATE sys_menu SET icon = 'audit' WHERE menu_id = 20135; -- 点评记录
|
||||
UPDATE sys_menu SET icon = 'audit' WHERE menu_id = 20136; -- 医生排名
|
||||
|
||||
-- 跨模块协同子菜单
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20142; -- 会诊反馈
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20143; -- 会诊超时
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20144; -- DRG绩效
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20145; -- 药品效期
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20146; -- 增强救护
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20147; -- 增强抗菌
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20148; -- 增强知情
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20149; -- DRG预警
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20150; -- 增强护理
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20152; -- 交接统计
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20153; -- 检验预警
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20154; -- 病案质量
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20155; -- 护士执行
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20156; -- 报告反馈
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20157; -- 审核统计
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20158; -- 库存拦截
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20159; -- 手术闭环
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20160; -- 手术关联
|
||||
UPDATE sys_menu SET icon = 'teamwork' WHERE menu_id = 20162; -- 患者转运
|
||||
|
||||
-- 门诊医生工作站子菜单
|
||||
UPDATE sys_menu SET icon = 'doctor' WHERE menu_id = 2114; -- 医生常用语
|
||||
UPDATE sys_menu SET icon = 'doctor' WHERE menu_id = 2143; -- 今日门诊
|
||||
|
||||
-- 预约管理子菜单
|
||||
UPDATE sys_menu SET icon = 'schedule' WHERE menu_id = 2105; -- 医生排班管理
|
||||
UPDATE sys_menu SET icon = 'appointment' WHERE menu_id = 2097; -- 门诊出诊医生诊室设置
|
||||
UPDATE sys_menu SET icon = 'appointment' WHERE menu_id = 2112; -- 科室预约工作时间维护
|
||||
UPDATE sys_menu SET icon = 'appointment' WHERE menu_id = 2113; -- 门诊预约挂号
|
||||
|
||||
-- 手术管理子菜单
|
||||
UPDATE sys_menu SET icon = 'surgery' WHERE menu_id = 2120; -- 手术管理
|
||||
UPDATE sys_menu SET icon = 'surgery' WHERE menu_id = 2144; -- 手术室管理
|
||||
|
||||
-- 住院医生增强子菜单
|
||||
UPDATE sys_menu SET icon = 'doctor' WHERE menu_id = 20172; -- 住院病历
|
||||
|
||||
-- 住院护士增强子菜单
|
||||
UPDATE sys_menu SET icon = 'nurse' WHERE menu_id = 20182; -- 护士工作站
|
||||
UPDATE sys_menu SET icon = 'nurse' WHERE menu_id = 20183; -- 退药管理
|
||||
UPDATE sys_menu SET icon = 'nurse' WHERE menu_id = 20184; -- 滚费管理
|
||||
UPDATE sys_menu SET icon = 'vital-signs' WHERE menu_id = 20185; -- TPR表
|
||||
|
||||
-- 住院辅助子菜单
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 20222; -- 住院结算
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 20223; -- 费用类型转换
|
||||
UPDATE sys_menu SET icon = 'diagnosis' WHERE menu_id = 20224; -- 住院诊断
|
||||
UPDATE sys_menu SET icon = 'emr' WHERE menu_id = 20225; -- 住院病历
|
||||
UPDATE sys_menu SET icon = 'order' WHERE menu_id = 20226; -- 医嘱管理
|
||||
UPDATE sys_menu SET icon = 'surgery' WHERE menu_id = 20228; -- 住院手术
|
||||
|
||||
-- 基础数据子菜单
|
||||
UPDATE sys_menu SET icon = 'patient' WHERE menu_id = 205; -- 患者管理
|
||||
UPDATE sys_menu SET icon = 'patient' WHERE menu_id = 206; -- 患者档案管理
|
||||
UPDATE sys_menu SET icon = 'department' WHERE menu_id = 212; -- 科室管理
|
||||
UPDATE sys_menu SET icon = 'supplier' WHERE menu_id = 214; -- 供应商管理
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 216; -- 挂号收费项目
|
||||
UPDATE sys_menu SET icon = 'pharmacy' WHERE menu_id = 238; -- 库房/药房管理
|
||||
UPDATE sys_menu SET icon = 'appointment' WHERE menu_id = 245; -- 门诊号源管理
|
||||
UPDATE sys_menu SET icon = 'user' WHERE menu_id = 246; -- 客户数据
|
||||
UPDATE sys_menu SET icon = 'bed-management' WHERE menu_id = 247; -- 病区/床位管理
|
||||
|
||||
-- 目录管理子菜单
|
||||
UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 201; -- 药品目录
|
||||
UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 202; -- 诊疗目录
|
||||
UPDATE sys_menu SET icon = 'inventory' WHERE menu_id = 203; -- 耗材目录
|
||||
UPDATE sys_menu SET icon = 'diagnosis' WHERE menu_id = 204; -- 诊断目录
|
||||
|
||||
-- 基础数据子菜单 - 新增
|
||||
UPDATE sys_menu SET icon = 'bed-management' WHERE menu_id = 20257; -- 床体管理
|
||||
UPDATE sys_menu SET icon = 'body' WHERE menu_id = 20258; -- 体表结构
|
||||
UPDATE sys_menu SET icon = 'diagnosis' WHERE menu_id = 20259; -- 常用诊断
|
||||
UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 20260; -- 费用管理
|
||||
UPDATE sys_menu SET icon = 'location' WHERE menu_id = 20261; -- 位置管理
|
||||
UPDATE sys_menu SET icon = 'order' WHERE menu_id = 20262; -- 医嘱组合
|
||||
UPDATE sys_menu SET icon = 'medication' WHERE menu_id = 20263; -- 中医处方
|
||||
|
||||
-- 为剩余没有图标的菜单设置默认图标
|
||||
UPDATE sys_menu SET icon = 'list' WHERE menu_type = 'C' AND (icon IS NULL OR icon = '');
|
||||
UPDATE sys_menu SET icon = 'list' WHERE menu_type = 'M' AND (icon IS NULL OR icon = '');
|
||||
@@ -1,22 +0,0 @@
|
||||
-- TCM diagnosis table
|
||||
CREATE TABLE IF NOT EXISTS healthlink_his.tcm_diagnosis (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
encounter_id BIGINT,
|
||||
patient_id BIGINT,
|
||||
diagnosis_type VARCHAR(50),
|
||||
diagnosis_name VARCHAR(200),
|
||||
diagnosis_code VARCHAR(50),
|
||||
syndrome_type VARCHAR(50),
|
||||
syndrome_name VARCHAR(200),
|
||||
syndrome_code VARCHAR(50),
|
||||
remark TEXT,
|
||||
enabled CHAR(1) DEFAULT '1',
|
||||
tenant_id INTEGER DEFAULT 0,
|
||||
delete_flag CHAR(1) DEFAULT '0',
|
||||
create_by VARCHAR(64),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_by VARCHAR(64),
|
||||
update_time TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_tcm_diagnosis_encounter ON healthlink_his.tcm_diagnosis(encounter_id);
|
||||
@@ -1,6 +0,0 @@
|
||||
-- Add auto-screen fields to epidemic_report
|
||||
ALTER TABLE healthlink_his.epidemic_report ADD COLUMN IF NOT EXISTS screen_result TEXT;
|
||||
ALTER TABLE healthlink_his.epidemic_report ADD COLUMN IF NOT EXISTS screen_time TIMESTAMP;
|
||||
ALTER TABLE healthlink_his.epidemic_report ADD COLUMN IF NOT EXISTS screen_level VARCHAR(20);
|
||||
ALTER TABLE healthlink_his.epidemic_report ADD COLUMN IF NOT EXISTS address VARCHAR(500);
|
||||
ALTER TABLE healthlink_his.epidemic_report ADD COLUMN IF NOT EXISTS contact_phone VARCHAR(50);
|
||||
@@ -0,0 +1,86 @@
|
||||
CREATE TABLE cdss_rule (
|
||||
id BIGINT NOT NULL,
|
||||
rule_code VARCHAR(64) NOT NULL,
|
||||
rule_name VARCHAR(128) NOT NULL,
|
||||
rule_type VARCHAR(32) NOT NULL,
|
||||
severity VARCHAR(16) NOT NULL DEFAULT 'INFO',
|
||||
trigger_type VARCHAR(32) NOT NULL,
|
||||
condition_expr TEXT NOT NULL,
|
||||
action_expr TEXT NOT NULL,
|
||||
description TEXT,
|
||||
department_id BIGINT,
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
tenant_id BIGINT,
|
||||
create_by VARCHAR(64),
|
||||
create_time TIMESTAMP,
|
||||
update_by VARCHAR(64),
|
||||
update_time TIMESTAMP,
|
||||
delete_flag SMALLINT NOT NULL DEFAULT 0,
|
||||
CONSTRAINT pk_cdss_rule PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE cdss_rule IS 'CDSS临床决策支持规则';
|
||||
COMMENT ON COLUMN cdss_rule.id IS '规则ID';
|
||||
COMMENT ON COLUMN cdss_rule.rule_code IS '规则编码';
|
||||
COMMENT ON COLUMN cdss_rule.rule_name IS '规则名称';
|
||||
COMMENT ON COLUMN cdss_rule.rule_type IS '规则类型(drug_interaction/diagnosis/reminder/alert)';
|
||||
COMMENT ON COLUMN cdss_rule.severity IS '严重程度(INFO/WARNING/CRITICAL)';
|
||||
COMMENT ON COLUMN cdss_rule.trigger_type IS '触发时机(order/admission/discharge/vital_sign)';
|
||||
COMMENT ON COLUMN cdss_rule.condition_expr IS '触发条件表达式(JSON)';
|
||||
COMMENT ON COLUMN cdss_rule.action_expr IS '执行动作表达式(JSON)';
|
||||
COMMENT ON COLUMN cdss_rule.description IS '规则描述';
|
||||
COMMENT ON COLUMN cdss_rule.department_id IS '所属科室ID';
|
||||
COMMENT ON COLUMN cdss_rule.status IS '状态(0禁用 1启用)';
|
||||
COMMENT ON COLUMN cdss_rule.sort_order IS '排序号';
|
||||
|
||||
CREATE UNIQUE INDEX idx_cdss_rule_code ON cdss_rule(rule_code) WHERE delete_flag = 0;
|
||||
CREATE INDEX idx_cdss_rule_type ON cdss_rule(rule_type);
|
||||
CREATE INDEX idx_cdss_rule_dept ON cdss_rule(department_id);
|
||||
CREATE INDEX idx_cdss_rule_status ON cdss_rule(status);
|
||||
|
||||
CREATE TABLE cdss_alert (
|
||||
id BIGINT NOT NULL,
|
||||
encounter_id BIGINT NOT NULL,
|
||||
patient_id BIGINT NOT NULL,
|
||||
rule_id BIGINT NOT NULL,
|
||||
rule_code VARCHAR(64) NOT NULL,
|
||||
rule_name VARCHAR(128) NOT NULL,
|
||||
severity VARCHAR(16) NOT NULL DEFAULT 'INFO',
|
||||
alert_title VARCHAR(256) NOT NULL,
|
||||
alert_message TEXT NOT NULL,
|
||||
suggestion TEXT,
|
||||
acknowledged SMALLINT NOT NULL DEFAULT 0,
|
||||
acknowledged_by VARCHAR(64),
|
||||
acknowledged_time TIMESTAMP,
|
||||
acknowledge_remark TEXT,
|
||||
tenant_id BIGINT,
|
||||
create_by VARCHAR(64),
|
||||
create_time TIMESTAMP,
|
||||
update_by VARCHAR(64),
|
||||
update_time TIMESTAMP,
|
||||
delete_flag SMALLINT NOT NULL DEFAULT 0,
|
||||
CONSTRAINT pk_cdss_alert PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE cdss_alert IS 'CDSS临床决策支持告警';
|
||||
COMMENT ON COLUMN cdss_alert.id IS '告警ID';
|
||||
COMMENT ON COLUMN cdss_alert.encounter_id IS '就诊ID';
|
||||
COMMENT ON COLUMN cdss_alert.patient_id IS '患者ID';
|
||||
COMMENT ON COLUMN cdss_alert.rule_id IS '规则ID';
|
||||
COMMENT ON COLUMN cdss_alert.rule_code IS '规则编码';
|
||||
COMMENT ON COLUMN cdss_alert.rule_name IS '规则名称';
|
||||
COMMENT ON COLUMN cdss_alert.severity IS '严重程度(INFO/WARNING/CRITICAL)';
|
||||
COMMENT ON COLUMN cdss_alert.alert_title IS '告警标题';
|
||||
COMMENT ON COLUMN cdss_alert.alert_message IS '告警详情';
|
||||
COMMENT ON COLUMN cdss_alert.suggestion IS '处理建议';
|
||||
COMMENT ON COLUMN cdss_alert.acknowledged IS '是否已确认(0未确认 1已确认)';
|
||||
COMMENT ON COLUMN cdss_alert.acknowledged_by IS '确认人';
|
||||
COMMENT ON COLUMN cdss_alert.acknowledged_time IS '确认时间';
|
||||
COMMENT ON COLUMN cdss_alert.acknowledge_remark IS '确认备注';
|
||||
|
||||
CREATE INDEX idx_cdss_alert_encounter ON cdss_alert(encounter_id);
|
||||
CREATE INDEX idx_cdss_alert_patient ON cdss_alert(patient_id);
|
||||
CREATE INDEX idx_cdss_alert_rule ON cdss_alert(rule_id);
|
||||
CREATE INDEX idx_cdss_alert_severity ON cdss_alert(severity);
|
||||
CREATE INDEX idx_cdss_alert_acknowledged ON cdss_alert(acknowledged);
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.healthlink.his.cdss.mapper.CdssAlertMapper">
|
||||
|
||||
<resultMap type="com.healthlink.his.cdss.domain.CdssAlert" id="CdssAlertResult">
|
||||
<id column="id" property="id"/>
|
||||
<result column="encounter_id" property="encounterId"/>
|
||||
<result column="patient_id" property="patientId"/>
|
||||
<result column="rule_id" property="ruleId"/>
|
||||
<result column="rule_code" property="ruleCode"/>
|
||||
<result column="rule_name" property="ruleName"/>
|
||||
<result column="severity" property="severity"/>
|
||||
<result column="alert_title" property="alertTitle"/>
|
||||
<result column="alert_message" property="alertMessage"/>
|
||||
<result column="suggestion" property="suggestion"/>
|
||||
<result column="acknowledged" property="acknowledged"/>
|
||||
<result column="acknowledged_by" property="acknowledgedBy"/>
|
||||
<result column="acknowledged_time" property="acknowledgedTime"/>
|
||||
<result column="acknowledge_remark" property="acknowledgeRemark"/>
|
||||
<result column="tenant_id" property="tenantId"/>
|
||||
<result column="create_by" property="createBy"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_by" property="updateBy"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="delete_flag" property="deleteFlag"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id, encounter_id, patient_id, rule_id, rule_code, rule_name,
|
||||
severity, alert_title, alert_message, suggestion,
|
||||
acknowledged, acknowledged_by, acknowledged_time, acknowledge_remark,
|
||||
tenant_id, create_by, create_time, update_by, update_time, delete_flag
|
||||
</sql>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.healthlink.his.cdss.mapper.CdssRuleMapper">
|
||||
|
||||
<resultMap type="com.healthlink.his.cdss.domain.CdssRule" id="CdssRuleResult">
|
||||
<id column="id" property="id"/>
|
||||
<result column="rule_code" property="ruleCode"/>
|
||||
<result column="rule_name" property="ruleName"/>
|
||||
<result column="rule_type" property="ruleType"/>
|
||||
<result column="severity" property="severity"/>
|
||||
<result column="trigger_type" property="triggerType"/>
|
||||
<result column="condition_expr" property="conditionExpr"/>
|
||||
<result column="action_expr" property="actionExpr"/>
|
||||
<result column="description" property="description"/>
|
||||
<result column="department_id" property="departmentId"/>
|
||||
<result column="status" property="status"/>
|
||||
<result column="sort_order" property="sortOrder"/>
|
||||
<result column="tenant_id" property="tenantId"/>
|
||||
<result column="create_by" property="createBy"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_by" property="updateBy"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="delete_flag" property="deleteFlag"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id, rule_code, rule_name, rule_type, severity, trigger_type,
|
||||
condition_expr, action_expr, description, department_id,
|
||||
status, sort_order, tenant_id, create_by, create_time,
|
||||
update_by, update_time, delete_flag
|
||||
</sql>
|
||||
|
||||
</mapper>
|
||||
@@ -601,6 +601,7 @@
|
||||
WHERE T1.delete_flag = '0'
|
||||
AND T1.refund_medicine_id IS NULL
|
||||
AND T1.status_enum != #{stopped}
|
||||
AND T1.status_enum != #{dispenseCompleted}
|
||||
AND T1.generate_source_enum = #{doctorPrescription}
|
||||
AND CASE
|
||||
WHEN T1.status_enum = #{draft}
|
||||
@@ -737,6 +738,7 @@
|
||||
AND af.delete_flag = '0'
|
||||
WHERE T1.delete_flag = '0'
|
||||
AND T1.status_enum != #{stopped}
|
||||
AND T1.status_enum != #{dispenseCompleted}
|
||||
AND T1.generate_source_enum = #{doctorPrescription}
|
||||
AND T2.category_code != #{transfer}
|
||||
AND T2.category_code != #{discharge}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.healthlink.his.cdss.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.core.common.core.domain.HisBaseEntity;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("cdss_alert")
|
||||
public class CdssAlert extends HisBaseEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long encounterId;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long patientId;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long ruleId;
|
||||
|
||||
private String ruleCode;
|
||||
|
||||
private String ruleName;
|
||||
|
||||
private String severity;
|
||||
|
||||
private String alertTitle;
|
||||
|
||||
private String alertMessage;
|
||||
|
||||
private String suggestion;
|
||||
|
||||
private Integer acknowledged;
|
||||
|
||||
private String acknowledgedBy;
|
||||
|
||||
private Date acknowledgedTime;
|
||||
|
||||
private String acknowledgeRemark;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.healthlink.his.cdss.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.core.common.core.domain.HisBaseEntity;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("cdss_rule")
|
||||
public class CdssRule extends HisBaseEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
private String ruleCode;
|
||||
|
||||
private String ruleName;
|
||||
|
||||
private String ruleType;
|
||||
|
||||
private String severity;
|
||||
|
||||
private String triggerType;
|
||||
|
||||
private String conditionExpr;
|
||||
|
||||
private String actionExpr;
|
||||
|
||||
private String description;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long departmentId;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Integer sortOrder;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.cdss.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.healthlink.his.cdss.domain.CdssAlert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CdssAlertMapper extends BaseMapper<CdssAlert> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.cdss.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.healthlink.his.cdss.domain.CdssRule;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CdssRuleMapper extends BaseMapper<CdssRule> {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.healthlink.his.cdss.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.cdss.domain.CdssAlert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ICdssAlertService extends IService<CdssAlert> {
|
||||
|
||||
List<CdssAlert> findByEncounterId(Long encounterId);
|
||||
|
||||
boolean acknowledgeAlert(Long id, String operator, String remark);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.healthlink.his.cdss.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.cdss.domain.CdssRule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ICdssRuleService extends IService<CdssRule> {
|
||||
|
||||
List<CdssRule> findActiveRules(String triggerType, Long departmentId);
|
||||
|
||||
List<CdssRule> findByCondition(String ruleType, String severity, Integer status);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.healthlink.his.cdss.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.healthlink.his.cdss.domain.CdssAlert;
|
||||
import com.healthlink.his.cdss.mapper.CdssAlertMapper;
|
||||
import com.healthlink.his.cdss.service.ICdssAlertService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class CdssAlertServiceImpl extends ServiceImpl<CdssAlertMapper, CdssAlert> implements ICdssAlertService {
|
||||
|
||||
@Override
|
||||
public List<CdssAlert> findByEncounterId(Long encounterId) {
|
||||
LambdaQueryWrapper<CdssAlert> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CdssAlert::getEncounterId, encounterId)
|
||||
.orderByDesc(CdssAlert::getCreateTime);
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acknowledgeAlert(Long id, String operator, String remark) {
|
||||
CdssAlert alert = baseMapper.selectById(id);
|
||||
if (alert == null || alert.getAcknowledged() == 1) {
|
||||
return false;
|
||||
}
|
||||
alert.setAcknowledged(1);
|
||||
alert.setAcknowledgedBy(operator);
|
||||
alert.setAcknowledgedTime(new Date());
|
||||
alert.setAcknowledgeRemark(remark);
|
||||
return baseMapper.updateById(alert) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.healthlink.his.cdss.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.healthlink.his.cdss.domain.CdssRule;
|
||||
import com.healthlink.his.cdss.mapper.CdssRuleMapper;
|
||||
import com.healthlink.his.cdss.service.ICdssRuleService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class CdssRuleServiceImpl extends ServiceImpl<CdssRuleMapper, CdssRule> implements ICdssRuleService {
|
||||
|
||||
@Override
|
||||
public List<CdssRule> findActiveRules(String triggerType, Long departmentId) {
|
||||
LambdaQueryWrapper<CdssRule> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CdssRule::getStatus, 1);
|
||||
if (triggerType != null && !triggerType.isEmpty()) {
|
||||
wrapper.eq(CdssRule::getTriggerType, triggerType);
|
||||
}
|
||||
if (departmentId != null) {
|
||||
wrapper.and(w -> w.isNull(CdssRule::getDepartmentId).or().eq(CdssRule::getDepartmentId, departmentId));
|
||||
}
|
||||
wrapper.orderByAsc(CdssRule::getSortOrder);
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CdssRule> findByCondition(String ruleType, String severity, Integer status) {
|
||||
LambdaQueryWrapper<CdssRule> wrapper = new LambdaQueryWrapper<>();
|
||||
if (ruleType != null && !ruleType.isEmpty()) {
|
||||
wrapper.eq(CdssRule::getRuleType, ruleType);
|
||||
}
|
||||
if (severity != null && !severity.isEmpty()) {
|
||||
wrapper.eq(CdssRule::getSeverity, severity);
|
||||
}
|
||||
if (status != null) {
|
||||
wrapper.eq(CdssRule::getStatus, status);
|
||||
}
|
||||
wrapper.orderByAsc(CdssRule::getSortOrder);
|
||||
return baseMapper.selectList(wrapper);
|
||||
}
|
||||
}
|
||||
25
healthlink-his-ui/src/api/cdss/cdssAlert.js
Normal file
25
healthlink-his-ui/src/api/cdss/cdssAlert.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function evaluateRules(params) {
|
||||
return request({
|
||||
url: '/cdss/evaluate',
|
||||
method: 'post',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function getAlerts(encounterId, query) {
|
||||
return request({
|
||||
url: '/cdss/alerts/' + encounterId,
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function acknowledgeAlert(id, data) {
|
||||
return request({
|
||||
url: '/cdss/alerts/' + id + '/acknowledge',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
32
healthlink-his-ui/src/api/cdss/cdssRule.js
Normal file
32
healthlink-his-ui/src/api/cdss/cdssRule.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getCdssRuleList(query) {
|
||||
return request({
|
||||
url: '/cdss/rules',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addCdssRule(data) {
|
||||
return request({
|
||||
url: '/cdss/rules',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateCdssRule(data) {
|
||||
return request({
|
||||
url: '/cdss/rules',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteCdssRule(id) {
|
||||
return request({
|
||||
url: '/cdss/rules/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -19,3 +19,8 @@ export function getCompletenessResults(emrId) { return request({ url: "/emr/comp
|
||||
|
||||
export function checkTimeliness(encounterId) { return request({ url: "/emr/timeliness/check", method: "post", params: { encounterId } }) }
|
||||
export function getTimelinessAlerts(params) { return request({ url: "/emr/timeliness/alerts", method: "get", params }) }
|
||||
|
||||
export function extractStructuredData(emrId) { return request({ url: "/emr/warehouse/extract", method: "post", params: { emrId } }) }
|
||||
export function getStructuredData(encounterId) { return request({ url: "/emr/warehouse/data/" + encounterId, method: "get" }) }
|
||||
export function calculateQualityScore(encounterId) { return request({ url: "/emr/warehouse/quality-score", method: "post", params: { encounterId } }) }
|
||||
export function getQualityScores(encounterId) { return request({ url: "/emr/warehouse/quality-scores", method: "get", params: { encounterId } }) }
|
||||
|
||||
5
healthlink-his-ui/src/api/reportmanage/dimension.js
Normal file
5
healthlink-his-ui/src/api/reportmanage/dimension.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getReportByDimension(params) {
|
||||
return request({ url: '/report-manage/report-dimension/query', method: 'get', params })
|
||||
}
|
||||
224
healthlink-his-ui/src/views/cdss/cdssAlerts/index.vue
Normal file
224
healthlink-his-ui/src/views/cdss/cdssAlerts/index.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" v-show="showSearch" label-width="100px">
|
||||
<el-form-item label="就诊ID" prop="encounterId">
|
||||
<el-input v-model="queryParams.encounterId" placeholder="请输入就诊ID" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="严重程度" prop="severity">
|
||||
<el-select v-model="queryParams.severity" placeholder="请选择" clearable style="width: 140px">
|
||||
<el-option label="INFO" value="INFO" />
|
||||
<el-option label="WARNING" value="WARNING" />
|
||||
<el-option label="CRITICAL" value="CRITICAL" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认状态" prop="acknowledged">
|
||||
<el-select v-model="queryParams.acknowledged" placeholder="请选择" clearable style="width: 140px">
|
||||
<el-option label="未确认" :value="0" />
|
||||
<el-option label="已确认" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
<el-button type="warning" icon="Monitor" @click="handleEvaluate">评估规则</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<vxe-table :data="alertList" :loading="loading" border stripe height="auto">
|
||||
<vxe-column type="seq" title="序号" width="70" />
|
||||
<vxe-column field="alertTitle" title="告警标题" min-width="200" show-overflow />
|
||||
<vxe-column field="severity" title="严重程度" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="severityTagType(row.severity)">{{ row.severity }}</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="ruleName" title="规则名称" width="160" show-overflow />
|
||||
<vxe-column field="alertMessage" title="告警详情" min-width="240" show-overflow />
|
||||
<vxe-column field="suggestion" title="处理建议" min-width="200" show-overflow />
|
||||
<vxe-column field="acknowledged" title="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.acknowledged === 1 ? 'success' : 'danger'">
|
||||
{{ row.acknowledged === 1 ? '已确认' : '未确认' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="acknowledgedBy" title="确认人" width="120" />
|
||||
<vxe-column field="createTime" title="触发时间" width="180" />
|
||||
<vxe-column title="操作" width="120" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.acknowledged === 0" link type="primary" icon="Check" v-hasPermi="['cdss:alert:acknowledge']" @click="handleAcknowledge(row)">确认</el-button>
|
||||
<span v-else class="text-gray">-</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
|
||||
<el-dialog title="评估CDSS规则" v-model="evaluateDialogVisible" width="500px" append-to-body>
|
||||
<el-form :model="evaluateForm" label-width="100px">
|
||||
<el-form-item label="就诊ID" required>
|
||||
<el-input v-model="evaluateForm.encounterId" placeholder="请输入就诊ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="患者ID" required>
|
||||
<el-input v-model="evaluateForm.patientId" placeholder="请输入患者ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="触发类型">
|
||||
<el-select v-model="evaluateForm.triggerType" placeholder="请选择" clearable>
|
||||
<el-option label="医嘱" value="order" />
|
||||
<el-option label="入院" value="admission" />
|
||||
<el-option label="出院" value="discharge" />
|
||||
<el-option label="生命体征" value="vital_sign" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="科室ID">
|
||||
<el-input v-model="evaluateForm.departmentId" placeholder="请输入科室ID" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="evaluateDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitEvaluate">确认评估</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="确认告警" v-model="acknowledgeDialogVisible" width="450px" append-to-body>
|
||||
<el-form :model="acknowledgeForm" label-width="80px">
|
||||
<el-form-item label="告警标题">
|
||||
<span>{{ acknowledgeForm.alertTitle }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认备注">
|
||||
<el-input v-model="acknowledgeForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="acknowledgeDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitAcknowledge">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="CdssAlerts" ref="queryFormRef">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { evaluateRules, getAlerts, acknowledgeAlert } from '@/api/cdss/cdssAlert'
|
||||
|
||||
const alertList = ref([])
|
||||
const loading = ref(false)
|
||||
const showSearch = ref(true)
|
||||
|
||||
const queryParams = reactive({
|
||||
encounterId: '',
|
||||
severity: '',
|
||||
acknowledged: undefined
|
||||
})
|
||||
|
||||
const evaluateDialogVisible = ref(false)
|
||||
const evaluateForm = reactive({
|
||||
encounterId: '',
|
||||
patientId: '',
|
||||
triggerType: '',
|
||||
departmentId: ''
|
||||
})
|
||||
|
||||
const acknowledgeDialogVisible = ref(false)
|
||||
const acknowledgeForm = reactive({
|
||||
id: null,
|
||||
alertTitle: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const severityTagType = (severity) => {
|
||||
const map = { INFO: 'info', WARNING: 'warning', CRITICAL: 'danger' }
|
||||
return map[severity] || 'info'
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
if (!queryParams.encounterId) {
|
||||
alertList.value = []
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getAlerts(queryParams.encounterId, {
|
||||
acknowledged: queryParams.acknowledged
|
||||
})
|
||||
if (res.code === 200) {
|
||||
let list = res.data || []
|
||||
if (queryParams.severity) {
|
||||
list = list.filter(item => item.severity === queryParams.severity)
|
||||
}
|
||||
alertList.value = list
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleQuery = () => {
|
||||
getList()
|
||||
}
|
||||
|
||||
const resetQuery = () => {
|
||||
queryParams.severity = ''
|
||||
queryParams.acknowledged = undefined
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
const handleEvaluate = () => {
|
||||
evaluateForm.encounterId = ''
|
||||
evaluateForm.patientId = ''
|
||||
evaluateForm.triggerType = ''
|
||||
evaluateForm.departmentId = ''
|
||||
evaluateDialogVisible.value = true
|
||||
}
|
||||
|
||||
const submitEvaluate = async () => {
|
||||
if (!evaluateForm.encounterId || !evaluateForm.patientId) {
|
||||
ElMessage.error('就诊ID和患者ID不能为空')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const params = {
|
||||
encounterId: evaluateForm.encounterId,
|
||||
patientId: evaluateForm.patientId
|
||||
}
|
||||
if (evaluateForm.triggerType) params.triggerType = evaluateForm.triggerType
|
||||
if (evaluateForm.departmentId) params.departmentId = evaluateForm.departmentId
|
||||
const res = await evaluateRules(params)
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('评估完成,触发 ' + res.data.triggeredAlerts + ' 条告警')
|
||||
evaluateDialogVisible.value = false
|
||||
queryParams.encounterId = evaluateForm.encounterId
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '评估失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('评估失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleAcknowledge = (row) => {
|
||||
acknowledgeForm.id = row.id
|
||||
acknowledgeForm.alertTitle = row.alertTitle
|
||||
acknowledgeForm.remark = ''
|
||||
acknowledgeDialogVisible.value = true
|
||||
}
|
||||
|
||||
const submitAcknowledge = async () => {
|
||||
try {
|
||||
const res = await acknowledgeAlert(acknowledgeForm.id, { remark: acknowledgeForm.remark })
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('确认成功')
|
||||
acknowledgeDialogVisible.value = false
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '确认失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('确认失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
@@ -81,7 +81,6 @@
|
||||
class="inspection-table"
|
||||
:row-config="{ keyField: 'applicationId', keyField: 'itemId' }"
|
||||
@checkbox-change="handleSelectionChange"
|
||||
@current-change="handleRowClick"
|
||||
@cell-click="handleCellClick"
|
||||
>
|
||||
<vxe-column
|
||||
@@ -2142,15 +2141,32 @@ const handleSave = () => {
|
||||
let hasErrors = false
|
||||
|
||||
// 修复【#406】:保存前尝试从 props 同步患者信息,避免因加载时序导致信息缺失
|
||||
if ((!formData.patientName?.trim() || !formData.medicalrecordNumber?.trim()) && props.patientInfo && props.patientInfo.encounterId) {
|
||||
formData.patientName = props.patientInfo.patientName || ''
|
||||
formData.medicalrecordNumber = props.patientInfo.identifierNo || ''
|
||||
formData.encounterId = props.patientInfo.encounterId || ''
|
||||
formData.visitNo = props.patientInfo.busNo || ''
|
||||
formData.patientId = props.patientInfo.patientId || ''
|
||||
formData.applyDepartment = props.patientInfo.organizationName || ''
|
||||
formData.applyDeptCode = props.patientInfo.organizationName || ''
|
||||
formData.applyOrganizationId = props.patientInfo.orgId || ''
|
||||
if (props.patientInfo && props.patientInfo.encounterId) {
|
||||
// encounterId 来自 adm_encounter 表,lab_apply 表无此字段,需始终从 props 同步
|
||||
if (!formData.encounterId) {
|
||||
formData.encounterId = props.patientInfo.encounterId || ''
|
||||
}
|
||||
if (!formData.patientName?.trim()) {
|
||||
formData.patientName = props.patientInfo.patientName || ''
|
||||
}
|
||||
if (!formData.medicalrecordNumber?.trim()) {
|
||||
formData.medicalrecordNumber = props.patientInfo.identifierNo || ''
|
||||
}
|
||||
if (!formData.visitNo) {
|
||||
formData.visitNo = props.patientInfo.busNo || ''
|
||||
}
|
||||
if (!formData.patientId) {
|
||||
formData.patientId = props.patientInfo.patientId || ''
|
||||
}
|
||||
if (!formData.applyDepartment) {
|
||||
formData.applyDepartment = props.patientInfo.organizationName || ''
|
||||
}
|
||||
if (!formData.applyDeptCode) {
|
||||
formData.applyDeptCode = props.patientInfo.organizationName || ''
|
||||
}
|
||||
if (!formData.applyOrganizationId) {
|
||||
formData.applyOrganizationId = props.patientInfo.orgId || ''
|
||||
}
|
||||
}
|
||||
|
||||
// P0:检查患者信息是否已加载
|
||||
@@ -2457,10 +2473,13 @@ const handleDelete = (row) => {
|
||||
}
|
||||
|
||||
// 单元格点击 - 点击表格行时加载申请单详情
|
||||
const handleCellClick = (row, column) => {
|
||||
const handleCellClick = (params) => {
|
||||
// vxe-table cell-click 事件参数是 { row, column, $event, ... } 对象,需安全提取行数据
|
||||
const row = params.row || params;
|
||||
const column = params.column || params;
|
||||
// 如果点击的是操作列或展开列,不触发数据填充
|
||||
if (column.property === '操作' || column.label === '操作' ||
|
||||
column.type === 'expand' || column.type === 'selection') {
|
||||
if (column.type === 'expand' || column.type === 'selection' ||
|
||||
column.title === '操作' || column.property === '操作') {
|
||||
return;
|
||||
}
|
||||
// 点击表格行时,将该申请单的数据加载到表单中
|
||||
@@ -2470,15 +2489,6 @@ const handleCellClick = (row, column) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 行点击事件处理
|
||||
const handleRowClick = (currentRow, oldRow) => {
|
||||
// 点击表格行时,将该申请单的数据加载到表单中
|
||||
// 使用 applyNo 判断是否有效,同时检查是否处于删除状态
|
||||
if (currentRow && currentRow.applyNo && !isDeleting.value) {
|
||||
loadApplicationToForm(currentRow);
|
||||
}
|
||||
}
|
||||
|
||||
// 提取公共方法加载申请单到表单
|
||||
const loadApplicationToForm = async (row) => {
|
||||
// 停止申请日期实时更新(加载已保存的申请单)
|
||||
|
||||
@@ -332,7 +332,9 @@ function resetQuery() {
|
||||
getSummaryList();
|
||||
}
|
||||
|
||||
function getDetails(row) {
|
||||
function getDetails(params) {
|
||||
// cell-click 事件参数是 { row, column, $event, ... } 对象,需安全提取行数据
|
||||
const row = params.row || params;
|
||||
loading.value = true;
|
||||
getFromSummaryDetails({ summaryNo: row.busNo }).then((res) => {
|
||||
summaryDetailsData.value = res.data;
|
||||
|
||||
125
healthlink-his-ui/src/views/reportmanage/ReportDimension.vue
Normal file
125
healthlink-his-ui/src/views/reportmanage/ReportDimension.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div class="report-dimension-container">
|
||||
<div class="page-header">
|
||||
<span class="tab-title">多维度报表</span>
|
||||
</div>
|
||||
|
||||
<el-card shadow="never" style="margin-bottom: 16px">
|
||||
<template #header>
|
||||
<span>查询条件</span>
|
||||
</template>
|
||||
<el-form :model="queryParams" inline>
|
||||
<el-form-item label="统计维度">
|
||||
<el-select v-model="queryParams.dimension" style="width: 140px">
|
||||
<el-option label="按质控状态" value="status" />
|
||||
<el-option label="按DRG分组" value="drg" />
|
||||
<el-option label="按主要诊断" value="diagnosis" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始日期">
|
||||
<el-date-picker v-model="queryParams.startDate" type="date" value-format="YYYY-MM-DD" placeholder="开始日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结束日期">
|
||||
<el-date-picker v-model="queryParams.endDate" type="date" value-format="YYYY-MM-DD" placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadData" :loading="loading">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-row :gutter="16" style="margin-bottom: 16px">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" style="color: #409eff">{{ reportData.totalCount || 0 }}</div>
|
||||
<div class="stat-label">总病案数</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" style="color: #e6a23c">{{ formatCost(reportData.totalCost) }}</div>
|
||||
<div class="stat-label">总费用</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" style="color: #67c23a">{{ formatCost(reportData.avgCost) }}</div>
|
||||
<div class="stat-label">平均费用</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<span>{{ dimensionLabel }}明细</span>
|
||||
</template>
|
||||
<el-table :data="reportData.data || []" v-loading="loading" border stripe style="width: 100%">
|
||||
<el-table-column prop="dimension" :label="dimensionLabel" min-width="160" />
|
||||
<el-table-column prop="count" label="病案数" width="100" />
|
||||
<el-table-column prop="totalCost" label="总费用" width="140">
|
||||
<template #default="{ row }">{{ formatCost(row.totalCost) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="avgCost" label="平均费用" width="140">
|
||||
<template #default="{ row }">{{ formatCost(row.avgCost) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="avgLosDays" label="平均住院日" width="120">
|
||||
<template #default="{ row }">{{ row.avgLosDays }}天</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getReportByDimension } from '@/api/reportmanage/dimension'
|
||||
|
||||
const loading = ref(false)
|
||||
const queryParams = reactive({
|
||||
dimension: 'status',
|
||||
startDate: '',
|
||||
endDate: ''
|
||||
})
|
||||
const reportData = ref({})
|
||||
|
||||
const DIMENSION_LABEL = { status: '质控状态', drg: 'DRG分组', diagnosis: '主要诊断' }
|
||||
const dimensionLabel = computed(() => DIMENSION_LABEL[queryParams.dimension] || '维度')
|
||||
|
||||
const formatCost = (val) => {
|
||||
if (!val || val === '0') return '¥0'
|
||||
return '¥' + Number(val).toLocaleString('zh-CN', { minimumFractionDigits: 2 })
|
||||
}
|
||||
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = { dimension: queryParams.dimension }
|
||||
if (queryParams.startDate) params.startDate = queryParams.startDate
|
||||
if (queryParams.endDate) params.endDate = queryParams.endDate
|
||||
const res = await getReportByDimension(params)
|
||||
reportData.value = res.data || {}
|
||||
} catch (e) {
|
||||
ElMessage.error('加载失败: ' + (e.message || '未知错误'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => loadData())
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.report-dimension-container { padding: 16px; }
|
||||
.page-header { margin-bottom: 16px; }
|
||||
.tab-title { font-size: 18px; font-weight: bold; }
|
||||
.stat-card { text-align: center; padding: 12px 0; }
|
||||
.stat-value { font-size: 28px; font-weight: bold; }
|
||||
.stat-label { font-size: 13px; color: #909399; margin-top: 4px; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user