package com.vincent.rsf.server.ai.service.provider; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.vincent.rsf.server.ai.model.AiDiagnosticToolResult; import com.vincent.rsf.server.ai.model.AiPromptContext; import com.vincent.rsf.server.manager.entity.DeviceSite; import com.vincent.rsf.server.manager.mapper.DeviceSiteMapper; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Service public class AiDeviceSiteSummaryService implements AiDiagnosticDataProvider { private static final String TOOL_CODE = "device_site_summary"; private static final String TOOL_NAME = "设备站点摘要"; @Resource private DeviceSiteMapper deviceSiteMapper; /** * 返回设备站点工具默认顺序。 */ @Override public int getOrder() { return 30; } /** * 返回设备站点工具编码。 */ @Override public String getToolCode() { return TOOL_CODE; } /** * 返回设备站点工具展示名。 */ @Override public String getToolName() { return TOOL_NAME; } /** * 返回设备站点工具默认说明。 */ @Override public String getDefaultToolPrompt() { return "结合设备站点摘要判断设备状态、巷道分布和最近更新站点。"; } /** * 汇总站点状态、设备分布和最近更新站点,生成设备站点摘要。 */ @Override public AiDiagnosticToolResult buildDiagnosticData(AiPromptContext context) { String summary = buildDeviceSiteSummary(context); String severity = summary.contains("未查询到") ? "WARN" : "INFO"; return new AiDiagnosticToolResult() .setToolCode(getToolCode()) .setToolName(getToolName()) .setSeverity(severity) .setSummaryText(summary); } /** * 基于 man_device_site 生成设备站点总览。 */ private String buildDeviceSiteSummary(AiPromptContext context) { List deviceSites = deviceSiteMapper.selectList(new LambdaQueryWrapper() .select(DeviceSite::getSite, DeviceSite::getName, DeviceSite::getType, DeviceSite::getDevice, DeviceSite::getDeviceCode, DeviceSite::getDeviceSite, DeviceSite::getStatus, DeviceSite::getChannel, DeviceSite::getUpdateTime) .eq(DeviceSite::getTenantId, context.getTenantId()) .orderByDesc(DeviceSite::getUpdateTime) .last("limit 50")); if (deviceSites.isEmpty()) { return "当前未查询到 man_device_site 设备站点数据,请提示用户核对基础数据或租户配置。"; } Map statusCounters = new LinkedHashMap<>(); Map deviceCounters = new LinkedHashMap<>(); Map channelCounters = new LinkedHashMap<>(); for (DeviceSite deviceSite : deviceSites) { String status = resolveStatus(deviceSite.getStatus()); String device = emptyToDefault(deviceSite.getDevice$(), "未配置设备类型"); String channel = deviceSite.getChannel() == null ? "未配置巷道" : "巷道" + deviceSite.getChannel(); statusCounters.put(status, statusCounters.getOrDefault(status, 0L) + 1); deviceCounters.put(device, deviceCounters.getOrDefault(device, 0L) + 1); channelCounters.put(channel, channelCounters.getOrDefault(channel, 0L) + 1); } StringBuilder summary = new StringBuilder(); summary.append("以下是基于 man_device_site 的实时设备站点摘要,请结合任务和库存数据综合判断:"); summary.append("\n设备站点总览:共 ").append(deviceSites.size()).append(" 条有效站点记录。"); summary.append("\n站点状态分布:").append(formatCounter(statusCounters)).append("。"); summary.append("\n设备类型分布:").append(formatCounter(deviceCounters)).append("。"); summary.append("\n巷道分布:").append(formatCounter(channelCounters)).append("。"); summary.append("\n最近更新站点 TOP5:").append(formatLatestSites(deviceSites.subList(0, Math.min(deviceSites.size(), 5)))).append("。"); return summary.toString(); } /** * 格式化计数类摘要。 */ private String formatCounter(Map counter) { List parts = new ArrayList<>(); for (Map.Entry item : counter.entrySet()) { parts.add(item.getKey() + " " + item.getValue() + " 条"); } return String.join(",", parts); } /** * 格式化最近更新站点列表。 */ private String formatLatestSites(List deviceSites) { List parts = new ArrayList<>(); for (DeviceSite deviceSite : deviceSites) { parts.add(emptyToDefault(deviceSite.getName(), emptyToDefault(deviceSite.getSite(), "未命名站点")) + "(" + resolveStatus(deviceSite.getStatus()) + ",设备 " + emptyToDefault(deviceSite.getDevice$(), "-") + ",接驳位 " + emptyToDefault(deviceSite.getDeviceCode(), "-") + ",巷道 " + (deviceSite.getChannel() == null ? "-" : deviceSite.getChannel()) + ")"); } return String.join(";", parts); } /** * 将站点状态码转成可读文本。 */ private String resolveStatus(Integer status) { if (status == null) { return "未知状态"; } return status == 1 ? "正常" : status == 0 ? "冻结" : "状态" + status; } /** * 统一处理空值展示。 */ private String emptyToDefault(String value, String defaultValue) { return value == null || value.trim().isEmpty() ? defaultValue : value; } }