瀏覽代碼

feat(job): 新增AI自动审核与风控任务

- 实现AI自动审核任务(aiCheckJobHandler),定时处理用户违规举报记录
- 添加二手商品风控记录审核任务(riskControlCheckJobHandler)
- 引入RestTemplate和相关实体映射,支持HTTP接口调用
- 配置第三方登录接口及认证信息获取逻辑
- 新增店铺AI审核任务(aiApproveStoreInfoTask),处理待审核门店数据
- 构建审核请求体并调用AI服务接口进行自动审核
- 添加日志记录与异常处理机制,确保任务稳定运行
Lhaibo 1 周之前
父節點
當前提交
c843eb789c

+ 199 - 1
alien-job/src/main/java/shop/alien/job/second/AiCheckXxlJob.java

@@ -1,19 +1,217 @@
 package shop.alien.job.second;
 
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.http.*;
+import shop.alien.entity.second.SecondGoodsRecord;
+import shop.alien.entity.second.SecondRiskControlRecord;
+import shop.alien.entity.store.LifeUser;
+import shop.alien.entity.store.LifeUserViolation;
+import shop.alien.entity.store.StoreDictionary;
+import shop.alien.mapper.LifeUserMapper;
+import shop.alien.mapper.LifeUserViolationMapper;
+import shop.alien.mapper.StoreDictionaryMapper;
+import shop.alien.mapper.second.SecondGoodsRecordMapper;
+import shop.alien.mapper.second.SecondRiskControlRecordMapper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * @author Lhaibo
  * @date 2025/11/28
- * @since 1.0.0
  * @desc: xxl-job
  * AI调用审核任务
