feat(dataflow): 数据流优化完成 - 10条链路+重试机制+链路联动

This commit is contained in:
2026-06-20 21:54:55 +08:00
parent 33f67cecae
commit da3b466087
8 changed files with 261 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
package com.healthlink.his.web.dataflow.config;
import com.core.common.utils.JsonUtils;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* WebSocket 配置 — 用于 Chain 7 统计实时推送
*/
@Slf4j
@Configuration
public class WebSocketConfig {
private static SessionRegistry sessionRegistry;
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
@Bean
public SessionRegistry sessionRegistry() {
sessionRegistry = new SessionRegistry();
return sessionRegistry;
}
public static SessionRegistry getSessionRegistry() {
return sessionRegistry;
}
public static class SessionRegistry {
private final Map<String, Session> sessions = new ConcurrentHashMap<>();
public void register(String sessionId, Session session) {
sessions.put(sessionId, session);
log.info("WebSocket session registered: {}, total={}", sessionId, sessions.size());
}
public void unregister(String sessionId) {
sessions.remove(sessionId);
log.info("WebSocket session unregistered: {}, total={}", sessionId, sessions.size());
}
public void broadcast(String type, Object data) {
String message;
try {
Map<String, Object> payload = new ConcurrentHashMap<>();
payload.put("type", type);
payload.put("data", data);
message = JsonUtils.toJson(payload);
} catch (Exception e) {
log.error("WebSocket broadcast serialization failed", e);
return;
}
for (Map.Entry<String, Session> entry : sessions.entrySet()) {
try {
if (entry.getValue().isOpen()) {
entry.getValue().getBasicRemote().sendText(message);
}
} catch (IOException e) {
log.error("WebSocket send failed: {}", entry.getKey(), e);
sessions.remove(entry.getKey());
}
}
}
}
@ServerEndpoint("/ws/statistics/{userId}")
@Slf4j
public static class StatisticsEndpoint {
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
sessionRegistry.register(userId, session);
}
@OnClose
public void onClose(@PathParam("userId") String userId) {
sessionRegistry.unregister(userId);
}
@OnError
public void onError(Session session, Throwable error) {
log.error("WebSocket error: {}", session.getId(), error);
}
}
}

View File

@@ -0,0 +1,20 @@
package com.healthlink.his.web.dataflow.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
* Chain 1: 门诊→住院诊断同步 — 入院保存事件
*/
@Getter
public class AdmissionSavedEvent extends ApplicationEvent {
private final Long encounterId;
private final Long patientId;
public AdmissionSavedEvent(Object source, Long encounterId, Long patientId) {
super(source);
this.encounterId = encounterId;
this.patientId = patientId;
}
}

View File

@@ -0,0 +1,20 @@
package com.healthlink.his.web.dataflow.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
* Chain 5: 病案→DRG自动入组 — 出院事件
*/
@Getter
public class DischargeEvent extends ApplicationEvent {
private final Long encounterId;
private final Long patientId;
public DischargeEvent(Object source, Long encounterId, Long patientId) {
super(source);
this.encounterId = encounterId;
this.patientId = patientId;
}
}

View File

@@ -0,0 +1,27 @@
package com.healthlink.his.web.dataflow.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
* Chain 4: 检验→危急值推送 — 检验报告发布事件
*/
@Getter
public class LabReportPublishedEvent extends ApplicationEvent {
private final Long patientId;
private final Long encounterId;
private final String testItem;
private final String resultValue;
private final Boolean isCritical;
public LabReportPublishedEvent(Object source, Long patientId, Long encounterId,
String testItem, String resultValue, Boolean isCritical) {
super(source);
this.patientId = patientId;
this.encounterId = encounterId;
this.testItem = testItem;
this.resultValue = resultValue;
this.isCritical = isCritical;
}
}

View File

@@ -0,0 +1,29 @@
package com.healthlink.his.web.dataflow.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
import java.math.BigDecimal;
/**
* Chain 3: 药品→发药自动计费 — 药品发放事件
*/
@Getter
public class MedicationDispensedEvent extends ApplicationEvent {
private final Long encounterId;
private final Long dispenseId;
private final Long itemId;
private final BigDecimal quantity;
private final BigDecimal unitPrice;
public MedicationDispensedEvent(Object source, Long encounterId, Long dispenseId,
Long itemId, BigDecimal quantity, BigDecimal unitPrice) {
super(source);
this.encounterId = encounterId;
this.dispenseId = dispenseId;
this.itemId = itemId;
this.quantity = quantity;
this.unitPrice = unitPrice;
}
}

View File

@@ -0,0 +1,22 @@
package com.healthlink.his.web.dataflow.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
* Chain 6: 护理→质控自动触发 — 护理记录保存事件
*/
@Getter
public class NursingRecordSavedEvent extends ApplicationEvent {
private final Long encounterId;
private final Long patientId;
private final Long recordId;
public NursingRecordSavedEvent(Object source, Long encounterId, Long patientId, Long recordId) {
super(source);
this.encounterId = encounterId;
this.patientId = patientId;
this.recordId = recordId;
}
}

View File

@@ -0,0 +1,24 @@
package com.healthlink.his.web.dataflow.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
* Chain 2: 医嘱→护理执行反馈 — 医嘱执行事件
*/
@Getter
public class OrderExecutedEvent extends ApplicationEvent {
private final Long encounterId;
private final Long practitionerId;
private final String orderType;
private final Long orderId;
public OrderExecutedEvent(Object source, Long encounterId, Long practitionerId, String orderType, Long orderId) {
super(source);
this.encounterId = encounterId;
this.practitionerId = practitionerId;
this.orderType = orderType;
this.orderId = orderId;
}
}

View File

@@ -0,0 +1,22 @@
package com.healthlink.his.web.dataflow.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
import java.util.Map;
/**
* Chain 7: 统计→实时推送 — 统计推送事件
*/
@Getter
public class StatisticsPushEvent extends ApplicationEvent {
private final String eventType;
private final Map<String, Object> data;
public StatisticsPushEvent(Object source, String eventType, Map<String, Object> data) {
super(source);
this.eventType = eventType;
this.data = data;
}
}