Explorar o código

Merge remote-tracking branch 'origin/sit-three-categories' into sit-three-categories

liyafei hai 3 meses
pai
achega
c78835b858
Modificáronse 19 ficheiros con 543 adicións e 235 borrados
  1. 4 0
      alien-entity/src/main/java/shop/alien/entity/store/SportsFacilityArea.java
  2. 12 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreComment.java
  3. 10 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreInfo.java
  4. 3 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/StoreInfoScoreVo.java
  5. 29 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/UpdateAreaHeadUrlRequestVo.java
  6. 5 5
      alien-entity/src/main/java/shop/alien/mapper/StoreCommentMapper.java
  7. 0 0
      alien-store/api_docs/36-店铺问答讨论模块接口.md
  8. 7 1
      alien-store/pom.xml
  9. 93 0
      alien-store/src/main/java/shop/alien/store/controller/AiSearchController.java
  10. 46 5
      alien-store/src/main/java/shop/alien/store/controller/SportsFacilityAreaController.java
  11. 31 20
      alien-store/src/main/java/shop/alien/store/controller/StoreCommentController.java
  12. 3 3
      alien-store/src/main/java/shop/alien/store/controller/StoreInfoController.java
  13. 9 3
      alien-store/src/main/java/shop/alien/store/controller/StorePlatformDiscussionController.java
  14. 10 0
      alien-store/src/main/java/shop/alien/store/service/SportsFacilityAreaService.java
  15. 15 19
      alien-store/src/main/java/shop/alien/store/service/StoreCommentService.java
  16. 47 0
      alien-store/src/main/java/shop/alien/store/service/impl/SportsFacilityAreaServiceImpl.java
  17. 138 154
      alien-store/src/main/java/shop/alien/store/service/impl/StoreCommentServiceImpl.java
  18. 49 17
      alien-store/src/main/java/shop/alien/store/service/impl/StorePlatformDiscussionServiceImpl.java
  19. 32 8
      alien-util/src/main/java/shop/alien/util/file/FileUtil.java

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

@@ -67,5 +67,9 @@ public class SportsFacilityArea implements Serializable {
     @ApiModelProperty(value = "区域logo图地址")
     @ApiModelProperty(value = "区域logo图地址")
     @TableField("area_logo_img")
     @TableField("area_logo_img")
     private String areaLogoImg;
     private String areaLogoImg;
+
+    @ApiModelProperty(value = "区域头图URL")
+    @TableField("area_head_url")
+    private String areaHeadUrl;
 }
 }
 
 

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

@@ -131,4 +131,16 @@ public class StoreComment extends Model<StoreComment> {
     @TableField("lawyer_id")
     @TableField("lawyer_id")
     private Integer lawyerId;
     private Integer lawyerId;
 
 
+    @ApiModelProperty(value = "口味评分")
+    @TableField("score_one")
+    private Double scoreOne;
+
+    @ApiModelProperty(value = "环境评分")
+    @TableField("score_two")
+    private Double scoreTwo;
+
+    @ApiModelProperty(value = "服务评分")
+    @TableField("score_three")
+    private Double scoreThree;
+
 }
 }

+ 10 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreInfo.java

@@ -341,4 +341,14 @@ public class StoreInfo {
     @TableField("business_category_name")
     @TableField("business_category_name")
     private String businessCategoryName;
     private String businessCategoryName;
 
 
+    @ApiModelProperty(value = "评价1")
+    @TableField("score_one")
+    private Double scoreOne;
+     @ApiModelProperty(value = "评价2")
+    @TableField("score_two")
+    private Double scoreTwo;
+     @ApiModelProperty(value = "评价3")
+    @TableField("score_three")
+    private Double scoreThree;
+
 }
 }

+ 3 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreInfoScoreVo.java

@@ -9,4 +9,7 @@ public class StoreInfoScoreVo {
     private Double tasteScore;
     private Double tasteScore;
     private Double enScore;
     private Double enScore;
     private Double serviceScore;
     private Double serviceScore;
+    private Double scoreOne;
+    private Double scoreTwo;
+    private Double scoreThree;
 }
 }

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

@@ -0,0 +1,29 @@
+package shop.alien.entity.store.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 更新区域头图请求VO
+ *
+ * @author assistant
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "UpdateAreaHeadUrlRequestVo对象", description = "更新区域头图请求视图对象")
+public class UpdateAreaHeadUrlRequestVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "区域ID", required = true, example = "1")
+    private Integer areaId;
+
+    @ApiModelProperty(value = "区域头图URL(长字符串)", required = true, example = "https://example.com/head1.jpg,https://example.com/head2.jpg")
+    private String areaHeadUrl;
+}
+

+ 5 - 5
alien-entity/src/main/java/shop/alien/mapper/StoreCommentMapper.java

@@ -116,14 +116,14 @@ public interface StoreCommentMapper extends BaseMapper<StoreComment> {
 
 
     @Select("SELECT " +
     @Select("SELECT " +
             "ifnull(SUM( score ),0) score," +
             "ifnull(SUM( score ),0) score," +
-            "ifnull(SUM( taste_score ),0) tasteScore," +
-            "ifnull(SUM( en_score ),0) enScore," +
-            "ifnull(SUM( service_score ),0) serviceScore," +
+            "ifnull(SUM( score_one ),0) scoreOne," +
+            "ifnull(SUM( score_two ),0) scoreTwo," +
+            "ifnull(SUM( score_three ),0) scoreThree," +
             "COUNT(0) total " +
             "COUNT(0) total " +
             "FROM" +
             "FROM" +
             "`store_comment` " +
             "`store_comment` " +
             "WHERE " +
             "WHERE " +
-            "business_type = 5 " +
+            "business_type = 6 " +
             "AND delete_flag = 0 " +
             "AND delete_flag = 0 " +
             "AND reply_id IS NULL " +
             "AND reply_id IS NULL " +
             "AND store_id = #{storeId}")
             "AND store_id = #{storeId}")
@@ -194,7 +194,7 @@ WHERE
             "\tstore_comment s\n" +
             "\tstore_comment s\n" +
             "\tLEFT JOIN life_user lu ON s.user_id = lu.id \n" +
             "\tLEFT JOIN life_user lu ON s.user_id = lu.id \n" +
             "WHERE\n" +
             "WHERE\n" +
-            "\ts.business_type = 5 \n" +
+            "\ts.business_type = 6 \n" +
             "\tAND s.store_id = #{storeId}\n" +
             "\tAND s.store_id = #{storeId}\n" +
             "\tLIMIT 1")
             "\tLIMIT 1")
     StoreCommentVo getCommentOneInfo(@Param("storeId") int storeId);
     StoreCommentVo getCommentOneInfo(@Param("storeId") int storeId);

+ 0 - 0
alien-store-platform/接口文档/36-店铺问答讨论模块接口.md → alien-store/api_docs/36-店铺问答讨论模块接口.md


+ 7 - 1
alien-store/pom.xml

@@ -11,7 +11,7 @@
     <artifactId>alien-store</artifactId>
     <artifactId>alien-store</artifactId>
     <version>1.0.0</version>
     <version>1.0.0</version>
     <name>alien-store</name>
     <name>alien-store</name>
-    <description>爱丽恩二期项目</description>
+    <description>爱丽恩二期项目 用户端</description>
 
 
     <properties>
     <properties>
         <java.version>1.8</java.version>
         <java.version>1.8</java.version>
@@ -48,6 +48,11 @@
         </dependency>
         </dependency>
 
 
         <dependency>
         <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson-spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.commons</groupId>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-pool2</artifactId>
             <artifactId>commons-pool2</artifactId>
         </dependency>
         </dependency>
