13
0

2 Commits 2702237b51 ... b3050220e7

Autor SHA1 Nachricht Datum
  Lhaibo b3050220e7 feat(store): 增加AI审核相关字段支持 vor 2 Wochen
  Lhaibo 71bb60ab2e feat(job): 新增AI自动审核与风控任务 vor 1 Woche

+ 29 - 0
alien-entity/src/main/java/shop/alien/entity/store/LifeUserDynamics.java

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -112,4 +113,32 @@ public class LifeUserDynamics {
     @ApiModelProperty(value = "启用状态0-启用,1-禁用")
     @TableField("enable_status")
     private Integer enableStatus;
+
+    @ApiModelProperty(value = "达人id")
+    @TableField("expert_id")
+    private Integer expertId;
+
+    @ApiModelProperty(value = "业务id")
+    @TableField("business_id")
+    private Integer businessId;
+
+    @ApiModelProperty(value = "转发量")
+    @TableField("transfer_count")
+    private Integer transferCount;
+
+    @ApiModelProperty(value = "达人动态实际浏览数")
+    @TableField("reality_count")
+    private Integer realityCount;
+
+    @ApiModelProperty(value = "是否审核(未审核:0,审核中:1,审核完成:2)")
+    @TableField("check_flag")
+    private Integer checkFlag;
+
+    @ApiModelProperty(value = "AI审核结果查询id")
+    @TableField("ai_task_id")
+    private String aiTaskId;
+
+    @ApiModelProperty(value = "审核失败原因")
+    @TableField("reason")
+    private String reason;
 }

+ 12 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreClockIn.java

@@ -83,6 +83,18 @@ public class StoreClockIn extends Model<StoreClockIn> {
     @TableField(value = "updated_user_id", fill = FieldFill.INSERT_UPDATE)
     private Integer updatedUserId;
 
+    @ApiModelProperty(value = "是否审核(未审核:0,审核中:1,审核完成:2)")
+    @TableField("check_flag")
+    private Integer checkFlag;
+
+    @ApiModelProperty(value = "AI审核结果查询id")
+    @TableField("ai_task_id")
+    private String aiTaskId;
+
+    @ApiModelProperty(value = "审核失败原因")
+    @TableField("reason")
+    private String reason;
+
 
     @Override
     protected Serializable pkVal() {

+ 217 - 0
alien-job/src/main/java/shop/alien/job/second/AiCheckXxlJob.java

@@ -0,0 +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
+ * @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("二手商品风控记录审核任务执行完成");
+    }
+}

+ 445 - 10
alien-job/src/main/java/shop/alien/job/store/AiTagJob.java

@@ -2,31 +2,29 @@ package shop.alien.job.store;
 
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.xxl.job.core.context.XxlJobHelper;
 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.http.*;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
 import org.springframework.web.client.RestTemplate;
 import shop.alien.entity.result.R;
