ソースを参照

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

panzhilin 3 ヶ月 前
コミット
669a5dd246
34 ファイル変更1027 行追加254 行削除
  1. 12 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreComment.java
  2. 1 1
      alien-entity/src/main/java/shop/alien/entity/store/StoreCuisine.java
  3. 10 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreInfo.java
  4. 1 1
      alien-entity/src/main/java/shop/alien/entity/store/StorePlatformDiscussion.java
  5. 1 1
      alien-entity/src/main/java/shop/alien/entity/store/StorePlatformDiscussionLike.java
  6. 1 1
      alien-entity/src/main/java/shop/alien/entity/store/StorePrice.java
  7. 20 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/AiQuestionClassificationRequestDto.java
  8. 8 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/CuisineComboDto.java
  9. 3 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/StoreInfoScoreVo.java
  10. 1 1
      alien-entity/src/main/java/shop/alien/entity/store/vo/StorePlatformDiscussionReplyVo.java
  11. 2 2
      alien-entity/src/main/java/shop/alien/entity/store/vo/StorePlatformDiscussionUserVo.java
  12. 5 5
      alien-entity/src/main/java/shop/alien/mapper/StoreCommentMapper.java
  13. 2 2
      alien-entity/src/main/java/shop/alien/mapper/StorePlatformDiscussionLikeMapper.java
  14. 2 2
      alien-entity/src/main/java/shop/alien/mapper/StorePlatformDiscussionMapper.java
  15. 155 0
      alien-store/src/main/java/shop/alien/store/aspect/AiAuditAspect.java
  16. 64 0
      alien-store/src/main/java/shop/alien/store/controller/AiQuestionClassificationController.java
  17. 93 0
      alien-store/src/main/java/shop/alien/store/controller/AiSearchController.java
  18. 31 20
      alien-store/src/main/java/shop/alien/store/controller/StoreCommentController.java
  19. 3 3
      alien-store/src/main/java/shop/alien/store/controller/StoreInfoController.java
  20. 8 8
      alien-store/src/main/java/shop/alien/store/controller/StorePlatformDiscussionController.java
  21. 5 3
      alien-store/src/main/java/shop/alien/store/controller/StoreStaffConfigController.java
  22. 21 0
      alien-store/src/main/java/shop/alien/store/service/AiQuestionClassificationService.java
  23. 15 19
      alien-store/src/main/java/shop/alien/store/service/StoreCommentService.java
  24. 5 5
      alien-store/src/main/java/shop/alien/store/service/StorePlatformDiscussionService.java
  25. 1 1
      alien-store/src/main/java/shop/alien/store/service/StoreStaffConfigService.java
  26. 88 0
      alien-store/src/main/java/shop/alien/store/service/impl/AiQuestionClassificationServiceImpl.java
  27. 30 2
      alien-store/src/main/java/shop/alien/store/service/impl/PerformanceListServiceImpl.java
  28. 138 154
      alien-store/src/main/java/shop/alien/store/service/impl/StoreCommentServiceImpl.java
  29. 10 9
      alien-store/src/main/java/shop/alien/store/service/impl/StorePlatformDiscussionServiceImpl.java
  30. 4 4
      alien-store/src/main/java/shop/alien/store/service/impl/StoreStaffConfigServiceImpl.java
  31. 252 0
      alien-store/src/main/java/shop/alien/store/util/LoginUserUtil.java
  32. 2 2
      alien-store/src/main/java/shop/alien/store/util/ai/AiFeedbackAssignUtils.java
  33. 1 0
      alien-store/src/main/java/shop/alien/store/util/ai/AiImageColorExtractUtil.java
  34. 32 8
      alien-util/src/main/java/shop/alien/util/file/FileUtil.java

+ 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")
     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;
+
 }

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

@@ -82,7 +82,7 @@ public class StoreCuisine {
     @TableField("shelf_status")
     private Integer shelfStatus;
 
-    @ApiModelProperty(value = "拒绝原因")
+    @ApiModelProperty(value = "拒绝原因(审核失败原因)")
     @TableField("rejection_reason")
     private String rejectionReason;
 

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

@@ -341,4 +341,14 @@ public class StoreInfo {
     @TableField("business_category_name")
     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;
+
 }

+ 1 - 1
alien-store-platform/src/main/java/shop/alien/storeplatform/entity/StorePlatformDiscussion.java → alien-entity/src/main/java/shop/alien/entity/store/StorePlatformDiscussion.java

@@ -1,4 +1,4 @@
-package shop.alien.storeplatform.entity;
+package shop.alien.entity.store;
 
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonFormat;

+ 1 - 1
alien-store-platform/src/main/java/shop/alien/storeplatform/entity/StorePlatformDiscussionLike.java → alien-entity/src/main/java/shop/alien/entity/store/StorePlatformDiscussionLike.java

@@ -1,4 +1,4 @@
-package shop.alien.storeplatform.entity;
+package shop.alien.entity.store;
 
 import com.baomidou.mybatisplus.annotation.*;
 import io.swagger.annotations.ApiModel;

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

@@ -83,7 +83,7 @@ public class StorePrice {
     @TableField("shelf_status")
     private Integer shelfStatus;
 
-    @ApiModelProperty(value = "拒绝原因")
+    @ApiModelProperty(value = "拒绝原因(审核失败原因)")
     @TableField("rejection_reason")
     private String rejectionReason;
 

+ 20 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/AiQuestionClassificationRequestDto.java

@@ -0,0 +1,20 @@
+package shop.alien.entity.store.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 问题分类请求DTO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "QuestionClassificationRequestDto对象", description = "问题分类请求DTO")
+public class AiQuestionClassificationRequestDto {
+
+    @ApiModelProperty(value = "问题文本", required = true, example = "我想了解一下这个产品的使用方法")
+    private String question;
+}
+

+ 8 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/CuisineComboDto.java

@@ -71,4 +71,12 @@ public class CuisineComboDto {
     @ApiModelProperty(value = "使用规则")
     @TableField("usage_rule")
     private String usageRule;
+
+    @ApiModelProperty(value = "状态:0-待审核 1-审核通过 2-审核拒绝")
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "拒绝原因(审核失败原因)")
+    @TableField("rejection_reason")
+    private String rejectionReason;
 }

