diff --git a/klp-wms/src/main/java/com/klp/controller/WmsImageRecognitionController.java b/klp-wms/src/main/java/com/klp/controller/WmsImageRecognitionController.java index 82cfa0e0..0ebd1492 100644 --- a/klp-wms/src/main/java/com/klp/controller/WmsImageRecognitionController.java +++ b/klp-wms/src/main/java/com/klp/controller/WmsImageRecognitionController.java @@ -43,98 +43,4 @@ public class WmsImageRecognitionController extends BaseController { return R.ok(iImageRecognitionService.recognizeImage(bo)); } - /** - * 识别BOM内容 - */ - @PostMapping("/recognizeBom") - public R recognizeBom(@RequestBody @Validated(AddGroup.class) ImageRecognitionBo bo) { - bo.setRecognitionType("bom"); - return R.ok(iImageRecognitionService.recognizeBom(bo)); - } - - /** - * 识别文字内容 - */ - @PostMapping("/recognizeText") - public R recognizeText(@RequestBody @Validated(AddGroup.class) ImageRecognitionBo bo) { - bo.setRecognitionType("text"); - return R.ok(iImageRecognitionService.recognizeText(bo)); - } - - /** - * 批量识别图片 - */ - @PostMapping("/recognizeBatch") - public R> recognizeBatch(@RequestBody @Validated(AddGroup.class) List boList) { - return R.ok(iImageRecognitionService.recognizeImages(boList)); - } - - /** - * 测试AI连接 - */ - @PostMapping("/testConnection") - public R> testConnection() { - return R.ok(iImageRecognitionService.testAiConnection()); - } - - /** - * 获取识别配置 - */ - @GetMapping("/config") - public R> getConfig() { - return R.ok(iImageRecognitionService.getRecognitionConfig()); - } - - /** - * 更新识别配置 - */ - @PostMapping("/config") - public R updateConfig(@RequestBody Map config) { - iImageRecognitionService.updateRecognitionConfig(config); - return R.ok(); - } - - /** - * 获取识别历史 - */ - @PostMapping("/history") - public R> getHistory(@RequestBody Map pageQuery) { - return R.ok(iImageRecognitionService.getRecognitionHistory(pageQuery)); - } - - /** - * 简单识别接口(兼容原有格式) - */ - @PostMapping("/recognizeTextSimple") - public R recognizeTextSimple(@RequestBody Map request) { - String imgUrl = request.get("imgUrl"); - if (imgUrl == null || imgUrl.trim().isEmpty()) { - return R.fail("图片URL不能为空"); - } - - ImageRecognitionBo bo = new ImageRecognitionBo(); - bo.setImageUrl(imgUrl); - bo.setRecognitionType("text"); - - ImageRecognitionVo result = iImageRecognitionService.recognizeText(bo); - return R.ok(result); - } - - /** - * 识别BOM接口(兼容原有格式) - */ - @PostMapping("/recognizeBomSimple") - public R recognizeBomSimple(@RequestBody Map request) { - String imgUrl = request.get("imgUrl"); - if (imgUrl == null || imgUrl.trim().isEmpty()) { - return R.fail("图片URL不能为空"); - } - - ImageRecognitionBo bo = new ImageRecognitionBo(); - bo.setImageUrl(imgUrl); - bo.setRecognitionType("bom"); - - ImageRecognitionVo result = iImageRecognitionService.recognizeBom(bo); - return R.ok(result); - } } diff --git a/klp-wms/src/main/java/com/klp/domain/bo/ImageRecognitionBo.java b/klp-wms/src/main/java/com/klp/domain/bo/ImageRecognitionBo.java index e038b909..eebb4df2 100644 --- a/klp-wms/src/main/java/com/klp/domain/bo/ImageRecognitionBo.java +++ b/klp-wms/src/main/java/com/klp/domain/bo/ImageRecognitionBo.java @@ -34,7 +34,7 @@ public class ImageRecognitionBo extends BaseEntity { /** * 是否启用多轮投票 */ - private Boolean enableVoting = true; + private Boolean enableVoting = false; /** * 投票轮数 @@ -60,4 +60,4 @@ public class ImageRecognitionBo extends BaseEntity { * 识别任务描述 */ private String taskDescription; -} \ No newline at end of file +} diff --git a/klp-wms/src/main/java/com/klp/domain/vo/AttributeVo.java b/klp-wms/src/main/java/com/klp/domain/vo/AttributeVo.java new file mode 100644 index 00000000..363005ca --- /dev/null +++ b/klp-wms/src/main/java/com/klp/domain/vo/AttributeVo.java @@ -0,0 +1,19 @@ +package com.klp.domain.vo; + +import lombok.Data; + +/** + * 属性信息 + */ +@Data +public class AttributeVo { + /** + * 属性名称 + */ + private String attrKey; + + /** + * 属性值 + */ + private String attrValue; +} diff --git a/klp-wms/src/main/java/com/klp/domain/vo/BomItemVo.java b/klp-wms/src/main/java/com/klp/domain/vo/BomItemVo.java new file mode 100644 index 00000000..aa35eebb --- /dev/null +++ b/klp-wms/src/main/java/com/klp/domain/vo/BomItemVo.java @@ -0,0 +1,39 @@ +package com.klp.domain.vo; + +import lombok.Data; + +/** + * BOM项目信息 + */ +@Data +public class BomItemVo { + /** + * 原材料ID + */ + private String rawMaterialId; + + /** + * 原材料名称 + */ + private String rawMaterialName; + + /** + * 数量 + */ + private Double quantity; + + /** + * 单位 + */ + private String unit; + + /** + * 规格 + */ + private String specification; + + /** + * 备注 + */ + private String remark; +} diff --git a/klp-wms/src/main/java/com/klp/domain/vo/ImageRecognitionVo.java b/klp-wms/src/main/java/com/klp/domain/vo/ImageRecognitionVo.java index bbf0a03a..5778c459 100644 --- a/klp-wms/src/main/java/com/klp/domain/vo/ImageRecognitionVo.java +++ b/klp-wms/src/main/java/com/klp/domain/vo/ImageRecognitionVo.java @@ -1,10 +1,8 @@ package com.klp.domain.vo; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serializable; -import java.util.Date; import java.util.List; import java.util.Map; @@ -19,11 +17,6 @@ public class ImageRecognitionVo implements Serializable { private static final long serialVersionUID = 1L; - /** - * 识别ID - */ - private Long recognitionId; - /** * 图片URL */ @@ -54,11 +47,6 @@ public class ImageRecognitionVo implements Serializable { */ private List attributes; - /** - * 识别置信度 - */ - private Double confidence; - /** * 识别状态:success-成功,failed-失败,processing-处理中 */ @@ -74,61 +62,6 @@ public class ImageRecognitionVo implements Serializable { */ private Long processingTime; - /** - * 创建时间 - */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; - /** - * BOM项目信息 - */ - @Data - public static class BomItemVo { - /** - * 原材料ID - */ - private String rawMaterialId; - /** - * 原材料名称 - */ - private String rawMaterialName; - - /** - * 数量 - */ - private Double quantity; - - /** - * 单位 - */ - private String unit; - - /** - * 规格 - */ - private String specification; - - /** - * 备注 - */ - private String remark; - } - - /** - * 属性信息 - */ - @Data - public static class AttributeVo { - /** - * 属性名称 - */ - private String attrKey; - - /** - * 属性值 - */ - private String attrValue; - } -} \ No newline at end of file +} diff --git a/klp-wms/src/main/java/com/klp/service/IImageRecognitionService.java b/klp-wms/src/main/java/com/klp/service/IImageRecognitionService.java index 57a9c108..f9d6770c 100644 --- a/klp-wms/src/main/java/com/klp/service/IImageRecognitionService.java +++ b/klp-wms/src/main/java/com/klp/service/IImageRecognitionService.java @@ -22,56 +22,5 @@ public interface IImageRecognitionService { */ ImageRecognitionVo recognizeImage(ImageRecognitionBo bo); - /** - * 批量识别图片 - * - * @param boList 识别请求参数列表 - * @return 识别结果列表 - */ - List recognizeImages(List boList); - /** - * 识别BOM内容 - * - * @param bo 识别请求参数 - * @return BOM识别结果 - */ - ImageRecognitionVo recognizeBom(ImageRecognitionBo bo); - - /** - * 识别文字内容 - * - * @param bo 识别请求参数 - * @return 文字识别结果 - */ - ImageRecognitionVo recognizeText(ImageRecognitionBo bo); - - /** - * 测试AI连接 - * - * @return 连接测试结果 - */ - Map testAiConnection(); - - /** - * 获取识别配置 - * - * @return 配置信息 - */ - Map getRecognitionConfig(); - - /** - * 更新识别配置 - * - * @param config 配置信息 - */ - void updateRecognitionConfig(Map config); - - /** - * 获取识别历史 - * - * @param pageQuery 分页查询参数 - * @return 识别历史列表 - */ - Map getRecognitionHistory(Map pageQuery); -} \ No newline at end of file +} diff --git a/klp-wms/src/main/java/com/klp/service/impl/ImageRecognitionServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/ImageRecognitionServiceImpl.java index 1499ad11..6bbd91e1 100644 --- a/klp-wms/src/main/java/com/klp/service/impl/ImageRecognitionServiceImpl.java +++ b/klp-wms/src/main/java/com/klp/service/impl/ImageRecognitionServiceImpl.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.klp.config.ImageRecognitionConfig; import com.klp.domain.bo.ImageRecognitionBo; +import com.klp.domain.vo.AttributeVo; import com.klp.domain.vo.ImageRecognitionVo; import com.klp.service.IImageRecognitionService; import com.klp.utils.ImageProcessingUtils; @@ -34,7 +35,7 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { private final ImageRecognitionConfig config; private final ImageProcessingUtils imageProcessingUtils; - + @Qualifier("salesScriptRestTemplate") private final RestTemplate restTemplate; @@ -45,7 +46,7 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { public ImageRecognitionVo recognizeImage(ImageRecognitionBo bo) { long startTime = System.currentTimeMillis(); ImageRecognitionVo result = new ImageRecognitionVo(); - + try { // 验证图片URL if (!imageProcessingUtils.isValidImageUrl(bo.getImageUrl())) { @@ -67,7 +68,7 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { result.setStatus("success"); result.setProcessingTime(System.currentTimeMillis() - startTime); - + } catch (Exception e) { log.error("图片识别失败", e); result.setStatus("failed"); @@ -78,58 +79,32 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { return result; } - @Override - public List recognizeImages(List boList) { - List> futures = new ArrayList<>(); - - for (ImageRecognitionBo bo : boList) { - CompletableFuture future = CompletableFuture.supplyAsync(() -> - recognizeImage(bo), executorService); - futures.add(future); - } - List results = new ArrayList<>(); - for (CompletableFuture future : futures) { - try { - results.add(future.get()); - } catch (Exception e) { - log.error("批量识别失败", e); - ImageRecognitionVo errorResult = new ImageRecognitionVo(); - errorResult.setStatus("failed"); - errorResult.setErrorMessage(e.getMessage()); - results.add(errorResult); - } - } - - return results; - } - - @Override public ImageRecognitionVo recognizeBom(ImageRecognitionBo bo) { String prompt = buildBomPrompt(bo); String aiResponse = callAiApi(bo.getImageUrl(), prompt, bo.getEnableVoting(), bo.getVotingRounds()); - + ImageRecognitionVo result = new ImageRecognitionVo(); result.setImageUrl(bo.getImageUrl()); result.setRecognitionType("bom"); result.setRecognizedText(aiResponse); - + // 解析识别结果 try { // 直接解析属性数组 - List attributes = parseAttributesResponse(aiResponse); + List attributes = parseAttributesResponse(aiResponse); result.setAttributes(attributes); - + // 构建结构化结果 Map structuredResult = new HashMap<>(); structuredResult.put("attributes", attributes); structuredResult.put("summary", "材料质保单识别结果"); structuredResult.put("totalItems", attributes.size()); result.setStructuredResult(structuredResult); - + // BOM项目为空,因为这是质保单识别 result.setBomItems(new ArrayList<>()); - + } catch (Exception e) { log.warn("解析识别响应失败: {}", e.getMessage()); result.setRecognizedText(aiResponse); @@ -138,79 +113,18 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { return result; } - @Override public ImageRecognitionVo recognizeText(ImageRecognitionBo bo) { String prompt = buildTextPrompt(bo); String aiResponse = callAiApi(bo.getImageUrl(), prompt, bo.getEnableVoting(), bo.getVotingRounds()); - + ImageRecognitionVo result = new ImageRecognitionVo(); result.setImageUrl(bo.getImageUrl()); result.setRecognitionType("text"); result.setRecognizedText(aiResponse); - + return result; } - @Override - public Map testAiConnection() { - Map result = new HashMap<>(); - try { - // 构建测试请求 - Map requestBody = new HashMap<>(); - requestBody.put("model", config.getModelName()); - - Map message = new HashMap<>(); - message.put("role", "user"); - message.put("content", "你好"); - requestBody.put("messages", Arrays.asList(message)); - requestBody.put("max_tokens", 10); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setBearerAuth(config.getApiKey()); - - HttpEntity> entity = new HttpEntity<>(requestBody, headers); - ResponseEntity response = restTemplate.postForEntity( - config.getApiUrl(), entity, Map.class); - - result.put("success", true); - result.put("message", "AI连接测试成功"); - result.put("response", response.getBody()); - } catch (Exception e) { - log.error("AI连接测试失败", e); - result.put("success", false); - result.put("message", "AI连接测试失败: " + e.getMessage()); - } - return result; - } - - @Override - public Map getRecognitionConfig() { - Map configMap = new HashMap<>(); - configMap.put("apiUrl", config.getApiUrl()); - configMap.put("modelName", config.getModelName()); - configMap.put("apiKey", config.getApiKey().substring(0, 10) + "..."); - configMap.put("maxRetries", config.getMaxRetries()); - configMap.put("temperature", config.getTemperature()); - configMap.put("maxTokens", config.getMaxTokens()); - configMap.put("maxImageDimension", config.getMaxImageDimension()); - configMap.put("imageQuality", config.getImageQuality()); - return configMap; - } - - @Override - public void updateRecognitionConfig(Map config) { - log.info("更新识别配置: {}", config); - // 这里可以实现配置更新逻辑 - } - - @Override - public Map getRecognitionHistory(Map pageQuery) { - Map result = new HashMap<>(); - result.put("rows", new ArrayList<>()); - result.put("total", 0L); - return result; - } /** * 通用识别方法 @@ -218,12 +132,12 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { private ImageRecognitionVo recognizeGeneral(ImageRecognitionBo bo) { String prompt = buildGeneralPrompt(bo); String aiResponse = callAiApi(bo.getImageUrl(), prompt, bo.getEnableVoting(), bo.getVotingRounds()); - + ImageRecognitionVo result = new ImageRecognitionVo(); result.setImageUrl(bo.getImageUrl()); result.setRecognitionType("general"); result.setRecognizedText(aiResponse); - + return result; } @@ -238,9 +152,9 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { // 构建请求体 Map requestBody = new HashMap<>(); requestBody.put("model", config.getModelName()); - + List> contents = new ArrayList<>(); - + // 添加图片内容 Map imageContent = new HashMap<>(); imageContent.put("type", "image_url"); @@ -249,17 +163,17 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { imageUrlObj.put("detail", "low"); imageContent.put("image_url", imageUrlObj); contents.add(imageContent); - + // 添加文本内容 Map textContent = new HashMap<>(); textContent.put("type", "text"); textContent.put("text", prompt); contents.add(textContent); - + Map message = new HashMap<>(); message.put("role", "user"); message.put("content", contents); - + requestBody.put("messages", Arrays.asList(message)); requestBody.put("enable_thinking", true); requestBody.put("temperature", config.getTemperature()); @@ -319,9 +233,9 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { */ private String callAiApiWithVoting(Map requestBody, int rounds) { List> futures = new ArrayList<>(); - + for (int i = 0; i < rounds; i++) { - CompletableFuture future = CompletableFuture.supplyAsync(() -> + CompletableFuture future = CompletableFuture.supplyAsync(() -> callAiApiSingle(requestBody), executorService); futures.add(future); } @@ -361,12 +275,12 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { prompt.append("5. 如有值缺失或为空的字段,仍保留字段,value 留空字符串;\n"); prompt.append("6. 严格按照图像中文字布局顺序返回;\n"); prompt.append("7. 只输出 JSON 结果,不需要解释或说明;\n\n"); - + if (bo.getProductId() != null) { prompt.append("【产品信息】\n"); prompt.append("产品ID: ").append(bo.getProductId()).append("\n\n"); } - + if (bo.getCustomPrompt() != null && !bo.getCustomPrompt().isEmpty()) { prompt.append("【自定义要求】\n"); prompt.append(bo.getCustomPrompt()).append("\n\n"); @@ -387,12 +301,12 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { prompt.append("3. 识别表格、列表等结构化内容\n"); prompt.append("4. 识别数字、符号等特殊字符\n"); prompt.append("5. 保持段落和换行格式\n\n"); - + if (bo.getCustomPrompt() != null && !bo.getCustomPrompt().isEmpty()) { prompt.append("【自定义要求】\n"); prompt.append(bo.getCustomPrompt()).append("\n\n"); } - + prompt.append("【输出格式】\n"); prompt.append("请直接输出识别到的文字内容,保持原有格式。"); @@ -411,12 +325,12 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { prompt.append("3. 分析图片的结构和布局\n"); prompt.append("4. 提取关键信息和数据\n"); prompt.append("5. 识别图片中的表格、图表等结构化内容\n\n"); - + if (bo.getCustomPrompt() != null && !bo.getCustomPrompt().isEmpty()) { prompt.append("【自定义要求】\n"); prompt.append(bo.getCustomPrompt()).append("\n\n"); } - + prompt.append("【输出格式】\n"); prompt.append("请提供详细的分析结果,包括文字内容、结构分析等。"); @@ -426,39 +340,39 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { /** * 解析属性数组响应 */ - private List parseAttributesResponse(String response) { + private List parseAttributesResponse(String response) { try { // 尝试直接解析JSON数组 - List> attrList = objectMapper.readValue(response, + List> attrList = objectMapper.readValue(response, objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class)); - - List attributes = new ArrayList<>(); + + List attributes = new ArrayList<>(); for (Map attr : attrList) { - ImageRecognitionVo.AttributeVo attribute = new ImageRecognitionVo.AttributeVo(); + AttributeVo attribute = new AttributeVo(); attribute.setAttrKey((String) attr.get("attrKey")); attribute.setAttrValue((String) attr.get("attrValue")); attributes.add(attribute); } return attributes; - + } catch (JsonProcessingException e) { // 如果直接解析失败,尝试提取JSON数组部分 Pattern jsonArrayPattern = Pattern.compile("\\[[\\s\\S]*\\]"); Matcher matcher = jsonArrayPattern.matcher(response); if (matcher.find()) { try { - List> attrList = objectMapper.readValue(matcher.group(), + List> attrList = objectMapper.readValue(matcher.group(), objectMapper.getTypeFactory().constructCollectionType(List.class, Map.class)); - - List attributes = new ArrayList<>(); + + List attributes = new ArrayList<>(); for (Map attr : attrList) { - ImageRecognitionVo.AttributeVo attribute = new ImageRecognitionVo.AttributeVo(); + AttributeVo attribute = new AttributeVo(); attribute.setAttrKey((String) attr.get("attrKey")); attribute.setAttrValue((String) attr.get("attrValue")); attributes.add(attribute); } return attributes; - + } catch (JsonProcessingException ex) { log.warn("无法解析属性响应为JSON数组: {}", response); return new ArrayList<>(); @@ -469,132 +383,5 @@ public class ImageRecognitionServiceImpl implements IImageRecognitionService { } } - /** - * 解析BOM响应(保留用于兼容性) - */ - private Map parseBomResponse(String response) { - try { - // 尝试直接解析JSON - return objectMapper.readValue(response, Map.class); - } catch (JsonProcessingException e) { - // 如果直接解析失败,尝试提取JSON部分 - Pattern jsonPattern = Pattern.compile("\\{[\\s\\S]*\\}"); - Matcher matcher = jsonPattern.matcher(response); - if (matcher.find()) { - try { - return objectMapper.readValue(matcher.group(), Map.class); - } catch (JsonProcessingException ex) { - log.warn("无法解析BOM响应为JSON: {}", response); - Map fallback = new HashMap<>(); - fallback.put("rawText", response); - return fallback; - } - } - Map fallback = new HashMap<>(); - fallback.put("rawText", response); - return fallback; - } - } - /** - * 提取BOM项目列表 - */ - private List extractBomItems(Map structuredResult) { - List bomItems = new ArrayList<>(); - - try { - List> items = (List>) structuredResult.get("bomItems"); - if (items != null) { - for (Map item : items) { - ImageRecognitionVo.BomItemVo bomItem = new ImageRecognitionVo.BomItemVo(); - bomItem.setRawMaterialId((String) item.get("rawMaterialId")); - bomItem.setRawMaterialName((String) item.get("rawMaterialName")); - - Object quantity = item.get("quantity"); - if (quantity instanceof Number) { - bomItem.setQuantity(((Number) quantity).doubleValue()); - } - - bomItem.setUnit((String) item.get("unit")); - bomItem.setSpecification((String) item.get("specification")); - bomItem.setRemark((String) item.get("remark")); - - bomItems.add(bomItem); - } - } - } catch (Exception e) { - log.warn("提取BOM项目失败: {}", e.getMessage()); - } - - return bomItems; - } - - /** - * 提取属性列表 - */ - private List extractAttributes(Map structuredResult) { - List attributes = new ArrayList<>(); - - try { - List> attrList = (List>) structuredResult.get("attributes"); - if (attrList != null) { - for (Map attr : attrList) { - ImageRecognitionVo.AttributeVo attribute = new ImageRecognitionVo.AttributeVo(); - attribute.setAttrKey((String) attr.get("attrKey")); - attribute.setAttrValue((String) attr.get("attrValue")); - attributes.add(attribute); - } - } - - // 如果没有attributes字段,尝试从其他字段生成属性 - if (attributes.isEmpty()) { - attributes = generateAttributesFromResult(structuredResult); - } - } catch (Exception e) { - log.warn("提取属性失败: {}", e.getMessage()); - } - - return attributes; - } - - /** - * 从识别结果生成属性列表 - */ - private List generateAttributesFromResult(Map structuredResult) { - List attributes = new ArrayList<>(); - - try { - // 提取summary作为内容总结 - String summary = (String) structuredResult.get("summary"); - if (summary != null && !summary.isEmpty()) { - ImageRecognitionVo.AttributeVo summaryAttr = new ImageRecognitionVo.AttributeVo(); - summaryAttr.setAttrKey("内容总结"); - summaryAttr.setAttrValue(summary); - attributes.add(summaryAttr); - } - - // 提取totalItems - Object totalItems = structuredResult.get("totalItems"); - if (totalItems != null) { - ImageRecognitionVo.AttributeVo totalAttr = new ImageRecognitionVo.AttributeVo(); - totalAttr.setAttrKey("总项目数"); - totalAttr.setAttrValue(String.valueOf(totalItems)); - attributes.add(totalAttr); - } - - // 提取bomItems数量 - List> bomItems = (List>) structuredResult.get("bomItems"); - if (bomItems != null && !bomItems.isEmpty()) { - ImageRecognitionVo.AttributeVo bomCountAttr = new ImageRecognitionVo.AttributeVo(); - bomCountAttr.setAttrKey("BOM项目数"); - bomCountAttr.setAttrValue(String.valueOf(bomItems.size())); - attributes.add(bomCountAttr); - } - - } catch (Exception e) { - log.warn("生成属性失败: {}", e.getMessage()); - } - - return attributes; - } -} \ No newline at end of file +}