@@ -292,6 +297,7 @@
             <groupId>org.springframework.boot</groupId>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-security</artifactId>
             <artifactId>spring-boot-starter-security</artifactId>
         </dependency>
         </dependency>
+
     </dependencies>
     </dependencies>
 
 
     <build>
     <build>

+ 93 - 0
alien-store/src/main/java/shop/alien/store/controller/AiSearchController.java

@@ -0,0 +1,93 @@
+package shop.alien.store.controller;
+
+import com.alibaba.fastjson2.JSONObject;
+import io.swagger.annotations.Api;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+import shop.alien.entity.result.R;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+@Slf4j
+@Api(tags = {"ai搜索"})
+@CrossOrigin
+@RestController
+@RequestMapping("/aiSearch")
+@RequiredArgsConstructor
+@RefreshScope
+public class AiSearchController {
+
+    @Value("${third-party-ai-search.base-url:http://124.93.18.180:7870/api/v1/search}")
+    private String aiSearchUrl;
+
+    private final RestTemplate restTemplate;
+
+    @RequestMapping("/search")
+    public R search(@RequestBody Map<String,String> map) {
+
+
+        // 初始化请求体Map
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("query", map.get("storeName"));
+        requestBody.put("limit", map.get("pageSize"));
+        requestBody.put("user_lat", map.get("lat"));
+        requestBody.put("user_lng", map.get("lan"));
+        requestBody.put("category", map.get("category"));
+        HttpHeaders aiHeaders = new HttpHeaders();
+        aiHeaders.setContentType(MediaType.APPLICATION_JSON);
+//        aiHeaders.set("Authorization", "Bearer " + accessToken);
+//        aiHeaders.set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1cHN0b3JlQGFkbWluLmNvbSIsImlkIjo2LCJ0aW1lIjoxNzYyOTI1NDAzLjY1MTY5MjZ9.07lz8Ox2cGC28UCmqcKCt5R6Rfwtgs-Eiu0ttgWRxws");
+
+        HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, null);
+        try {
+            ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(aiSearchUrl, request, String.class);
+            String body = stringResponseEntity.getBody();
+            JSONObject jsonObject = JSONObject.parseObject(body);
+            JSONObject jsonObject1 = new JSONObject();
+            jsonObject1.put("total",jsonObject.get("total"));
+            jsonObject1.put("records",jsonObject.get("results"));
+            jsonObject1.put("size",map.get("pageSize"));
+            log.info("调用AI搜索接口 接口返回------{}", body);
+            return R.data(jsonObject1);
+        } catch (Exception e) {
+            log.error("调用AI搜索接口 接口异常------", e);
+        }
+        return  R.fail("请求失败");
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}

+ 46 - 5
alien-store/src/main/java/shop/alien/store/controller/SportsFacilityAreaController.java

@@ -10,6 +10,7 @@ import shop.alien.entity.store.SportsFacilityArea;
 import shop.alien.entity.store.vo.BatchDeleteAreaRequestVo;
 import shop.alien.entity.store.vo.BatchDeleteAreaRequestVo;
 import shop.alien.entity.store.vo.CreateAreaRequestVo;
 import shop.alien.entity.store.vo.CreateAreaRequestVo;
 import shop.alien.entity.store.vo.DeleteAreaRequestVo;
 import shop.alien.entity.store.vo.DeleteAreaRequestVo;
+import shop.alien.entity.store.vo.UpdateAreaHeadUrlRequestVo;
 import shop.alien.store.service.SportsFacilityAreaService;
 import shop.alien.store.service.SportsFacilityAreaService;
 
 
 import java.util.List;
 import java.util.List;
@@ -22,7 +23,7 @@ import java.util.List;
  */
  */
 @Slf4j
 @Slf4j
 @Api(tags = {"商户端-运动设施区域管理"})
 @Api(tags = {"商户端-运动设施区域管理"})
-@ApiSort(2)
+@ApiSort(1)
 @CrossOrigin
 @CrossOrigin
 @RestController
 @RestController
 @RequestMapping("/sports/facility/area")
 @RequestMapping("/sports/facility/area")
@@ -41,7 +42,7 @@ public class SportsFacilityAreaController {
      */
      */
     private static final String INVALID_STORE_ID_MSG = "门店ID不能为空且必须大于0";
     private static final String INVALID_STORE_ID_MSG = "门店ID不能为空且必须大于0";
 
 
-    @ApiOperation("新建区域(创建新的设施区域)")
+    @ApiOperation("新建区域")
     @ApiOperationSupport(order = 1)
     @ApiOperationSupport(order = 1)
     @ApiImplicitParams({
     @ApiImplicitParams({
             @ApiImplicitParam(name = "request", value = "新建区域请求参数", dataType = "CreateAreaRequestVo", paramType = "body", required = true)
             @ApiImplicitParam(name = "request", value = "新建区域请求参数", dataType = "CreateAreaRequestVo", paramType = "body", required = true)
@@ -142,9 +143,49 @@ public class SportsFacilityAreaController {
         }
         }
     }
     }
 
 
-    @ApiOperation("删除区域(逻辑删除,同时删除该区域下的所有设施)")
+    @ApiOperation("更新区域头图")
     @ApiOperationSupport(order = 4)
     @ApiOperationSupport(order = 4)
     @ApiImplicitParams({
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "request", value = "更新区域头图请求参数", dataType = "UpdateAreaHeadUrlRequestVo", paramType = "body", required = true)
+    })
+    @PostMapping("/updateHeadUrl")
+    public R<Boolean> updateAreaHeadUrl(@RequestBody UpdateAreaHeadUrlRequestVo request) {
+        log.info("更新区域头图,request={}", request);
+        try {
+            // 参数验证
+            if (request == null) {
+                log.warn("更新区域头图失败,请求参数为空");
+                return R.fail("请求参数不能为空");
+            }
+
+            if (request.getAreaId() == null || request.getAreaId() < MIN_VALID_VALUE) {
+                log.warn("更新区域头图失败,区域ID无效:{}", request.getAreaId());
+                return R.fail("区域ID不能为空且必须大于0");
+            }
+
+            if (request.getAreaHeadUrl() == null) {
+                log.warn("更新区域头图失败,区域头图URL为空");
+                return R.fail("区域头图URL不能为空");
+            }
+
+            boolean result = areaService.updateAreaHeadUrl(request.getAreaId(), request.getAreaHeadUrl());
+            if (result) {
+                log.info("更新区域头图成功,areaId={}", request.getAreaId());
+                return R.success("更新区域头图成功");
+            }
+            return R.fail("更新区域头图失败");
+        } catch (IllegalArgumentException e) {
+            log.warn("更新区域头图失败,参数验证失败:{}", e.getMessage());
+            return R.fail(e.getMessage());
+        } catch (Exception e) {
+            log.error("更新区域头图异常,request={},异常信息:{}", request, e.getMessage(), e);
+            return R.fail("更新区域头图失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperation("删除区域")
+    @ApiOperationSupport(order = 5)
+    @ApiImplicitParams({
             @ApiImplicitParam(name = "request", value = "删除区域请求参数", dataType = "DeleteAreaRequestVo", paramType = "body", required = true)
             @ApiImplicitParam(name = "request", value = "删除区域请求参数", dataType = "DeleteAreaRequestVo", paramType = "body", required = true)
     })
     })
     @PostMapping("/delete")
     @PostMapping("/delete")
@@ -177,8 +218,8 @@ public class SportsFacilityAreaController {
         }
         }
     }
     }
 
 
