Просмотр исходного кода

Merge remote-tracking branch 'origin/sit' into uat-20260202

dujian 1 неделя назад
Родитель
Сommit
6935f76153

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

@@ -168,4 +168,16 @@ public class LifeUser implements Serializable {
     @ApiModelProperty(value = "是否被封禁(0-否  1-是)")
     @TableField("is_banned")
     private Integer isBanned;
+
+    @ApiModelProperty(value = "关注数")
+    @TableField(exist = false)
+    private Integer followCount;
+
+    @ApiModelProperty(value = "粉丝数")
+    @TableField(exist = false)
+    private Integer fansCount;
+
+    @ApiModelProperty(value = "获赞数")
+    @TableField(exist = false)
+    private Integer likeCount;
 }

+ 1 - 1
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreCommentAppealInfoVo.java

@@ -33,7 +33,7 @@ public class StoreCommentAppealInfoVo extends Model<StoreCommentAppealInfoVo> {
     @ApiModelProperty(value = "商家申诉原因")
     private String appealReason;
 
-    @ApiModelProperty(value = "图片id")
+    @ApiModelProperty(value = "申诉图片,多个OSS地址英文逗号分隔(兼容旧数据为图片id")
     private String imgId;
 
     @ApiModelProperty(value = "申诉状态: 0:待处理, 1:已驳回, 2:已同意")

+ 13 - 6
alien-entity/src/main/java/shop/alien/mapper/second/SecondGoodsMapper.java

@@ -194,17 +194,24 @@ public interface SecondGoodsMapper extends BaseMapper<SecondGoods> {
      * @param queryWrapper 查询条件
      * @return 商品列表
      */
-    @Select("SELECT " +
+    @Select("<script>" +
+            "SELECT " +
             "sg.*, " +
             "sgc1.category_name as categoryOneName, " +
-            "sgc2.category_name as categoryTwoName, "+
-            "ROUND(ST_Distance_Sphere(ST_GeomFromText(CONCAT('POINT(',#{currentLongitude},' ',#{currentLatitude} , ')' )), ST_GeomFromText(CONCAT('POINT(', REPLACE(sg.position, ',', ' '), ')' ))) / 1000, 2) AS distance "+
-            " FROM second_goods sg " +
+            "sgc2.category_name as categoryTwoName, " +
+            "<if test=\"currentLatitude != null and currentLongitude != null\">" +
+            "ROUND(ST_Distance_Sphere(ST_GeomFromText(CONCAT('POINT(',#{currentLongitude},' ',#{currentLatitude},')')), ST_GeomFromText(CONCAT('POINT(', REPLACE(sg.position, ',', ' '), ')' ))) / 1000, 2) AS distance " +
+            "</if>" +
+            "<if test=\"currentLatitude == null or currentLongitude == null\">" +
+            "NULL AS distance " +
+            "</if>" +
+            "FROM second_goods sg " +
             "left JOIN second_goods_category sgc1 " +
             "on sg.category_one_id = sgc1.id " +
             "left JOIN second_goods_category sgc2 " +
-            "on sg.category_two_id = sgc2.id "+
-            "${ew.customSqlSegment}")
+            "on sg.category_two_id = sgc2.id " +
+            "${ew.customSqlSegment}" +
+            "</script>")
     IPage<SecondGoodsVo> getUserGoodsPage(IPage<SecondGoodsVo> page,@Param("currentLatitude") Double currentLatitude , @Param("currentLongitude") Double currentLongitude,  @Param(Constants.WRAPPER) QueryWrapper<SecondGoodsVo> queryWrapper);
 
     /**

+ 2 - 0
alien-entity/src/main/java/shop/alien/mapper/second/SecondRecommendMapper.java

@@ -26,4 +26,6 @@ public interface SecondRecommendMapper extends BaseMapper<SecondGoodsRecommendVo
     List<SecondCommentVo> querySecondCommentInfo(@Param("ids") List<Integer> ids);
 
     SecondGoodsRecommendVo querySecondGoodsDetail(@Param("goodsId") Integer goodsId, @Param("phoneId") String phoneId, @Param("position") String position);
+
+    SecondGoodsRecommendVo querySecondGoodsDetailWithoutPosition(@Param("goodsId") Integer goodsId, @Param("phoneId") String phoneId);
 }

+ 31 - 0
alien-entity/src/main/resources/mapper/second/SecondGoodsInfoMapper.xml

@@ -267,4 +267,35 @@
             and g.position != '' and g.position is not null
     </select>
 
+    <select id="querySecondGoodsDetailWithoutPosition" resultType="shop.alien.entity.second.vo.SecondGoodsRecommendVo">
+        select
+            g.id,
+            g.user_id,
+            g.title,
+            g.description,
+            g.price as amount,
+            g.position,
+            g.like_count,
+            g.collect_count,
+            g.category_one_id,
+            g.category_two_id,
+            g.label,
+            g.topic,
+            g.home_image,
+            g.release_time,
+            g.video_first_frame,
+            lu.user_name,
+            CONCAT('user_', lu.user_phone) as user_phone,
+            lu.user_image,
+            goods_status,
+            NULL AS dist,
+            case when llr.id is null then '0' else '1' end likeStatus,
+            case when lc.id is null then '0' else '1' end collectStatus
+        from second_goods g inner join life_user lu on g.user_id = lu.id and lu.delete_flag = 0
+            left join life_like_record llr on llr.dianzan_id = #{phoneId} and llr.huifu_id = g.id and llr.type = 6 and llr.delete_flag = 0
+            left join life_collect lc on lc.business_id = g.id and lc.user_id = #{phoneId} and lc.delete_flag = 0 and lc.business_type = 1
+        where g.id = #{goodsId} and g.delete_flag = 0
+            and g.position != '' and g.position is not null
+    </select>
+
 </mapper>

+ 9 - 1
alien-second/src/main/java/shop/alien/second/controller/SecondRecommendController.java

@@ -7,6 +7,7 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiSort;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.second.vo.SecondGoodsRecommendVo;
@@ -73,7 +74,7 @@ public class SecondRecommendController {
             @RequestParam(value = "longitude", required = false) String longitude,
             @RequestParam(value = "latitude", required = false) String latitude) throws Exception {
         log.info("LifeCollectController.cancelCollect?goodsId={},longitude={},latitude={}", goodsId, longitude, latitude);
-        return R.data(service.querySecondGoodsDetail(goodsId, longitude + "," + latitude), "查询成功");
+        return R.data(service.querySecondGoodsDetail(goodsId, buildUserPosition(longitude, latitude)), "查询成功");
     }
 
     @ApiOperation(value = "商品详情(匿名/带手机号)", notes = "需传当前用户 phoneId(可为裸手机号或 user_ 前缀),与 collect/addCollect 写入的 life_collect.user_id 一致;响应 collectStatus:0=未收藏,1=已收藏")
@@ -87,4 +88,11 @@ public class SecondRecommendController {
         return R.data(service.querySecondGoodsDetailWithOutJWT(phoneId, goodsId, longitude + "," + latitude), "查询成功");
     }
 
+    private static String buildUserPosition(String longitude, String latitude) {
+        if (!StringUtils.hasText(longitude) || !StringUtils.hasText(latitude)) {
+            return null;
+        }
+        return longitude.trim() + "," + latitude.trim();
+    }
+
 }

+ 4 - 4
alien-second/src/main/java/shop/alien/second/controller/UserGoodsController.java

@@ -162,14 +162,14 @@ public class UserGoodsController {
     @ApiOperation("他的商品-个人主页用户发布的商品")
     @ApiImplicitParams({
             @ApiImplicitParam(name = "userId", value = "主页用户id", dataType = "Integer", paramType = "query", required = true),
-            @ApiImplicitParam(name = "currentLongitude", value = "经度", dataType = "Double", paramType = "query", required = true),
-            @ApiImplicitParam(name = "currentLatitude", value = "纬度", dataType = "Double", paramType = "query", required = true),
+            @ApiImplicitParam(name = "currentLongitude", value = "经度", dataType = "Double", paramType = "query", required = false),
+            @ApiImplicitParam(name = "currentLatitude", value = "纬度", dataType = "Double", paramType = "query", required = false),
             @ApiImplicitParam(name = "pageNum", value = "分页页数", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "pageSize", value = "分页条数", dataType = "Integer", paramType = "query", required = true)})
     public R<IPage<SecondGoodsVo>> getUserGoodsPage(
             @RequestParam Integer userId,
-            @RequestParam Double currentLongitude,
-            @RequestParam Double currentLatitude,
+            @RequestParam(required = false) Double currentLongitude,
+            @RequestParam(required = false) Double currentLatitude,
             @RequestParam(defaultValue = "1") Integer pageNum,
             @RequestParam(defaultValue = "10") Integer pageSize) {
         log.info("SecondGoodsController.getDraftList?userId={},currentLongitude={},currentLatitude={},page={},size={},",userId,currentLongitude,currentLatitude, pageNum,pageSize);

+ 3 - 1
alien-second/src/main/java/shop/alien/second/service/impl/SecondRecommendServiceImpl.java

@@ -192,7 +192,9 @@ public class SecondRecommendServiceImpl extends ServiceImpl<SecondRecommendMappe
                 return null;
             }
             String collectUserId = toLifeCollectUserId(phoneId);
-            SecondGoodsRecommendVo item = mapper.querySecondGoodsDetail(goodsId, collectUserId, position);
+            SecondGoodsRecommendVo item = StringUtil.isBlank(position)
+                    ? mapper.querySecondGoodsDetailWithoutPosition(goodsId, collectUserId)
+                    : mapper.querySecondGoodsDetail(goodsId, collectUserId, position);
             applySecondGoodsDetailEnrichment(item, phoneId, goodsId);
             return item;
         } catch (Exception e) {

+ 1 - 1
alien-second/src/main/resources/bootstrap.yml

@@ -1,3 +1,3 @@
 spring:
   profiles:
-    active: dev
+    active: test

+ 6 - 6
alien-store/src/main/java/shop/alien/store/controller/StoreCommentAppealController.java

@@ -54,19 +54,19 @@ public class StoreCommentAppealController {
             targetType = "STORE"
     )
     @ApiOperationSupport(order = 2)
-    @ApiOperation(value = "商家端-新增申诉(0:申诉成功, 1:申诉失败, 2:申诉已存在)")
-    @ApiImplicitParams({@ApiImplicitParam(name = "multipartRequest", value = "文件", dataType = "File", paramType = "query", required = true),
+    @ApiOperation(value = "商家端-新增申诉(0:申诉成功, 1:申诉失败, 2:申诉已存在, 3:文本内容异常)")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "imgUrls", value = "申诉图片OSS地址,多个用英文逗号分隔", dataType = "String", paramType = "query"),
             @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "commentId", value = "评论id", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "appealReason", value = "申诉原因", dataType = "String", paramType = "query", required = true)})
     @PostMapping("/addAppealNew")
-    public R<StoreCommentAppealInfoVo> addAppealNew(MultipartRequest multipartRequest,
+    public R<StoreCommentAppealInfoVo> addAppealNew(@RequestParam(value = "imgUrls", required = false) String imgUrls,
                                                  @RequestParam("storeId") Integer storeId,
                                                  @RequestParam("commentId") Integer commentId,
                                                  @RequestParam("appealReason") String appealReason) {
-        Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
-        log.info("StoreCommentAppealController.addAppealNew?multipartRequest={}&storeId={}&commentId={}&appealReason={}", fileNameSet, storeId, commentId, appealReason);
-        return R.data(storeCommentAppealService.addAppealNew(multipartRequest, storeId, commentId, appealReason));
+        log.info("StoreCommentAppealController.addAppealNew?imgUrls={}&storeId={}&commentId={}&appealReason={}", imgUrls, storeId, commentId, appealReason);
+        return R.data(storeCommentAppealService.addAppealNew(imgUrls, storeId, commentId, appealReason));
     }
 
     @ApiOperationSupport(order = 2)

+ 10 - 9
alien-store/src/main/java/shop/alien/store/controller/WxJsSdkController.java

@@ -1,13 +1,13 @@
 package shop.alien.store.controller;
 
 import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
+import shop.alien.store.dto.WxJsSdkConfigRequest;
 import shop.alien.store.dto.WxJsSdkConfigVo;
 import shop.alien.store.service.WxJsSdkService;
 
@@ -24,13 +24,14 @@ public class WxJsSdkController {
 
     private final WxJsSdkService wxJsSdkService;
 
-    @ApiOperation("获取微信 JS-SDK 签名参数(前端 wx.config 使用)")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "url", value = "当前 H5 页面完整 URL(不含 # 及后面部分,需与前端 location.href 处理后一致)",
-                    dataType = "String", paramType = "query", required = true)
-    })
-    @GetMapping("/getWxConfig")
-    public R<WxJsSdkConfigVo> getWxConfig(@RequestParam String url) {
+    @ApiOperation(value = "获取微信 JS-SDK 签名参数(前端 wx.config 使用)",
+            notes = "url 放在请求体,避免 GET query 过长导致 413")
+    @PostMapping("/getWxConfig")
+    public R<WxJsSdkConfigVo> getWxConfig(@RequestBody WxJsSdkConfigRequest request) {
+        if (request == null || !StringUtils.hasText(request.getUrl())) {
+            return R.fail("url 不能为空");
+        }
+        String url = request.getUrl().trim();
         log.info("WxJsSdkController.getWxConfig url={}", url);
         return R.data(wxJsSdkService.buildJsSdkConfig(url));
     }

+ 16 - 0
alien-store/src/main/java/shop/alien/store/dto/WxJsSdkConfigRequest.java

@@ -0,0 +1,16 @@
+package shop.alien.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 微信 JS-SDK 签名请求
+ */
+@Data
+@ApiModel(value = "微信 JS-SDK 签名请求")
+public class WxJsSdkConfigRequest {
+
+    @ApiModelProperty(value = "当前 H5 页面完整 URL(不含 # 及后面部分,需与前端 location.href 处理后一致)", required = true)
+    private String url;
+}

+ 28 - 1
alien-store/src/main/java/shop/alien/store/service/LifeUserService.java

@@ -71,6 +71,8 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
 
     private final LifeFansMapper lifeFansMapper;
 
+    private final LifeUserDynamicsMapper lifeUserDynamicsMapper;
+
     private final BaseRedisService baseRedisService;
 
     private final LifeNoticeMapper lifeNoticeMapper;
@@ -444,7 +446,32 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
     public LifeUser getUserByPhone(String phoneNum) {
         LambdaQueryWrapper<LifeUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
         lambdaQueryWrapper.eq(LifeUser::getUserPhone, phoneNum);
-        return this.getOne(lambdaQueryWrapper);
+        LifeUser user = this.getOne(lambdaQueryWrapper);
+        if (user != null) {
+            String userId = "user_" + phoneNum;
+            LambdaQueryWrapper<LifeFans> followWrapper = new LambdaQueryWrapper<>();
+            followWrapper.eq(LifeFans::getFansId, userId);
+            long followCount = lifeFansMapper.selectCount(followWrapper);
+            user.setFollowCount((int) followCount);
+
+            LambdaQueryWrapper<LifeFans> fansWrapper = new LambdaQueryWrapper<>();
+            fansWrapper.eq(LifeFans::getFollowedId, userId);
+            long fansCount = lifeFansMapper.selectCount(fansWrapper);
+            user.setFansCount((int) fansCount);
+
+            LambdaQueryWrapper<LifeUserDynamics> dynamicsWrapper = new LambdaQueryWrapper<>();
+            dynamicsWrapper.eq(LifeUserDynamics::getPhoneId, userId)
+                    .eq(LifeUserDynamics::getDeleteFlag, 0);
+            List<LifeUserDynamics> dynamicsList = lifeUserDynamicsMapper.selectList(dynamicsWrapper);
+            long likeCount = 0L;
+            if (dynamicsList != null && !dynamicsList.isEmpty()) {
+                likeCount = dynamicsList.stream()
+                        .mapToLong(d -> d.getDianzanCount() != null ? d.getDianzanCount() : 0)
+                        .sum();
+            }
+            user.setLikeCount((int) likeCount);
+        }
+        return user;
     }
 
     public void liftCancelAccount(LifeUser user) {

+ 6 - 6
alien-store/src/main/java/shop/alien/store/service/StoreCommentAppealService.java

@@ -49,13 +49,13 @@ public interface StoreCommentAppealService extends IService<StoreCommentAppeal>
     /**
      * 新增申诉
      *
-     * @param multipartRequest 文件
-     * @param storeId          门店id
-     * @param commentId        评论id
-     * @param appealReason     申诉原因
-     * @return Integer(0 : 申诉成功, 1 : 申诉失败, 2 : 申诉已存在, 3 : 文本内容异常)
+     * @param imgUrls       申诉图片OSS地址,多个用英文逗号分隔
+     * @param storeId       门店id
+     * @param commentId     评论id
+     * @param appealReason  申诉原因
+     * @return StoreCommentAppealInfoVo(result: 0申诉成功, 1申诉失败, 2申诉已存在, 3文本内容异常)
      */
-    StoreCommentAppealInfoVo addAppealNew(MultipartRequest multipartRequest, Integer storeId, Integer commentId, String appealReason);
+    StoreCommentAppealInfoVo addAppealNew(String imgUrls, Integer storeId, Integer commentId, String appealReason);
 
 
 

+ 54 - 72
alien-store/src/main/java/shop/alien/store/service/impl/StoreCommentAppealServiceImpl.java

@@ -134,15 +134,7 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
 
         IPage<StoreCommentAppealVo> storeCommentAppealPage = storeCommentAppealMapper.getStoreCommentAppealPage(new Page<>(pageNum, pageSize), wrapper);
         storeCommentAppealPage.getRecords().forEach(item -> {
-            String[] split = item.getImgId().split(",");
-            List<String> imgList = new ArrayList<>();
-            for (String s : split) {
-                StoreImg storeImg = storeImgMapper.selectById(s);
-                if (null != storeImg) {
-                    imgList.add(storeImg.getImgUrl());
-                }
-            }
-            item.setImgList(imgList);
+            item.setImgList(buildAppealImgList(item.getImgId()));
 
             if (StringUtils.isNotEmpty(item.getCommentImgId())) {
                 String[] imgId = item.getCommentImgId().split(",");
@@ -257,14 +249,14 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
     /**
      * 新增申诉
      *
-     * @param multipartRequest 文件
-     * @param storeId          门店id
-     * @param commentId        评论id
-     * @param appealReason     申诉原因
-     * @return Integer(0 : 申诉成功, 1 : 申诉失败, 2 : 申诉已存在, 3 : 文本内容异常)
+     * @param imgUrls       申诉图片OSS地址,多个用英文逗号分隔
+     * @param storeId       门店id
+     * @param commentId     评论id
+     * @param appealReason  申诉原因
+     * @return StoreCommentAppealInfoVo(result: 0申诉成功, 1申诉失败, 2申诉已存在, 3文本内容异常)
      */
     @Override
-    public StoreCommentAppealInfoVo addAppealNew(MultipartRequest multipartRequest, Integer storeId, Integer commentId, String appealReason) {
+    public StoreCommentAppealInfoVo addAppealNew(String imgUrls, Integer storeId, Integer commentId, String appealReason) {
         StoreCommentAppealInfoVo storeCommentAppealInfoVo = new StoreCommentAppealInfoVo();
         try {
             Map<String, String> checkText = TextCheckUtil.check(appealReason);
@@ -283,7 +275,6 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
                 return storeCommentAppealInfoVo;
             }
 
-            List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
             LambdaQueryWrapper<StoreCommentAppeal> wrapper = new LambdaQueryWrapper<>();
             //待审批, 已通过
             List<Integer> list = new ArrayList<>();
@@ -302,21 +293,8 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
                 return 2;
             }*/
             StoreCommentAppeal storeCommentAppeal = new StoreCommentAppeal();
-            StringBuilder imgId = new StringBuilder();
-            for (int i = 0; i < fileNameSet.size(); i++) {
-                MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
-                if (null != multipartFile) {
-                    StoreImg storeImg = new StoreImg();
-                    storeImg.setStoreId(storeId);
-                    storeImg.setImgType(9);
-                    storeImg.setImgSort(i + 1);
-                    storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
-                    storeImgMapper.insert(storeImg);
-                    imgId.append(storeImg.getId()).append(",");
-                }
-            }
-            if (!imgId.toString().isEmpty()) {
-                storeCommentAppeal.setImgId(imgId.substring(0, imgId.length() - 1));
+            if (StringUtils.isNotEmpty(imgUrls)) {
+                storeCommentAppeal.setImgId(normalizeAppealImgUrls(imgUrls));
             }
             storeCommentAppeal.setStoreId(storeId);
             storeCommentAppeal.setCommentId(commentId);
@@ -397,15 +375,7 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
         storeCommentAppealVoQueryWrapper.eq("a.id", id);
         StoreCommentAppealVo commentDetail = storeCommentAppealMapper.getCommentDetail(storeCommentAppealVoQueryWrapper);
 
-        String[] split = commentDetail.getImgId().split(",");
-        List<String> imgList = new ArrayList<>();
-        for (String s : split) {
-            StoreImg storeImg = storeImgMapper.selectById(s);
-            if (null != storeImg) {
-                imgList.add(storeImg.getImgUrl());
-            }
-        }
-        commentDetail.setImgList(imgList);
+        commentDetail.setImgList(buildAppealImgList(commentDetail.getImgId()));
 
         // 处理评价图片(common_rating.image_urls 已经是URL字符串,不是ID)
         if (StringUtils.isNotEmpty(commentDetail.getCommentImgId())) {
@@ -484,15 +454,7 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
                         .filter(Objects::nonNull)
                         .collect(Collectors.toList());
                 item.setStoreTypeStr(String.join(",", typeDetails));
-                String[] split = item.getImgId().split(",");
-                List<String> imgList = new ArrayList<>();
-                for (String s : split) {
-                    StoreImg storeImg = storeImgMapper.selectById(s);
-                    if (null != storeImg) {
-                        imgList.add(storeImg.getImgUrl());
-                    }
-                }
-                item.setImgList(imgList);
+                item.setImgList(buildAppealImgList(item.getImgId()));
             });
         }
         toExcel = storeCommentAppealPage.getRecords();
@@ -724,6 +686,41 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
     }
 
     /**
+     * 规范化申诉图片URL(逗号分隔)
+     */
+    private String normalizeAppealImgUrls(String imgUrls) {
+        return Arrays.stream(imgUrls.split(","))
+                .map(String::trim)
+                .filter(StringUtils::isNotEmpty)
+                .collect(Collectors.joining(","));
+    }
+
+    /**
+     * 解析申诉图片:新数据为OSS URL,旧数据为 store_img 主键
+     */
+    private List<String> buildAppealImgList(String imgId) {
+        List<String> imgList = new ArrayList<>();
+        if (StringUtils.isEmpty(imgId)) {
+            return imgList;
+        }
+        for (String item : imgId.split(",")) {
+            String trimmed = item.trim();
+            if (StringUtils.isEmpty(trimmed)) {
+                continue;
+            }
+            if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
+                imgList.add(trimmed);
+            } else {
+                StoreImg storeImg = storeImgMapper.selectById(trimmed);
+                if (storeImg != null && StringUtils.isNotEmpty(storeImg.getImgUrl())) {
+                    imgList.add(storeImg.getImgUrl());
+                }
+            }
+        }
+        return imgList;
+    }
+
+    /**
      * 调用AI分析接口提交申诉分析任务
      *
      * @param storeCommentAppeal 申诉记录
@@ -732,12 +729,12 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
     private Integer invokeAiAnalyze(StoreCommentAppeal storeCommentAppeal) {
         log.info("开始调用AI差评申诉置信度分析接口,申诉ID: {}", storeCommentAppeal.getId());
         
-        // 1. 获取访问令牌(使用工具类)
-        String accessToken = aiAuthTokenUtil.getAccessToken();
-        if (!org.springframework.util.StringUtils.hasText(accessToken)) {
-            log.error("调用AI分析接口失败,获取accessToken失败,申诉ID: {}", storeCommentAppeal.getId());
-            return null;
-        }
+//        // 1. 获取访问令牌(使用工具类)
+//        String accessToken = aiAuthTokenUtil.getAccessToken();
+//        if (!org.springframework.util.StringUtils.hasText(accessToken)) {
+//            log.error("调用AI分析接口失败,获取accessToken失败,申诉ID: {}", storeCommentAppeal.getId());
+//            return null;
+//        }
 
         // 2. 查询评论信息(CommonRating)
         CommonRating rating = commonRatingMapper.selectById(storeCommentAppeal.getCommentId());
@@ -760,22 +757,7 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
         
         // 商家图片:暂时传空数组,先测试文本分析流程
         // TODO: 后续需要将图片转换为Base64
-        List<String> merchantImages = new ArrayList<>();
-         if (org.springframework.util.StringUtils.hasText(storeCommentAppeal.getImgId())) {
-             String[] imgIds = storeCommentAppeal.getImgId().split(",");
-             for (String imgId : imgIds) {
-                 StoreImg storeImg = storeImgMapper.selectById(imgId.trim());
-//                 if (storeImg != null && org.springframework.util.StringUtils.hasText(storeImg.getImgUrl())) {
-//                     String base64 = convertImageToBase64(storeImg.getImgUrl());
-//                     if (org.springframework.util.StringUtils.hasText(base64)) {
-//                         merchantImages.add(base64);
-//                     }
-//                 }
-                 if (storeImg.getImgUrl() != null) {
-                     merchantImages.add(storeImg.getImgUrl());
-                 }
-             }
-         }
+        List<String> merchantImages = buildAppealImgList(storeCommentAppeal.getImgId());
         analyzeRequest.put("merchant_images", merchantImages);
         
         // 用户图片:暂时传空数组,先测试文本分析流程
@@ -805,7 +787,7 @@ public class StoreCommentAppealServiceImpl extends ServiceImpl<StoreCommentAppea
         // 4. 设置请求头
         HttpHeaders analyzeHeaders = new HttpHeaders();
         analyzeHeaders.setContentType(MediaType.APPLICATION_JSON);
-        analyzeHeaders.set("Authorization", "Bearer " + accessToken);
+//        analyzeHeaders.set("Authorization", "Bearer " + accessToken);
         HttpEntity<Map<String, Object>> analyzeEntity = new HttpEntity<>(analyzeRequest, analyzeHeaders);
 
         // 5. 调用AI接口