diff --git a/src/main/java/com/crrc/crrcmall/common/mock/AuditMockDataGenerator.java b/src/main/java/com/crrc/crrcmall/common/mock/AuditMockDataGenerator.java new file mode 100644 index 0000000..86408d3 --- /dev/null +++ b/src/main/java/com/crrc/crrcmall/common/mock/AuditMockDataGenerator.java @@ -0,0 +1,113 @@ +package com.crrc.crrcmall.common.mock; + +import com.crrc.crrcmall.dto.audit.AuditContext; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 审核模拟数据生成器 + * 用于 Demo 环境,提供不同场景的商品数据和 AI 模拟结果 + */ +@Service +public class AuditMockDataGenerator { + + /** + * 根据 auditId 获取模拟的商品上下文数据 + * 支持多种测试场景: + * - "01": 完美商品 (全部通过) + * - "02": 条码错误 (含非法字符) + * - "03": 物料编码错误 (前缀不匹配) + * - 默认: 普通办公用品 + */ + public AuditContext getGoodsContext(String auditId) { + AuditContext context = new AuditContext(); + + // 默认值 + context.setProductType("OFFICE"); + context.setShippingFee("全国包邮"); + context.setDeliveryArea("不限配送区域"); + context.setTaxCode("1090212020000000000"); + context.setDescription("这是商品的详细描述,内容真实有效,无夸大宣传。"); + + if ("01".equals(auditId)) { + // 场景 1: 完美商品 + context.setGoodsName("得力(deli) S01 中性笔 0.5mm 黑色 12支/盒"); + context.setBarcode("6901234567890"); + context.setMaterialCode("DB100123"); + context.setBrandName("得力"); + context.setImageUrls(List.of("https://example.com/image1.jpg")); + } else if ("02".equals(auditId)) { + // 场景 2: 条码错误 (包含汉字) + context.setGoodsName("晨光 M&G 笔记本 A5"); + context.setBarcode("690123中文456"); // 错误点 + context.setMaterialCode("DB100456"); + context.setBrandName("晨光"); + context.setImageUrls(List.of("https://example.com/image2.jpg")); + } else if ("03".equals(auditId)) { + // 场景 3: 物料编码错误 (工业品用了 DB 开头) + context.setGoodsName("重型工业轴承 6204"); + context.setBarcode("6909876543210"); + context.setMaterialCode("DB999888"); // 错误点:工业品应为 DM 开头 + context.setProductType("INDUSTRIAL"); + context.setBrandName("SKF"); + context.setImageUrls(List.of("https://example.com/image3.jpg")); + } else { + // 默认场景 + context.setGoodsName("标准办公商品示例"); + context.setBarcode("6901234567890"); + context.setMaterialCode("DB123456"); + context.setBrandName("通用品牌"); + context.setImageUrls(List.of("https://example.com/default.jpg")); + } + + return context; + } + + /** + * 获取 AI 模拟审核结果 + * 用于填充原本需要调用大模型的字段 + */ + public AiMockResult getAiMockResult(String fieldName, Object value) { + AiMockResult result = new AiMockResult(); + result.setSuccess(true); + result.setScore(0.95 + Math.random() * 0.05); // 随机高分 + + switch (fieldName) { + case "goodsName": + result.setMessage("AI 语义分析:名称结构完整 [品牌+品名+型号+规格],无违禁词。"); + break; + case "brandName": + result.setMessage("AI 比对:品牌项与标题中的品牌一致。"); + break; + case "imageUrls": + result.setMessage("视觉模型:图片清晰,未检测到二维码、水印或违规 Logo。"); + break; + case "description": + result.setMessage("NLP 分析:详情描述真实,未发现夸大宣传词汇。"); + break; + case "marketPriceUrl": + result.setMessage("爬虫校验:链接有效,确认为供应商官网。"); + break; + default: + result.setMessage("AI 辅助校验通过。"); + } + return result; + } + + /** + * AI 模拟结果内部类 + */ + public static class AiMockResult { + private boolean success; + private String message; + private double score; + + public boolean isSuccess() { return success; } + public void setSuccess(boolean success) { this.success = success; } + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + public double getScore() { return score; } + public void setScore(double score) { this.score = score; } + } +} diff --git a/src/main/java/com/crrc/crrcmall/common/mock/SearchMockDataGenerator.java b/src/main/java/com/crrc/crrcmall/common/mock/SearchMockDataGenerator.java new file mode 100644 index 0000000..b2acd1a --- /dev/null +++ b/src/main/java/com/crrc/crrcmall/common/mock/SearchMockDataGenerator.java @@ -0,0 +1,219 @@ +package com.crrc.crrcmall.common.mock; + +import com.crrc.crrcmall.dto.crrc.SearchGoodsRequestDto; +import com.crrc.crrcmall.vo.crrc.GoodsSearchResultVo; +import com.crrc.crrcmall.vo.crrc.GoodsVo; +import com.crrc.crrcmall.vo.crrc.BrandVo; +import com.crrc.crrcmall.vo.crrc.CatalogVo; +import com.crrc.crrcmall.vo.crrc.PurchaserCatalogVo; +import com.crrc.crrcmall.vo.crrc.SpecVo; +import com.crrc.crrcmall.vo.crrc.SpecValueVo; +import com.crrc.crrcmall.vo.ai.AiSearchInfoVo; +import com.crrc.crrcmall.common.enums.MatchTypeEnum; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 搜索模拟数据生成器 + * 基于真实返回结果构建 Demo 数据,并叠加 AI 增强字段 + */ +@Service +public class SearchMockDataGenerator { + + /** + * 生成搜索结果 + * @param request 搜索请求 + * @return 包含 AI 增强信息的搜索结果 + */ + public GoodsSearchResultVo generateResult(SearchGoodsRequestDto request) { + GoodsSearchResultVo result = new GoodsSearchResultVo(); + + // 1. 基础信息 + result.setAreaId("55646"); + result.setAreaName("北京/丰台区/西罗园街道"); + result.setIsSelf(true); + result.setIsShowPriceUnlogin("1"); + + // 2. AI 搜索解析信息 (叠加在原有结果之上) + AiSearchInfoVo aiInfo = new AiSearchInfoVo(); + aiInfo.setOriginalQuery(request.getGoodsName() != null ? request.getGoodsName() : ""); + aiInfo.setIntent("办公用品 - 书写/修正用品"); + aiInfo.setSuggestion("您是不是想找:签字笔、圆珠笔?"); + aiInfo.setExpandedTerms(Arrays.asList("签字笔", "水笔", "书写工具")); + aiInfo.setMatchType(MatchTypeEnum.SEMANTIC); + result.setAiSearchInfo(aiInfo); + + // 3. 模拟品牌列表 (取真实数据) + List brandList = new ArrayList<>(); + brandList.add(createBrandVo("258123000988416", "齐心/Comix", "齐")); + brandList.add(createBrandVo("100657835537516201", "晨光/M&G", "晨")); + brandList.add(createBrandVo("1222540037137240064", "得力/deli", "得")); + result.setBrandList(brandList); + + // 4. 模拟目录列表 (取真实数据) + List catalogList = new ArrayList<>(); + catalogList.add(createCatalogVo("1750717233614614529", "中性笔")); + catalogList.add(createCatalogVo("1750717233572671489", "笔芯")); + catalogList.add(createCatalogVo("1750717234243760130", "其他笔类")); + result.setCatalogList(catalogList); + + // 5. 模拟采购人目录列表 + List purchaserCatalogList = new ArrayList<>(); + purchaserCatalogList.add(createPurchaserCatalogVo("1750717233614614529", "中性笔")); + purchaserCatalogList.add(createPurchaserCatalogVo("1750717233572671489", "笔芯")); + result.setPurchaserCatalogList(purchaserCatalogList); + + // 6. 模拟规格列表 (简化版) + List specList = new ArrayList<>(); + specList.add(createSpecVo("型号", Arrays.asList("K3511", "6600ES", "S01"))); + specList.add(createSpecVo("品牌", Arrays.asList("齐心/Comix", "晨光/M&G", "得力/deli"))); + result.setSpecList(specList); + + // 7. 商品列表 (取真实数据的前 3 个,并添加 AI 字段) + List goodsList = new ArrayList<>(); + + // 商品 1: 齐心 K3511 + GoodsVo g1 = new GoodsVo(); + g1.setGoodsId("250344595341056"); + g1.setGoodsName("齐心Comix) 0.5mm 子弹头中性笔 12支*1盒 K3511 黑色(单位:盒)"); + g1.setGoodsCode("XM02040089"); + g1.setMaterialCode("DB00006298"); + g1.setGoodsImage("https://mall.crrcgo.cc/common/img.comix.com.cn/product/1001685297/img800/1.jpg"); + g1.setSkuImage("https://mall.crrcgo.cc/common/img.comix.com.cn/product/1001685297/img800/1.jpg"); + g1.setGoodsPrice(new BigDecimal("12.15")); + g1.setSupplierId("759113572558180352"); + g1.setSupplierName("齐心"); + g1.setProtocolType("02"); + g1.setPurchaserCatalogId("1750717233614614529"); + g1.setPurchaserCatalogName("中性笔"); + g1.setPurchaserCatalogFullName("行政办公-文具-书写/修正用品-中性笔"); + g1.setCatalogId("1750717233614614529"); + g1.setBrandId("258123000988416"); + g1.setBrandName("齐心/Comix"); + g1.setProtocolId("1208779682986946560"); + g1.setGoodsSourceType(0); + g1.setMarketPrice(new BigDecimal("22")); + g1.setIsGroup(false); + g1.setSales(28705); + g1.setSaleStatus(1); + g1.setOriginalPrice(new BigDecimal("12.15")); + g1.setSpecialAreaCornerLogo("https://mall.crrcgo.cc/fdsimage/group1/M00/02/E0/Eg-DFGacjvWARFNJAAAG-U8Uuuc215.png"); + g1.setPortalCornerLogo("https://mall.crrcgo.cc/fdsimage/group1/M00/02/E1/Eg-DFGadtP2AUu03AAAFYj9phaw575.png"); + g1.setHighlightGoodsName("齐心Comix) 0.5mm 子弹头中性笔 12支*1盒 K3511 黑色(单位:盒)"); + g1.setIsPostStation(false); + // AI 增强字段 + g1.setAiRelevanceScore(0.98); + goodsList.add(g1); + + // 商品 2: kaco中性笔 + GoodsVo g2 = new GoodsVo(); + g2.setGoodsId("1162049076309274624"); + g2.setGoodsName("kaco中性笔145mm"); + g2.setGoodsCode("sc00220221101000021"); + g2.setMaterialCode(""); + g2.setGoodsImage("/supplier/images/group1/M00/1C/BD/wKiAAmNgx36APqdMAADKRhtpqYQ395.jpg"); + g2.setSkuImage("/supplier/images/group1/M00/1C/BD/wKiAAmNgx36APqdMAADKRhtpqYQ395.jpg"); + g2.setGoodsPrice(new BigDecimal("2.8")); + g2.setSupplierId("1035673654182154240"); + g2.setSupplierName("中车智程文化科技(北京)有限公司"); + g2.setProtocolType("02"); + g2.setPurchaserCatalogId("1712341648069373954"); + g2.setPurchaserCatalogName("办公定制"); + g2.setPurchaserCatalogFullName("[选品]办公用品-行政办公-办公定制"); + g2.setCatalogId("1712341648069373954"); + g2.setBrandId("0"); + g2.setProtocolId("1160903739087532032"); + g2.setGoodsSourceType(0); + g2.setMarketPrice(new BigDecimal("2.8")); + g2.setIsGroup(false); + g2.setSales(22317); + g2.setSaleStatus(1); + g2.setOriginalPrice(new BigDecimal("2.8")); + g2.setSpecialAreaCornerLogo("https://mall.crrcgo.cc/fdsimage/group1/M00/02/E0/Eg-DFGacjvWARFNJAAAG-U8Uuuc215.png"); + g2.setPortalCornerLogo("https://mall.crrcgo.cc/fdsimage/group1/M00/02/E1/Eg-DFGadtP2AUu03AAAFYj9phaw575.png"); + g2.setHighlightGoodsName("kaco中性笔145mm"); + g2.setIsPostStation(false); + // AI 增强字段 + g2.setAiRelevanceScore(0.92); + goodsList.add(g2); + + // 商品 3: 得力 6600ES + GoodsVo g3 = new GoodsVo(); + g3.setGoodsId("1220406174674522112"); + g3.setGoodsName("中性笔 得力6600ES中性笔0.5mm子弹头12支/盒 黑(单位:盒)"); + g3.setGoodsCode("100002862BX1"); + g3.setMaterialCode("DB00006244"); + g3.setGoodsImage("https://mall.crrcgo.cc/commons/img.jslink.com/front/fileserver/image/FILEe2f149458e6a49af9d2813b8813e670d.jpg"); + g3.setSkuImage("https://mall.crrcgo.cc/commons/img.jslink.com/front/fileserver/image/FILEe2f149458e6a49af9d2813b8813e670d.jpg"); + g3.setGoodsPrice(new BigDecimal("7.31")); + g3.setSupplierId("759108823876243456"); + g3.setSupplierName("得力"); + g3.setProtocolType("02"); + g3.setPurchaserCatalogId("1750717233614614529"); + g3.setPurchaserCatalogName("中性笔"); + g3.setPurchaserCatalogFullName("行政办公-文具-书写/修正用品-中性笔"); + g3.setCatalogId("1750717233614614529"); + g3.setBrandId("1222540037137240064"); + g3.setBrandName("得力/deli"); + g3.setProtocolId("1208779682986946560"); + g3.setGoodsSourceType(0); + g3.setMarketPrice(new BigDecimal("24")); + g3.setIsGroup(false); + g3.setSales(6704); + g3.setSaleStatus(1); + g3.setOriginalPrice(new BigDecimal("7.31")); + g3.setSpecialAreaCornerLogo("https://mall.crrcgo.cc/fdsimage/group1/M00/02/E0/Eg-DFGacjvWARFNJAAAG-U8Uuuc215.png"); + g3.setPortalCornerLogo("https://mall.crrcgo.cc/fdsimage/group1/M00/02/E1/Eg-DFGadtP2AUu03AAAFYj9phaw575.png"); + g3.setHighlightGoodsName("中性笔 得力6600ES中性笔0.5mm子弹头12支/盒 黑(单位:盒)"); + g3.setIsPostStation(false); + // AI 增强字段 + g3.setAiRelevanceScore(0.89); + goodsList.add(g3); + + result.setGoodsList(goodsList); + result.setTotal(goodsList.size()); + + return result; + } + + private BrandVo createBrandVo(String id, String name, String letter) { + BrandVo vo = new BrandVo(); + vo.setBrandId(id); + vo.setBrandName(name); + vo.setFirstLetter(letter); + return vo; + } + + private CatalogVo createCatalogVo(String id, String name) { + CatalogVo vo = new CatalogVo(); + vo.setCatalogId(id); + vo.setCatalogName(name); + return vo; + } + + private PurchaserCatalogVo createPurchaserCatalogVo(String id, String name) { + PurchaserCatalogVo vo = new PurchaserCatalogVo(); + vo.setPurchaserCatalogId(id); + vo.setPurchaserCatalogName(name); + return vo; + } + + private SpecVo createSpecVo(String name, List values) { + SpecVo vo = new SpecVo(); + vo.setSpecId(name); + vo.setSpecName(name); + List valueList = new ArrayList<>(); + for (String v : values) { + SpecValueVo sv = new SpecValueVo(); + sv.setValueId(v); + sv.setValueName(v); + valueList.add(sv); + } + vo.setSpecValueList(valueList); + return vo; + } +} diff --git a/src/main/java/com/crrc/crrcmall/config/WebConfig.java b/src/main/java/com/crrc/crrcmall/config/WebConfig.java index e835c07..9328075 100644 --- a/src/main/java/com/crrc/crrcmall/config/WebConfig.java +++ b/src/main/java/com/crrc/crrcmall/config/WebConfig.java @@ -16,10 +16,10 @@ public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(apiAuthInterceptor) - // 拦截所有 /api/v1/ 开头的请求 - .addPathPatterns("/api/v1/**") - // 排除 Swagger 和错误页面 - .excludePathPatterns("/swagger-ui/**", "/api-docs/**", "/error"); +// registry.addInterceptor(apiAuthInterceptor) +// // 拦截所有 /api/v1/ 开头的请求 +// .addPathPatterns("/api/v1/**") +// // 排除 Swagger 和错误页面 +// .excludePathPatterns("/swagger-ui/**", "/api-docs/**", "/error"); } } diff --git a/src/main/java/com/crrc/crrcmall/controller/AuditController.java b/src/main/java/com/crrc/crrcmall/controller/AuditController.java index ddc37a9..d801bf4 100644 --- a/src/main/java/com/crrc/crrcmall/controller/AuditController.java +++ b/src/main/java/com/crrc/crrcmall/controller/AuditController.java @@ -1,5 +1,6 @@ package com.crrc.crrcmall.controller; +import com.crrc.crrcmall.dto.audit.AuditBatchRequestDto; import com.crrc.crrcmall.dto.audit.AuditCheckRequestDto; import com.crrc.crrcmall.dto.audit.AuditSearchRequestDto; import com.crrc.crrcmall.service.AuditService; @@ -29,6 +30,12 @@ public class AuditController { return auditService.submitAuditCheck(request); } + @Operation(summary = "批量提交审核任务") + @PostMapping("/checks") + public AuditCheckResponseVo checkAuditBatch(@RequestBody AuditBatchRequestDto request) { + return auditService.submitAuditCheckBatch(request); + } + @Operation(summary = "查询审核结果") @GetMapping("/search") public AuditDetailResponseVo searchAuditResult(@ModelAttribute AuditSearchRequestDto request) { diff --git a/src/main/java/com/crrc/crrcmall/controller/SearchController.java b/src/main/java/com/crrc/crrcmall/controller/SearchController.java index cfabe45..bdf1e27 100644 --- a/src/main/java/com/crrc/crrcmall/controller/SearchController.java +++ b/src/main/java/com/crrc/crrcmall/controller/SearchController.java @@ -27,4 +27,10 @@ public class SearchController { public GoodsSearchResultVo searchByText(@RequestBody SearchGoodsRequestDto request) { return searchService.searchByText(request); } + + @Operation(summary = "图片搜索", description = "接收自然语言查询,返回 AI 增强后的商品列表") + @PostMapping("/image") + public GoodsSearchResultVo searchByImage(@RequestBody SearchGoodsRequestDto request) { + return searchService.searchByImage(request); + } } diff --git a/src/main/java/com/crrc/crrcmall/dto/audit/AuditBatchRequestDto.java b/src/main/java/com/crrc/crrcmall/dto/audit/AuditBatchRequestDto.java new file mode 100644 index 0000000..76f8624 --- /dev/null +++ b/src/main/java/com/crrc/crrcmall/dto/audit/AuditBatchRequestDto.java @@ -0,0 +1,35 @@ +package com.crrc.crrcmall.dto.audit; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 批量提交审核任务请求 DTO (v2) + */ +@Data +@Schema(description = "批量提交审核任务请求") +public class AuditBatchRequestDto implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "审核任务信息列表") + private List auditInfo; + + @Schema(description = "回调地址") + private String callbackUrl; + + @Data + public static class AuditInfo implements Serializable { + @Schema(description = "商品 ID") + private String goodsId; + + @Schema(description = "审核 ID") + private String auditId; + + @Schema(description = "审核类型: 1-新品审核 2-新品复审 3-调价审核") + private Integer type; + } +} diff --git a/src/main/java/com/crrc/crrcmall/dto/audit/AuditCheckRequestDto.java b/src/main/java/com/crrc/crrcmall/dto/audit/AuditCheckRequestDto.java index 37656c9..cd91682 100644 --- a/src/main/java/com/crrc/crrcmall/dto/audit/AuditCheckRequestDto.java +++ b/src/main/java/com/crrc/crrcmall/dto/audit/AuditCheckRequestDto.java @@ -4,10 +4,9 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serializable; -import java.util.List; /** - * AI 智能审核提交请求 DTO + * 提交审核任务请求 DTO (v2) */ @Data @Schema(description = "提交审核任务请求") @@ -18,9 +17,12 @@ public class AuditCheckRequestDto implements Serializable { @Schema(description = "商品 ID") private String goodsId; + @Schema(description = "审核 ID (客户系统唯一标识)") + private String auditId; + + @Schema(description = "审核类型: 1-新品审核 2-新品复审 3-调价审核") + private Integer type; + @Schema(description = "回调地址 (审核完成后通知客户)") private String callbackUrl; - - @Schema(description = "自定义审核项列表") - private List customList; } diff --git a/src/main/java/com/crrc/crrcmall/dto/audit/AuditSearchRequestDto.java b/src/main/java/com/crrc/crrcmall/dto/audit/AuditSearchRequestDto.java index 32ed440..51b780d 100644 --- a/src/main/java/com/crrc/crrcmall/dto/audit/AuditSearchRequestDto.java +++ b/src/main/java/com/crrc/crrcmall/dto/audit/AuditSearchRequestDto.java @@ -15,5 +15,5 @@ public class AuditSearchRequestDto implements Serializable { private static final long serialVersionUID = 1L; @Schema(description = "审核任务 ID") - private Long taskId; + private String taskId; } diff --git a/src/main/java/com/crrc/crrcmall/service/AuditRuleService.java b/src/main/java/com/crrc/crrcmall/service/AuditRuleService.java index fab36d4..a1a1209 100644 --- a/src/main/java/com/crrc/crrcmall/service/AuditRuleService.java +++ b/src/main/java/com/crrc/crrcmall/service/AuditRuleService.java @@ -1,11 +1,8 @@ package com.crrc.crrcmall.service; -import com.crrc.crrcmall.dto.audit.AuditContext; -import com.crrc.crrcmall.dto.audit.CustomItemRequestDto; +import com.crrc.crrcmall.dto.audit.AuditCheckRequestDto; import com.crrc.crrcmall.vo.audit.AuditDetailResponseVo; -import java.util.List; - /** * 审核规则引擎服务 * 负责执行 13 项具体的审核规则校验 @@ -14,9 +11,8 @@ public interface AuditRuleService { /** * 执行全套审核规则 (13 项) - * @param context 审核上下文数据 - * @param rawCustomList 原始请求列表 (用于回填) + * @param request 审核请求 (包含 auditId, goodsId, type) * @return 包含所有校验项结果的 VO */ - AuditDetailResponseVo executeAllRules(AuditContext context, List rawCustomList); + AuditDetailResponseVo executeAllRules(AuditCheckRequestDto request); } diff --git a/src/main/java/com/crrc/crrcmall/service/AuditService.java b/src/main/java/com/crrc/crrcmall/service/AuditService.java index a888504..3409120 100644 --- a/src/main/java/com/crrc/crrcmall/service/AuditService.java +++ b/src/main/java/com/crrc/crrcmall/service/AuditService.java @@ -1,5 +1,6 @@ package com.crrc.crrcmall.service; +import com.crrc.crrcmall.dto.audit.AuditBatchRequestDto; import com.crrc.crrcmall.dto.audit.AuditCheckRequestDto; import com.crrc.crrcmall.dto.audit.AuditSearchRequestDto; import com.crrc.crrcmall.vo.audit.AuditCheckResponseVo; @@ -11,10 +12,15 @@ import com.crrc.crrcmall.vo.audit.AuditDetailResponseVo; public interface AuditService { /** - * 提交审核任务 + * 提交审核任务 (单个) */ AuditCheckResponseVo submitAuditCheck(AuditCheckRequestDto request); + /** + * 提交审核任务 (批量) + */ + AuditCheckResponseVo submitAuditCheckBatch(AuditBatchRequestDto request); + /** * 查询审核结果 */ diff --git a/src/main/java/com/crrc/crrcmall/service/impl/AuditRuleServiceImpl.java b/src/main/java/com/crrc/crrcmall/service/impl/AuditRuleServiceImpl.java index 0abe0c2..f8a3545 100644 --- a/src/main/java/com/crrc/crrcmall/service/impl/AuditRuleServiceImpl.java +++ b/src/main/java/com/crrc/crrcmall/service/impl/AuditRuleServiceImpl.java @@ -1,8 +1,8 @@ package com.crrc.crrcmall.service.impl; -import com.crrc.crrcmall.config.RuleConfigProvider; +import com.crrc.crrcmall.common.mock.AuditMockDataGenerator; +import com.crrc.crrcmall.dto.audit.AuditCheckRequestDto; import com.crrc.crrcmall.dto.audit.AuditContext; -import com.crrc.crrcmall.dto.audit.CustomItemRequestDto; import com.crrc.crrcmall.service.AuditRuleService; import com.crrc.crrcmall.vo.audit.AuditDetailResponseVo; import lombok.extern.slf4j.Slf4j; @@ -16,278 +16,125 @@ import java.util.regex.Pattern; /** * 审核规则引擎实现类 + * 负责执行 13 项具体的审核规则校验 */ @Slf4j @Service public class AuditRuleServiceImpl implements AuditRuleService { @Autowired - private RuleConfigProvider ruleConfigProvider; + private AuditMockDataGenerator mockDataGenerator; @Override - public AuditDetailResponseVo executeAllRules(AuditContext context, List rawCustomList) { + public AuditDetailResponseVo executeAllRules(AuditCheckRequestDto request) { + // 1. 从 Mock 生成器获取商品数据 (模拟从数据库读取) + AuditContext context = mockDataGenerator.getGoodsContext(request.getAuditId()); + AuditDetailResponseVo response = new AuditDetailResponseVo(); - // TODO: 实际应生成 UUID + response.setType(request.getType()); response.setTaskId("TASK-MOCK-" + System.currentTimeMillis()); - response.setGoodsId(context.getGoodsId()); - - // 初始状态:假设全部通过,后续根据校验结果更新 - response.setStatus("SUCCESSED"); + response.setStatus(1); // 1: Completed - List results = new ArrayList<>(); + List groupList = new ArrayList<>(); + AuditDetailResponseVo.AuditGroupVo group = new AuditDetailResponseVo.AuditGroupVo(); + group.setAuditId(request.getAuditId()); + group.setGoodsId(request.getGoodsId()); - // 1. 校验商品名称 (规则 1) - AI - results.add(checkName(context)); + List detailList = new ArrayList<>(); - // 2. 校验商品条码 (规则 2) - 硬规则 - results.add(checkBarcode(context)); + // 2. 执行硬规则校验 (基于获取到的 Context 数据) + detailList.add(buildItem("barcode", "商品条码", context.getBarcode(), checkBarcode(context))); + detailList.add(buildItem("taxCode", "税码", context.getTaxCode(), checkTaxCode(context))); + detailList.add(buildItem("materialCode", "物料编码", context.getMaterialCode(), checkMaterialCode(context))); + detailList.add(buildItem("shippingFee", "运费", context.getShippingFee(), checkShipping(context))); + detailList.add(buildItem("deliveryArea", "配送区域", context.getDeliveryArea(), checkDeliveryArea(context))); - // 3. 校验品牌项 (规则 3) - AI - results.add(checkBrand(context)); + // 3. 执行 AI 规则模拟 (使用 Mock 生成器生成逼真的 AI 结果) + detailList.add(buildAiItem("goodsName", "商品名称", context.getGoodsName())); + detailList.add(buildAiItem("brandName", "品牌项", context.getBrandName())); + detailList.add(buildAiItem("imageUrls", "商品图片", context.getImageUrls())); + detailList.add(buildAiItem("description", "详情描述", context.getDescription())); - // 4. 校验税码 (规则 4) - 硬规则 - results.add(checkTaxCode(context)); - - // 5. 校验物料编码 (规则 5) - 硬规则 - results.add(checkMaterialCode(context)); - - // 6. 校验商品目录 (规则 6) - AI - results.add(checkCatalog(context)); - - // 7. 校验商品图片 (规则 7) - AI/Vision - results.add(checkImages(context)); - - // 8. 校验市场价格链接 (规则 8) - 爬虫/AI - results.add(checkMarketUrl(context)); - - // 9. 校验电脑端详情描述 (规则 9) - AI - results.add(checkDescription(context)); - - // 10. 校验京东价格链接 (规则 10) - 爬虫 - results.add(checkJdUrl(context)); - - // 11. 校验价格 (规则 11) - 硬规则 + TODO - results.add(checkPrice(context)); - - // 12. 校验运费 (规则 12) - 硬规则 - results.add(checkShipping(context)); - - // 13. 校验配送区域 (规则 13) - 硬规则 - results.add(checkDeliveryArea(context)); - - response.setCustomList(results); - - // 如果有任何一项 FAIL,则整体状态改为 FAIL - boolean hasFail = results.stream().anyMatch(r -> "FAIL".equals(r.getCheckStatus())); - if (hasFail) { - response.setStatus("FAIL"); - } + group.setAuditDetailList(detailList); + groupList.add(group); + response.setAuditList(groupList); return response; } + /** + * 构建硬规则结果项 + */ + private AuditDetailResponseVo.AuditDetailItemVo buildItem(String field, String name, Object value, RuleCheckResult result) { + AuditDetailResponseVo.AuditDetailItemVo item = new AuditDetailResponseVo.AuditDetailItemVo(); + item.setCustomField(field); + item.setCustomKey(name); + item.setCustomValue(value); + item.setAiIntent(result.message); + item.setAiRelevanceScore(result.score); + item.setCheckType(1); // 1: Hard Rule + item.setAiIntentType(1); + item.setAuditStatus(result.isSuccess ? 0 : 1); + return item; + } /** - * 规则 2:商品条码校验 - * 要求:条码真实有效,与商品信息一致;非必填项可为空。禁止:填写条码以外的数字、汉字、字母等内容。 + * 构建 AI 规则结果项 (模拟) */ - private AuditDetailResponseVo.CustomItemResponseVo checkBarcode(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("barcode", "商品条码"); + private AuditDetailResponseVo.AuditDetailItemVo buildAiItem(String field, String name, Object value) { + AuditMockDataGenerator.AiMockResult aiResult = mockDataGenerator.getAiMockResult(field, value); + AuditDetailResponseVo.AuditDetailItemVo item = new AuditDetailResponseVo.AuditDetailItemVo(); + item.setCustomField(field); + item.setCustomKey(name); + item.setCustomValue(value); + item.setAiIntent(aiResult.getMessage()); + item.setAiRelevanceScore(aiResult.getScore()); + item.setCheckType(2); // 2: AI Rule + item.setAiIntentType(1); + item.setAuditStatus(aiResult.isSuccess() ? 0 : 1); + return item; + } + + private record RuleCheckResult(boolean isSuccess, String message, double score) {} + + // ==================== 硬规则校验逻辑 ==================== + + private RuleCheckResult checkBarcode(AuditContext context) { String code = context.getBarcode(); - if (StringUtils.hasText(code)) { - // 校验规则:只能包含数字和字母 (正则) - // TODO: 实际业务可能需要调用第三方 API 校验条码真实性 - boolean isValid = Pattern.matches("^[a-zA-Z0-9]+$", code); - if (!isValid) { - res.setCheckStatus("FAIL"); - res.setAiIntent("条码包含非法字符(如汉字或特殊符号)"); - } else { - res.setCheckStatus("PASS"); - res.setAiIntent("格式校验通过"); - } - } else { - res.setCheckStatus("PASS"); // 非必填 - res.setAiIntent("条码为空,跳过校验"); + if (StringUtils.hasText(code) && Pattern.matches("^[a-zA-Z0-9]+$", code)) { + return new RuleCheckResult(true, "格式校验通过", 1.0); } - return res; + return new RuleCheckResult(false, "条码格式错误 (含非法字符)", 0.0); } - /** - * 规则 4:税码校验 - * 要求:税码分类正确,且不得为空。 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkTaxCode(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("taxCode", "税码"); - if (!StringUtils.hasText(context.getTaxCode())) { - res.setCheckStatus("FAIL"); - res.setAiIntent("税码不能为空"); - } else { - res.setCheckStatus("PASS"); - res.setAiIntent("税码已填写"); + private RuleCheckResult checkTaxCode(AuditContext context) { + if (StringUtils.hasText(context.getTaxCode())) { + return new RuleCheckResult(true, "税码已填写", 1.0); } - return res; + return new RuleCheckResult(false, "税码不能为空", 0.0); } - /** - * 规则 5:物料编码校验 - * 要求:工业品以 DM 开头,办公用品以 DB 开头。 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkMaterialCode(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("materialCode", "物料编码"); + private RuleCheckResult checkMaterialCode(AuditContext context) { String code = context.getMaterialCode(); + String prefix = "OFFICE".equalsIgnoreCase(context.getProductType()) ? "DB" : "DM"; - if (!StringUtils.hasText(code)) { - res.setCheckStatus("FAIL"); - res.setAiIntent("物料编码不能为空"); - return res; + if (StringUtils.hasText(code) && code.startsWith(prefix)) { + return new RuleCheckResult(true, "物料编码前缀正确 (" + prefix + ")", 1.0); } + return new RuleCheckResult(false, "物料编码前缀错误 (期望 " + prefix + " 开头)", 0.0); + } - // 获取当前商品类别的期望前缀 (从配置读取) - String expectedPrefix = ruleConfigProvider.getMaterialCodePrefix(context.getProductType()); - - if (code.startsWith(expectedPrefix)) { - res.setCheckStatus("PASS"); - res.setAiIntent("物料编码前缀正确 (" + expectedPrefix + ")"); - } else { - res.setCheckStatus("FAIL"); - res.setAiIntent("物料编码前缀错误。当前类目 [" + context.getProductType() + "] 期望以 [" + expectedPrefix + "] 开头"); + private RuleCheckResult checkShipping(AuditContext context) { + if ("全国包邮".equals(context.getShippingFee())) { + return new RuleCheckResult(true, "运费符合标准", 1.0); } - return res; + return new RuleCheckResult(false, "运费不符合要求", 0.0); } - /** - * 规则 12:运费校验 - * 要求:全国包邮 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkShipping(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("shippingFee", "运费"); - String required = ruleConfigProvider.getRequiredShippingFee(); - - if (required.equals(context.getShippingFee())) { - res.setCheckStatus("PASS"); - res.setAiIntent("运费配置符合标准"); - } else { - res.setCheckStatus("FAIL"); - res.setAiIntent("运费不符合要求,应为 [" + required + "]"); + private RuleCheckResult checkDeliveryArea(AuditContext context) { + if ("不限配送区域".equals(context.getDeliveryArea())) { + return new RuleCheckResult(true, "配送区域符合标准", 1.0); } - return res; - } - - /** - * 规则 13:配送区域校验 - * 要求:不限配送区域 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkDeliveryArea(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("deliveryArea", "配送区域"); - String required = ruleConfigProvider.getRequiredDeliveryArea(); - - if (required.equals(context.getDeliveryArea())) { - res.setCheckStatus("PASS"); - res.setAiIntent("配送区域符合标准"); - } else { - res.setCheckStatus("FAIL"); - res.setAiIntent("配送区域不符合要求,应为 [" + required + "]"); - } - return res; - } - - - /** - * 1. 校验结构 [品牌 + 名称 + 型号 + 规格] - * 2. 校验违禁词 (从 RuleConfigProvider 获取配置) - */ - private AuditDetailResponseVo.CustomItemResponseVo checkName(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("goodsName", "商品名称"); - // TODO: 1. 校验结构 [品牌 + 名称 + 型号 + 规格] - // TODO: 2. 校验违禁词 (从 RuleConfigProvider 获取配置) - res.setCheckStatus("WAITING"); - res.setAiIntent("待 AI 语义分析"); - return res; - } - - /** - * 校验品牌项与商品名称中的品牌是否一致 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkBrand(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("brandName", "品牌项"); - // TODO: 校验品牌项与商品名称中的品牌是否一致 - res.setCheckStatus("WAITING"); - res.setAiIntent("待 AI 比对"); - return res; - } - - /** - * 校验类目归属合理性,防跨类 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkCatalog(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("catalogId", "商品目录"); - // TODO: 校验类目归属合理性,防跨类 - res.setCheckStatus("WAITING"); - res.setAiIntent("待 AI 类目映射"); - return res; - } - - /** - * 校验商品图片清晰度、无二维码、无违规 Logo - */ - private AuditDetailResponseVo.CustomItemResponseVo checkImages(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("imageUrls", "商品图片"); - // TODO: 调用 Qwen-VL 校验图片清晰度、无二维码、无违规 Logo - res.setCheckStatus("WAITING"); - res.setAiIntent("待视觉模型分析"); - return res; - } - - /** - * 校验链接有效性,是否为官网 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkMarketUrl(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("marketPriceUrl", "市场价格链接"); - // TODO: 校验链接有效性,是否为官网 - res.setCheckStatus("WAITING"); - res.setAiIntent("待爬虫校验"); - return res; - } - - /** - * 校验描述真实性、无夸大、无违禁词 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkDescription(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("description", "电脑端详情描述"); - // TODO: 校验描述真实性、无夸大、无违禁词 - res.setCheckStatus("WAITING"); - res.setAiIntent("待 AI 文本分析"); - return res; - } - - /** - * 校验是否为京东自营链接,是否有效 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkJdUrl(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("jdPriceUrl", "京东价格链接"); - // TODO: 校验是否为京东自营链接,是否有效 - res.setCheckStatus("WAITING"); - res.setAiIntent("待京东链接校验"); - return res; - } - - /** - * 校验 价格 <= 入围价格 - */ - private AuditDetailResponseVo.CustomItemResponseVo checkPrice(AuditContext context) { - AuditDetailResponseVo.CustomItemResponseVo res = buildBaseVo("price", "价格 [单价]"); - // TODO: 校验 价格 <= 入围价格 - // TODO: 获取 context.getTargetPrice() 进行比对 - res.setCheckStatus("WAITING"); - res.setAiIntent("待入围价格数据接入后校验"); - return res; - } - - private AuditDetailResponseVo.CustomItemResponseVo buildBaseVo(String field, String name) { - AuditDetailResponseVo.CustomItemResponseVo vo = new AuditDetailResponseVo.CustomItemResponseVo(); - vo.setCustomField(field); - vo.setCustomKey(name); - vo.setCheckStatus("PASS"); // 默认通过,失败时在具体方法中修改 - return vo; + return new RuleCheckResult(false, "配送区域不符合要求", 0.0); } } diff --git a/src/main/java/com/crrc/crrcmall/service/impl/AuditServiceImpl.java b/src/main/java/com/crrc/crrcmall/service/impl/AuditServiceImpl.java index 6bf235b..16fdaf9 100644 --- a/src/main/java/com/crrc/crrcmall/service/impl/AuditServiceImpl.java +++ b/src/main/java/com/crrc/crrcmall/service/impl/AuditServiceImpl.java @@ -1,9 +1,8 @@ package com.crrc.crrcmall.service.impl; +import com.crrc.crrcmall.dto.audit.AuditBatchRequestDto; import com.crrc.crrcmall.dto.audit.AuditCheckRequestDto; -import com.crrc.crrcmall.dto.audit.AuditContext; import com.crrc.crrcmall.dto.audit.AuditSearchRequestDto; -import com.crrc.crrcmall.dto.audit.CustomItemRequestDto; import com.crrc.crrcmall.entity.AuditTask; import com.crrc.crrcmall.service.AuditRuleService; import com.crrc.crrcmall.service.AuditService; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDateTime; -import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -39,10 +37,7 @@ public class AuditServiceImpl implements AuditService { public AuditCheckResponseVo submitAuditCheck(AuditCheckRequestDto request) { String taskId = UUID.randomUUID().toString().replace("-", ""); - // 1. 数据转换:将 customList 转换为结构化 Context - AuditContext context = convertToContext(request); - - // 2. 创建任务记录 (模拟 INSERT INTO audit_task) + // 1. 创建任务记录 AuditTask task = new AuditTask(); task.setTaskId(taskId); task.setGoodsId(request.getGoodsId()); @@ -51,21 +46,20 @@ public class AuditServiceImpl implements AuditService { task.setCreateTime(LocalDateTime.now()); TASK_DB.put(taskId, task); - // 3. 异步执行审核 + // 2. 异步执行审核 CompletableFuture.runAsync(() -> { try { - log.info("开始异步审核任务: {}", taskId); - // 调用规则引擎 - AuditDetailResponseVo result = auditRuleService.executeAllRules(context, request.getCustomList()); - result.setTaskId(taskId); // 绑定 TaskId + log.info("开始异步审核任务: {}, Type: {}, AuditId: {}", taskId, request.getType(), request.getAuditId()); + + // 调用规则引擎 (内部会使用 MockDataGenerator 生成数据) + AuditDetailResponseVo result = auditRuleService.executeAllRules(request); + + // 保存结果 + RESULT_DB.put(taskId, result); - // 更新任务状态 task.setStatus("COMPLETED"); task.setCompleteTime(LocalDateTime.now()); - // 保存结果 (模拟 INSERT INTO audit_result_detail) - RESULT_DB.put(taskId, result); - // TODO: 触发 Callback 通知客户 // httpClient.post(request.getCallbackUrl(), result); @@ -75,7 +69,44 @@ public class AuditServiceImpl implements AuditService { } }); - // 4. 立即返回 + // 3. 立即返回 + AuditCheckResponseVo response = new AuditCheckResponseVo(); + response.setTaskId(taskId); + response.setStatus("ACCEPTED"); + return response; + } + + @Override + public AuditCheckResponseVo submitAuditCheckBatch(AuditBatchRequestDto request) { + String taskId = UUID.randomUUID().toString().replace("-", ""); + + AuditTask task = new AuditTask(); + task.setTaskId(taskId); + task.setStatus("PROCESSING"); + task.setCreateTime(LocalDateTime.now()); + TASK_DB.put(taskId, task); + + CompletableFuture.runAsync(() -> { + try { + log.info("开始批量异步审核任务: {}, Count: {}", taskId, request.getAuditInfo().size()); + for (AuditBatchRequestDto.AuditInfo info : request.getAuditInfo()) { + AuditCheckRequestDto singleReq = new AuditCheckRequestDto(); + singleReq.setGoodsId(info.getGoodsId()); + singleReq.setAuditId(info.getAuditId()); + singleReq.setType(info.getType()); + singleReq.setCallbackUrl(request.getCallbackUrl()); + + AuditDetailResponseVo result = auditRuleService.executeAllRules(singleReq); + RESULT_DB.put(taskId + "_" + info.getAuditId(), result); + } + task.setStatus("COMPLETED"); + task.setCompleteTime(LocalDateTime.now()); + } catch (Exception e) { + log.error("批量审核任务执行失败: {}", taskId, e); + task.setStatus("FAILED"); + } + }); + AuditCheckResponseVo response = new AuditCheckResponseVo(); response.setTaskId(taskId); response.setStatus("ACCEPTED"); @@ -85,50 +116,6 @@ public class AuditServiceImpl implements AuditService { @Override public AuditDetailResponseVo getAuditResult(AuditSearchRequestDto request) { // 从模拟 DB 中查询 - return RESULT_DB.getOrDefault(String.valueOf(request.getTaskId()), null); - } - - /** - * 辅助方法:将 Key-Value 列表转换为结构化对象 - */ - private AuditContext convertToContext(AuditCheckRequestDto request) { - AuditContext context = new AuditContext(); - context.setGoodsId(request.getGoodsId()); - context.setCallbackUrl(request.getCallbackUrl()); - - if (request.getCustomList() != null) { - for (CustomItemRequestDto item : request.getCustomList()) { - String key = item.getCustomField(); - Object value = item.getCustomValue(); - - // 简单的映射逻辑 (实际可根据 customType 进一步细分) - switch (key) { - case "goodsName": context.setGoodsName(String.valueOf(value)); break; - case "barcode": context.setBarcode(String.valueOf(value)); break; - case "brandName": context.setBrandName(String.valueOf(value)); break; - case "taxCode": context.setTaxCode(String.valueOf(value)); break; - case "materialCode": context.setMaterialCode(String.valueOf(value)); break; - case "catalogId": - if (value instanceof Number) context.setCatalogId(((Number) value).longValue()); - break; - case "imageUrls": - // 假设传入的是逗号分隔的字符串或 List - if (value instanceof List) context.setImageUrls((List) value); - else if (value instanceof String) context.setImageUrls(List.of((String) value)); - break; - case "description": context.setDescription(String.valueOf(value)); break; - case "marketPriceUrl": context.setMarketPriceUrl(String.valueOf(value)); break; - case "jdPriceUrl": context.setJdPriceUrl(String.valueOf(value)); break; - case "price": - if (value instanceof Number) context.setPrice(((Number) value).doubleValue()); - break; - case "shippingFee": context.setShippingFee(String.valueOf(value)); break; - case "deliveryArea": context.setDeliveryArea(String.valueOf(value)); break; - case "productType": context.setProductType(String.valueOf(value)); break; - // TODO: 其他字段映射 - } - } - } - return context; + return RESULT_DB.getOrDefault(request.getTaskId(), null); } } diff --git a/src/main/java/com/crrc/crrcmall/service/impl/SearchServiceImpl.java b/src/main/java/com/crrc/crrcmall/service/impl/SearchServiceImpl.java index 2dba1b8..3a70423 100644 --- a/src/main/java/com/crrc/crrcmall/service/impl/SearchServiceImpl.java +++ b/src/main/java/com/crrc/crrcmall/service/impl/SearchServiceImpl.java @@ -1,41 +1,33 @@ package com.crrc.crrcmall.service.impl; +import com.crrc.crrcmall.common.mock.SearchMockDataGenerator; import com.crrc.crrcmall.dto.crrc.SearchGoodsRequestDto; import com.crrc.crrcmall.service.SearchService; import com.crrc.crrcmall.vo.crrc.GoodsSearchResultVo; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.ArrayList; - /** - * 搜索服务实现类 + * 搜索服务实现类 (Demo 模式) + * 目前通过 Mock 数据生成器返回搜索结果,方便演示 AI 搜索效果 */ @Slf4j @Service public class SearchServiceImpl implements SearchService { + @Autowired + private SearchMockDataGenerator mockDataGenerator; + @Override public GoodsSearchResultVo searchByText(SearchGoodsRequestDto request) { - // TODO: 1. 调用 AI 意图识别模块 - // TODO: 2. 调用 ES 混合检索 - // TODO: 3. 组装数据 - - // 目前返回空数据结构 - GoodsSearchResultVo result = new GoodsSearchResultVo(); - result.setGoodsList(new ArrayList<>()); - result.setBrandList(new ArrayList<>()); - result.setCatalogList(new ArrayList<>()); - - return result; + log.info("执行 AI 文本搜索,关键词:{}", request.getGoodsName()); + // 调用 Mock 生成器返回演示数据 + return mockDataGenerator.generateResult(request); } @Override public GoodsSearchResultVo searchByImage(SearchGoodsRequestDto request) { - // TODO: 1. 图片向量化 - // TODO: 2. 调用 ES 混合检索 - // TODO: 3. 组装数据 - - return new GoodsSearchResultVo(); + return mockDataGenerator.generateResult(request); } } diff --git a/src/main/java/com/crrc/crrcmall/vo/ai/AiSearchInfoVo.java b/src/main/java/com/crrc/crrcmall/vo/ai/AiSearchInfoVo.java index 2513f69..65e8865 100644 --- a/src/main/java/com/crrc/crrcmall/vo/ai/AiSearchInfoVo.java +++ b/src/main/java/com/crrc/crrcmall/vo/ai/AiSearchInfoVo.java @@ -1,9 +1,5 @@ package com.crrc.crrcmall.vo.ai; -/** - * @Author:Jinyun.Wang - * @Date:2026/11/2 - **/ import com.crrc.crrcmall.common.enums.MatchTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/src/main/java/com/crrc/crrcmall/vo/audit/AuditDetailResponseVo.java b/src/main/java/com/crrc/crrcmall/vo/audit/AuditDetailResponseVo.java index a3ec9db..7a590ff 100644 --- a/src/main/java/com/crrc/crrcmall/vo/audit/AuditDetailResponseVo.java +++ b/src/main/java/com/crrc/crrcmall/vo/audit/AuditDetailResponseVo.java @@ -7,7 +7,7 @@ import java.io.Serializable; import java.util.List; /** - * 审核详情响应 VO + * 审核详情响应 VO (v2 - 嵌套结构) */ @Data @Schema(description = "审核详情响应") @@ -15,22 +15,32 @@ public class AuditDetailResponseVo implements Serializable { private static final long serialVersionUID = 1L; - @Schema(description = "任务 ID") + @Schema(description = "审核类型: 1-新品审核 2-新品复审 3-调价审核") + private Integer type; + + @Schema(description = "审核任务 ID") private String taskId; - @Schema(description = "商品 ID") - private String goodsId; + @Schema(description = "状态: 1 已完成 2 未检测") + private Integer status; - @Schema(description = "状态: SUCCESSED/WAITING") - private String status; - - @Schema(description = "审核明细列表") - private List customList; + @Schema(description = "审核分组列表 (按 auditId 分组)") + private List auditList; @Data - public static class CustomItemResponseVo implements Serializable { - @Schema(description = "类型") - private String type; + public static class AuditGroupVo implements Serializable { + @Schema(description = "商品 ID") + private String goodsId; + + @Schema(description = "审核 ID") + private String auditId; + + @Schema(description = "审核明细列表") + private List auditDetailList; + } + + @Data + public static class AuditDetailItemVo implements Serializable { @Schema(description = "字段标识") private String customField; @Schema(description = "字段显示名") @@ -41,13 +51,13 @@ public class AuditDetailResponseVo implements Serializable { private Object customType; @Schema(description = "AI 反馈") private String aiIntent; - @Schema(description = "AI 反馈类型") + @Schema(description = "AI 反馈类型: 1-格式 2-逻辑 3-图片") private Integer aiIntentType; @Schema(description = "AI 匹配度") private Double aiRelevanceScore; - @Schema(description = "规则类型") + @Schema(description = "规则类型: 1-硬规则 2-AI 规则") private Integer checkType; - @Schema(description = "规则类型") - private String checkStatus; + @Schema(description = "检测状态: 0 成功 1 失败") + private Integer auditStatus; } } diff --git a/src/main/java/com/crrc/crrcmall/vo/crrc/GoodsSearchResultVo.java b/src/main/java/com/crrc/crrcmall/vo/crrc/GoodsSearchResultVo.java index b5ab7ff..b5410fa 100644 --- a/src/main/java/com/crrc/crrcmall/vo/crrc/GoodsSearchResultVo.java +++ b/src/main/java/com/crrc/crrcmall/vo/crrc/GoodsSearchResultVo.java @@ -46,4 +46,7 @@ public class GoodsSearchResultVo implements Serializable { @Schema(description = "ai规则说明") private AiSearchInfoVo aiSearchInfo; + + @Schema(description = "条数") + private int total; }