+ 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 enScore;
     private Double serviceScore;
+    private Double scoreOne;
+    private Double scoreTwo;
+    private Double scoreThree;
 }

+ 1 - 1
alien-store-platform/src/main/java/shop/alien/storeplatform/vo/StorePlatformDiscussionReplyVo.java → alien-entity/src/main/java/shop/alien/entity/store/vo/StorePlatformDiscussionReplyVo.java

@@ -1,4 +1,4 @@
-package shop.alien.storeplatform.vo;
+package shop.alien.entity.store.vo;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import io.swagger.annotations.ApiModel;

+ 2 - 2
alien-store-platform/src/main/java/shop/alien/storeplatform/vo/StorePlatformDiscussionUserVo.java → alien-entity/src/main/java/shop/alien/entity/store/vo/StorePlatformDiscussionUserVo.java

@@ -1,10 +1,10 @@
-package shop.alien.storeplatform.vo;
+package shop.alien.entity.store.vo;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import shop.alien.storeplatform.entity.StorePlatformDiscussion;
+import shop.alien.entity.store.StorePlatformDiscussion;
 
 /**
  * 店铺讨论人员VO

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

@@ -116,14 +116,14 @@ public interface StoreCommentMapper extends BaseMapper<StoreComment> {
 
     @Select("SELECT " +
             "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 " +
             "FROM" +
             "`store_comment` " +
             "WHERE " +
-            "business_type = 5 " +
+            "business_type = 6 " +
             "AND delete_flag = 0 " +
             "AND reply_id IS NULL " +
             "AND store_id = #{storeId}")
@@ -194,7 +194,7 @@ WHERE
             "\tstore_comment s\n" +
             "\tLEFT JOIN life_user lu ON s.user_id = lu.id \n" +
             "WHERE\n" +
-            "\ts.business_type = 5 \n" +
+            "\ts.business_type = 6 \n" +
             "\tAND s.store_id = #{storeId}\n" +
             "\tLIMIT 1")
     StoreCommentVo getCommentOneInfo(@Param("storeId") int storeId);

+ 2 - 2
alien-store-platform/src/main/java/shop/alien/storeplatform/mapper/StorePlatformDiscussionLikeMapper.java → alien-entity/src/main/java/shop/alien/mapper/StorePlatformDiscussionLikeMapper.java

@@ -1,8 +1,8 @@
-package shop.alien.storeplatform.mapper;
+package shop.alien.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
-import shop.alien.storeplatform.entity.StorePlatformDiscussionLike;
+import shop.alien.entity.store.StorePlatformDiscussionLike;
 
 /**
  * 店铺讨论点赞记录表 Mapper 接口

+ 2 - 2
alien-store-platform/src/main/java/shop/alien/storeplatform/mapper/StorePlatformDiscussionMapper.java → alien-entity/src/main/java/shop/alien/mapper/StorePlatformDiscussionMapper.java

@@ -1,8 +1,8 @@
-package shop.alien.storeplatform.mapper;
+package shop.alien.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
-import shop.alien.storeplatform.entity.StorePlatformDiscussion;
+import shop.alien.entity.store.StorePlatformDiscussion;
 
 /**
  * 店铺讨论表 Mapper 接口

+ 155 - 0
alien-store/src/main/java/shop/alien/store/aspect/AiAuditAspect.java

@@ -0,0 +1,155 @@
+package shop.alien.store.aspect;
+
+import com.alibaba.fastjson.JSON;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.store.StorePrice;
+import shop.alien.entity.store.dto.CuisineComboDto;
+import shop.alien.store.util.ai.AiContentModerationUtil;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * AI 审核切面:拦截美食与通用价目新增/修改接口
+ */
+@Slf4j
+@Aspect
+@Component
+@Order(2)
+@RequiredArgsConstructor
+public class AiAuditAspect {
+
+    private final AiContentModerationUtil aiContentModerationUtil;
+
+    /**
+     * 仅拦截美食新增/修改与通用价目新增/修改接口
+     */
+    @Pointcut(
+            "execution(* shop.alien.store.controller.StoreCuisineController.addCuisineCombo(..))"
+                    + " || execution(* shop.alien.store.controller.StoreCuisineController.updateCuisineCombo(..))"
+                    + " || execution(* shop.alien.store.controller.StorePriceController.save(..))"
+                    + " || execution(* shop.alien.store.controller.StorePriceController.update(..))")
+    public void aiAuditPointcut() {
+        // pointcut definition
+    }
+
+    /**
+     * 环绕通知:组合请求参数,获取AI token,并设置审核状态
+     */
+    @Around("aiAuditPointcut()")
+    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
+        Object[] args = joinPoint.getArgs();
+
+        String payload = JSON.toJSONString(args);
+        log.info("AI审核切面拦截方法: {}, payload={}", joinPoint.getSignature().toShortString(), payload);
+
+        List<String> imageUrls = extractImageUrls(args);
+
+        // AI审核:文本采用入参JSON,图片列表来自入参的 images 字符串字段
+        boolean auditPassed = performAiAudit( payload, imageUrls, args);
+
+        // 将审核结果写入请求对象
+        applyStatus(args, auditPassed);
+
+        return joinPoint.proceed(args);
+    }
+
+    /**
+     * AI审核调用:使用文本审核(图片列表暂为空)
+     */
+    private boolean performAiAudit(String payload, List<String> imageUrls, Object[] args) {
+        try {
+            // token 目前仅预留,如后续需要可添加到header或payload
+            AiContentModerationUtil.AuditResult result = aiContentModerationUtil.auditContent(payload, imageUrls);
+            if (result == null) {
+                log.warn("AI审核返回为空,视为未通过");
+                applyFailureReason(args, "审核异常");
+                return false;
+            }
+            boolean passed = result.isPassed();
+            if (!passed) {
+                String reason = result.getFailureReason();
+                log.warn("AI审核不通过,原因: {}", reason);
+                applyFailureReason(args, reason);
+            }
+            return passed;
+        } catch (Exception e) {
+            log.error("AI审核调用异常", e);
+            applyFailureReason(args, "审核异常");
+            return false;
+        }
+    }
+
+    /**
+     * 将审核结果写入入参的status字段(通过=1,不通过=0)
+     */
+    private void applyStatus(Object[] args, boolean passed) {
+        int status = passed ? 1 : 0;
+        for (Object arg : args) {
+            if (arg == null) {
+                continue;
+            }
+            if (arg instanceof CuisineComboDto) {
+                ((CuisineComboDto) arg).setStatus(status);
+            } else if (arg instanceof StorePrice) {
+                ((StorePrice) arg).setStatus(status);
+            }
+        }
+    }
+
+    /**
+     * 将审核失败原因写入入参
+     */
+    private void applyFailureReason(Object[] args, String reason) {
+        String safeReason = reason != null ? reason : "审核未通过";
+        for (Object arg : args) {
+            if (arg == null) {
+                continue;
+            }
+            if (arg instanceof CuisineComboDto) {
+                ((CuisineComboDto) arg).setRejectionReason(safeReason);
+            } else if (arg instanceof StorePrice) {
+                ((StorePrice) arg).setRejectionReason(safeReason);
+            }
+        }
+    }
+
+    /**
+     * 从入参中提取图片URL列表;images字段为JSON字符串数组
+     */
+    private List<String> extractImageUrls(Object[] args) {
+        for (Object arg : args) {
+            if (arg instanceof CuisineComboDto) {
+                return parseImages(((CuisineComboDto) arg).getImages());
+            }
+            if (arg instanceof StorePrice) {
+                return parseImages(((StorePrice) arg).getImages());
+            }
+        }
+        return Collections.emptyList();
+    }
+
+    private List<String> parseImages(String images) {
+        if (images == null || images.trim().isEmpty()) {
+            return Collections.emptyList();
+        }
+        try {
+            // 期望格式为 JSON 数组字符串
+            return JSON.parseArray(images, String.class);
+        } catch (Exception e) {
+            log.warn("解析图片列表失败,images={}", images, e);
+            List<String> single = new ArrayList<>();
+            single.add(images);
+            return single;
+        }
+    }
+}
+

