浏览代码

feat(store): 实现验证码持久化存储功能

- 在AliSms类中新增验证码保存至数据库的功能
- 添加saveVerificationCode方法将验证码信息写入StoreVerificationCode表
- 优化验证码发送逻辑,确保测试和正式环境均能正确保存验证码
- 引入StoreVerificationCode实体类和对应的Mapper接口

fix(job): 重构差评申诉AI处理任务

- 将差评申诉相关接口从UserStoreController迁移至独立的BadReviewAppealJob类
- 新增两个XXL-JOB任务:getBadReviewAppealJob和getAppealCompletedResult
- 完善AI服务认证及申诉材料分析流程
- 改进图片处理逻辑,支持多图上传与Base64编码转换
- 增强异常处理机制,提高系统稳定性
- 更新接口地址配置方式,便于维护和部署

refactor(entity): 扩展StoreCommentAppeal实体属性

- 为StoreCommentAppeal类增加appealAiApproval字段
- 用于记录AI审批过程中的详细信息

refactor(mapper): 优化待处理申诉查询SQL

- 修改getPendingAppeals方法的查询语句
- 明确筛选条件为appeal_status = 0的数据
- 提高查询效率和准确性
fcw 2 周之前
父节点
当前提交
adbe0cc94f

+ 4 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreCommentAppeal.java

@@ -77,4 +77,8 @@ public class StoreCommentAppeal extends Model<StoreCommentAppeal> {
     @ApiModelProperty(value = "AI接口返回的ID")
     @ApiModelProperty(value = "AI接口返回的ID")
     @TableField("record_id")
     @TableField("record_id")
     private Integer recordId;
     private Integer recordId;
+
+    @ApiModelProperty(value = "申诉ai审批过程")
+    @TableField("appeal_ai_approval")
+    private String appealAiApproval;
 }
 }

+ 3 - 2
alien-entity/src/main/java/shop/alien/mapper/StoreCommentAppealMapper.java

@@ -80,8 +80,9 @@ public interface StoreCommentAppealMapper extends BaseMapper<StoreCommentAppeal>
     List<Map<String, Object>> getAppealList();
     List<Map<String, Object>> getAppealList();
 
 
 
 