-import shop.alien.entity.store.StoreCommentSummary;
-import shop.alien.entity.store.StoreCommentSummaryInterest;
-import shop.alien.entity.store.TagsMain;
-import shop.alien.entity.store.TagsSynonym;
-import shop.alien.mapper.StoreCommentSummaryInterestMapper;
-import shop.alien.mapper.StoreCommentSummaryMapper;
-import shop.alien.mapper.TagsMainMapper;
-import shop.alien.mapper.TagsSynonymMapper;
+import shop.alien.entity.store.*;
+import shop.alien.entity.store.vo.AiApproveStoreInfo;
+import shop.alien.mapper.*;
 
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
+
+import static com.alipay.api.internal.util.AlipayUtils.getFileSuffix;
 
 /**
  * 调用AI标签数据服务类
@@ -49,6 +47,12 @@ public class AiTagJob {
 
     private final StoreCommentSummaryInterestMapper storeCommentSummaryInterestMapper;
 
+    private final LifeUserDynamicsMapper lifeUserDynamicsMapper;
+
+    private final StoreClockInMapper storeClockInMapper;
+
+    private final StoreInfoMapper storeInfoMapper;
+
     // 第三方接口地址 获取所有标签主表信息
     @Value("${third-party-tag.base-url}")
     private String tagMainUrl;
@@ -73,6 +77,13 @@ public class AiTagJob {
     @Value("${third-party-savetag.base-url}")
     private String saveTagUrl;
 
+    // 第三方接口地址 内容合规检测接口
+    @Value("${third-party-contentcheck.base-url}")
+    private String contentComplianceUrl;
+
+    @Value("${third-party-getresult.base-url}")
+    private String getResultUrl;
+
     //用户名
     @Value("${third-party-user-name.base-url}")
     private String userName;
@@ -567,6 +578,430 @@ public class AiTagJob {
         return R.success("任务执行失败 状态码" + responseEntity.getStatusCodeValue());
     }
 
+    /**
+     * 利用AI审核违规内容
+     */
+    @XxlJob("contentComplianceCheckTask")
+    public R<String> contentComplianceCheckTask() {
+        List<LifeUserDynamics> lifeUserDynamics = lifeUserDynamicsMapper.selectList(new LambdaQueryWrapper<LifeUserDynamics>()
+                .eq(LifeUserDynamics::getCheckFlag, 0).eq(LifeUserDynamics::getDeleteFlag, 0));
+
+        // 只依赖数据库字段即可判定待审核的动态,避免重复提交
+        // 常见图片后缀(可按需添加,如 .heic、.svg 等)
+        HashSet<String> IMAGE_SUFFIXES = new HashSet<>(Arrays.asList(
+                "jpg", "jpeg", "png", "gif", "bmp", "webp", "heic", "svg", "tiff"
+        ));
+        // 常见视频后缀(可按需添加,如 .avi、.flv 等)
+        HashSet<String> VIDEO_SUFFIXES = new HashSet<>(Arrays.asList(
+                "mp4", "mov", "mkv", "avi", "flv", "wmv", "mpeg", "mpg", "webm"
+        ));
+
+        log.info("登录Ai服务获取token..." + loginUrl);
+        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+        formData.add("username", userName);
+        formData.add("password", passWord);
+
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
+        ResponseEntity<String> postForEntity = null;
+        try {
+            log.info("请求Ai服务登录接口===================>");
+            postForEntity = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
+        } catch (Exception e) {
+            log.error("请求AI服务登录接口失败", e);
+        }
+        HttpHeaders aiHeaders = new HttpHeaders();
+        if (postForEntity != null && postForEntity.getStatusCodeValue() == 200) {
+            log.info("请求Ai服务登录成功 postForEntity.getBody()\t" + postForEntity.getBody());
+            String responseBody = postForEntity.getBody();
+            JSONObject jsonObject = JSONObject.parseObject(responseBody);
+            if (jsonObject != null) {
+                JSONObject dataJson = jsonObject.getJSONObject("data");
+                String accessToken = dataJson.getString("access_token");
+
+                aiHeaders.setContentType(MediaType.APPLICATION_JSON);
+                aiHeaders.set("Authorization", "Bearer " + accessToken);
+            }
+        }
+
+        List<StoreClockIn> storeClockIns = storeClockInMapper.selectList(new LambdaQueryWrapper<StoreClockIn>()
+                .eq(StoreClockIn::getDeleteFlag, 0).eq(StoreClockIn::getCheckFlag, 0));
+        for (StoreClockIn storeClockIn : storeClockIns) {
+            String imagePath = storeClockIn.getImgUrl() != null ? storeClockIn.getImgUrl() : "";
+            List<String> imageList = new ArrayList<>();
+            List<String> videoList = new ArrayList<>();
+            // 按分隔符拆分路径数组(处理连续分隔符如 ",," 产生的空字符串)
+            String[] allPaths = imagePath.split(",");
+            for (String path : allPaths) {
+                // 去除路径前后空格(避免 " a.jpg " 这类情况)
+                String trimmedPath = path.trim();
+                if (trimmedPath.isEmpty()) {
+                    continue; // 跳过空路径
+                }
+                // 获取文件后缀(忽略大小写)
+                // 找到最后一个 "." 的位置
+                int lastDotIndex = trimmedPath.lastIndexOf('.');
+                // 截取后缀(从 "." 后一位到结尾)
+                String suffix = trimmedPath.substring(lastDotIndex + 1);
+                // 分类添加到对应列表
+                if (IMAGE_SUFFIXES.contains(suffix)) {
+                    imageList.add(trimmedPath);
+                } else if (VIDEO_SUFFIXES.contains(suffix)) {
+                    videoList.add(trimmedPath);
+                }
+            }
+            // 对每一条动态逐条申请 token 并提交,避免批量失败导致重试逻辑复杂化
+            try {
+                Map<String, Object> jsonBody = new HashMap<>();
+                // text/img/video 三种维度一起传入 AI,便于一次完成合规审查
+                jsonBody.put("text", storeClockIn.getContent());
+                jsonBody.put("image_urls", imageList);
+                jsonBody.put("video_urls", videoList);
+
+                HttpEntity<Map<String, Object>> request = new HttpEntity<>(jsonBody, aiHeaders);
+                ResponseEntity<String> response = null;
+                try {
+                    response = restTemplate.postForEntity(contentComplianceUrl, request, String.class);
+                    if (response.getStatusCodeValue() != 200) {
+                        log.error("AI内容审核接口调用失败 http状态:" + response.getStatusCode());
+                    }
+                    JSONObject responseNode = JSONObject.parseObject(response.getBody());
+                    if (responseNode == null) {
+                        log.error("AI接口调用失败,响应内容为空");
+                    }
+                    Integer code = null;
+                    if (responseNode != null) {
+                        code = responseNode.getInteger("code");
+                        if (code == 200) {
+                            JSONObject dataNode = JSONObject.from(responseNode.get("data"));
+                            // 审核发起后仅标记 checkFlag=1 并保存任务号,等待回调或后续轮询更新
+                            StoreClockIn clockIn = new StoreClockIn();
+                            clockIn.setId(storeClockIn.getId());
+                            clockIn.setCheckFlag(1);
+                            clockIn.setAiTaskId(dataNode.get("task_id").toString());
+                            storeClockInMapper.updateById(clockIn);
+                            log.info("动态审核成功,AI返回内容: {}", response.getBody());
+                            XxlJobHelper.handleSuccess("动态内容审核任务执行成功");
+                        }
+                    } else {
+                        log.error("AI接口调用失败,错误码: " + code);
+                    }
+                } catch (Exception e) {
+                    log.error("调用AI内容审核接口失败", e);
+                }
+            } catch (RuntimeException ex) {
+                XxlJobHelper.handleFail("动态内容审核任务执行失败:" + ex.getMessage());
+                return R.fail("动态内容审核任务执行失败:" + ex.getMessage());
+            }
+        }
+
+        for (LifeUserDynamics lifeUserDynamic : lifeUserDynamics) {
+            String imagePath = lifeUserDynamic.getImagePath();
+            List<String> imageList = new ArrayList<>();
+            List<String> videoList = new ArrayList<>();
+            // 按分隔符拆分路径数组(处理连续分隔符如 ",," 产生的空字符串)
+            String[] allPaths = imagePath.split(",");
+            for (String path : allPaths) {
+                // 去除路径前后空格(避免 " a.jpg " 这类情况)
+                String trimmedPath = path.trim();
+                if (trimmedPath.isEmpty()) {
+                    continue; // 跳过空路径
+                }
+                // 获取文件后缀(忽略大小写)
+                // 找到最后一个 "." 的位置
+                int lastDotIndex = trimmedPath.lastIndexOf('.');
+                // 截取后缀(从 "." 后一位到结尾)
+                String suffix = trimmedPath.substring(lastDotIndex + 1);
+                // 分类添加到对应列表
+                if (IMAGE_SUFFIXES.contains(suffix)) {
+                    imageList.add(trimmedPath);
+                } else if (VIDEO_SUFFIXES.contains(suffix)) {
+                    videoList.add(trimmedPath);
+                }
+            }
+            try {
+                Map<String, Object> jsonBody = new HashMap<>();
+                // text/img/video 三种维度一起传入 AI,便于一次完成合规审查
+                jsonBody.put("text", lifeUserDynamic.getContext());
+                jsonBody.put("image_urls", imageList);
+                jsonBody.put("video_urls", videoList);
+
+                HttpEntity<Map<String, Object>> request = new HttpEntity<>(jsonBody, aiHeaders);
+                ResponseEntity<String> response = null;
+                try {
+                    response = restTemplate.postForEntity(contentComplianceUrl, request, String.class);
+                    if (response.getStatusCodeValue() != 200) {
+                        log.error("AI内容审核接口调用失败 http状态:" + response.getStatusCode());
+                    }
+                    JSONObject responseNode = JSONObject.parseObject(response.getBody());
+                    if (responseNode == null) {
+                        log.error("AI接口调用失败,响应内容为空");
+                    }
+                    Integer code = null;
+                    if (responseNode != null) {
+                        code = responseNode.getInteger("code");
+                        if (code == 200) {
+                            JSONObject dataNode = JSONObject.from(responseNode.get("data"));
+                            // 审核发起后仅标记 checkFlag=1 并保存任务号,等待回调或后续轮询更新
+                            LifeUserDynamics dynamics = new LifeUserDynamics();
+                            dynamics.setId(lifeUserDynamic.getId());
+                            dynamics.setCheckFlag(1);
+                            dynamics.setAiTaskId(dataNode.get("task_id").toString());
+                            lifeUserDynamicsMapper.updateById(dynamics);
+                            log.info("动态审核成功,AI返回内容: {}", response.getBody());
+                            XxlJobHelper.handleSuccess("动态内容审核任务执行成功");
+                        }
+                    } else {
+                        log.error("AI接口调用失败,错误码: " + code);
+                    }
+                } catch (Exception e) {
+                    log.error("调用AI内容审核接口失败", e);
+                }
+            } catch (RuntimeException ex) {
+                XxlJobHelper.handleFail("动态内容审核任务执行失败:" + ex.getMessage());
+                return R.fail("动态内容审核任务执行失败:" + ex.getMessage());
+            }
+        }
+        return R.success("动态内容审核任务执行成功");
+    }
+
+    /**
+     * 获取审核违规内容结果
+     */
+    @XxlJob("getCheckTask")
+    public R<String> getCheckTask() {
+        List<LifeUserDynamics> lifeUserDynamics = lifeUserDynamicsMapper.selectList(new LambdaQueryWrapper<LifeUserDynamics>()
+                .eq(LifeUserDynamics::getCheckFlag, 1).eq(LifeUserDynamics::getDeleteFlag, 0));
+        log.info("登录Ai服务获取token..." + loginUrl);
+        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+        formData.add("username", userName);
+        formData.add("password", passWord);
+
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
+        ResponseEntity<String> postForEntity = null;
+        try {
+            log.info("请求Ai服务登录接口===================>");
+            postForEntity = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
+        } catch (Exception e) {
+            log.error("请求AI服务登录接口失败", e);
+        }
+        RestTemplate restTemplateWithAuth = new RestTemplate();
+        if (postForEntity != null && postForEntity.getStatusCodeValue() == 200) {
+            log.info("请求Ai服务登录成功 postForEntity.getBody()\t" + postForEntity.getBody());
+            String responseBody = postForEntity.getBody();
+            JSONObject jsonObject = JSONObject.parseObject(responseBody);
+            if (jsonObject != null) {
+                JSONObject dataJson = jsonObject.getJSONObject("data");
+                String accessToken = dataJson.getString("access_token");
+                List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
+                interceptors.add((request, body, execution) -> {
+                    request.getHeaders().set("Authorization", "Bearer " + accessToken);
+                    return execution.execute(request, body);
+                });
+                restTemplateWithAuth.setInterceptors(interceptors);
+            }
+        }
+
+        List<StoreClockIn> storeClockIns = storeClockInMapper.selectList(new LambdaQueryWrapper<StoreClockIn>().eq(StoreClockIn::getCheckFlag, 1));
+        for (StoreClockIn storeClockIn : storeClockIns) {
+            // 针对已提交且未删除的动态轮询查询结果
+            try {
+                ResponseEntity<String> response = null;
+                try {
+                    response = restTemplateWithAuth.getForEntity(getResultUrl + "?task_id=" + storeClockIn.getAiTaskId(), String.class);
+                    if (response.getStatusCodeValue() != 200) {
+                        log.error("AI内容审核结果获取接口调用失败 http状态:" + response.getStatusCode());
+                    }
+                    JSONObject responseNode = JSONObject.parseObject(response.getBody());
+                    if (responseNode == null) {
+                        log.error("AI接口调用失败,响应内容为空");
+                    }
+                    Integer code = null;
+                    if (responseNode != null) {
+                        code = responseNode.getInteger("code");
+                        if (code == 200) {
+                            JSONObject dataNode = JSONObject.from(responseNode.get("data"));
+                            StoreClockIn clockIn = new StoreClockIn();
+                            clockIn.setId(storeClockIn.getId());
+                            if ("completed".equals(dataNode.get("status"))) {
+                                if (!(boolean) dataNode.get("is_compliant")) {
+                                    // 只要 AI 判定不合规,立即禁用动态并记录原因
+                                    clockIn.setDeleteFlag(1);
+                                    clockIn.setReason(String.valueOf(dataNode.get("failure_reason")));
+                                }
+                                clockIn.setCheckFlag(2);
+                                storeClockInMapper.updateById(clockIn);
+                                if (!(boolean) dataNode.get("is_compliant")) {
+                                    storeClockInMapper.deleteById(clockIn);
+                                }
+                                log.info("动态审核结果获取成功,AI返回内容: {}", response.getBody());
+                                XxlJobHelper.handleSuccess("动态内容审核任务结果获取执行成功");
+                            } else {
+                                log.info("动态审核未完成,AI返回内容: {}", response.getBody());
+                            }
+                        } else {
+                            log.error("AI接口调用失败,错误码: " + code);
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("调用AI内容审核结果获取接口失败", e);
+                }
+            } catch (RuntimeException ex) {
+                XxlJobHelper.handleFail("动态内容审核任务结果获取执行失败:" + ex.getMessage());
+                return R.fail("动态内容审核任务结果获取执行失败:" + ex.getMessage());
+            }
+        }
+
+        for (LifeUserDynamics lifeUserDynamic : lifeUserDynamics) {
+            // 针对已提交且未删除的动态轮询查询结果
+            try {
+                ResponseEntity<String> response = null;
+                try {
+                    response = restTemplateWithAuth.getForEntity(getResultUrl + "?task_id=" + lifeUserDynamic.getAiTaskId(), String.class);
+                    if (response.getStatusCodeValue() != 200) {
+                        log.error("AI内容审核结果获取接口调用失败 http状态:" + response.getStatusCode());
+                    }
+                    JSONObject responseNode = JSONObject.parseObject(response.getBody());
+                    if (responseNode == null) {
+                        log.error("AI接口调用失败,响应内容为空");
+                    }
+                    Integer code = null;
+                    if (responseNode != null) {
+                        code = responseNode.getInteger("code");
+                        if (code == 200) {
+                            JSONObject dataNode = JSONObject.from(responseNode.get("data"));
+                            LifeUserDynamics dynamics = new LifeUserDynamics();
+                            dynamics.setId(lifeUserDynamic.getId());
+                            if ("completed".equals(dataNode.get("status"))) {
+                                if (!(boolean) dataNode.get("is_compliant")) {
+                                    // 只要 AI 判定不合规,立即禁用动态并记录原因
+                                    dynamics.setEnableStatus(1);
+                                    dynamics.setReason(String.valueOf(dataNode.get("failure_reason")));
+                                }
+                                dynamics.setCheckFlag(2);
+                                lifeUserDynamicsMapper.updateById(dynamics);
+                                log.info("动态审核结果获取成功,AI返回内容: {}", response.getBody());
+                                XxlJobHelper.handleSuccess("动态内容审核任务结果获取执行成功");
+                            } else {
+                                log.info("动态审核未完成,AI返回内容: {}", response.getBody());
+                            }
+                        } else {
+                            log.error("AI接口调用失败,错误码: " + code);
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("调用AI内容审核结果获取接口失败", e);
+                }
+            } catch (RuntimeException ex) {
+                XxlJobHelper.handleFail("动态内容审核任务结果获取执行失败:" + ex.getMessage());
+                return R.fail("动态内容审核任务结果获取执行失败:" + ex.getMessage());
+            }
+        }
+        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;