+ 64 - 0
alien-store/src/main/java/shop/alien/store/controller/AiQuestionClassificationController.java

@@ -0,0 +1,64 @@
+package shop.alien.store.controller;
+
+import com.alibaba.fastjson2.JSONObject;
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.store.dto.AiQuestionClassificationRequestDto;
+import shop.alien.store.service.AiQuestionClassificationService;
+
+/**
+ * 问题分类控制器
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Api(tags = {"AI问题分类"})
+@CrossOrigin
+@RestController
+@RequestMapping("/questionClassification")
+@RequiredArgsConstructor
+@RefreshScope
+public class AiQuestionClassificationController {
+
+    private final AiQuestionClassificationService questionClassificationService;
+
+    /**
+     * 问题分类接口
+     *
+     * @param requestDto 问题分类请求DTO
+     * @return AI接口返回的原始响应
+     */
+    @ApiOperation(value = "问题分类", notes = "对用户问题进行AI分类")
+    @ApiOperationSupport(order = 1)
+    @PostMapping("/classify")
+    public ResponseEntity<String> classify(@RequestBody AiQuestionClassificationRequestDto requestDto) {
+        log.info("收到问题分类请求,问题:{}", requestDto != null ? requestDto.getQuestion() : null);
+        
+        // 参数校验
+        if (requestDto == null || !StringUtils.hasText(requestDto.getQuestion())) {
+            log.warn("问题分类请求参数为空或问题文本为空");
+            JSONObject errorResponse = new JSONObject();
+            errorResponse.put("code", 400);
+            errorResponse.put("message", "问题文本不能为空");
+            return ResponseEntity.badRequest().body(errorResponse.toJSONString());
+        }
+        
+        try {
+            String result = questionClassificationService.classify(requestDto);
+            return ResponseEntity.ok(result);
+        } catch (Exception e) {
+            log.error("问题分类失败,问题:{}", requestDto.getQuestion(), e);
+            JSONObject errorResponse = new JSONObject();
+            errorResponse.put("code", 500);
+            errorResponse.put("message", "问题分类失败:" + e.getMessage());
+            return ResponseEntity.status(500).body(errorResponse.toJSONString());
+        }
+    }
+}
+