-    @Select("SELECT sca.id, sca.appeal_status, sca.final_result, sca.comment_id" +
-            "FROM store_comment_appeal sca ")
+    @Select("SELECT sca.id, sca.appeal_status, sca.final_result, sca.comment_id, sca.record_id " +
+            "FROM store_comment_appeal sca " +
+            "WHERE sca.appeal_status = 0")
     List<StoreCommentAppeal> getPendingAppeals();
     List<StoreCommentAppeal> getPendingAppeals();
 
 
     @Update("UPDATE store_comment_appeal " +
     @Update("UPDATE store_comment_appeal " +

+ 313 - 106
alien-job/src/main/java/shop/alien/job/store/BadReviewAppealJob.java

@@ -6,21 +6,31 @@ import com.xxl.job.core.context.XxlJobHelper;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.RequiredArgsConstructor;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.map.HashedMap;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
 import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.client.RestTemplate;
+import shop.alien.entity.store.StoreComment;
 import shop.alien.entity.store.StoreCommentAppeal;
 import shop.alien.entity.store.StoreCommentAppeal;
 import shop.alien.entity.result.R;
 import shop.alien.entity.result.R;
 import shop.alien.mapper.StoreCommentAppealMapper;
 import shop.alien.mapper.StoreCommentAppealMapper;
+import shop.alien.mapper.StoreCommentMapper;
 
 
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.time.LocalDate;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
 
 /**
 /**
  * 调用AI差评申诉辅助系统服务类
  * 调用AI差评申诉辅助系统服务类
@@ -37,8 +47,13 @@ public class BadReviewAppealJob {
 
 
     private final StoreCommentAppealMapper storeCommentAppealMapper;
     private final StoreCommentAppealMapper storeCommentAppealMapper;
 
 
-    @Value("${third-party-login.base-url}")
-    private String loginUrl;
+    private final StoreCommentMapper storeCommentMapper;
+
+//    @Value("${third-party-login.base-url}")
+//    private String loginUrl;
+
+    private String loginUrl = "http://192.168.2.250:9000/ai/user-auth-core/api/v1/auth/login";
+
 
 
     @Value("${third-party-user-name.base-url}")
     @Value("${third-party-user-name.base-url}")
     private String userName;
     private String userName;
@@ -46,160 +61,352 @@ public class BadReviewAppealJob {
     @Value("${third-party-pass-word.base-url}")
     @Value("${third-party-pass-word.base-url}")
     private String passWord;
     private String passWord;
 
 
+    private String analyzeUrl = "http://192.168.2.250:9000/ai/auto-review/api/v1/analyze";
+
+    private String resultUrl = "http://192.168.2.250:9000/ai/auto-review";
+
+
+
     /**
     /**
      * 差评申述置信度分析接口地址
      * 差评申述置信度分析接口地址
      * 例如: http://192.168.2.250:9004/api/v1/analyze 或通过网关: http://192.168.2.250:9000/ai/auto_review/api/v1/analyze
      * 例如: http://192.168.2.250:9004/api/v1/analyze 或通过网关: http://192.168.2.250:9000/ai/auto_review/api/v1/analyze
      */
      */
-    @Value("${bad-review-analyze.base-url}")
-    private String analyzeUrl;
+//    @Value("${bad-review-analyze.base-url}")
+//    private String analyzeUrl;
 
 
     /**
     /**
      * 调用AI服务获取Token
      * 调用AI服务获取Token
      */
      */
-    @XxlJob("badReviewAppealJob")
-    public R<String> badReviewAppealJob() {
-        log.info("登录Ai服务获取token..." + loginUrl);
-        //构建请求参数
-        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
-        formData.add("username", userName);    // 表单字段 1:用户名
-        formData.add("password", passWord);    // 表单字段 2:密码
+    @XxlJob("getBadReviewAppealJob")
+    public R<String> getBadReviewAppealJob() {
+        String accessToken = fetchAiServiceToken();
+        if (!StringUtils.hasText(accessToken)) {
+            return R.fail("调用差评申诉辅助系统登录任务执行失败 返回异常");
+        }
+        return invokeAnalyzeTask(accessToken);
+    }
 
 
-        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("请求差评申诉辅助系统登录接口===================>");
-            postForEntity = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
-        } catch (Exception e) {
-            log.error("调用差评申诉辅助系统登录接口异常", e);
+    @XxlJob("getAppealCompletedResult")
+    public R<String> getAppealCompletedResult() {
+        String accessToken = fetchAiServiceToken();
+        if (!StringUtils.hasText(accessToken)) {
+            return R.fail("调用差评申诉辅助系统 登录接口失败");
         }
         }
+        return getNegativeReviewAppealCompletedResult(accessToken);
+    }
 
 
-        if (postForEntity != null) {
-            if (postForEntity.getStatusCodeValue() == 200) {
-                log.info("差评申诉辅助系统登录成功 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");
-                // 调用差评申述置信度分析任务
-                return invokeAnalyzeTask(accessToken);
-            } else {
-                log.error("请求差评申诉辅助系统 登录接口失败 http状态:" + postForEntity.getStatusCode());
-                return R.fail("请求差评申诉辅助系统 登录接口失败 http状态:" + postForEntity.getStatusCode());
+    private R<String> getNegativeReviewAppealCompletedResult(String accessToken) {
+
+
+        HttpHeaders analyzeHeaders = new HttpHeaders();
+        analyzeHeaders.setContentType(MediaType.APPLICATION_JSON);
+        analyzeHeaders.set("Authorization", "Bearer " + accessToken);
+        // 查询所有状态为处理中的申诉
+        List<StoreCommentAppeal> pendingAppeals = storeCommentAppealMapper.getPendingAppeals();
+        // 循环调用查询结果接口
+        for (StoreCommentAppeal appeal : pendingAppeals) {
+            String completedUrl = buildCompletedUrl(appeal.getRecordId());
+
+            ResponseEntity<String> analyzeResp;
+
+            RestTemplate restTemplateWithAuth = new RestTemplate();
+            List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
+            interceptors.add((request, body, execution) -> {
+                request.getHeaders().set("Authorization", "Bearer " + accessToken);
+                return execution.execute(request, body);
+            });
+            restTemplateWithAuth.setInterceptors(interceptors);
+
+            ResponseEntity<String> response = null;
+
+            try {
+                analyzeResp = restTemplateWithAuth.getForEntity(completedUrl, String.class);
+
+                if (analyzeResp != null && analyzeResp.getStatusCodeValue() == 200) {
+                    String analyzeBody = analyzeResp.getBody();
+                    log.info("差评申述置信度分析提交成功, 返回: {}", analyzeBody);
+
+                    JSONObject analyzeJson = JSONObject.parseObject(analyzeBody);
+                    JSONObject dataJsonObj = analyzeJson.getJSONObject("data");
+
+                    if (dataJsonObj == null) {
+                        log.error("差评申述置信度分析返回数据为空");
+                        R.fail("差评申述置信度分析返回数据为空");
+                        continue;
+                    }
+
+                    // 获取record_id用于后续查询
+                    Integer recordId = dataJsonObj.getInteger("record_id");
+                    if (recordId == null) {
+                        log.error("差评申述置信度分析返回record_id为空");
+                        R.fail("差评申述置信度分析返回record_id为空");
+                        continue;
+                    }
+
+                    StoreCommentAppeal sCommentAppeal = new StoreCommentAppeal();
+                    sCommentAppeal.setRecordId(appeal.getRecordId());
+                    // 判断得分大小
+                    if (dataJsonObj.getDouble("user_confidence") > dataJsonObj.getDouble("merchant_confidence")){
+                        sCommentAppeal.setAppealStatus(1);
+                        sCommentAppeal.setFinalResult("已驳回");
+                    } else {
+                        sCommentAppeal.setAppealStatus(2);
+                        sCommentAppeal.setFinalResult("已同意");
+                        //假删除评论
+                        StoreComment storeComment = new StoreComment();
+                        storeComment.setId(appeal.getCommentId());
+                        storeComment.setDeleteFlag(1);
+                        storeCommentMapper.updateById(storeComment);
+                    }
+                    sCommentAppeal.setAppealAiApproval(dataJsonObj.toJSONString());
+
+                    sCommentAppeal.setRecordId(recordId);
+                    storeCommentAppealMapper.updateByRecordId(appeal.getRecordId(),
+                            sCommentAppeal.getAppealStatus(),
+                            sCommentAppeal.getFinalResult());
+                } else {
+                    if (analyzeResp != null) {
+                        log.error("调用差评申述置信度分析接口失败, http状态: {}", analyzeResp.getStatusCode());
+                        R.fail("调用差评申述置信度分析接口失败, http状态: " + analyzeResp.getStatusCode());
+                    }
+                }
+            } catch (Exception e) {
+                log.error("调用差评申述查询结果接口异常", e);
             }
             }
         }
         }
-        XxlJobHelper.handleFail("调用差评申诉辅助系统登录任务执行失败 返回异常");
-        return R.fail("调用差评申诉辅助系统登录任务执行失败 返回异常");
-
+        return R.success("调用差评申述置信度分析结果接口完成");
     }
     }
 
 
-    private R<String> invokeAnalyzeTask(String token) {
-        log.info("开始调用差评申述置信度分析接口, url: {}", analyzeUrl);
-
-        // 获取当前日期
-        LocalDate today = LocalDate.now();
 
 
-        // 获取当月第一天
-        LocalDate firstDayOfMonth = today.withDayOfMonth(1);
 
 
-        // 获取当月最后一天
-        LocalDate lastDayOfMonth = today.withDayOfMonth(today.lengthOfMonth());
 
 
-        // 格式化为字符串(可根据需要调整格式)
-        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-        String startDate = firstDayOfMonth.format(formatter);
-        String endDate = lastDayOfMonth.format(formatter);
+    private R<String> invokeAnalyzeTask(String token) {
+        log.info("开始调用差评申述置信度分析接口, url: {}", analyzeUrl);
 
 
         HttpHeaders analyzeHeaders = new HttpHeaders();
         HttpHeaders analyzeHeaders = new HttpHeaders();
         analyzeHeaders.setContentType(MediaType.APPLICATION_JSON);
         analyzeHeaders.setContentType(MediaType.APPLICATION_JSON);
         analyzeHeaders.set("Authorization", "Bearer " + token);
         analyzeHeaders.set("Authorization", "Bearer " + token);
 
 
-        AnalyzeRequest analyzeRequest = new AnalyzeRequest();
-        analyzeRequest.setStart_time(startDate + "T00:00:00");
-        analyzeRequest.setEnd_time(endDate + "T23:59:59");
+        // 查询一段时间内的差评申述
+        // 循环插入
+        List<Map<String, Object>> appealList = storeCommentAppealMapper.getAppealList();
 
 
-        HttpEntity<AnalyzeRequest> analyzeEntity = new HttpEntity<>(analyzeRequest, analyzeHeaders);
-        ResponseEntity<String> analyzeResp = null;
-        try {
-            analyzeResp = restTemplate.postForEntity(analyzeUrl, analyzeEntity, String.class);
-        } catch (Exception e) {
-            log.error("调用差评申述置信度分析接口异常", e);
+        if (appealList == null || appealList.isEmpty()) {
+            log.info("没有需要处理的差评申述");
+            return R.success("没有需要处理的差评申述");
         }
         }
 
 
-        if (analyzeResp != null) {
-            if (analyzeResp.getStatusCodeValue() == 200) {
-                log.info("postForEntity.getBody()\t" + analyzeResp.getStatusCode());
+        for (Map<String, Object> storeCommentAppeal : appealList) {
+            Map<String, Object> analyzeRequest = new HashedMap<>();
+
+            // 商家申诉材料
+            analyzeRequest.put("merchant_material",
+                    storeCommentAppeal.get("appeal_reason") == null ? "" : storeCommentAppeal.get("appeal_reason").toString());
+
+            // 用户差评内容
+            analyzeRequest.put("user_material",
+                    storeCommentAppeal.get("comment_content") == null ? "" : storeCommentAppeal.get("comment_content").toString());
+
+            // 商家图片:支持多张,转成 Base64 数组
+            List<String> merchantImages = new ArrayList<>();
+            String imgUrls = storeCommentAppeal.get("img_url") == null ? "" : storeCommentAppeal.get("img_url").toString();
+            if (StringUtils.hasText(imgUrls)) {
+                // 假设 img_url 是多个图片用逗号分隔的字符串
+                for (String imageUrl : imgUrls.split(",")) {
+                    String base64 = convertImageToBase64(imageUrl.trim());
+                    if (StringUtils.hasText(base64)) {
+                        merchantImages.add(base64);
+                    }
+                }
+            }
+            analyzeRequest.put("merchant_images", merchantImages);
+
+            // 用户图片:同理
+            List<String> userImages = new ArrayList<>();
+            String userImgUrls = storeCommentAppeal.get("user_img_url") == null ? "" : storeCommentAppeal.get("user_img_url").toString();
+            if (StringUtils.hasText(userImgUrls)) {
+                for (String imageUrl : userImgUrls.split(",")) {
+                    String base64 = convertImageToBase64(imageUrl.trim());
+                    if (StringUtils.hasText(base64)) {
+                        userImages.add(base64);
+                    }
+                }
+            }
+            analyzeRequest.put("user_images", userImages);
+
+            // 其他字段
+            analyzeRequest.put("case_id", storeCommentAppeal.get("comment_id") == null ? "" : storeCommentAppeal.get("comment_id").toString());
+            analyzeRequest.put("order_id", storeCommentAppeal.get("business_id") == null ? "" : storeCommentAppeal.get("business_id").toString());
+
+            HttpEntity<Map<String, Object>> analyzeEntity = new HttpEntity<>(analyzeRequest, analyzeHeaders);
+
+            ResponseEntity<String> analyzeResp = null;
+            try {
+                analyzeResp = restTemplate.postForEntity(analyzeUrl, analyzeEntity, String.class);
+            } catch (org.springframework.web.client.HttpServerErrorException.ServiceUnavailable e) {
+                log.error("调用差评申述置信度分析接口返回503 Service Unavailable错误: {}", e.getResponseBodyAsString());
+                continue;
+            } catch (Exception e) {
+                log.error("调用差评申述置信度分析接口异常", e);
+                continue;
+            }
+
+            if (analyzeResp != null && analyzeResp.getStatusCodeValue() == 200) {
                 String analyzeBody = analyzeResp.getBody();
                 String analyzeBody = analyzeResp.getBody();
-                log.info("差评申述置信度分析成功, 返回: {}", analyzeBody);
+                log.info("差评申述置信度分析提交成功, 返回: {}", analyzeBody);
 
 
                 JSONObject analyzeJson = JSONObject.parseObject(analyzeBody);
                 JSONObject analyzeJson = JSONObject.parseObject(analyzeBody);
-                JSONObject dataJsonObj = null;
-                if (analyzeJson != null) {
-                    dataJsonObj = analyzeJson.getJSONObject("data");
-                }
+                JSONObject dataJsonObj = analyzeJson.getJSONObject("data");
+
                 if (dataJsonObj == null) {
                 if (dataJsonObj == null) {
                     log.error("差评申述置信度分析返回数据为空");
                     log.error("差评申述置信度分析返回数据为空");
-                    XxlJobHelper.handleFail("差评申述置信度分析返回数据为空");
-                    return R.fail("差评申述置信度分析返回数据为空");
+                    R.fail("差评申述置信度分析返回数据为空");
+                    continue;
+                }
+
+                // 获取record_id用于后续查询
+                Integer recordId = dataJsonObj.getInteger("record_id");
+                if (recordId == null) {
+                    log.error("差评申述置信度分析返回record_id为空");
+                    R.fail("差评申述置信度分析返回record_id为空");
+                    continue;
                 }
                 }
 
 
-                StoreCommentAppeal storeCommentAppeal = new StoreCommentAppeal();
-//                storeCommentAppeal.setStoreId(dataJsonObj.get());
-//                storeCommentAppeal.setCommentId(appealParam.getCommentId());
-//                storeCommentAppeal.setAppealReason(appealParam.getMerchantMaterial());
-//                storeCommentAppeal.setFinalResult(dataJsonObj.toJSONString());
-//                storeCommentAppeal.setAppealStatus(0);
-//                storeCommentAppeal.setDeleteFlag(0);
-//                storeCommentAppealMapper.insert(storeCommentAppeal);
-
-                XxlJobHelper.handleSuccess("差评申述置信度分析任务执行成功并写入 store_comment_appeal");
-                return R.success("差评申述置信度分析成功,已写入 store_comment_appeal 表");
+                //修改评论状态为"处理中"
+                StoreCommentAppeal sCommentAppeal = new StoreCommentAppeal();
+                sCommentAppeal.setId((Integer) storeCommentAppeal.get("id"));
+                sCommentAppeal.setAppealStatus(0);
+                sCommentAppeal.setRecordId(recordId);
+                storeCommentAppealMapper.updateById(sCommentAppeal);
+
             } else {
             } else {
-                log.error("调用差评申述置信度分析接口失败, http状态: {}", analyzeResp.getStatusCode());
-                XxlJobHelper.handleFail("调用差评申述置信度分析接口失败, http状态:" + analyzeResp.getStatusCode());
-                return R.fail("调用差评申述置信度分析接口失败 http状态:" + analyzeResp.getStatusCode());
+                if (analyzeResp != null) {
+                    log.error("调用差评申述置信度分析接口失败, http状态: {}", analyzeResp.getStatusCode());
+                    R.fail("调用差评申述置信度分析接口失败, http状态: " + analyzeResp.getStatusCode());
+                }
             }
             }
         }
         }
-        log.error("调用差评申述置信度分析接口返回为空或异常");
-        XxlJobHelper.handleFail("调用差评申述置信度分析接口返回为空或异常");
-        return R.fail("调用差评申述置信度分析接口返回为空或异常");
+        return R.success("调用差评申述置信度分析接口完成");
     }
     }
 
 
-
     /**
     /**
-     * 差评申述置信度分析请求体
+     * 将图片URL转换为Base64编码
      *
      *
-     * 对应文档中的:
-     * {
-     *   "merchant_material": "商家申述材料内容(必填)",
-     *   "user_material": "用户举证材料内容(必填)",
-     *   "order_id": "关联订单ID(可选)",
-     *   "case_id": "申述案件ID(可选)",
-     *   "merchant_images": [...],
-     *   "user_images": [...]
-     * }
+     * @param imageUrl 图片URL
+     * @return Base64编码字符串
      */
      */
-    class AnalyzeRequest {
-        private String start_time;
-        private String end_time;
+    private String convertImageToBase64(String imageUrl) {
+        // 1. 检查是否为空
+        if (!StringUtils.hasText(imageUrl)) {
+            log.warn("图片URL为空");
+            return "";
+        }
+
+        // 2. 对URL进行编码处理(解决特殊字符问题)
+        String encodedUrl = encodeImageUrl(imageUrl);
 
 
-        public String getStart_time() {
-            return start_time;
+        // 3. 验证URL格式
+        if (!isValidUrl(encodedUrl)) {
+            log.warn("无效的图片URL: {}", imageUrl);
+            return "";
         }
         }
 
 
-        public void setStart_time(String start_time) {
-            this.start_time = start_time;
+        try {
+            // 4. 下载图片并转换Base64
+            byte[] imageBytes = restTemplate.getForObject(encodedUrl, byte[].class);
+            if (imageBytes != null) {
+                return java.util.Base64.getEncoder().encodeToString(imageBytes);
+            }
+        } catch (org.springframework.web.client.HttpClientErrorException.NotFound e) {
+            log.warn("图片不存在 (404), URL: {}", imageUrl);
+            return "";
+        } catch (Exception e) {
+            log.error("图片转换为Base64失败, URL: {}", imageUrl, e);
+            return "";
         }
         }
+        return "";
+    }
+
+    // 新增方法:对URL中的特殊字符进行编码
+    private String encodeImageUrl(String imageUrl) {
+        try {
+            URI uri = new URI(imageUrl);
+            String scheme = uri.getScheme();
+            String host = uri.getHost();
+            String path = uri.getPath();
+            String query = uri.getQuery();
+
+            // 对路径中的特殊字符进行编码
+            String encodedPath = java.net.URLEncoder.encode(path, "UTF-8")
+                    .replace("%2F", "/")  // 保留斜杠
+                    .replace("+", "%20"); // 空格编码
+
+            StringBuilder encodedUrl = new StringBuilder();
+            encodedUrl.append(scheme).append("://").append(host).append(encodedPath);
+
+            if (query != null) {
+                encodedUrl.append("?").append(query);
+            }
 
 
-        public String getEnd_time() {
-            return end_time;
+            return encodedUrl.toString();
+        } catch (Exception e) {
+            log.warn("URL编码失败,使用原始URL: {}", imageUrl);
+            return imageUrl;
         }
         }
+    }
+
 
 
-        public void setEnd_time(String end_time) {
-            this.end_time = end_time;
+
+    // 辅助方法:验证URL格式合法性
+    private boolean isValidUrl(String url) {
+        try {
+            // 尝试构造URI,验证格式
+            new URI(url);
+            // 进一步检查是否以http/https开头(可选,根据业务需求)
+            return url.startsWith("http://") || url.startsWith("https://");
+        } catch (URISyntaxException e) {
+            return false;
+        }
+    }
+
+    private String fetchAiServiceToken() {
+        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);
+
+        try {
+            ResponseEntity<String> response = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
+            if (response != null && response.getStatusCodeValue() == 200 && response.getBody() != null) {
+                JSONObject jsonObject = JSONObject.parseObject(response.getBody());
+                JSONObject dataJson = jsonObject.getJSONObject("data");
+                return dataJson != null ? dataJson.getString("access_token") : null;
+            }
+            log.error("请求差评申诉辅助系统 登录接口失败 http状态:{}", response != null ? response.getStatusCode() : null);
+        } catch (Exception e) {
+            log.error("调用差评申诉辅助系统登录接口异常", e);
+        }
+        return null;
+    }
+
+    private String buildCompletedUrl(Integer recordId) {
+        String baseUrl = resultUrl;
+        if (!StringUtils.hasText(baseUrl)) {
+            throw new IllegalStateException("差评申述分析接口地址未配置");
+        }
+        if (baseUrl.endsWith("/")) {
+            baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
+        }
+        String completedBase = baseUrl.replace("/api/v1/analyze", "");
+        if (!completedBase.endsWith("/")) {
+            completedBase = completedBase + "/";
         }
         }
+        return completedBase + "api/v1/records/" + recordId + "/completed";
     }
     }
 
 
 }
 }