-    @ApiOperation("批量删除区域(逻辑删除,同时删除这些区域下的所有设施)")
-    @ApiOperationSupport(order = 5)
+    @ApiOperation("批量删除区域")
+    @ApiOperationSupport(order = 6)
     @ApiImplicitParams({
     @ApiImplicitParams({
             @ApiImplicitParam(name = "request", value = "批量删除区域请求参数", dataType = "BatchDeleteAreaRequestVo", paramType = "body", required = true)
             @ApiImplicitParam(name = "request", value = "批量删除区域请求参数", dataType = "BatchDeleteAreaRequestVo", paramType = "body", required = true)
     })
     })

+ 31 - 20
alien-store/src/main/java/shop/alien/store/controller/StoreCommentController.java

@@ -7,11 +7,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartRequest;
 import org.springframework.web.multipart.MultipartRequest;
 import shop.alien.entity.result.R;
 import shop.alien.entity.result.R;
-import shop.alien.entity.store.vo.LifeUserOrderCommentVo;
-import shop.alien.entity.store.vo.StoreCommentCountVo;
-import shop.alien.entity.store.vo.StoreCommentVo;
-import shop.alien.entity.store.vo.StoreCommitPercentVo;
-import shop.alien.entity.store.vo.UserOrderVo;
+import shop.alien.entity.store.vo.*;
 import shop.alien.store.service.StoreCommentService;
 import shop.alien.store.service.StoreCommentService;
 
 
 import java.util.Map;
 import java.util.Map;
@@ -120,6 +116,7 @@ public class StoreCommentController {
             @ApiImplicitParam(name = "phoneId", value = "用户id", dataType = "String", paramType = "query")
             @ApiImplicitParam(name = "phoneId", value = "用户id", dataType = "String", paramType = "query")
     })
     })
     @PostMapping("/saveComment")
     @PostMapping("/saveComment")
+    @Deprecated
     public R<Integer> saveComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
     public R<Integer> saveComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
         log.info("StoreCommentController.saveComment?id={}&businessId={}&businessType={}&storeId={}&userId={}&replyId={}&commentContent={}&score={}&otherScore={}&isAnonymous={}&evaluationTags={}&phoneId={}", id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId);
         log.info("StoreCommentController.saveComment?id={}&businessId={}&businessType={}&storeId={}&userId={}&replyId={}&commentContent={}&score={}&otherScore={}&isAnonymous={}&evaluationTags={}&phoneId={}", id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId);
         Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
         Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
@@ -127,30 +124,44 @@ public class StoreCommentController {
         return R.data(storeCommentService.addComment(multipartRequest, id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId));
         return R.data(storeCommentService.addComment(multipartRequest, id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId));
     }
     }
 
 
-    @ApiOperation(value = "新增或修改评论/评价(new)", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    @ApiOperation(value = "新增或修改评论/评价(单独对商家)", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
     @ApiImplicitParams({
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "multipartRequest", value = "文件", dataType = "File", paramType = "query"),
+//            @ApiImplicitParam(name = "multipartRequest", value = "文件", dataType = "File", paramType = "query"),
+            @ApiImplicitParam(name = "imageUrls", value = "图片url", dataType = "String", paramType = "query"),
             @ApiImplicitParam(name = "id", value = "主键", dataType = "Integer", paramType = "query"),
             @ApiImplicitParam(name = "id", value = "主键", dataType = "Integer", paramType = "query"),
-            @ApiImplicitParam(name = "businessId", value = "业务id", dataType = "Integer", paramType = "query"),
-            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "businessType", value = "业务类型(1:订单评论, 2:动态社区评论, 3:活动评论, 4:店铺打卡评论, 5:订单评价,6:评论店铺)", dataType = "Integer", paramType = "query"),
             @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query"),
             @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query"),
-            @ApiImplicitParam(name = "orderId", value = "订单id", dataType = "Integer", paramType = "query"),
-            @ApiImplicitParam(name = "lawyerId", value = "律师id", dataType = "Integer", paramType = "query"),
             @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "replyId", value = "回复id", dataType = "Integer", paramType = "query"),
             @ApiImplicitParam(name = "replyId", value = "回复id", dataType = "Integer", paramType = "query"),
             @ApiImplicitParam(name = "commentContent", value = "评论内容", dataType = "String", paramType = "query"),
             @ApiImplicitParam(name = "commentContent", value = "评论内容", dataType = "String", paramType = "query"),
             @ApiImplicitParam(name = "score", value = "评分", dataType = "Double", paramType = "query"),
             @ApiImplicitParam(name = "score", value = "评分", dataType = "Double", paramType = "query"),
             @ApiImplicitParam(name = "otherScore", value = "其他评分", dataType = "String", paramType = "query"),
             @ApiImplicitParam(name = "otherScore", value = "其他评分", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "isAnonymous", value = "是否匿名(0:否(默认), 1:是)", dataType = "Integer", paramType = "query"),
-            @ApiImplicitParam(name = "evaluationTags", value = "评价标签", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "phoneId", value = "用户id", dataType = "String", paramType = "query")
+            @ApiImplicitParam(name = "isAnonymous", value = "是否匿名(0:否(默认), 1:是)", dataType = "Integer", paramType = "query")
     })
     })
-    @PostMapping("/saveCommentNew")
-    public R<Integer> saveCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
-        log.info("StoreCommentController.saveComment?id={}&businessId={}&businessType={}&storeId={}&userId={}&replyId={}&commentContent={}&score={}&otherScore={}&isAnonymous={}&evaluationTags={}&phoneId={}", id, businessId, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId);
-        Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
-        log.info(String.valueOf(fileNameSet.size()));
-        return R.data(storeCommentService.addCommentNew(multipartRequest, id, businessId, businessType, storeId,storeId,storeId, orderId, lawyerId, commentContent, score, otherScore, isAnonymous, evaluationTags, phoneId));
+    @PostMapping("/saveCommentOnlyStore")
+    public R<Integer> saveCommentOnlyStore(@RequestBody Map<String,String> map) {
+//        log.info("StoreCommentController.saveComment?id={}&businessType={}&storeId={}&userId={}&replyId={}&commentContent={}&score={}&otherScore={}&isAnonymous={}", id, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous);
+//        log.info(String.valueOf(imageUrls));
+        String imageUrls = map.get("imageUrls");
+        String s = map.get("id");
+        Integer id = null;
+        if(null != s) {
+            id =  Integer.parseInt(s);
+        }
+        Integer businessType = Integer.parseInt(map.get("businessType"));
+        Integer storeId = Integer.parseInt(map.get("storeId"));
+        Integer userId = Integer.parseInt(map.get("userId"));
+        String b = map.get("replyId");
+        Integer replyId = null;
+        if(null != b) {
+            replyId =  Integer.parseInt(b);
+        }
+
+        String commentContent = map.get("commentContent");
+        Double score = Double.parseDouble(map.get("score"));
+        String otherScore = map.get("otherScore");
+        Integer isAnonymous = Integer.parseInt(map.get("isAnonymous"));
+        return R.data(storeCommentService.saveCommentOnlyStore(imageUrls, id, businessType, storeId, userId, replyId, commentContent, score, otherScore, isAnonymous));
     }
     }
 
 
     @ApiOperation(value = "回复率, 评价比例")
     @ApiOperation(value = "回复率, 评价比例")

+ 3 - 3
alien-store/src/main/java/shop/alien/store/controller/StoreInfoController.java

