diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/IEsbMonitorAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/IEsbMonitorAppService.java new file mode 100644 index 000000000..fa716bdde --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/IEsbMonitorAppService.java @@ -0,0 +1,15 @@ +package com.healthlink.his.web.esbmanage.appservice; + +import com.healthlink.his.esb.domain.CodeMapping; +import com.healthlink.his.esb.domain.EsbDeadLetter; +import com.healthlink.his.esb.domain.EsbMonitorStats; + +import java.util.List; +import java.util.Map; + +public interface IEsbMonitorAppService { + Map getMonitorStats(); + List getDeadLetters(String status, String sourceSystem); + List getCodeMappings(String mappingType, String sourceSystem); + Map getCodeMappingStats(); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/impl/EsbMonitorAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/impl/EsbMonitorAppServiceImpl.java new file mode 100644 index 000000000..cd572b624 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/impl/EsbMonitorAppServiceImpl.java @@ -0,0 +1,114 @@ +package com.healthlink.his.web.esbmanage.appservice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.healthlink.his.esb.domain.*; +import com.healthlink.his.esb.service.*; +import com.healthlink.his.web.esbmanage.appservice.IEsbMonitorAppService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +@RequiredArgsConstructor +public class EsbMonitorAppServiceImpl implements IEsbMonitorAppService { + + private final IEsbMessageService messageService; + private final IEsbDeadLetterService deadLetterService; + private final IEsbMonitorStatsService monitorStatsService; + private final ICodeMappingService codeMappingService; + private final IEsbServiceRegistryService registryService; + + @Override + public Map getMonitorStats() { + Map stats = new LinkedHashMap<>(); + + long totalMessages = messageService.count(); + stats.put("totalMessages", totalMessages); + + String[] statuses = {"待发送", "已发送", "发送失败", "重试中", "死信"}; + Map statusCounts = new LinkedHashMap<>(); + for (String s : statuses) { + long count = messageService.count(new LambdaQueryWrapper().eq(EsbMessage::getStatus, s)); + statusCounts.put(s, count); + } + stats.put("statusCounts", statusCounts); + + long successCount = statusCounts.getOrDefault("已发送", 0L); + stats.put("successRate", totalMessages > 0 ? Math.round(successCount * 100.0 / totalMessages) : 100); + + long pendingDeadLetters = deadLetterService.count( + new LambdaQueryWrapper().eq(EsbDeadLetter::getStatus, "PENDING")); + stats.put("pendingDeadLetters", pendingDeadLetters); + + long totalDeadLetters = deadLetterService.count(); + stats.put("totalDeadLetters", totalDeadLetters); + + long totalMappings = codeMappingService.count(); + stats.put("totalCodeMappings", totalMappings); + + long enabledServices = registryService.count( + new LambdaQueryWrapper().eq(EsbServiceRegistry::getServiceStatus, "启用")); + long totalServices = registryService.count(); + stats.put("enabledServices", enabledServices); + stats.put("totalServices", totalServices); + + LambdaQueryWrapper statsWrapper = new LambdaQueryWrapper<>(); + statsWrapper.orderByDesc(EsbMonitorStats::getStatHour).last("LIMIT 24"); + List recentStats = monitorStatsService.list(statsWrapper); + int totalRetry = recentStats.stream().mapToInt(s -> s.getRetryCount() != null ? s.getRetryCount() : 0).sum(); + int totalFail = recentStats.stream().mapToInt(s -> s.getFailCount() != null ? s.getFailCount() : 0).sum(); + int totalSuccess = recentStats.stream().mapToInt(s -> s.getSuccessCount() != null ? s.getSuccessCount() : 0).sum(); + double avgDuration = recentStats.stream() + .filter(s -> s.getAvgDurationMs() != null) + .mapToInt(EsbMonitorStats::getAvgDurationMs) + .average().orElse(0.0); + stats.put("recentTotal", totalRetry + totalFail + totalSuccess); + stats.put("recentRetry", totalRetry); + stats.put("recentFail", totalFail); + stats.put("recentSuccess", totalSuccess); + stats.put("avgDurationMs", Math.round(avgDuration)); + + return stats; + } + + @Override + public List getDeadLetters(String status, String sourceSystem) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(StringUtils.hasText(status), EsbDeadLetter::getStatus, status) + .like(StringUtils.hasText(sourceSystem), EsbDeadLetter::getSourceSystem, sourceSystem) + .orderByDesc(EsbDeadLetter::getCreateTime); + return deadLetterService.list(wrapper); + } + + @Override + public List getCodeMappings(String mappingType, String sourceSystem) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(StringUtils.hasText(mappingType), CodeMapping::getMappingType, mappingType) + .eq(StringUtils.hasText(sourceSystem), CodeMapping::getSourceSystem, sourceSystem) + .orderByDesc(CodeMapping::getCreateTime); + return codeMappingService.list(wrapper); + } + + @Override + public Map getCodeMappingStats() { + Map stats = new LinkedHashMap<>(); + long total = codeMappingService.count(); + stats.put("total", total); + + List allMappings = codeMappingService.list(); + Map byType = allMappings.stream() + .collect(Collectors.groupingBy(CodeMapping::getMappingType, Collectors.counting())); + stats.put("byType", byType); + + Map bySource = allMappings.stream() + .collect(Collectors.groupingBy(CodeMapping::getSourceSystem, Collectors.counting())); + stats.put("bySource", bySource); + + return stats; + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbMonitorController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbMonitorController.java new file mode 100644 index 000000000..8a78115f0 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/EsbMonitorController.java @@ -0,0 +1,55 @@ +package com.healthlink.his.web.esbmanage.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.esb.domain.CodeMapping; +import com.healthlink.his.esb.domain.EsbDeadLetter; +import com.healthlink.his.web.esbmanage.appservice.IEsbMonitorAppService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * ESB监控+编码映射 Controller — 统计/死信/编码映射查询 + */ +@RestController +@RequestMapping("/esb/monitor") +@Slf4j +@RequiredArgsConstructor +public class EsbMonitorController { + + private final IEsbMonitorAppService esbMonitorAppService; + + @GetMapping("/stats") + @PreAuthorize("hasAuthority('infection:esb:list')") + public R getMonitorStats() { + return R.ok(esbMonitorAppService.getMonitorStats()); + } + + @GetMapping("/dead-letters") + @PreAuthorize("hasAuthority('infection:esb:list')") + public R getDeadLetters( + @RequestParam(value = "status", required = false) String status, + @RequestParam(value = "sourceSystem", required = false) String sourceSystem) { + List list = esbMonitorAppService.getDeadLetters(status, sourceSystem); + return R.ok(list); + } + + @GetMapping("/mapping/list") + @PreAuthorize("hasAuthority('infection:esb:list')") + public R getCodeMappings( + @RequestParam(value = "mappingType", required = false) String mappingType, + @RequestParam(value = "sourceSystem", required = false) String sourceSystem) { + List list = esbMonitorAppService.getCodeMappings(mappingType, sourceSystem); + return R.ok(list); + } + + @GetMapping("/mapping/stats") + @PreAuthorize("hasAuthority('infection:esb:list')") + public R getCodeMappingStats() { + return R.ok(esbMonitorAppService.getCodeMappingStats()); + } +} diff --git a/healthlink-his-ui/src/views/esbmanage/esbmonitor/api.js b/healthlink-his-ui/src/views/esbmanage/esbmonitor/api.js new file mode 100644 index 000000000..157022703 --- /dev/null +++ b/healthlink-his-ui/src/views/esbmanage/esbmonitor/api.js @@ -0,0 +1,5 @@ +import request from '@/utils/request' +export function getMonitorStats() { return request({ url: '/esb/monitor/stats', method: 'get' }) } +export function getDeadLetters(params) { return request({ url: '/esb/monitor/dead-letters', method: 'get', params }) } +export function getCodeMappings(params) { return request({ url: '/esb/monitor/mapping/list', method: 'get', params }) } +export function getCodeMappingStats() { return request({ url: '/esb/monitor/mapping/stats', method: 'get' }) } diff --git a/healthlink-his-ui/src/views/esbmanage/esbmonitor/index.vue b/healthlink-his-ui/src/views/esbmanage/esbmonitor/index.vue new file mode 100644 index 000000000..13a911809 --- /dev/null +++ b/healthlink-his-ui/src/views/esbmanage/esbmonitor/index.vue @@ -0,0 +1,154 @@ + +