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.DeviceSite; import com.vincent.rsf.server.manager.entity.LocItem; import com.vincent.rsf.server.manager.enums.LocStsType; import com.vincent.rsf.server.manager.service.DeviceSiteService; import com.vincent.rsf.server.manager.service.LocItemService; 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 RsfWmsStockTools { private final LocItemService locItemService; private final DeviceSiteService deviceSiteService; @Tool(name = "rsf_query_available_inventory", description = "只读查询工具。根据物料编码或物料名称查询当前在库且可用于出库的库存明细。") public List> queryAvailableInventory( @ToolParam(description = "物料编码,优先使用") String matnr, @ToolParam(description = "物料名称,当没有物料编码时使用") String maktx, @ToolParam(description = "返回条数,默认 10,最大 50") Integer limit) { String normalizedMatnr = BuiltinToolGovernanceSupport.sanitizeQueryText(matnr, "物料编码", 64); String normalizedMaktx = BuiltinToolGovernanceSupport.sanitizeQueryText(maktx, "物料名称", 100); BuiltinToolGovernanceSupport.requireAnyFilter("物料编码或物料名称至少需要提供一个", normalizedMatnr, normalizedMaktx); int finalLimit = BuiltinToolGovernanceSupport.normalizeLimit(limit, 10, 50); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (StringUtils.hasText(normalizedMatnr)) { queryWrapper.eq(LocItem::getMatnrCode, normalizedMatnr); } else { queryWrapper.like(LocItem::getMaktx, normalizedMaktx); } queryWrapper.apply( "EXISTS (SELECT 1 FROM man_loc ml WHERE ml.use_status = {0} AND ml.id = man_loc_item.loc_id)", LocStsType.LOC_STS_TYPE_F.type ); queryWrapper.orderByDesc(LocItem::getId).last("LIMIT " + finalLimit); List locItems = locItemService.list(queryWrapper); List> result = new ArrayList<>(); for (LocItem locItem : locItems) { if (!Objects.isNull(locItem.getFieldsIndex())) { locItem.setExtendFields(FieldsUtils.getFields(locItem.getFieldsIndex())); } Map item = new LinkedHashMap<>(); item.put("id", locItem.getId()); item.put("locId", locItem.getLocId()); item.put("locCode", locItem.getLocCode()); item.put("matnrCode", locItem.getMatnrCode()); item.put("maktx", locItem.getMaktx()); item.put("trackCode", locItem.getTrackCode()); item.put("batch", locItem.getBatch()); item.put("spec", locItem.getSpec()); item.put("model", locItem.getModel()); item.put("unit", locItem.getUnit()); item.put("anfme", locItem.getAnfme()); item.put("status", locItem.getStatus()); item.put("extendFields", locItem.getExtendFields()); result.add(item); } return result; } @Tool(name = "rsf_query_station_list", description = "只读查询工具。根据作业类型列表查询可用站点,返回站点编号、名称、目标位置和状态等信息。") public List> queryStationList( @ToolParam(required = true, description = "作业类型列表") List types, @ToolParam(description = "返回条数,默认 20,最大 50") Integer limit) { List normalizedTypes = BuiltinToolGovernanceSupport.sanitizeStringList(types, "站点类型列表", 10, 32); int finalLimit = BuiltinToolGovernanceSupport.normalizeLimit(limit, 20, 50); List sites = deviceSiteService.list(new LambdaQueryWrapper() .in(DeviceSite::getType, normalizedTypes) .orderByAsc(DeviceSite::getType) .orderByAsc(DeviceSite::getSite) .last("LIMIT " + finalLimit)); List> result = new ArrayList<>(); for (DeviceSite site : sites) { Map item = new LinkedHashMap<>(); item.put("id", site.getId()); item.put("type", site.getType()); item.put("site", site.getSite()); item.put("name", site.getName()); item.put("target", site.getTarget()); item.put("label", site.getLabel()); item.put("device", site.getDevice()); item.put("deviceCode", site.getDeviceCode()); item.put("deviceSite", site.getDeviceSite()); item.put("channel", site.getChannel()); item.put("status", site.getStatus()); result.add(item); } return result; } }