@@ -872,7 +872,7 @@ public class StoreInfoController {
         log.info("StoreInfoController.getStoreEvaluateTags?storeId={}, tagType={}", storeId);
         log.info("StoreInfoController.getStoreEvaluateTags?storeId={}, tagType={}", storeId);
         Map<String,Object> map = new HashMap<>();
         Map<String,Object> map = new HashMap<>();
         List<TagsMainVo> voList = tagsMainMapper.getStoreEvaluateTags(storeId);
         List<TagsMainVo> voList = tagsMainMapper.getStoreEvaluateTags(storeId);
-        if(voList !=null && voList.size()>0){
+//        if(voList !=null && voList.size()>0){
             StoreCommentVo storeComment = storeCommentMapper.getCommentOneInfo(storeId);
             StoreCommentVo storeComment = storeCommentMapper.getCommentOneInfo(storeId);
             if(storeComment!=null){
             if(storeComment!=null){
                 if(storeComment.getImgId()!=null){
                 if(storeComment.getImgId()!=null){
@@ -882,14 +882,14 @@ public class StoreInfoController {
                 }
                 }
                 LambdaQueryWrapper<StoreComment> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
                 LambdaQueryWrapper<StoreComment> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
                 lambdaQueryWrapper1.eq(StoreComment :: getStoreId, storeId);
                 lambdaQueryWrapper1.eq(StoreComment :: getStoreId, storeId);
-                lambdaQueryWrapper1.eq(StoreComment :: getBusinessType, 5);
+                lambdaQueryWrapper1.eq(StoreComment :: getBusinessType, 6);
                 lambdaQueryWrapper1.eq(StoreComment :: getDeleteFlag, 0);
                 lambdaQueryWrapper1.eq(StoreComment :: getDeleteFlag, 0);
                 Integer commitCount = storeCommentMapper.selectCount(lambdaQueryWrapper1);
                 Integer commitCount = storeCommentMapper.selectCount(lambdaQueryWrapper1);
                 map.put("commitCount",commitCount);
                 map.put("commitCount",commitCount);
             }
             }
             map.put("tag",voList);
             map.put("tag",voList);
             map.put("evaluate",storeComment);
             map.put("evaluate",storeComment);
-        }
+//        }
         return R.data(map);
         return R.data(map);
     }
     }
 
 

+ 9 - 3
alien-store/src/main/java/shop/alien/store/controller/StorePlatformDiscussionController.java

@@ -20,6 +20,7 @@ import java.util.List;
  *
  *
  * @author dujian
  * @author dujian
  * @since 2025-12-30
  * @since 2025-12-30
+ * Fixme 用户发主贴之后,异步提AI做关键词分析。异步线程得到关键词后,与store_id绑定,注意意向上的历史标签去重。※新建问答标签-店铺关联表
  */
  */
 @Slf4j
 @Slf4j
 @Api(tags = {"用户端-店铺问答讨论"})
 @Api(tags = {"用户端-店铺问答讨论"})
@@ -30,7 +31,7 @@ public class StorePlatformDiscussionController {
 
 
     private final StorePlatformDiscussionService storePlatformDiscussionService;
     private final StorePlatformDiscussionService storePlatformDiscussionService;
 
 
-    @ApiOperation("发布一级问答讨论 (主贴)")
+    @ApiOperation("发布主贴")
     @PostMapping("/postTopic")
     @PostMapping("/postTopic")
     public R<Boolean> postTopic(@RequestBody StorePlatformDiscussion discussion) {
     public R<Boolean> postTopic(@RequestBody StorePlatformDiscussion discussion) {
         log.info("StorePlatformDiscussionController.postTopic?discussion={}", discussion);
         log.info("StorePlatformDiscussionController.postTopic?discussion={}", discussion);
@@ -60,8 +61,13 @@ public class StorePlatformDiscussionController {
     @PostMapping("/like/{id}")
     @PostMapping("/like/{id}")
     public R<Boolean> like(@PathVariable Integer id) {
     public R<Boolean> like(@PathVariable Integer id) {
         log.info("StorePlatformDiscussionController.like?id={}", id);
         log.info("StorePlatformDiscussionController.like?id={}", id);
-        boolean success = storePlatformDiscussionService.likeDiscussion(id);
-        return success ? R.success("点赞成功") : R.fail("点赞失败");
+        try {
+            boolean success = storePlatformDiscussionService.likeDiscussion(id);
+            return success ? R.success("点赞讨论成功") : R.fail("点赞讨论失败");
+        } catch (Exception e) {
+            log.error("点赞讨论失败", e);
+            return R.fail(e.getMessage());
+        }
     }
     }
 
 
     @ApiOperation("分页获取店铺一级问答讨论列表 (支持搜索和排序)")
     @ApiOperation("分页获取店铺一级问答讨论列表 (支持搜索和排序)")

+ 10 - 0
alien-store/src/main/java/shop/alien/store/service/SportsFacilityAreaService.java

@@ -42,6 +42,16 @@ public interface SportsFacilityAreaService extends IService<SportsFacilityArea>
     boolean updateArea(Integer areaId, String areaName, Integer sortOrder);
     boolean updateArea(Integer areaId, String areaName, Integer sortOrder);
 
 
     /**
     /**
+     * 更新区域头图
+     * 将传入的长字符串URL覆盖原有的area_head_url字段中的数据
+     *
+     * @param areaId 区域ID,不能为空且必须大于0
+     * @param areaHeadUrl 区域头图URL(长字符串),必填
+     * @return 更新是否成功
+     */
+    boolean updateAreaHeadUrl(Integer areaId, String areaHeadUrl);
+
+    /**
      * 删除区域(逻辑删除)
      * 删除区域(逻辑删除)
      * 删除区域时,会同时逻辑删除该区域下的所有设施
      * 删除区域时,会同时逻辑删除该区域下的所有设施
      *
      *

+ 15 - 19
alien-store/src/main/java/shop/alien/store/service/StoreCommentService.java

@@ -93,25 +93,6 @@ public interface StoreCommentService extends IService<StoreComment> {
      */
      */
     Integer addComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId);
     Integer addComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId);
 
 
-    /**
-     * 新增或修改评论/评价
-     *
-     * @param multipartRequest 文件
-     * @param id               主键
-     * @param businessId       业务id
-     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
-     * @param storeId          门店id
-     * @param userId           用户id
-     * @param replyId          回复id
-     * @param commentContent   评价内容
-     * @param score            评分
-     * @param otherScore       其他评分
-     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
-     * @param evaluationTags   评价标签
-     * @param phoneId          用户id
-     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
-     */
-    Integer addCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId);
 
 
     /**
     /**
      * 回复率, 评价比例
      * 回复率, 评价比例
@@ -145,4 +126,19 @@ public interface StoreCommentService extends IService<StoreComment> {
      */
      */
     IPage<UserOrderVo> getUserAllOrders(Integer pageNum, Integer pageSize, Integer userId, Integer type);
     IPage<UserOrderVo> getUserAllOrders(Integer pageNum, Integer pageSize, Integer userId, Integer type);
 
 
+    /**
+     * 新增或修改评论/评价(仅店铺)
+     * @param imageUrls 图片url
+     * @param id               主键
+     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
+     * @param storeId          门店id
+     * @param userId           用户id
+     * @param replyId          回复id
+     * @param commentContent   评价内容
+     * @param score            评分
+     * @param otherScore       其他评分
+     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
+     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
+     */
+    Integer saveCommentOnlyStore(String imageUrls, Integer id, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous);
 }
 }

+ 47 - 0
alien-store/src/main/java/shop/alien/store/service/impl/SportsFacilityAreaServiceImpl.java