+ 0 - 251
alien-store/src/main/java/shop/alien/store/controller/UserStoreController.java

@@ -167,255 +167,4 @@ public class UserStoreController {
         return R.data(lifeUserStoreService.buyQuan(quanId, couponId, userId, cnt, payPrice, orderNo));
         return R.data(lifeUserStoreService.buyQuan(quanId, couponId, userId, cnt, payPrice, orderNo));
     }
     }
 
 
-
-
-    @PostMapping("/getBadReviewAppealJob")
-    @ApiOperation("调用查询差评申诉")
-    public R<String> getBadReviewAppealJob() {
-        String accessToken = fetchAiServiceToken();
-        if (!StringUtils.hasText(accessToken)) {
-            return R.fail("调用差评申诉辅助系统登录任务执行失败 返回异常");
-        }
-        return invokeAnalyzeTask(accessToken);
-    }
-
-    @ApiOperation("差评申述处理完成结果查询")
-    @GetMapping("/getAppealCompletedResult")
-    public R<String> getAppealCompletedResult() {
-        String accessToken = fetchAiServiceToken();
-        if (!StringUtils.hasText(accessToken)) {
-            return R.fail("调用差评申诉辅助系统 登录接口失败");
-        }
-        return getNegativeReviewAppealCompletedResult(accessToken);
-    }
-
-    private R<String> getNegativeReviewAppealCompletedResult(String accessToken) {
-
-
-        HttpHeaders analyzeHeaders = new HttpHeaders();
-        analyzeHeaders.setContentType(MediaType.APPLICATION_JSON);
-        analyzeHeaders.set("Authorization", "Bearer " + accessToken);
-        // 查询所有状态为处理中的申诉
-        List<StoreCommentAppeal> pendingAppeals = storeCommentAppealMapper.getPendingAppeals();
-        // 循环调用查询结果接口
-        for (StoreCommentAppeal appeal : pendingAppeals) {
-            String completedUrl = buildCompletedUrl(appeal.getRecordId());
-            Map<String, Object> analyzeRequest = new HashedMap<>();
-            analyzeRequest.put("record_id", appeal.getRecordId());
-
-            HttpEntity<Map<String, Object>> analyzeEntity = new HttpEntity<>(analyzeRequest, analyzeHeaders);
-
-            ResponseEntity<String> analyzeResp;
-            try {
-                analyzeResp = restTemplate.postForEntity(completedUrl, analyzeEntity, String.class);
-
-                if (analyzeResp != null && analyzeResp.getStatusCodeValue() == 200) {
-                    String analyzeBody = analyzeResp.getBody();
-                    log.info("差评申述置信度分析提交成功, 返回: {}", analyzeBody);
-
-                    JSONObject analyzeJson = JSONObject.parseObject(analyzeBody);
-                    JSONObject dataJsonObj = analyzeJson.getJSONObject("data");
-
-                    if (dataJsonObj == null) {
-                        log.error("差评申述置信度分析返回数据为空");
-                        R.fail("差评申述置信度分析返回数据为空");
-                        continue;
-                    }
-
-                    // 获取record_id用于后续查询
-                    Integer recordId = dataJsonObj.getInteger("record_id");
-                    if (recordId == null) {
-                        log.error("差评申述置信度分析返回record_id为空");
-                        R.fail("差评申述置信度分析返回record_id为空");
-                        continue;
-                    }
-
-                    StoreCommentAppeal sCommentAppeal = new StoreCommentAppeal();
-                    sCommentAppeal.setRecordId(appeal.getRecordId());
-                    // 判断得分大小
-                    if (dataJsonObj.getDouble("user_confidence") > dataJsonObj.getDouble("merchant_confidence")){
-                        sCommentAppeal.setAppealStatus(1);
-                    } else {
-                        sCommentAppeal.setAppealStatus(2);
-                        //假删除评论
-                        StoreComment storeComment = new StoreComment();
-                        storeComment.setId(appeal.getCommentId());
-                        storeComment.setDeleteFlag(1);
-                        storeCommentMapper.updateById(storeComment);
-                    }
-                    sCommentAppeal.setFinalResult(dataJsonObj.toJSONString());
-
-                    sCommentAppeal.setRecordId(recordId);
-                    storeCommentAppealMapper.updateByRecordId(appeal.getRecordId(),
-                            sCommentAppeal.getAppealStatus(),
-                            sCommentAppeal.getFinalResult());
-                } else {
-                    if (analyzeResp != null) {
-                        log.error("调用差评申述置信度分析接口失败, http状态: {}", analyzeResp.getStatusCode());
-                        R.fail("调用差评申述置信度分析接口失败, http状态: " + analyzeResp.getStatusCode());
-                    }
-                }
-            } catch (Exception e) {
-                log.error("调用差评申述查询结果接口异常", e);
-            }
-        }
-        return R.success("调用差评申述置信度分析结果接口完成");
-    }
-
-
-
-
-    private R<String> invokeAnalyzeTask(String token) {
-        log.info("开始调用差评申述置信度分析接口, url: {}", analyzeUrl);
-
-        HttpHeaders analyzeHeaders = new HttpHeaders();
-        analyzeHeaders.setContentType(MediaType.APPLICATION_JSON);
-        analyzeHeaders.set("Authorization", "Bearer " + token);
-
-        // 查询一段时间内的差评申述
-        // 循环插入
-        List<Map<String, Object>> appealList = storeCommentAppealMapper.getAppealList();
-
-        if (appealList == null || appealList.isEmpty()) {
-            log.info("没有需要处理的差评申述");
-            return R.success("没有需要处理的差评申述");
-        }
-
-        for (Map<String, Object> storeCommentAppeal : appealList) {
-            Map<String, Object> analyzeRequest = new HashedMap<>();
-            analyzeRequest.put("merchant_material", storeCommentAppeal.get("appeal_reason") == null ? "" :storeCommentAppeal.get("appeal_reason").toString());
-            analyzeRequest.put("user_material", storeCommentAppeal.get("comment_content") == null ? "" :storeCommentAppeal.get("comment_content").toString());
-            analyzeRequest.put("merchant_images", storeCommentAppeal.get("img_url") == null ? "" :convertImageToBase64(storeCommentAppeal.get("img_url").toString()));
-            analyzeRequest.put("user_images", storeCommentAppeal.get("user_img_url") == null ? "" :convertImageToBase64(storeCommentAppeal.get("user_img_url").toString()));
-            analyzeRequest.put("case_id", storeCommentAppeal.get("comment_id") == null ? "" :storeCommentAppeal.get("comment_id").toString());
-            analyzeRequest.put("order_id", storeCommentAppeal.get("business_id") == null ? "" :storeCommentAppeal.get("business_id").toString());
-
-            HttpEntity<Map<String, Object>> analyzeEntity = new HttpEntity<>(analyzeRequest, analyzeHeaders);
-
-            ResponseEntity<String> analyzeResp = null;
-            try {
-                analyzeResp = restTemplate.postForEntity(analyzeUrl, analyzeEntity, String.class);
-            } catch (Exception e) {
-                log.error("调用差评申述置信度分析接口异常", e);
-            }
-
-            if (analyzeResp != null && analyzeResp.getStatusCodeValue() == 200) {
-                String analyzeBody = analyzeResp.getBody();
-                log.info("差评申述置信度分析提交成功, 返回: {}", analyzeBody);
-
-                JSONObject analyzeJson = JSONObject.parseObject(analyzeBody);
-                JSONObject dataJsonObj = analyzeJson.getJSONObject("data");
-
-                if (dataJsonObj == null) {
-                    log.error("差评申述置信度分析返回数据为空");
-                    R.fail("差评申述置信度分析返回数据为空");
-                    continue;
-                }
-
-                // 获取record_id用于后续查询
-                Integer recordId = dataJsonObj.getInteger("record_id");
-                if (recordId == null) {
-                    log.error("差评申述置信度分析返回record_id为空");
-                    R.fail("差评申述置信度分析返回record_id为空");
-                    continue;
-                }
-
-                //修改评论状态为"处理中"
-                StoreCommentAppeal sCommentAppeal = new StoreCommentAppeal();
-                sCommentAppeal.setId((Integer) storeCommentAppeal.get("id"));
-                sCommentAppeal.setAppealStatus(3);
-                sCommentAppeal.setRecordId(recordId);
-                storeCommentAppealMapper.updateById(sCommentAppeal);
-
-            } else {
-                if (analyzeResp != null) {
-                    log.error("调用差评申述置信度分析接口失败, http状态: {}", analyzeResp.getStatusCode());
-                    R.fail("调用差评申述置信度分析接口失败, http状态: " + analyzeResp.getStatusCode());
-                }
-            }
-        }
-        return R.success("调用差评申述置信度分析接口完成");
-    }
-
-    /**
-     * 将图片URL转换为Base64编码
-     *
-     * @param imageUrl 图片URL
-     * @return Base64编码字符串
-     */
-    private String convertImageToBase64(String imageUrl) {
-        // 1. 检查是否为空或非URL格式
-        if (!StringUtils.hasText(imageUrl) || !isValidUrl(imageUrl)) {
-            log.warn("无效的图片URL: {}", imageUrl);
-            return "";
-        }
-
-        try {
-            // 2. 下载图片并转换Base64
-            byte[] imageBytes = restTemplate.getForObject(imageUrl, byte[].class);
-            if (imageBytes != null) {
-                return java.util.Base64.getEncoder().encodeToString(imageBytes);
-            }
-        } catch (org.springframework.web.client.HttpClientErrorException.NotFound e) {
-            // 专门处理404错误
-            log.warn("图片不存在 (404), URL: {}", imageUrl);
-            return ""; // 返回空字符串而不是抛出异常
-        } catch (Exception e) {
-            log.error("图片转换为Base64失败, URL: {}", imageUrl, e);
-            return ""; // 其他异常也返回空字符串,避免中断整个流程
-        }
-        return "";
-    }
-
-
-    // 辅助方法:验证URL格式合法性
-    private boolean isValidUrl(String url) {
-        try {
-            // 尝试构造URI,验证格式
-            new URI(url);
-            // 进一步检查是否以http/https开头(可选,根据业务需求)
-            return url.startsWith("http://") || url.startsWith("https://");
-        } catch (URISyntaxException e) {
-            return false;
-        }
-    }
-
-    private String fetchAiServiceToken() {
-        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);
-
-        try {
-            ResponseEntity<String> response = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
-            if (response != null && response.getStatusCodeValue() == 200 && response.getBody() != null) {
-                JSONObject jsonObject = JSONObject.parseObject(response.getBody());
-                JSONObject dataJson = jsonObject.getJSONObject("data");
-                return dataJson != null ? dataJson.getString("access_token") : null;
-            }
-            log.error("请求差评申诉辅助系统 登录接口失败 http状态:{}", response != null ? response.getStatusCode() : null);
-        } catch (Exception e) {
-            log.error("调用差评申诉辅助系统登录接口异常", e);
-        }
-        return null;
-    }
-
-    private String buildCompletedUrl(Integer recordId) {
-        String baseUrl = analyzeUrl;
-        if (!StringUtils.hasText(baseUrl)) {
-            throw new IllegalStateException("差评申述分析接口地址未配置");
-        }
-        if (baseUrl.endsWith("/")) {
-            baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
-        }
-        String completedBase = baseUrl.replace("/api/v1/analyze", "");
-        if (!completedBase.endsWith("/")) {
-            completedBase = completedBase + "/";
-        }
-        return completedBase + "api/v1/records/" + recordId + "/completed";
-    }
 }
 }