+ * @since 1.0.0
  */
 @Slf4j
 @Component
 @RequiredArgsConstructor
 public class AiCheckXxlJob {
 
+    // 添加RestTemplate用于HTTP调用
+    private final RestTemplate restTemplate;
+
+    private final LifeUserViolationMapper lifeUserViolationMapper;
+
+    private final StoreDictionaryMapper storeDictionaryMapper;
+
+    private final LifeUserMapper lifeUserMapper;
+
+    private final SecondGoodsRecordMapper secondGoodsRecordMapper;
+
+    private final SecondRiskControlRecordMapper secondRiskControlRecordMapper;
+
+    // 第三方接口地址 登录接口URL
+    @Value("${third-party-login.base-url}")
+    private String loginUrl;
+
+    //用户名
+    @Value("${third-party-user-name.base-url}")
+    private String userName;
+
+    //密码
+    @Value("${third-party-pass-word.base-url}")
+    private String passWord;
+
+    /**
+     * AI自动审核任务处理器
+     * <p>
+     * 定时任务方法,用于批量处理用户违规举报记录,通过AI接口进行自动审核。
+     * 主要流程:
+     * 1. 查询所有待处理的用户违规记录
+     * 2. 遍历每条记录,组装审核请求数据
+     * 3. 调用AI审核接口进行自动审核(当前代码中已准备请求体,待实现接口调用)
+     * </p>
+     *
+     * @author Lhaibo
+     * @date 2025/11/28
+     * @since 1.0.0
+     */
+    @XxlJob("aiCheckJobHandler")
+    public void aiCheckJobHandler() {
+        log.info("开始执行AI自动审核任务");
+
+        try {
+            log.info("登录Ai服务获取token..." + loginUrl);
+            //构建请求参数
+            MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+            formData.add("username", "admin");    // 表单字段 1:用户名
+            formData.add("password", "123456");    // 表单字段 2:密码
+
+            //设置请求头
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+            HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
+            ResponseEntity<String> postForEntity = null;
+            try {
+                postForEntity = restTemplate.postForEntity("http://192.168.2.78:9000/ai/user-auth-core/api/v1/auth/login", requestEntity, String.class);
+            } catch (Exception e) {
+                log.error("类:PostMethod 方法:post", e);
+            }
+
+            if (postForEntity != null) {
+                if (postForEntity.getStatusCodeValue() == 200) {
+                    log.info("请求Ai服务登录成功 postForEntity.getBody()\t" + postForEntity.getBody());
+                    String responseBody = postForEntity.getBody();
+                    JSONObject jsonObject = JSONObject.parseObject(responseBody);
+                    JSONObject dataJson = jsonObject.getJSONObject("data");
+                    String accessToken = dataJson.getString("access_token");
+                    // 查询所有待处理的用户违规记录
+                    List<LifeUserViolation> lifeUserViolations = lifeUserViolationMapper.selectList(new LambdaQueryWrapper<LifeUserViolation>().eq(LifeUserViolation::getProcessingStatus, "5"));
+
+                    // 遍历每条违规记录,组装AI审核请求数据
+                    for (LifeUserViolation violation : lifeUserViolations) {
+                        // 初始化请求体Map
+                        Map<String, Object> requestBody = new HashMap<>();
+
+                        // 设置投诉记录ID
+                        requestBody.put("complaint_id", violation.getId());
+
+                        // 查询投诉类型字典信息
+                        StoreDictionary storeDictionary = storeDictionaryMapper.selectOne(new LambdaQueryWrapper<StoreDictionary>()
+                                .eq(StoreDictionary::getTypeName, violation.getDictId()).eq(StoreDictionary::getTypeName, violation.getDictType()));
+                        String complaint_type = "";
+                        if (storeDictionary != null) {
+                            // 设置投诉类型
+                            complaint_type = storeDictionary.getDictDetail();
+                        }
+                        requestBody.put("complaint_type", complaint_type);
+                        // 设置举报人信息
+                        requestBody.put("reporter_user_id", violation.getReportingUserId());
+                        requestBody.put("reporter_user_type", violation.getReportingUserType());
+                        requestBody.put("reporter_info", lifeUserMapper.selectById(violation.getReportingUserId()));
+
+                        // 查询被举报的商品记录
+                        SecondGoodsRecord secondGoodsRecord = secondGoodsRecordMapper.selectById(violation.getBusinessId());
+                        if (secondGoodsRecord != null) {
+                            // 设置被举报人信息
+                            requestBody.put("reported_user_id", secondGoodsRecord.getUserId());
+                            requestBody.put("reported_user_type", "");
+                            requestBody.put("reported_info", lifeUserMapper.selectById(secondGoodsRecord.getUserId()));
+                            requestBody.put("product_name", secondGoodsRecord.getTitle());
+                        }
+                        // 设置商品相关信息
+                        requestBody.put("product_info", secondGoodsRecord);
+                        requestBody.put("product_id", violation.getBusinessId());
+
+                        // 设置投诉文本内容
+                        requestBody.put("complaint_text", violation.getOtherReasonContent());
+
+                        // 设置证据图片数组(将逗号分隔的字符串转换为数组)
+                        requestBody.put("evidence_images", violation.getReportEvidenceImg() != null ? violation.getReportEvidenceImg().split(",") : new String[0]);
+
+                        HttpHeaders aiHeaders = new HttpHeaders();
+                        aiHeaders.setContentType(MediaType.APPLICATION_JSON);
+                        aiHeaders.set("Authorization", "Bearer " + accessToken);
+
+                        System.out.println(requestBody);
+                        HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, aiHeaders);
+                        ResponseEntity<String> response = null;
+                        try {
+                            response = restTemplate.postForEntity("http://192.168.2.78:9000/ai/auto-review/api/v1/product_complaint_record/submit", request, String.class);
+                            log.info("AI自动审核结果:{}", response.getBody());
+                        } catch (Exception e) {
+                            log.error("AI自动审核请求异常", e);
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("AI自动审核任务执行异常", e);
+        }
+
+        log.info("AI自动审核任务执行完成");
+    }
+
+    /**
+     * 二手商品风控记录审核任务
+     * <p>
+     * 定时查询风控记录表中待处理的数据(risk_status = 0),
+     * 预留后续风控审核/处理逻辑(如调用 AI 服务、通知运营等)。
+     * </p>
+     */
+    @XxlJob("riskControlCheckJobHandler")
+    public void riskControlCheckJobHandler() {
+        log.info("开始执行二手商品风控记录审核任务");
+
+        try {
+            // 查询风控记录表中待处理的记录(risk_status = 0)
+            List<SecondRiskControlRecord> riskControlRecords = secondRiskControlRecordMapper.selectList(
+                    new LambdaQueryWrapper<SecondRiskControlRecord>()
+                            .eq(SecondRiskControlRecord::getRiskStatus, 0)
+            );
+
+            log.info("本次待处理风控记录数量:{}", riskControlRecords.size());
+
+            // 按 ruleType 和 businessId 进行分组,生成新的嵌套结构
+            List<Map<String, List<SecondRiskControlRecord>>> groupedByRuleAndBusiness =
+                    (List<Map<String, List<SecondRiskControlRecord>>>) riskControlRecords.stream()
+                            .collect(Collectors.groupingBy(
+                                    SecondRiskControlRecord::getRuleType,
+                                    Collectors.groupingBy(SecondRiskControlRecord::getBusinessId)
+                            )).values();
+
+            for (Map<String, List<SecondRiskControlRecord>> byRuleAndBusiness : groupedByRuleAndBusiness) {
+
+
+            }
+        } catch (Exception e) {
+            log.error("二手商品风控记录审核任务执行异常", e);
+        }
+
+        log.info("二手商品风控记录审核任务执行完成");
+    }
 }

+ 102 - 0
alien-job/src/main/java/shop/alien/job/store/AiTagJob.java

@@ -17,6 +17,7 @@ import org.springframework.util.MultiValueMap;
 import org.springframework.web.client.RestTemplate;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
+import shop.alien.entity.store.vo.AiApproveStoreInfo;
 import shop.alien.mapper.*;
 
 import java.time.LocalDate;
@@ -48,6 +49,8 @@ public class AiTagJob {
 
     private final StoreClockInMapper storeClockInMapper;
 
+    private final StoreInfoMapper storeInfoMapper;
+
     // 第三方接口地址 获取所有标签主表信息
     @Value("${third-party-tag.base-url}")
     private String tagMainUrl;
@@ -898,6 +901,105 @@ public class AiTagJob {
         return R.success("动态内容审核任务结果获取执行成功");
     }
 
+    /**
+     * 店铺AI审核任务
+     * <p>
+     * 定时查询 store_info 表中审核状态为 0(待审核)的门店,
+     * 后续可在此处调用 AI 审核接口进行自动审核。
+     * </p>
+     */
+    @XxlJob("aiApproveStoreInfoTask")
+    public R<String> aiApproveStoreInfoTask() {
+        log.info("开始执行店铺AI审核任务...");
+        try {
+            // 1. 查询待审核门店:store_application_status = 0 且 未删除
+            List<StoreInfo> pendingStores = storeInfoMapper.selectList(
+                    new LambdaQueryWrapper<StoreInfo>()
+                            .eq(StoreInfo::getStoreApplicationStatus, 0)
+                            .eq(StoreInfo::getDeleteFlag, 0)
+            );
+
+            if (pendingStores == null || pendingStores.isEmpty()) {
+                log.info("当前无待审核门店,任务结束。");
+                XxlJobHelper.handleSuccess("当前无待审核门店");
+                return R.success("当前无待审核门店");
+            }
+
+            log.info("本次待审核门店数量:{}", pendingStores.size());
+
+            // 2. 登录 AI 服务获取 token(如需调用 AI 审核接口,可在此处复用 token)
+            MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+            formData.add("username", userName);
+            formData.add("password", passWord);
+
+            HttpHeaders loginHeaders = new HttpHeaders();
+            loginHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+            HttpEntity<MultiValueMap<String, String>> loginRequest = new HttpEntity<>(formData, loginHeaders);
+
+            ResponseEntity<String> loginResponse = null;
+            try {
+                log.info("请求Ai服务登录接口===================> {}", loginUrl);
+                loginResponse = restTemplate.postForEntity(loginUrl, loginRequest, String.class);
+            } catch (Exception e) {
+                log.error("请求AI服务登录接口失败", e);
+            }
+
+            String accessToken = null;
+            if (loginResponse != null && loginResponse.getStatusCodeValue() == 200) {
+                log.info("请求Ai服务登录成功 body={}", loginResponse.getBody());
+                String body = loginResponse.getBody();
+                if (body != null) {
+                    JSONObject jsonObject = JSONObject.parseObject(body);
+                    if (jsonObject != null) {
+                        JSONObject dataJson = jsonObject.getJSONObject("data");
+                        if (dataJson != null) {
+                            accessToken = dataJson.getString("access_token");
+                        }
+                    }
+                }
+            }
+
+            if (accessToken == null) {
+                log.error("获取AI服务 access_token 失败,终止店铺AI审核任务");
+                XxlJobHelper.handleFail("获取AI服务 access_token 失败");
+                return R.fail("获取AI服务 access_token 失败");
+            }
+
+            // 3. 遍历待审核门店,构建 AiApproveStoreInfo 并预留调用 AI 审核接口(具体字段后续补充)
+            HttpHeaders aiHeaders = new HttpHeaders();
+            aiHeaders.setContentType(MediaType.APPLICATION_JSON);
+            aiHeaders.set("Authorization", "Bearer " + accessToken);
+
+            for (StoreInfo storeInfo : pendingStores) {
+                AiApproveStoreInfo aiApproveStoreInfo = new AiApproveStoreInfo();
+
+                HttpEntity<AiApproveStoreInfo> request = new HttpEntity<>(aiApproveStoreInfo, aiHeaders);
+                ResponseEntity<String> response = null;
+                try {
+                    response = restTemplate.postForEntity("http://192.168.2.250:9000/ai/auto-review/api/v1/merchant-onboarding/applications", request, String.class);
+                    if (response.getStatusCodeValue() != 200) {
+                        log.error("店铺AI审核接口调用失败 storeId={}, http状态={}", storeInfo.getId(), response.getStatusCode());
+                        continue;
+                    }
+                    String respBody = response.getBody();
+                    log.info("店铺AI审核返回结果 storeId={}, body={}", storeInfo.getId(), respBody);
+                    // 如需根据 AI 返回结果更新 store_info 审核状态,可在此处解析 respBody 并更新 DB
+                } catch (Exception e) {
+                    log.error("调用店铺AI审核接口异常, storeId={}", storeInfo.getId(), e);
+                }
+            }
+
+            XxlJobHelper.handleSuccess("店铺AI审核任务执行完成");
+            return R.success("店铺AI审核任务执行完成");
+        } catch (Exception e) {
+            log.error("店铺AI审核任务执行异常", e);
+            XxlJobHelper.handleFail("店铺AI审核任务执行异常: " + e.getMessage());
+            return R.fail("店铺AI审核任务执行异常: " + e.getMessage());
+        }
+    }
+
+
+
     class AnalysisRequest {
         private String start_time;
         private String end_time;