@@ -107,6 +107,8 @@ public class SportsFacilityAreaServiceImpl extends ServiceImpl<SportsFacilityAre
         }
         }
 
 
         // 查询该门店下的所有未删除区域,按排序号升序,相同排序号按创建时间降序
         // 查询该门店下的所有未删除区域,按排序号升序,相同排序号按创建时间降序
+        // 查询结果包含所有字段:id、storeId、areaName、sortOrder、deleteFlag、createdTime、updatedTime、
+        // createdUserId、updatedUserId、areaLogoImg、areaHeadUrl
         LambdaQueryWrapper<SportsFacilityArea> queryWrapper = new LambdaQueryWrapper<>();
         LambdaQueryWrapper<SportsFacilityArea> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(SportsFacilityArea::getStoreId, storeId)
         queryWrapper.eq(SportsFacilityArea::getStoreId, storeId)
                 .eq(SportsFacilityArea::getDeleteFlag, DELETE_FLAG_NOT_DELETED)
                 .eq(SportsFacilityArea::getDeleteFlag, DELETE_FLAG_NOT_DELETED)
@@ -114,6 +116,18 @@ public class SportsFacilityAreaServiceImpl extends ServiceImpl<SportsFacilityAre
                 .orderByDesc(SportsFacilityArea::getCreatedTime);
                 .orderByDesc(SportsFacilityArea::getCreatedTime);
 
 
         List<SportsFacilityArea> areaList = this.list(queryWrapper);
         List<SportsFacilityArea> areaList = this.list(queryWrapper);
+        
+        // 记录查询结果详情(包括区域头图URL长度信息,用于调试)
+        if (log.isDebugEnabled()) {
+            areaList.forEach(area -> {
+                log.debug("查询区域详情,areaId={},areaName={},areaHeadUrl长度={},areaLogoImg={}", 
+                        area.getId(), 
+                        area.getAreaName(),
+                        area.getAreaHeadUrl() != null ? area.getAreaHeadUrl().length() : 0,
+                        area.getAreaLogoImg());
+            });
+        }
+        
         log.info("查询区域列表成功,storeId={},区域数量:{}", storeId, areaList.size());
         log.info("查询区域列表成功,storeId={},区域数量:{}", storeId, areaList.size());
         return areaList;
         return areaList;
     }
     }
@@ -163,6 +177,39 @@ public class SportsFacilityAreaServiceImpl extends ServiceImpl<SportsFacilityAre
     }
     }
 
 
     @Override
     @Override
+    public boolean updateAreaHeadUrl(Integer areaId, String areaHeadUrl) {
+        log.info("更新区域头图,areaId={},areaHeadUrl长度={}", areaId, areaHeadUrl != null ? areaHeadUrl.length() : 0);
+
+        // 参数验证
+        if (areaId == null || areaId <= 0) {
+            log.warn("更新区域头图失败,区域ID无效:{}", areaId);
+            throw new IllegalArgumentException("区域ID不能为空且必须大于0");
+        }
+
+        if (areaHeadUrl == null) {
+            log.warn("更新区域头图失败,区域头图URL为空");
+            throw new IllegalArgumentException("区域头图URL不能为空");
+        }
+
+        // 查询区域是否存在
+        SportsFacilityArea existingArea = this.getById(areaId);
+        if (existingArea == null || existingArea.getDeleteFlag() == DELETE_FLAG_DELETED) {
+            log.warn("更新区域头图失败,区域不存在或已删除:areaId={}", areaId);
+            throw new IllegalArgumentException("区域不存在或已删除");
+        }
+
+        // 构建更新条件,直接覆盖原有的area_head_url字段
+        LambdaUpdateWrapper<SportsFacilityArea> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(SportsFacilityArea::getId, areaId)
+                .set(SportsFacilityArea::getAreaHeadUrl, areaHeadUrl);
+
+        // 执行更新
+        boolean updateResult = this.update(updateWrapper);
+        log.info("更新区域头图{},areaId={}", updateResult ? "成功" : "失败", areaId);
+        return updateResult;
+    }
+
+    @Override
     public boolean deleteArea(Integer areaId) {
     public boolean deleteArea(Integer areaId) {
         log.info("删除区域,areaId={}", areaId);
         log.info("删除区域,areaId={}", areaId);
 
 

+ 138 - 154
alien-store/src/main/java/shop/alien/store/service/impl/StoreCommentServiceImpl.java

@@ -1,10 +1,8 @@
 package shop.alien.store.service.impl;
 package shop.alien.store.service.impl;
 
 
-import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
@@ -22,11 +20,8 @@ import org.springframework.web.multipart.MultipartRequest;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.*;
 import shop.alien.entity.store.vo.*;
 import shop.alien.mapper.*;
 import shop.alien.mapper.*;
-import shop.alien.entity.store.vo.LawyerConsultationOrderVO;
-import shop.alien.entity.store.vo.UserOrderVo;
 import shop.alien.store.config.WebSocketProcess;
 import shop.alien.store.config.WebSocketProcess;
 import shop.alien.store.service.StoreCommentService;
 import shop.alien.store.service.StoreCommentService;
-import shop.alien.store.service.StoreImgService;
 import shop.alien.store.util.FileUploadUtil;
 import shop.alien.store.util.FileUploadUtil;
 import shop.alien.util.common.DateUtils;
 import shop.alien.util.common.DateUtils;
 import shop.alien.util.common.netease.ImageCheckUtil;
 import shop.alien.util.common.netease.ImageCheckUtil;
@@ -582,7 +577,7 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
      */
      */
     @Override
     @Override
     public Integer addComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
     public Integer addComment(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
-        try {
+      /*  try {
             List<String> servicesList = Lists.newArrayList();
             List<String> servicesList = Lists.newArrayList();
             servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
             servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
             servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
             servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
@@ -591,10 +586,10 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
                 return 2;
                 return 2;
             }
             }
 
 
-            /*Map<String, String> checkText = TextCheckUtil.check(commentContent);
+            *//*Map<String, String> checkText = TextCheckUtil.check(commentContent);
             if (null == checkText || checkText.get("result").equals("1")) {
             if (null == checkText || checkText.get("result").equals("1")) {
                 return 2;
                 return 2;
-            }*/
+            }*//*
             StoreComment storeComment = new StoreComment();
             StoreComment storeComment = new StoreComment();
             storeComment.setId(id);
             storeComment.setId(id);
             storeComment.setStoreId(storeId);
             storeComment.setStoreId(storeId);
@@ -704,153 +699,10 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
             log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
             log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
             return 1;
             return 1;
         }
         }
-
+*/
+        return 0;
     }
     }
 
 