+ 26 - 0
alien-store/src/main/java/shop/alien/store/util/ali/AliSms.java

@@ -9,10 +9,14 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
+import shop.alien.entity.store.StoreVerificationCode;
+import shop.alien.mapper.StoreVerificationCodeMapper;
 import shop.alien.store.config.BaseRedisService;
 import shop.alien.store.config.BaseRedisService;
 import shop.alien.store.config.NacosConfig;
 import shop.alien.store.config.NacosConfig;
 import shop.alien.util.common.RandomCreateUtil;
 import shop.alien.util.common.RandomCreateUtil;
 
 
+import java.util.Date;
+
 /**
 /**
  * 阿里云验证码配置
  * 阿里云验证码配置
  *
  *
@@ -28,6 +32,8 @@ public class AliSms {
 
 
     private final NacosConfig nacosConfig;
     private final NacosConfig nacosConfig;
 
 
+    private final StoreVerificationCodeMapper storeVerificationCodeMapper;
+
     @Value("${ali.sms.accessKeyId}")
     @Value("${ali.sms.accessKeyId}")
     private String accessKeyId;
     private String accessKeyId;
 
 
@@ -99,6 +105,7 @@ public class AliSms {
             if (nacosConfig.getTestPhone().contains(phone)) {
             if (nacosConfig.getTestPhone().contains(phone)) {
                 // 验证码发送成功,将验证码保存到redis中 设置60秒过期
                 // 验证码发送成功,将验证码保存到redis中 设置60秒过期
                 baseRedisService.setString("verification_" + appTypeStr + "_" + businessTypeStr + "_" + phone, "123456", codeTimeOut);
                 baseRedisService.setString("verification_" + appTypeStr + "_" + businessTypeStr + "_" + phone, "123456", codeTimeOut);
+                saveVerificationCode(appType, businessType, phone, "123456");
                 return 123456;
                 return 123456;
             }
             }
             // -----------------测试用手机号--------------------------------------------------------------------------------------------
             // -----------------测试用手机号--------------------------------------------------------------------------------------------
@@ -129,6 +136,8 @@ public class AliSms {
             }
             }
             // 验证码发送成功,将验证码保存到redis中 设置60秒过期
             // 验证码发送成功,将验证码保存到redis中 设置60秒过期
             baseRedisService.setString("verification_" + appTypeStr + "_" + businessTypeStr + "_" + phone, code.toString(), codeTimeOut);
             baseRedisService.setString("verification_" + appTypeStr + "_" + businessTypeStr + "_" + phone, code.toString(), codeTimeOut);
+            saveVerificationCode(appType, businessType, phone, code.toString());
+
             return code;
             return code;
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("AliSmsConfig.sendSms ERROR Msg={}", e.getMessage());
             log.error("AliSmsConfig.sendSms ERROR Msg={}", e.getMessage());
@@ -211,4 +220,21 @@ public class AliSms {
         }
         }
     }
     }
 
 
+    private void saveVerificationCode(Integer appType, Integer businessType, String phone, String code) {
+        try {
+            StoreVerificationCode entity = new StoreVerificationCode();
+            entity.setAppType(appType);
+            entity.setBusinessType(businessType);
+            entity.setPhone(phone);
+            entity.setCode(code);
+            Date now = new Date();
+            entity.setCreatedTime(now);
+            entity.setUpdatedTime(now);
+            entity.setDeleteFlag(0);
+            storeVerificationCodeMapper.insert(entity);
+        } catch (Exception ex) {
+            log.error("AliSms.saveVerificationCode ERROR Msg={}", ex.getMessage(), ex);
+        }
+    }
+
 }
 }