package com.vincent.rsf.server.ai.tool; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.common.utils.FieldsUtils; import com.vincent.rsf.server.manager.entity.Task; import com.vincent.rsf.server.manager.entity.TaskItem; import com.vincent.rsf.server.manager.service.TaskItemService; import com.vincent.rsf.server.manager.service.TaskService; import lombok.RequiredArgsConstructor; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @Component @RequiredArgsConstructor public class RsfWmsTaskTools { private final TaskService taskService; private final TaskItemService taskItemService; /** * 查询任务列表。 * 方法要求至少带一个过滤条件,避免模型把任务表当作可直接遍历的数据源。 */ @Tool(name = "rsf_query_task_list", description = "只读查询工具。按任务号、状态、任务类型、源站点、目标站点等条件查询任务列表。") public List> queryTaskList( @ToolParam(description = "任务号,可模糊查询") String taskCode, @ToolParam(description = "任务状态,可选") Integer taskStatus, @ToolParam(description = "任务类型,可选") Integer taskType, @ToolParam(description = "源站点,可选") String orgSite, @ToolParam(description = "目标站点,可选") String targSite, @ToolParam(description = "返回条数,默认 10,最大 50") Integer limit) { String normalizedTaskCode = BuiltinToolGovernanceSupport.sanitizeQueryText(taskCode, "任务号", 64); String normalizedOrgSite = BuiltinToolGovernanceSupport.sanitizeQueryText(orgSite, "源站点", 64); String normalizedTargSite = BuiltinToolGovernanceSupport.sanitizeQueryText(targSite, "目标站点", 64); BuiltinToolGovernanceSupport.requireAnyFilter("任务列表查询至少需要提供一个过滤条件", normalizedTaskCode, normalizedOrgSite, normalizedTargSite, taskStatus == null ? null : String.valueOf(taskStatus), taskType == null ? null : String.valueOf(taskType)); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); int finalLimit = BuiltinToolGovernanceSupport.normalizeLimit(limit, 10, 50); if (StringUtils.hasText(normalizedTaskCode)) { queryWrapper.like(Task::getTaskCode, normalizedTaskCode); } if (taskStatus != null) { queryWrapper.eq(Task::getTaskStatus, taskStatus); } if (taskType != null) { queryWrapper.eq(Task::getTaskType, taskType); } if (StringUtils.hasText(normalizedOrgSite)) { queryWrapper.eq(Task::getOrgSite, normalizedOrgSite); } if (StringUtils.hasText(normalizedTargSite)) { queryWrapper.eq(Task::getTargSite, normalizedTargSite); } queryWrapper.orderByDesc(Task::getCreateTime).last("LIMIT " + finalLimit); List tasks = taskService.list(queryWrapper); List> result = new ArrayList<>(); for (Task task : tasks) { result.add(buildTaskSummary(task)); } return result; } /** * 查询单个任务详情。 * 与列表查询不同,这里允许返回更丰富的字段,但仍然要求调用方通过任务 ID 或任务号做精确定位。 */ @Tool(name = "rsf_query_task_detail", description = "只读查询工具。查询任务列表有正常返回值可以根据任务ID查询任务详情。") public Map queryTaskDetail( @ToolParam(description = "任务 ID") Long taskId ) { if (taskId == null) { throw new CoolException("任务 ID 需要提供"); } List taskItems = new ArrayList<>(); taskItems = taskItemService.list(new LambdaQueryWrapper().eq(TaskItem::getTaskId, taskId)); if (taskItems.isEmpty()) { throw new CoolException("未查询到任务"); } return buildTaskItemDetail(taskItems); } private Map buildTaskSummary(Task task) { /** 把任务实体收敛为适合模型阅读和前端展示的摘要结构。 */ Map item = new LinkedHashMap<>(); item.put("id", task.getId()); item.put("taskCode", task.getTaskCode()); item.put("taskStatus", task.getTaskStatus()); item.put("taskStatusLabel", task.getTaskStatus$()); item.put("taskType", task.getTaskType()); item.put("taskTypeLabel", task.getTaskType$()); item.put("orgSite", task.getOrgSite()); item.put("orgSiteLabel", task.getOrgSite$()); item.put("targSite", task.getTargSite()); item.put("targSiteLabel", task.getTargSite$()); item.put("status", task.getStatus()); item.put("statusLabel", task.getStatus$()); item.put("createTime", task.getCreateTime$()); item.put("updateTime", task.getUpdateTime$()); return item; } private Map buildTaskItemDetail(List taskItems) { Map result = new LinkedHashMap<>(); result.put("taskId", taskItems.get(0).getTaskId()); result.put("itemCount", taskItems.size()); double totalAnfme = 0D; double totalWorkQty = 0D; double totalQty = 0D; List> items = new ArrayList<>(); for (TaskItem taskItem : taskItems) { totalAnfme += taskItem.getAnfme() == null ? 0D : taskItem.getAnfme(); totalWorkQty += taskItem.getWorkQty() == null ? 0D : taskItem.getWorkQty(); totalQty += taskItem.getQty() == null ? 0D : taskItem.getQty(); items.add(buildTaskItemRow(taskItem)); } result.put("totalAnfme", totalAnfme); result.put("totalWorkQty", totalWorkQty); result.put("totalQty", totalQty); result.put("items", items); return result; } private Map buildTaskItemRow(TaskItem taskItem) { if (!Objects.isNull(taskItem.getFieldsIndex())) { taskItem.setExtendFields(FieldsUtils.getFields(taskItem.getFieldsIndex())); } Map item = new LinkedHashMap<>(); item.put("id", taskItem.getId()); item.put("taskId", taskItem.getTaskId()); item.put("matnrId", taskItem.getMatnrId()); item.put("matnrCode", taskItem.getMatnrCode()); item.put("maktx", taskItem.getMaktx()); item.put("trackCode", taskItem.getTrackCode()); item.put("splrBatch", taskItem.getSplrBatch()); item.put("batch", taskItem.getBatch()); item.put("spec", taskItem.getSpec()); item.put("model", taskItem.getModel()); item.put("unit", taskItem.getUnit()); item.put("anfme", taskItem.getAnfme()); item.put("workQty", taskItem.getWorkQty()); item.put("qty", taskItem.getQty()); item.put("ableQty", taskItem.getAbleQty()); item.put("source", taskItem.getSource()); item.put("sourceId", taskItem.getSourceId()); item.put("sourceCode", taskItem.getSourceCode()); item.put("orderId", taskItem.getOrderId()); item.put("orderItemId", taskItem.getOrderItemId()); item.put("platItemId", taskItem.getPlatItemId()); item.put("platOrderCode", taskItem.getPlatOrderCode()); item.put("platWorkCode", taskItem.getPlatWorkCode()); item.put("projectCode", taskItem.getProjectCode()); item.put("orderType", taskItem.getOrderType()); item.put("orderTypeLabel", taskItem.getOrderType$()); item.put("wkType", taskItem.getWkType()); item.put("wkTypeLabel", taskItem.getWkType$()); item.put("isptResult", taskItem.getIsptResult()); item.put("isptResultLabel", taskItem.getIsptResult$()); item.put("fieldsIndex", taskItem.getFieldsIndex()); item.put("extendFields", taskItem.getExtendFields()); item.put("status", taskItem.getStatus()); item.put("statusLabel", taskItem.getStatus$()); item.put("memo", taskItem.getMemo()); item.put("createTime", taskItem.getCreateTime$()); item.put("updateTime", taskItem.getUpdateTime$()); return item; } }