-    /**
-     * 新增或修改评论/评价
-     *
-     * @param multipartRequest 文件
-     * @param id               主键
-     * @param businessId       业务id
-     * @param businessType     业务类型(1:订单评论, 2:动态社区评论, 3:活动评论,4:店铺打卡评论)
-     * @param storeId          门店id
-     * @param userId           用户id
-     * @param replyId          回复id
-     * @param commentContent   评价内容
-     * @param score            评分
-     * @param otherScore       其他评分
-     * @param isAnonymous      是否匿名(0:否(默认), 1:是)
-     * @param evaluationTags   评价标签
-     * @param phoneId          用户id
-     * @return 0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常
-     */
-    @Override
-    public Integer addCommentNew(MultipartRequest multipartRequest, Integer id, Integer businessId, Integer businessType, Integer storeId, Integer orderId, Integer lawyerId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous, String evaluationTags, String phoneId) {
-        try {
-            List<String> servicesList = Lists.newArrayList();
-            servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
-            servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
-            TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(commentContent, servicesList);
-            if ("high".equals(textCheckResult.getRiskLevel())) {
-                return 2;
-            }
-
-            /*Map<String, String> checkText = TextCheckUtil.check(commentContent);
-            if (null == checkText || checkText.get("result").equals("1")) {
-                return 2;
-            }*/
-            StoreComment storeComment = new StoreComment();
-            storeComment.setId(id);
-            storeComment.setStoreId(storeId);
-            storeComment.setUserId(userId);
-            storeComment.setCommentContent(commentContent);
-            storeComment.setReplyId(replyId);
-            storeComment.setBusinessId(businessId);
-            storeComment.setBusinessType(businessType);
-            storeComment.setScore(score);
-
-            if (StringUtils.isNotEmpty(otherScore)) {
-                List<LifeCouponVo> lifeCouponVos = JSONArray.parseArray(otherScore, LifeCouponVo.class);
-                lifeCouponVos.stream().filter(i -> "口味".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setTasteScore(Double.valueOf(item.getRateScore())));
-                lifeCouponVos.stream().filter(i -> "环境".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setEnScore(Double.valueOf(item.getRateScore())));
-                lifeCouponVos.stream().filter(i -> "服务".equals(i.getName())).findFirst().ifPresent(item -> storeComment.setServiceScore(Double.valueOf(item.getRateScore())));
-            }
-            storeComment.setOtherScore(otherScore);
-            storeComment.setIsAnonymous(isAnonymous);
-            storeComment.setEvaluationTags(evaluationTags);
-            storeComment.setPhoneId(phoneId);
-            List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
-            if (!fileNameSet.isEmpty() && storeId != null) {
-                StringBuilder imgId = new StringBuilder();
-                for (int i = 0; i < fileNameSet.size(); i++) {
-                    MultipartFile multipartFile = multipartRequest.getFileMap().get(fileNameSet.get(i));
-                    //b
-                    System.out.println(multipartFile.getSize());
-                    //kb
-                    System.out.println(multipartFile.getSize() / 1024);
-                    if (null != multipartFile && multipartFile.getSize() / 1024 > 0) {
-                        byte[] fileByte;
-                        try {
-                            fileByte = multipartFile.getBytes();
-                        } catch (IOException e) {
-                            return 1;
-                        }
-                        String base64 = Base64.getEncoder().encodeToString(fileByte);
-                        Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
-                        if (checkImage != null && checkImage.get("result").equals("1")) {
-                            return 3;
-                        }
-                        StoreImg storeImg = new StoreImg();
-                        storeImg.setStoreId(storeComment.getStoreId());
-                        storeImg.setImgType(8);
-                        storeImg.setImgSort(i + 1);
-                        storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
-                        storeImgMapper.insert(storeImg);
-                        imgId.append(storeImg.getId()).append(",");
-                    }
-                }
-                if (!imgId.toString().isEmpty()) {
-                    storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
-                }
-            }
-            storeComment.setCreatedUserId(storeComment.getUserId());
-            int i = this.save(storeComment) ? 0 : 1;
-
-            //判断类型如果为5是评价 更新订单表orderAppraise为1 订单已评价
-            if(businessType == 5){
-                LambdaUpdateWrapper<LifeUserOrder> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
-                lambdaUpdateWrapper.eq(LifeUserOrder :: getId, businessId );
-                lambdaUpdateWrapper.set(LifeUserOrder :: getOrderAppraise, 1);
-                lifeUserOrderMapper.update(null,lambdaUpdateWrapper);
-            }
-            StoreInfoScoreVo storeInfoScoreVo = storeCommentMapper.getCommentCountAndScoreInfo(storeId);
-            double total = storeInfoScoreVo.getTotal();
-            double scoreAvg = (total == 0 ? 0 : storeInfoScoreVo.getScore() / total);
-            double tasteScore = (total == 0 ? 0 : storeInfoScoreVo.getTasteScore() / total);
-            double enScore = (total == 0 ? 0 : storeInfoScoreVo.getEnScore() / total);
-            double serviceScore = (total == 0 ? 0 : storeInfoScoreVo.getServiceScore() / total);
-            StoreInfo storeInfo = new StoreInfo();
-            storeInfo.setId(storeId);
-            storeInfo.setScoreAvg(new BigDecimal(scoreAvg).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            storeInfo.setTasteScore(new BigDecimal(tasteScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            storeInfo.setEnScore(new BigDecimal(enScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            storeInfo.setServiceScore(new BigDecimal(serviceScore).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            storeInfoMapper.updateById(storeInfo);
-            StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfo.getId()).eq(StoreUser::getDeleteFlag, 0));
-
-            // 如果差评,则发送差评提醒
-            if(score != null && score >= 0.5 && score <= 2.5){
-                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-                String commonDate = simpleDateFormat.format(new Date());
-                LifeNotice lifeMessage = new LifeNotice();
-                lifeMessage.setReceiverId("store_" + storeUser.getPhone());
-                String text = "在"+commonDate+",您的店铺有一条差评记录,您可查看评价内容是否属实,如不属实,可向平台进行申诉。";
-                JSONObject jsonObject = new JSONObject();
-                jsonObject.put("message", text);
-                lifeMessage.setContext(jsonObject.toJSONString());
-                lifeMessage.setTitle("差评通知");
-                lifeMessage.setSenderId("system");
-                lifeMessage.setIsRead(0);
-                lifeMessage.setNoticeType(1);
-                lifeNoticeMapper.insert(lifeMessage);
-
-                WebSocketVo websocketVo = new WebSocketVo();
-                websocketVo.setSenderId("system");
-                websocketVo.setReceiverId("store_" + storeUser.getPhone());
-                websocketVo.setCategory("notice");
-                websocketVo.setNoticeType("1");
-                websocketVo.setIsRead(0);
-                websocketVo.setText(JSONObject.from(lifeMessage).toJSONString());
-                webSocketProcess.sendMessage("store_" + storeUser.getPhone(), JSONObject.from(websocketVo).toJSONString());
-            }
-            return i;
-        } catch (Exception e) {
-            log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
-            return 1;
-        }
-
-    }
 
 
     /**
     /**
      * 回复率, 评价比例
      * 回复率, 评价比例
@@ -1054,7 +906,7 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
         return new LambdaQueryWrapper<StoreComment>()
         return new LambdaQueryWrapper<StoreComment>()
                 .eq(StoreComment::getStoreId, storeId)
                 .eq(StoreComment::getStoreId, storeId)
                 .gt(StoreComment::getScore,0 )
                 .gt(StoreComment::getScore,0 )
-                .eq(StoreComment::getBusinessType, 5)
+                .eq(StoreComment::getBusinessType, 6)
                 .eq(StoreComment::getDeleteFlag, 0);
                 .eq(StoreComment::getDeleteFlag, 0);
     }
     }
 
 
@@ -1189,6 +1041,138 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
         return resultPage;
         return resultPage;
     }
     }
 
 
+     @Override
+    public Integer saveCommentOnlyStore(String imageUrls, Integer id, Integer businessType, Integer storeId, Integer userId, Integer replyId, String commentContent, Double score, String otherScore, Integer isAnonymous) {
+        try {
+            // 1.文本审核,
+            List<String> servicesList = Lists.newArrayList();
+            servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
+            servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
+            TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(commentContent, servicesList);
+            if ("high".equals(textCheckResult.getRiskLevel())) {
+                return 2;
+            }
+            // 2.构造评价实体类
+            StoreComment storeComment = new StoreComment();
+            storeComment.setId(id);
+            storeComment.setStoreId(storeId);
+            storeComment.setUserId(userId);
+            storeComment.setCommentContent(commentContent);
+            storeComment.setReplyId(replyId);
+            storeComment.setBusinessType(businessType);
+            storeComment.setScore(score);
+
+            if (StringUtils.isNotEmpty(otherScore)) {
+                JSONObject parse = JSONObject.parse(otherScore);
+                storeComment.setScoreOne(parse.getDouble("scoreOne"));
+                storeComment.setScoreTwo(parse.getDouble("scoreTwo"));
+                storeComment.setScoreThree(parse.getDouble("scoreThree"));
+            }
+            storeComment.setOtherScore(otherScore);
+            storeComment.setIsAnonymous(isAnonymous);
+//            List<String> fileNameSet = new ArrayList<>(multipartRequest.getMultiFileMap().keySet());
+            StringBuilder imgId = new StringBuilder();
+            String[] split = imageUrls.split(",");
+
+            for (int i = 0; i < split.length; i++) {
+                StoreImg storeImg = new StoreImg();
+                storeImg.setStoreId(storeComment.getStoreId());
+                storeImg.setImgType(8);
+                storeImg.setImgSort(i + 1);
+                storeImg.setImgUrl(split[i]);
+                storeImgMapper.insert(storeImg);
+                imgId.append(storeImg.getId()).append(",");
+            }
+            if (!imgId.toString().isEmpty()) {
+                storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
+            }
+            storeComment.setCreatedUserId(storeComment.getUserId());
+
+/*            List<MultipartFile> fileNameSet = multipartRequest.getMultiFileMap().get("file");
+            if (!fileNameSet.isEmpty() && storeId != null) {
+                StringBuilder imgId = new StringBuilder();
+                for (int i = 0; i < fileNameSet.size(); i++) {
+                    MultipartFile multipartFile = fileNameSet.get(i);
+                    //b
+                    System.out.println(multipartFile.getSize());
+                    //kb
+                    System.out.println(multipartFile.getSize() / 1024);
+                    if (null != multipartFile && !multipartFile.isEmpty()) {
+                        byte[] fileByte;
+                        try {
+                            fileByte = multipartFile.getBytes();
+                        } catch (IOException e) {
+                            return 1;
+                        }
+                        String base64 = Base64.getEncoder().encodeToString(fileByte);
+                        Map<String, String> checkImage = ImageCheckUtil.check(base64, 2);
+                        if (checkImage != null && checkImage.get("result").equals("1")) {
+                            return 3;
+                        }
+                        StoreImg storeImg = new StoreImg();
+                        storeImg.setStoreId(storeComment.getStoreId());
+                        storeImg.setImgType(8);
+                        storeImg.setImgSort(i + 1);
+                        storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
+                        storeImgMapper.insert(storeImg);
+                        imgId.append(storeImg.getId()).append(",");
+                    }
+                }
+                if (!imgId.toString().isEmpty()) {
+                    storeComment.setImgId(imgId.substring(0, imgId.length() - 1));
+                }
+            }*/
+            storeComment.setCreatedUserId(storeComment.getUserId());
+            int i = this.save(storeComment) ? 0 : 1;
+
+            // 更新门店评价信息
+            StoreInfoScoreVo storeInfoScoreVo = storeCommentMapper.getCommentCountAndScoreInfo(storeId);
+            double total = storeInfoScoreVo.getTotal();
+            double scoreAvg = (total == 0 ? 0 : storeInfoScoreVo.getScore() / total);
+            double scoreOne = (total == 0 ? 0 : storeInfoScoreVo.getScoreOne() / total);
+            double scoreTwo = (total == 0 ? 0 : storeInfoScoreVo.getScoreTwo() / total);
+            double scoreThree = (total == 0 ? 0 : storeInfoScoreVo.getScoreThree() / total);
+            StoreInfo storeInfo = new StoreInfo();
+            storeInfo.setId(storeId);
+            storeInfo.setScoreAvg(new BigDecimal(scoreAvg).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setScoreOne(new BigDecimal(scoreOne).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setScoreTwo(new BigDecimal(scoreTwo).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfo.setScoreThree(new BigDecimal(scoreThree).setScale(2, RoundingMode.HALF_UP).doubleValue());
+            storeInfoMapper.updateById(storeInfo);
+            StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfo.getId()).eq(StoreUser::getDeleteFlag, 0));
+
+            // 如果差评,则发送差评提醒
+            if(score != null && score >= 0.5 && score <= 2.5){
+                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                String commonDate = simpleDateFormat.format(new Date());
+                LifeNotice lifeMessage = new LifeNotice();
+                lifeMessage.setReceiverId("store_" + storeUser.getPhone());
+                String text = "在"+commonDate+",您的店铺有一条差评记录,您可查看评价内容是否属实,如不属实,可向平台进行申诉。";
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("message", text);
+                lifeMessage.setContext(jsonObject.toJSONString());
+                lifeMessage.setTitle("差评通知");
+                lifeMessage.setSenderId("system");
+                lifeMessage.setIsRead(0);
+                lifeMessage.setNoticeType(1);
+                lifeNoticeMapper.insert(lifeMessage);
+
+                WebSocketVo websocketVo = new WebSocketVo();
+                websocketVo.setSenderId("system");
+                websocketVo.setReceiverId("store_" + storeUser.getPhone());
+                websocketVo.setCategory("notice");
+                websocketVo.setNoticeType("1");
+                websocketVo.setIsRead(0);
+                websocketVo.setText(JSONObject.from(lifeMessage).toJSONString());
+                webSocketProcess.sendMessage("store_" + storeUser.getPhone(), JSONObject.from(websocketVo).toJSONString());
+            }
+            return i;
+        } catch (Exception e) {
+            log.error("StoreCommentService.saveCommentOnlyStore ERROR Msg={}", e.getMessage());
+            return 1;
+        }
+    }
+
     /**
     /**
      * 转换商户订单为统一VO
      * 转换商户订单为统一VO
      */
      */

+ 49 - 17
alien-store/src/main/java/shop/alien/store/service/impl/StorePlatformDiscussionServiceImpl.java

@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.Data;
 import lombok.Data;
 import lombok.RequiredArgsConstructor;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
@@ -27,6 +29,7 @@ import shop.alien.store.util.LoginUserUtil;
 import shop.alien.util.common.safe.DeepseekClient;
 import shop.alien.util.common.safe.DeepseekClient;
 
 
 import java.util.*;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 /**
 /**
@@ -43,8 +46,11 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
     private final LifeUserMapper lifeUserMapper;
     private final LifeUserMapper lifeUserMapper;
     private final StorePlatformDiscussionLikeMapper discussionLikeMapper;
     private final StorePlatformDiscussionLikeMapper discussionLikeMapper;
     private final StoreDiscussionConfig discussionConfig;
     private final StoreDiscussionConfig discussionConfig;
+    private final RedissonClient redissonClient;
     private final DeepseekClient deepseekClient = new DeepseekClient("sk-dd8a6e10972145c9847883791ac9fb41");
     private final DeepseekClient deepseekClient = new DeepseekClient("sk-dd8a6e10972145c9847883791ac9fb41");
 
 
+    private static final String DISCUSSION_LIKE_LOCK_PREFIX = "lock:discussion:like:";
+
     /**
     /**
      * 内部配置类
      * 内部配置类
      */
      */
@@ -84,21 +90,22 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
 
 
     @Override
     @Override
     public StorePlatformDiscussionReplyVo pageRepliesByRootId(Integer rootId, Integer pageNum, Integer pageSize, String tags, Integer sortMode) {
     public StorePlatformDiscussionReplyVo pageRepliesByRootId(Integer rootId, Integer pageNum, Integer pageSize, String tags, Integer sortMode) {
+        // 1. 获取主贴信息
         StorePlatformDiscussion root = this.getById(rootId);
         StorePlatformDiscussion root = this.getById(rootId);
         if (root == null) {
         if (root == null) {
             throw new RuntimeException("主贴讨论不存在");
             throw new RuntimeException("主贴讨论不存在");
         }
         }
         StorePlatformDiscussionUserVo topicVo = convertToVoWithUserInfo(root);
         StorePlatformDiscussionUserVo topicVo = convertToVoWithUserInfo(root);
 
 
-        LambdaQueryWrapper<StorePlatformDiscussion> wrapper = new LambdaQueryWrapper<StorePlatformDiscussion>()
+        // 2. 分页获取回复
+        Page<StorePlatformDiscussion> page = new Page<>(pageNum, pageSize);
+        IPage<StorePlatformDiscussion> replyPage = this.page(page, new LambdaQueryWrapper<StorePlatformDiscussion>()
                 .eq(StorePlatformDiscussion::getRootId, rootId)
                 .eq(StorePlatformDiscussion::getRootId, rootId)
-                .ne(StorePlatformDiscussion::getId, rootId);
-
-        applySorting(wrapper, sortMode);
+                .ne(StorePlatformDiscussion::getId, rootId) // 排除主贴本身
+                .orderByDesc(StorePlatformDiscussion::getCreatedTime));
+//                .orderByAsc(StorePlatformDiscussion::getCreatedTime));
 
 
-        Page<StorePlatformDiscussion> page = new Page<>(pageNum, pageSize);
-        IPage<StorePlatformDiscussion> replyPage = this.page(page, wrapper);
-        
+        // 3. 转换为VO并补充用户信息
         IPage<StorePlatformDiscussionUserVo> voPage = replyPage.convert(this::convertToVo);
         IPage<StorePlatformDiscussionUserVo> voPage = replyPage.convert(this::convertToVo);
         fillUserInfoBatch(voPage.getRecords());
         fillUserInfoBatch(voPage.getRecords());
 
 
@@ -237,6 +244,11 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
         return this.save(discussion);
         return this.save(discussion);
     }
     }
 
 
+    /**
+     * 用户点赞
+     * @param id 讨论ID
+     * @return
+     */
     @Override
     @Override
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public boolean likeDiscussion(Integer id) {
     public boolean likeDiscussion(Integer id) {
@@ -244,24 +256,44 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
         if (currentUserId == null) {
         if (currentUserId == null) {
             throw new RuntimeException("请先登录再进行点赞");
             throw new RuntimeException("请先登录再进行点赞");
         }
         }
-
         // 检查是否已点赞
         // 检查是否已点赞
         LambdaQueryWrapper<StorePlatformDiscussionLike> likeWrapper = new LambdaQueryWrapper<>();
         LambdaQueryWrapper<StorePlatformDiscussionLike> likeWrapper = new LambdaQueryWrapper<>();
         likeWrapper.eq(StorePlatformDiscussionLike::getDiscussionId, id)
         likeWrapper.eq(StorePlatformDiscussionLike::getDiscussionId, id)
-                   .eq(StorePlatformDiscussionLike::getUserId, currentUserId);
-        
+                .eq(StorePlatformDiscussionLike::getUserId, currentUserId);
+
         if (discussionLikeMapper.selectCount(likeWrapper) > 0) {
         if (discussionLikeMapper.selectCount(likeWrapper) > 0) {
             throw new RuntimeException("您已点赞过该内容");
             throw new RuntimeException("您已点赞过该内容");
         }
         }
 
 
-        // 插入点赞记录
-        StorePlatformDiscussionLike like = new StorePlatformDiscussionLike();
-        like.setDiscussionId(id);
-        like.setUserId(currentUserId);
-        discussionLikeMapper.insert(like);
+        // 针对同一个讨论id,同一时间只有一个线程可以执行更新点赞数操作
+        String lockKey = DISCUSSION_LIKE_LOCK_PREFIX + id;
+        RLock lock = redissonClient.getLock(lockKey);
+        try {
+            // 尝试加锁,最多等待5秒,启用看门狗机制自动续锁
+            if (lock.tryLock(5, TimeUnit.SECONDS)) {
+                log.info("加锁成功!");
+
+
+                // 插入点赞记录
+                StorePlatformDiscussionLike like = new StorePlatformDiscussionLike();
+                like.setDiscussionId(id);
+                like.setUserId(currentUserId);
+                discussionLikeMapper.insert(like);
 
 
-        // 更新点赞数
-        return this.update().setSql("like_count = like_count + 1").eq("id", id).update();
+                // 更新点赞数
+                return this.update().setSql("like_count = like_count + 1").eq("id", id).update();
+            } else {
+                throw new RuntimeException("点赞人数过多,请稍后再试");
+            }
+        } catch (InterruptedException e) {
+            log.error("获取讨论点赞锁失败, id={}", id, e);
+            Thread.currentThread().interrupt();
+            throw new RuntimeException("系统繁忙");
+        } finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
     }
     }
 
 
     @Override
     @Override

+ 32 - 8
alien-util/src/main/java/shop/alien/util/file/FileUtil.java

@@ -489,10 +489,22 @@ public class FileUtil {
     public static Map<String, String> getFileNameAndType(MultipartFile multipartFile) {
     public static Map<String, String> getFileNameAndType(MultipartFile multipartFile) {
         String originalFilename = multipartFile.getOriginalFilename();
         String originalFilename = multipartFile.getOriginalFilename();
         Map<String, String> map = new HashMap<>();
         Map<String, String> map = new HashMap<>();
-        String fileName = originalFilename.substring(0, originalFilename.lastIndexOf('.'));
-        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
-        map.put("name", fileName);
-        map.put("type", fileType);
+        if (originalFilename == null || originalFilename.isEmpty()) {
+            map.put("name", "");
+            map.put("type", "");
+            return map;
+        }
+        int lastDotIndex = originalFilename.lastIndexOf('.');
+        if (lastDotIndex == -1 || lastDotIndex == originalFilename.length() - 1) {
+            // 没有扩展名或点号在最后
+            map.put("name", originalFilename);
+            map.put("type", "");
+        } else {
+            String fileName = originalFilename.substring(0, lastDotIndex);
+            String fileType = originalFilename.substring(lastDotIndex + 1);
+            map.put("name", fileName);
+            map.put("type", fileType);
+        }
         return map;
         return map;
     }
     }
 
 
@@ -505,10 +517,22 @@ public class FileUtil {
     public static Map<String, String> getFileNameAndType(File file) {
     public static Map<String, String> getFileNameAndType(File file) {
         String originalFilename = file.getName();
         String originalFilename = file.getName();
         Map<String, String> map = new HashMap<>();
         Map<String, String> map = new HashMap<>();
-        String fileName = originalFilename.substring(0, originalFilename.lastIndexOf('.'));
-        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
-        map.put("name", fileName);
-        map.put("type", fileType);
+        if (originalFilename == null || originalFilename.isEmpty()) {
+            map.put("name", "");
+            map.put("type", "");
+            return map;
+        }
+        int lastDotIndex = originalFilename.lastIndexOf('.');
+        if (lastDotIndex == -1 || lastDotIndex == originalFilename.length() - 1) {
+            // 没有扩展名或点号在最后
+            map.put("name", originalFilename);
+            map.put("type", "");
+        } else {
+            String fileName = originalFilename.substring(0, lastDotIndex);
+            String fileType = originalFilename.substring(lastDotIndex + 1);
+            map.put("name", fileName);
+            map.put("type", fileType);
+        }
         return map;
         return map;
     }
     }
 }
 }