+ 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("请求失败");
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}

+ 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.multipart.MultipartRequest;
 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 java.util.Map;
@@ -120,6 +116,7 @@ public class StoreCommentController {
             @ApiImplicitParam(name = "phoneId", value = "用户id", dataType = "String", paramType = "query")
     })
     @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) {
         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();
@@ -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));
     }
 
-    @ApiOperation(value = "新增或修改评论/评价(new)", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    @ApiOperation(value = "新增或修改评论/评价(单独对商家)", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
     @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 = "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 = "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 = "replyId", value = "回复id", dataType = "Integer", paramType = "query"),
             @ApiImplicitParam(name = "commentContent", value = "评论内容", dataType = "String", paramType = "query"),
             @ApiImplicitParam(name = "score", value = "评分", dataType = "Double", 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 = "回复率, 评价比例")

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

+ 8 - 8
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformDiscussionController.java → alien-store/src/main/java/shop/alien/store/controller/StorePlatformDiscussionController.java

@@ -1,4 +1,4 @@
-package shop.alien.storeplatform.controller;
+package shop.alien.store.controller;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import io.swagger.annotations.Api;
@@ -8,21 +8,21 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
-import shop.alien.storeplatform.entity.StorePlatformDiscussion;
-import shop.alien.storeplatform.service.StorePlatformDiscussionService;
-import shop.alien.storeplatform.vo.StorePlatformDiscussionReplyVo;
-import shop.alien.storeplatform.vo.StorePlatformDiscussionUserVo;
+import shop.alien.entity.store.StorePlatformDiscussion;
+import shop.alien.entity.store.vo.StorePlatformDiscussionReplyVo;
+import shop.alien.entity.store.vo.StorePlatformDiscussionUserVo;
+import shop.alien.store.service.StorePlatformDiscussionService;
 
 import java.util.List;
 
 /**
- * 商户平台-店铺讨论Controller
+ * 用户端-店铺讨论Controller
  *
- * @author alien
+ * @author dujian
  * @since 2025-12-30
  */
 @Slf4j
-@Api(tags = {"商户平台-店铺问答讨论"})
+@Api(tags = {"用户端-店铺问答讨论"})
 @RestController
 @RequestMapping("/platformStoreDiscussion")
 @RequiredArgsConstructor

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

@@ -5,6 +5,8 @@ import io.swagger.annotations.*;
 import springfox.documentation.annotations.ApiIgnore;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.StoreStaffConfig;
@@ -282,9 +284,9 @@ public class StoreStaffConfigController {
             }
 
             // 获取用户ID(可能为null,如果用户未登录)
-            Integer userId = null;
-            if (userLoginInfo != null) {
-                userId = userLoginInfo.getUserId();
+            String userId = "";
+            if (userLoginInfo != null && StringUtils.isNoneBlank(userLoginInfo.getType()) && StringUtils.isNoneBlank(userLoginInfo.getUserPhone())) {
+                userId = userLoginInfo.getType()+ "_" + userLoginInfo.getUserPhone();
             }
 
             // 调用服务层查询

+ 21 - 0
alien-store/src/main/java/shop/alien/store/service/AiQuestionClassificationService.java

@@ -0,0 +1,21 @@
+package shop.alien.store.service;
+
+import shop.alien.entity.store.dto.AiQuestionClassificationRequestDto;
+
+/**
+ * 问题分类服务接口
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+public interface AiQuestionClassificationService {
+
+    /**
+     * 对问题进行分类
+     *
+     * @param requestDto 问题分类请求DTO
+     * @return AI接口返回的JSON字符串
+     */
+    String classify(AiQuestionClassificationRequestDto requestDto);
+}
+

+ 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);
 
-    /**
-     * 新增或修改评论/评价
-     *
-     * @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);
 
+    /**
+     * 新增或修改评论/评价(仅店铺)
+     * @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);
 }

+ 5 - 5
alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformDiscussionService.java → alien-store/src/main/java/shop/alien/store/service/StorePlatformDiscussionService.java

@@ -1,17 +1,17 @@
-package shop.alien.storeplatform.service;
+package shop.alien.store.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
-import shop.alien.storeplatform.entity.StorePlatformDiscussion;
-import shop.alien.storeplatform.vo.StorePlatformDiscussionReplyVo;
-import shop.alien.storeplatform.vo.StorePlatformDiscussionUserVo;
+import shop.alien.entity.store.StorePlatformDiscussion;
+import shop.alien.entity.store.vo.StorePlatformDiscussionReplyVo;
+import shop.alien.entity.store.vo.StorePlatformDiscussionUserVo;
 
 import java.util.List;
 
 /**
  * 店铺讨论表 服务类
  *
- * @author alien
+ * @author dujian
  * @since 2025-12-30
  */
 public interface StorePlatformDiscussionService extends IService<StorePlatformDiscussion> {

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

@@ -135,7 +135,7 @@ public interface StoreStaffConfigService {
      * @param userId 当前登录用户ID,可为null(未登录时)
      * @return 员工详情(包含演出列表),如果员工不存在则返回null
      */
-    shop.alien.entity.store.vo.StoreStaffDetailWithPerformanceVo queryStaffDetailWithPerformance(Integer id, Integer userId);
+    shop.alien.entity.store.vo.StoreStaffDetailWithPerformanceVo queryStaffDetailWithPerformance(Integer id, String userId);
 
     /**
      * 获取美食员工列表

+ 88 - 0
alien-store/src/main/java/shop/alien/store/service/impl/AiQuestionClassificationServiceImpl.java

@@ -0,0 +1,88 @@
+package shop.alien.store.service.impl;
+
+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.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.RestTemplate;
+import shop.alien.entity.store.dto.AiQuestionClassificationRequestDto;
+import shop.alien.store.service.AiQuestionClassificationService;
+import shop.alien.store.util.ai.AiAuthTokenUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 问题分类服务实现类
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@RefreshScope
+public class AiQuestionClassificationServiceImpl implements AiQuestionClassificationService {
+
+    private final AiAuthTokenUtil aiAuthTokenUtil;
+
+    private final RestTemplate restTemplate;
+
+    @Value("${third-party-ai-question-classification.base-url}")
+    private String questionClassificationUrl;
+
+    @Override
+    public String classify(AiQuestionClassificationRequestDto requestDto) {
+        log.info("开始调用问题分类接口,问题:{}", requestDto.getQuestion());
+
+        // 获取访问令牌
+        String accessToken = aiAuthTokenUtil.getAccessToken();
+        if (!StringUtils.hasText(accessToken)) {
+            log.error("调用问题分类接口失败,获取accessToken失败");
+            throw new RuntimeException("获取访问令牌失败");
+        }
+
+        // 构建请求体
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("question", requestDto.getQuestion());
+
+        // 构建请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        headers.set("Authorization", "Bearer " + accessToken);
+
+        HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
+
+        try {
+            log.info("调用问题分类接口,URL:{},请求参数:{}", questionClassificationUrl, requestBody);
+            ResponseEntity<String> responseEntity = restTemplate.postForEntity(
+                    questionClassificationUrl, request, String.class);
+
+            log.info("问题分类接口调用成功,响应状态:{},响应体:{}",
+                    responseEntity.getStatusCode(), responseEntity.getBody());
+
+            // 直接返回响应体
+            return responseEntity.getBody();
+
+        } catch (HttpClientErrorException e) {
+            log.error("调用问题分类接口返回客户端错误,状态码:{},响应体:{},URL:{}",
+                    e.getStatusCode(), e.getResponseBodyAsString(), questionClassificationUrl, e);
+            throw new RuntimeException("调用问题分类接口失败:" + e.getMessage(), e);
+        } catch (HttpServerErrorException e) {
+            log.error("调用问题分类接口返回服务器错误,状态码:{},响应体:{},URL:{}",
+                    e.getStatusCode(), e.getResponseBodyAsString(), questionClassificationUrl, e);
+            throw new RuntimeException("调用问题分类接口失败:" + e.getMessage(), e);
+        } catch (Exception e) {
+            log.error("调用问题分类接口异常,URL:{},异常信息:{}", questionClassificationUrl, e.getMessage(), e);
+            throw new RuntimeException("调用问题分类接口异常:" + e.getMessage(), e);
+        }
+    }
+}

+ 30 - 2
alien-store/src/main/java/shop/alien/store/service/impl/PerformanceListServiceImpl.java

@@ -144,7 +144,35 @@ public class PerformanceListServiceImpl implements PerformanceListService {
         queryWrapper.eq(BarPerformance::getStoreId, storeId)
                 .eq(BarPerformance::getDeleteFlag, CommonConstant.DELETE_FLAG_UNDELETE)
                 .eq(BarPerformance::getReviewStatus, CommonConstant.PERFORMANCE_REVIEW_STATUS_APPROVED)
-                .eq(BarPerformance::getOnlineStatus, CommonConstant.PERFORMANCE_ONLINE_STATUS_ONLINE);
+                .eq(BarPerformance::getOnlineStatus, CommonConstant.PERFORMANCE_ONLINE_STATUS_ONLINE).eq(BarPerformance::getStatus, 1);
+
+        // 过滤已过期的演出
+        Date now = new Date();
+        // 获取今天的开始时间(00:00:00)
+        java.util.Calendar cal = java.util.Calendar.getInstance();
+        cal.setTime(now);
+        cal.set(java.util.Calendar.HOUR_OF_DAY, 0);
+        cal.set(java.util.Calendar.MINUTE, 0);
+        cal.set(java.util.Calendar.SECOND, 0);
+        cal.set(java.util.Calendar.MILLISECOND, 0);
+        Date todayStart = cal.getTime();
+
+        // 使用and条件,确保至少满足以下条件之一(即未过期):
+        // 1. 单次演出:结束时间 >= 当前时间
+        // 2. 定时演出(每天定时或每周定时):结束日期 > 今天 或 (结束日期 = 今天 AND 结束时间 >= 当前时分秒)
+        queryWrapper.and(wrapper -> {
+            // 单次演出:结束时间 >= 现在
+            wrapper.or(w -> w.eq(BarPerformance::getPerformanceFrequency, "0")
+                    .ge(BarPerformance::getSingleEndDatetime, now));
+            // 定时演出:结束日期 > 今天 或 (结束日期 = 今天 AND 结束时间 >= 当前时分秒)
+            wrapper.or(w -> w.in(BarPerformance::getPerformanceFrequency, "1", "2")
+                    .and(subWrapper -> {
+                        // 结束日期 > 今天
+                        subWrapper.gt(BarPerformance::getDailyEndDate, todayStart)
+                                // 或 (结束日期 = 今天 AND 结束时间 >= 当前时分秒)
+                                .or(subSubWrapper -> subSubWrapper.apply("DATE(daily_end_date) = CURDATE() AND daily_end_time >= TIME(NOW())"));
+                    }));
+        });
 
         // 排序规则:按创建时间降序
         queryWrapper.orderByDesc(BarPerformance::getCreatedTime);
@@ -609,7 +637,7 @@ public class PerformanceListServiceImpl implements PerformanceListService {
         cal.set(java.util.Calendar.MILLISECOND, 0);
         Date todayStart = cal.getTime();
 
-        cal.add(java.util.Calendar.DAY_OF_MONTH, 30);
+        cal.add(java.util.Calendar.DAY_OF_MONTH, 365);
         Date futureEnd = cal.getTime();
 
         // 遍历演出,生成日期映射

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

@@ -1,10 +1,8 @@
 package shop.alien.store.service.impl;
 
-import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 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.toolkit.CollectionUtils;
 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.vo.*;
 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.service.StoreCommentService;
-import shop.alien.store.service.StoreImgService;
 import shop.alien.store.util.FileUploadUtil;
 import shop.alien.util.common.DateUtils;
 import shop.alien.util.common.netease.ImageCheckUtil;
@@ -582,7 +577,7 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
      */
     @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) {
-        try {
+      /*  try {
             List<String> servicesList = Lists.newArrayList();
             servicesList.add(TextReviewServiceEnum.COMMENT_DETECTION_PRO.getService());
             servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
@@ -591,10 +586,10 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
                 return 2;
             }
 
-            /*Map<String, String> checkText = TextCheckUtil.check(commentContent);
+            *//*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);
@@ -704,153 +699,10 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
             log.error("StoreCommentService.userComment ERROR Msg={}", e.getMessage());
             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>()
                 .eq(StoreComment::getStoreId, storeId)
                 .gt(StoreComment::getScore,0 )
-                .eq(StoreComment::getBusinessType, 5)
+                .eq(StoreComment::getBusinessType, 6)
                 .eq(StoreComment::getDeleteFlag, 0);
     }
 
@@ -1189,6 +1041,138 @@ public class StoreCommentServiceImpl extends ServiceImpl<StoreCommentMapper, Sto
         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
      */

+ 10 - 9
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformDiscussionServiceImpl.java → alien-store/src/main/java/shop/alien/store/service/impl/StorePlatformDiscussionServiceImpl.java

@@ -1,4 +1,4 @@
-package shop.alien.storeplatform.service.impl;
+package shop.alien.store.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -15,15 +15,15 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 import shop.alien.entity.store.LifeUser;
+import shop.alien.entity.store.StorePlatformDiscussion;
+import shop.alien.entity.store.StorePlatformDiscussionLike;
+import shop.alien.entity.store.vo.StorePlatformDiscussionReplyVo;
+import shop.alien.entity.store.vo.StorePlatformDiscussionUserVo;
 import shop.alien.mapper.LifeUserMapper;
-import shop.alien.storeplatform.entity.StorePlatformDiscussion;
-import shop.alien.storeplatform.entity.StorePlatformDiscussionLike;
-import shop.alien.storeplatform.mapper.StorePlatformDiscussionLikeMapper;
-import shop.alien.storeplatform.mapper.StorePlatformDiscussionMapper;
-import shop.alien.storeplatform.service.StorePlatformDiscussionService;
-import shop.alien.storeplatform.util.LoginUserUtil;
-import shop.alien.storeplatform.vo.StorePlatformDiscussionReplyVo;
-import shop.alien.storeplatform.vo.StorePlatformDiscussionUserVo;
+import shop.alien.mapper.StorePlatformDiscussionLikeMapper;
+import shop.alien.mapper.StorePlatformDiscussionMapper;
+import shop.alien.store.service.StorePlatformDiscussionService;
+import shop.alien.store.util.LoginUserUtil;
 import shop.alien.util.common.safe.DeepseekClient;
 
 import java.util.*;
@@ -187,6 +187,7 @@ public class StorePlatformDiscussionServiceImpl extends ServiceImpl<StorePlatfor
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean postTopic(StorePlatformDiscussion discussion) {
+        // 当前登录者
         Integer currentUserId = LoginUserUtil.getCurrentUserId();
         if (currentUserId == null) {
             throw new RuntimeException("请先登录再发表讨论");

+ 4 - 4
alien-store/src/main/java/shop/alien/store/service/impl/StoreStaffConfigServiceImpl.java

@@ -943,7 +943,7 @@ public class StoreStaffConfigServiceImpl implements StoreStaffConfigService {
      * @return 员工详情(包含演出列表),如果员工不存在则返回null
      */
     @Override
-    public StoreStaffDetailWithPerformanceVo queryStaffDetailWithPerformance(Integer id, Integer userId) {
+    public StoreStaffDetailWithPerformanceVo queryStaffDetailWithPerformance(Integer id, String userId) {
         log.info("查询员工详情(包含演出列表),id={},userId={}", id, userId);
 
         // 参数校验
@@ -1828,16 +1828,16 @@ public class StoreStaffConfigServiceImpl implements StoreStaffConfigService {
      * @param userId 用户ID,可为null(未登录时返回false)
      * @return true-已喜欢,false-未喜欢
      */
-    private Boolean checkIsLiked(Integer staffId, Integer userId) {
+    private Boolean checkIsLiked(Integer staffId, String userId) {
         // 如果用户未登录,返回false
-        if (userId == null || userId <= 0) {
+        if (StringUtils.isEmpty(userId)) {
             return false;
         }
 
         try {
             LambdaQueryWrapper<LifeLikeRecord> queryWrapper = new LambdaQueryWrapper<>();
             queryWrapper.eq(LifeLikeRecord::getType, "8") // 8-点赞员工
-                    .eq(LifeLikeRecord::getDianzanId, String.valueOf(userId))
+                    .eq(LifeLikeRecord::getDianzanId, userId)
                     .eq(LifeLikeRecord::getHuifuId, String.valueOf(staffId))
                     .eq(LifeLikeRecord::getDeleteFlag, 0);
             long count = lifeLikeRecordMapper.selectCount(queryWrapper);

+ 252 - 0
alien-store/src/main/java/shop/alien/store/util/LoginUserUtil.java

@@ -0,0 +1,252 @@
+package shop.alien.store.util;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.store.StoreUser;
+import shop.alien.mapper.StoreUserMapper;
+import shop.alien.util.common.JwtUtil;
+
+/**
+ * 登录用户工具类
+ * 用于获取当前登录用户的信息
+ *
+ * @author dujian
+ * @since 2025-11-17
+ */
+@Slf4j
+@Component
+public class LoginUserUtil {
+
+    private static StoreUserMapper storeUserMapper;
+
+    @Autowired
+    public void setStoreUserMapper(StoreUserMapper storeUserMapper) {
+        LoginUserUtil.storeUserMapper = storeUserMapper;
+    }
+
+    /**
+     * 获取当前登录用户的ID
+     *
+     * @return 用户ID,如果未登录返回null
+     */
+    public static Integer getCurrentUserId() {
+        try {
+            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
+            if (userInfo != null) {
+                return userInfo.getInteger("userId");
+            }
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentUserId - 获取用户ID失败: {}", e.getMessage(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前登录用户的手机号
+     *
+     * @return 手机号,如果未登录返回null
+     */
+    public static String getCurrentUserPhone() {
+        try {
+            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
+            if (userInfo != null) {
+                return userInfo.getString("phone");
+            }
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentUserPhone - 获取用户手机号失败: {}", e.getMessage(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前登录用户的用户类型
+     *
+     * @return 用户类型,如果未登录返回null
+     */
+    public static String getCurrentUserType() {
+        try {
+            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
+            if (userInfo != null) {
+                return userInfo.getString("userType");
+            }
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentUserType - 获取用户类型失败: {}", e.getMessage(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前登录用户的Token信息(JSONObject格式)
+     *
+     * @return 用户信息JSONObject,包含userId、phone、userType等字段,如果未登录返回null
+     */
+    public static JSONObject getCurrentUserInfo() {
+        try {
+            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
+            if (userInfo != null) {
+                log.debug("LoginUserUtil.getCurrentUserInfo - 获取用户信息成功: userId={}, phone={}", 
+                        userInfo.getString("userId"), userInfo.getString("phone"));
+                return userInfo;
+            }
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentUserInfo - 获取用户信息失败: {}", e.getMessage(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前登录用户的完整商户用户信息(从数据库查询)
+     *
+     * @return StoreUser对象,如果未登录或查询失败返回null
+     */
+    public static StoreUser getCurrentStoreUser() {
+        try {
+            Integer userId = getCurrentUserId();
+            if (userId == null) {
+                log.warn("LoginUserUtil.getCurrentStoreUser - 用户未登录");
+                return null;
+            }
+
+            // 从数据库查询完整用户信息
+            StoreUser storeUser = storeUserMapper.selectById(userId);
+            if (storeUser != null) {
+                log.debug("LoginUserUtil.getCurrentStoreUser - 查询用户信息成功: userId={}, phone={}", 
+                        storeUser.getId(), storeUser.getPhone());
+            } else {
+                log.warn("LoginUserUtil.getCurrentStoreUser - 用户不存在: userId={}", userId);
+            }
+            return storeUser;
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentStoreUser - 查询用户信息失败: {}", e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 根据手机号获取商户用户信息
+     *
+     * @return StoreUser对象,如果未登录或查询失败返回null
+     */
+    public static StoreUser getCurrentStoreUserByPhone() {
+        try {
+            String phone = getCurrentUserPhone();
+            if (phone == null) {
+                log.warn("LoginUserUtil.getCurrentStoreUserByPhone - 用户未登录");
+                return null;
+            }
+
+            // 从数据库根据手机号查询用户信息
+            LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(StoreUser::getPhone, phone);
+            StoreUser storeUser = storeUserMapper.selectOne(queryWrapper);
+            
+            if (storeUser != null) {
+                log.debug("LoginUserUtil.getCurrentStoreUserByPhone - 查询用户信息成功: userId={}, phone={}", 
+                        storeUser.getId(), storeUser.getPhone());
+            } else {
+                log.warn("LoginUserUtil.getCurrentStoreUserByPhone - 用户不存在: phone={}", phone);
+            }
+            return storeUser;
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentStoreUserByPhone - 查询用户信息失败: {}", e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 验证当前登录用户是否为指定用户
+     *
+     * @param userId 要验证的用户ID
+     * @return true-是当前用户, false-不是当前用户
+     */
+    public static boolean isCurrentUser(Integer userId) {
+        if (userId == null) {
+            return false;
+        }
+        Integer currentUserId = getCurrentUserId();
+        return userId.equals(currentUserId);
+    }
+
+    /**
+     * 验证当前用户是否已登录
+     *
+     * @return true-已登录, false-未登录
+     */
+    public static boolean isLogin() {
+        return getCurrentUserId() != null;
+    }
+
+    /**
+     * 验证当前用户类型是否为web端商户平台
+     *
+     * @return true-是商户平台用户, false-不是
+     */
+    public static boolean isStorePlatformUser() {
+        String userType = getCurrentUserType();
+        return "storePlatform".equals(userType);
+    }
+
+    /**
+     * 获取当前登录用户的门店ID
+     * 注意:需要先查询数据库获取完整用户信息
+     *
+     * @return 门店ID,如果未登录或用户无门店返回null
+     */
+    public static Integer getCurrentStoreId() {
+        try {
+            StoreUser storeUser = getCurrentStoreUser();
+            if (storeUser != null) {
+                return storeUser.getStoreId();
+            }
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentStoreId - 获取门店ID失败: {}", e.getMessage(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前登录用户的昵称
+     * 注意:需要先查询数据库获取完整用户信息
+     *
+     * @return 昵称,如果未登录返回null
+     */
+    public static String getCurrentNickName() {
+        try {
+            StoreUser storeUser = getCurrentStoreUser();
+            if (storeUser != null) {
+                return storeUser.getNickName();
+            }
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentNickName - 获取昵称失败: {}", e.getMessage(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 获取当前登录用户的真实姓名
+     * 注意:需要先查询数据库获取完整用户信息
+     *
+     * @return 真实姓名,如果未登录返回null
+     */
+    public static String getCurrentName() {
+        try {
+            StoreUser storeUser = getCurrentStoreUser();
+            if (storeUser != null) {
+                return storeUser.getName();
+            }
+        } catch (Exception e) {
+            log.error("LoginUserUtil.getCurrentName - 获取姓名失败: {}", e.getMessage(), e);
+        }
+        return null;
+    }
+}
+
+
+
+
+
+
+

+ 2 - 2
alien-store/src/main/java/shop/alien/store/util/ai/AiFeedbackAssignUtils.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
 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.core.io.ByteArrayResource;
 import org.springframework.http.*;
 import org.springframework.stereotype.Component;
@@ -22,6 +23,7 @@ import java.util.Map;
 @Slf4j
 @Component
 @RequiredArgsConstructor
+@RefreshScope
 public class AiFeedbackAssignUtils {
 
     private final RestTemplate restTemplate;
@@ -38,8 +40,6 @@ public class AiFeedbackAssignUtils {
     @Value("${ai.service.assign-staff-url}")
     private String assignStaffUrl;
 
-    private  final AlienAIFeign alienAIFeign;
-
     // 语音识别接口地址(从配置中读取,如果没有配置则使用默认值)
     @Value("${feign.alienAI.url}")
     private String aiServiceBaseUrl;

+ 1 - 0
alien-store/src/main/java/shop/alien/store/util/ai/AiImageColorExtractUtil.java

@@ -26,6 +26,7 @@ import java.util.Map;
 public class AiImageColorExtractUtil {
 
     private final RestTemplate restTemplate;
+
     private final AiAuthTokenUtil aiAuthTokenUtil;
 
     @Value("${ai.service.image-color-extract-url}")

+ 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) {
         String originalFilename = multipartFile.getOriginalFilename();
         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;
     }
 
@@ -505,10 +517,22 @@ public class FileUtil {
     public static Map<String, String> getFileNameAndType(File file) {
         String originalFilename = file.getName();
         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;
     }
 }