Explorar o código

Merge remote-tracking branch 'origin/dev' into dev

penghao hai 2 semanas
pai
achega
8bccd9bd4b
Modificáronse 38 ficheiros con 1184 adicións e 34 borrados
  1. 4 0
      alien-entity/src/main/java/shop/alien/entity/store/CommentAppeal.java
  2. 5 2
      alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationOrder.java
  3. 68 0
      alien-entity/src/main/java/shop/alien/entity/store/SecondAiTask.java
  4. 11 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreMenu.java
  5. 6 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerConsultationOrderDto.java
  6. 3 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/CommentAppealVo.java
  7. 3 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/OrderReviewVo.java
  8. 53 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/StoreAlbumDetailVo.java
  9. 25 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/StoreAlbumNameVo.java
  10. 29 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/StoreOfficialAlbumImgVo.java
  11. 4 2
      alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationOrderMapper.java
  12. 8 0
      alien-entity/src/main/java/shop/alien/mapper/OrderReviewMapper.java
  13. 14 0
      alien-entity/src/main/java/shop/alien/mapper/SecondAiTaskMapper.java
  14. 39 0
      alien-entity/src/main/java/shop/alien/mapper/StoreMenuMapper.java
  15. 5 0
      alien-entity/src/main/resources/mapper/CommentAppealMapper.xml
  16. 29 0
      alien-entity/src/main/resources/mapper/OrderReviewMapper.xml
  17. 19 0
      alien-job/src/main/java/shop/alien/job/second/AiCheckXxlJob.java
  18. 4 0
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerUserLogInController.java
  19. 15 0
      alien-lawyer/src/main/java/shop/alien/lawyer/controller/OrderReviewController.java
  20. 11 0
      alien-lawyer/src/main/java/shop/alien/lawyer/feign/AlienStoreFeign.java
  21. 8 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/OrderReviewService.java
  22. 34 16
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/CommentAppealServiceImpl.java
  23. 2 1
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerConsultationOrderServiceImpl.java
  24. 8 0
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/OrderExpirationServiceImpl.java
  25. 30 1
      alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/OrderReviewServiceImpl.java
  26. 35 0
      alien-store/src/main/java/shop/alien/store/controller/SecondAiTaskController.java
  27. 62 0
      alien-store/src/main/java/shop/alien/store/controller/StoreMenuController.java
  28. 92 5
      alien-store/src/main/java/shop/alien/store/controller/StoreOfficialAlbumController.java
  29. 12 0
      alien-store/src/main/java/shop/alien/store/service/SecondAiTaskService.java
  30. 25 0
      alien-store/src/main/java/shop/alien/store/service/StoreMenuService.java
  31. 24 0
      alien-store/src/main/java/shop/alien/store/service/StoreOfficialAlbumService.java
  32. 18 0
      alien-store/src/main/java/shop/alien/store/service/impl/SecondAiTaskServiceImpl.java
  33. 147 0
      alien-store/src/main/java/shop/alien/store/service/impl/StoreMenuServiceImpl.java
  34. 181 0
      alien-store/src/main/java/shop/alien/store/service/impl/StoreOfficialAlbumServiceImpl.java
  35. 47 1
      alien-store/src/main/java/shop/alien/store/strategy/payment/impl/AlipayPaymentStrategyImpl.java
  36. 25 5
      alien-store/src/main/java/shop/alien/store/strategy/payment/impl/WeChatPaymentStrategyImpl.java
  37. 1 1
      alien-store/src/main/resources/bootstrap.yml
  38. 78 0
      alien-util/src/main/java/shop/alien/util/ai/AiAuthTokenUtil.java

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

@@ -92,5 +92,9 @@ public class CommentAppeal extends Model<CommentAppeal> {
     @ApiModelProperty(value = "申诉人id")
     @TableField("lawyer_user_id")
     private String lawyerUserId;
+
+    @ApiModelProperty(value = "订单ID")
+    @TableField("order_id")
+    private Integer orderId;
 }
 

+ 5 - 2
alien-entity/src/main/java/shop/alien/entity/store/LawyerConsultationOrder.java

@@ -8,7 +8,6 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
-import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -169,12 +168,16 @@ public class LawyerConsultationOrder extends Model<LawyerConsultationOrder> {
     @TableField("reject_refund_reason")
     private String rejectRefundReason;
 
-    @ApiModelProperty(value = "是否已被申诉, 0:未申诉, 1:已申诉")
+    @ApiModelProperty(value = "是否已被申诉, 0:未申诉, 1:已申诉, 2:申诉中")
     @TableField("is_appealed")
     private Integer isAppealed;
 
     @ApiModelProperty(value = "退款申请处理动作:1-同意,2-拒绝")
     @TableField(exist = false)
     private String processAction;
+
+    @ApiModelProperty(value = "支付方式 1支付宝 2微信")
+    @TableField("pay_type")
+    private  String payType;
 }
 

+ 68 - 0
alien-entity/src/main/java/shop/alien/entity/store/SecondAiTask.java

@@ -0,0 +1,68 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * second_ai_task 表实体
+ */
+@Data
+@TableName("second_ai_task")
+@ApiModel(value = "SecondAiTask", description = "AI视频审核任务表")
+public class SecondAiTask implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("数据ID")
+    @TableField("data_id")
+    private String dataId;
+
+    @ApiModelProperty("视频URL")
+    @TableField("video_url")
+    private String videoUrl;
+
+    @ApiModelProperty("任务ID")
+    @TableField("task_id")
+    private String taskId;
+
+    @ApiModelProperty("任务状态 SUBMITTED/PROCESSING/...")
+    @TableField("status")
+    private String status;
+
+    @ApiModelProperty("风险级别 none/low/medium/high")
+    @TableField("risk_level")
+    private String riskLevel;
+
+    @ApiModelProperty("审核结果(JSON)")
+    @TableField("result")
+    private String result;
+
+    @ApiModelProperty("重试次数")
+    @TableField("retry_count")
+    private Integer retryCount;
+
+    @ApiModelProperty("创建时间")
+    @TableField("create_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+
+    @ApiModelProperty("更新时间")
+    @TableField("update_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updateTime;
+}
+
+

+ 11 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreMenu.java

@@ -93,5 +93,16 @@ public class StoreMenu {
     @TableField("description")
     private String description;
 
+    @ApiModelProperty(value = "酒精度")
+    @TableField("alcoholVolume")
+    private String alcoholVolume;
+
+    @ApiModelProperty(value = "分类")
+    @TableField("category")
+    private String category;
+
+    @ApiModelProperty(value = "品味")
+    @TableField("flavor")
+    private String flavor;
 
 }

+ 6 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/LawyerConsultationOrderDto.java

@@ -124,5 +124,11 @@ public class LawyerConsultationOrderDto extends Model<LawyerConsultationOrderDto
     @ApiModelProperty(value = "律师接单状态  0接单  1拒绝接单")
     @TableField("accept_orders_status")
     private  Integer acceptOrdersStatus;
+
+
+    @ApiModelProperty(value = "支付方式 1支付宝 2微信")
+    @TableField("pay_type")
+    private  String payType;
+
 }
 

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

@@ -139,5 +139,8 @@ public class CommentAppealVo implements Serializable {
 
     @ApiModelProperty(value = "申诉单号")
     private String appealNumber;
+
+    @ApiModelProperty(value = "订单ID")
+    private Integer orderId;
 }
 

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

@@ -88,5 +88,8 @@ public class OrderReviewVo {
 
     @ApiModelProperty(value = "逻辑删除")
     private Integer deleteFlag;
+
+    @ApiModelProperty(value = "订单申诉状态")
+    private Integer isAppealed;
 }
 

+ 53 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreAlbumDetailVo.java

@@ -0,0 +1,53 @@
+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.util.List;
+
+/**
+ * 官方相册详情VO(包含相册名称、图片列表和数量)
+ *
+ * @author zhangchen
+ * @since 2025-01-16
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "StoreAlbumDetailVo", description = "官方相册详情VO")
+public class StoreAlbumDetailVo {
+
+    @ApiModelProperty(value = "相册名称")
+    private String albumName;
+
+    @ApiModelProperty(value = "该相册下的图片数量")
+    private Integer imgCount;
+
+    @ApiModelProperty(value = "该相册下的图片列表")
+    private List<StoreImgInfo> imgList;
+
+    /**
+     * 图片信息
+     */
+    @Data
+    @JsonInclude
+    @ApiModel(value = "StoreImgInfo", description = "图片信息")
+    public static class StoreImgInfo {
+        @ApiModelProperty(value = "图片ID")
+        private Integer id;
+
+        @ApiModelProperty(value = "图片链接")
+        private String imgUrl;
+
+        @ApiModelProperty(value = "图片描述")
+        private String imgDescription;
+
+        @ApiModelProperty(value = "图片排序")
+        private Integer imgSort;
+
+        @ApiModelProperty(value = "图片类型")
+        private Integer imgType;
+    }
+}
+

+ 25 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreAlbumNameVo.java

@@ -0,0 +1,25 @@
+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;
+
+/**
+ * 官方相册名称VO
+ *
+ * @author zhangchen
+ * @since 2025-01-16
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "StoreAlbumNameVo", description = "官方相册名称VO")
+public class StoreAlbumNameVo {
+
+    @ApiModelProperty(value = "相册名称")
+    private String albumName;
+
+    @ApiModelProperty(value = "该相册下的图片数量")
+    private Integer imgCount;
+}
+

+ 29 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreOfficialAlbumImgVo.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 shop.alien.entity.store.StoreImg;
+
+import java.util.List;
+
+/**
+ * 官方相册图片列表返回VO
+ *
+ * @author zhangchen
+ * @since 2025-01-16
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "StoreOfficialAlbumImgVo", description = "官方相册图片列表返回VO")
+public class StoreOfficialAlbumImgVo {
+
+    @ApiModelProperty(value = "图片列表")
+    private List<StoreImg> imgList;
+
+    @ApiModelProperty(value = "图片总数")
+    private Integer totalCount;
+
+}
+

+ 4 - 2
alien-entity/src/main/java/shop/alien/mapper/LawyerConsultationOrderMapper.java

@@ -98,7 +98,8 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
             "lawyer_earnings ," +
             "accept_orders_time ," +
             "reason_order_refusal ," +
-            "accept_orders_status " +
+            "accept_orders_status ," +
+            "pay_type " +
             ")"+
             "VALUES" +
             " (" +
@@ -130,7 +131,8 @@ public interface LawyerConsultationOrderMapper extends BaseMapper<LawyerConsulta
             "#{lawyerEarnings} ," +
             "#{acceptOrdersTime} ," +
             "#{reasonOrderRefusal} ," +
-            "#{acceptOrdersStatus}" +
+            "#{acceptOrdersStatus} ," +
+            "#{payType} " +
             ")")
             int insertOrder(LawyerConsultationOrderDto order);
 

+ 8 - 0
alien-entity/src/main/java/shop/alien/mapper/OrderReviewMapper.java

@@ -128,5 +128,13 @@ public interface OrderReviewMapper extends BaseMapper<OrderReview> {
      * @return 有图评价数量
      */
     Integer getImageReviewCountByLawyerUserId(@Param("lawyerUserId") Integer lawyerUserId);
+
+    /**
+     * 根据订单ID查询关联评价
+     *
+     * @param orderId 订单ID
+     * @return 评价信息
+     */
+    OrderReviewVo getOrderEvaluation(@Param("orderId") Integer orderId);
 }
 

+ 14 - 0
alien-entity/src/main/java/shop/alien/mapper/SecondAiTaskMapper.java

@@ -0,0 +1,14 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.SecondAiTask;
+
+/**
+ * second_ai_task Mapper
+ */
+@Mapper
+public interface SecondAiTaskMapper extends BaseMapper<SecondAiTask> {
+}
+
+

+ 39 - 0
alien-entity/src/main/java/shop/alien/mapper/StoreMenuMapper.java

@@ -37,4 +37,43 @@ public interface StoreMenuMapper extends BaseMapper<StoreMenu> {
             "left join store_img b on a.img_id = b.id where a.delete_flag = 0 and b.delete_flag = 0 " +
             "and a.id = #{id}")
     StoreMenuVo getMenuInfo(@Param("id") Integer id);
+
+    /**
+     * 获取菜单(客户端)
+     * <p>
+     * 根据门店ID查询菜单列表,支持按菜品类型和菜单类型筛选。
+     * 查询未删除的菜单及其关联的图片信息。
+     * </p>
+     *
+     * @param storeId      门店ID,必填
+     * @param dishType     菜品类型,可选,0:非推荐, 1:推荐。当为null时,不限制菜品类型
+     * @param dishMenuType 菜单类型,可选,1-菜单,2-酒水。当为null时,不限制菜单类型
+     * @return 菜单列表,包含菜单信息和关联的图片信息
+     */
+    @Select("<script>" +
+            "SELECT " +
+            "    a.*, " +
+            "    b.img_url, " +
+            "    b.img_sort, " +
+            "    b.img_description " +
+            "FROM store_menu a " +
+            "LEFT JOIN store_img b ON a.img_id = b.id " +
+            "WHERE a.delete_flag = 0 " +
+            "    AND (b.delete_flag = 0 OR b.delete_flag IS NULL) " +
+            "    AND a.store_id = #{storeId} " +
+            "<if test='dishType != null'>" +
+            "    AND a.dish_type = #{dishType} " +
+            "</if>" +
+            "<if test='dishMenuType != null'>" +
+            "    AND a.dish_menu_type = #{dishMenuType} " +
+            "</if>" +
+            "</script>")
+    List<StoreMenuVo> getClientMenuByStoreId(@Param("storeId") Integer storeId, 
+                                             @Param("dishType") Integer dishType, 
+                                             @Param("dishMenuType") Integer dishMenuType);
+
+    @Select("select a.*, b.img_url, b.img_sort, b.img_description from store_menu a " +
+            "left join store_img b on a.img_id = b.id where a.delete_flag = 0 and b.delete_flag = 0 " +
+            "and a.id = #{id}")
+    StoreMenuVo getClientMenuInfoById(@Param("id") Integer id);
 }

+ 5 - 0
alien-entity/src/main/resources/mapper/CommentAppealMapper.xml

@@ -15,6 +15,7 @@
         <result column="updated_time" property="updatedTime" />
         <result column="updated_user_id" property="updatedUserId" />
         <result column="appeal_time" property="appealTime" />
+        <result column="order_id" property="orderId" />
     </resultMap>
 
     <!-- 申诉历史列表查询结果映射 -->
@@ -52,6 +53,7 @@
         <result column="lawyer_user_id" property="lawyerUserId" />
         <result column="lawyer_name" property="lawyerName" />
         <result column="lawyer_phone" property="lawyerPhone" />
+        <result column="order_id" property="orderId" />
     </resultMap>
 
     <!-- 查询申诉历史列表(包含评价和用户信息) -->
@@ -71,6 +73,7 @@
             ca.updated_time,
             ca.updated_user_id,
             ca.updated_user_id AS audit_user_id,
+            ca.order_id,
             orv.user_id AS review_user_id,
             lu.user_name,
             CASE
@@ -115,6 +118,7 @@
             ca.updated_user_id,
             ca.updated_user_id AS audit_user_id,
             ca.appeal_number,
+            ca.order_id,
             orv.user_id AS review_user_id,
             lu.user_name AS review_user_name,
             CASE
@@ -153,6 +157,7 @@
             ca.updated_time,
             ca.updated_user_id,
             ca.updated_user_id AS audit_user_id,
+            ca.order_id,
             orv.order_number,
             orv.user_id AS review_user_id,
             CASE

+ 29 - 0
alien-entity/src/main/resources/mapper/OrderReviewMapper.xml

@@ -25,6 +25,7 @@
         <result column="comment_count" property="commentCount" />
         <result column="is_liked" property="isLiked" />
         <result column="created_time" property="createdTime" />
+        <result column="is_appealed" property="isAppealed" />
     </resultMap>
 
     <!-- 分页查询评价列表(包含用户和律师信息) -->
@@ -362,5 +363,33 @@
         ORDER BY orv.created_time DESC
     </select>
 
+    <!-- 根据订单ID查询评价 -->
+    <select id="getOrderEvaluation" resultMap="OrderReviewVoResultMap">
+        SELECT
+            orv.id,
+            orv.order_id,
+            orv.order_number,
+            orv.user_id,
+            orv.lawyer_user_id,
+            orv.overall_rating,
+            orv.service_attitude_rating,
+            orv.response_time_rating,
+            orv.professional_ability_rating,
+            orv.review_content,
+            orv.review_images,
+            orv.is_anonymous,
+            orv.like_count,
+            orv.comment_count,
+            orv.created_time,
+            lco.is_appealed,
+            lu.user_name
+        FROM lawyer_order_review orv
+        INNER JOIN lawyer_consultation_order lco ON lco.id = orv.order_id AND lco.delete_flag = 0
+        LEFT JOIN life_user lu ON lu.id = orv.user_id AND lu.delete_flag = 0
+        WHERE orv.delete_flag = 0
+        AND orv.order_id = #{orderId}
+        LIMIT 1
+    </select>
+
 </mapper>
 

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

@@ -0,0 +1,19 @@
+package shop.alien.job.second;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Lhaibo
+ * @date 2025/11/28
+ * @since 1.0.0
+ * @desc: xxl-job
+ * AI调用审核任务
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class AiCheckXxlJob {
+
+}

+ 4 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/controller/LawyerUserLogInController.java

@@ -70,6 +70,10 @@ public class LawyerUserLogInController {
         if (lawyerUser.getStatus() == 0) {
             return R.fail("账号被禁用");
         }
+        LawyerUser lawyerUser1 = new LawyerUser();
+        lawyerUser1.setId(lawyerUser.getId());
+        lawyerUser1.setIsOnline(1);
+        lawyerUserMapper.updateById(lawyerUser1);
         return Optional.ofNullable(lawyerUser).
                 map(user -> lawyerUserDto.getIsPassword() ? checkPassword(user, lawyerUserDto.getPassword()) : lawyerUserService.createToKen(user)).
                 orElseGet(() -> R.fail("手机号不存在"));

+ 15 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/controller/OrderReviewController.java

@@ -260,5 +260,20 @@ public class OrderReviewController {
         }
         return orderReviewService.getReviewListByLawyerAndType(page, size, lawyerUserId, type, currentUserId);
     }
+
+    @ApiOperation("根据订单ID查询订单关联的评价")
+    @ApiOperationSupport(order = 13)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "orderId", value = "订单ID", dataType = "int", paramType = "query", required = true)
+    })
+    @GetMapping("/getByOrderId")
+    public R<OrderReviewVo> queryReviewByOrderId(
+            @RequestParam Integer orderId) {
+        log.info("OrderReviewController.queryReviewByOrderId?orderId={}", orderId);
+        if (orderId == null) {
+            return R.fail("订单ID不能为空");
+        }
+        return orderReviewService.getOrderEvaluation(orderId);
+    }
 }
 

+ 11 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/feign/AlienStoreFeign.java

@@ -2,7 +2,12 @@ package shop.alien.lawyer.feign;
 
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
+import shop.alien.entity.result.R;
+
+import java.util.Map;
 
 /**
  * @author ssk
@@ -25,4 +30,10 @@ public interface AlienStoreFeign {
                          @RequestParam(value = "refundAmount") String refundAmount,
                          @RequestParam(value = "refundReason") String refundReason,
                          @RequestParam(value = "partialRefundCode") String partialRefundCode);
+
+    /**
+     * 微信/支付宝退款
+     */
+    @PostMapping("payment/refunds")
+    R paymentRefunds(@RequestBody Map<String, String> params);
 }

+ 8 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/OrderReviewService.java

@@ -134,5 +134,13 @@ public interface OrderReviewService extends IService<OrderReview> {
      */
     R<shop.alien.entity.store.vo.LawyerReviewStatisticsVo> getLawyerReviewStatistics(Integer lawyerUserId);
 
+    /**
+     * 根据订单ID查询关联评价
+     *
+     * @param orderId 订单ID
+     * @return R<OrderReviewVo>
+     */
+    R<OrderReviewVo> getOrderEvaluation(Integer orderId);
+
 }
 

+ 34 - 16
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/CommentAppealServiceImpl.java

@@ -46,6 +46,7 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
     private final OrderReviewMapper orderReviewMapper;
     private final LifeUserMapper lifeUserMapper;
     private final LawyerUserMapper lawyerUserMapper;
+    private final LawyerConsultationOrderMapper lawyerConsultationOrderMapper;
 
 
     @Override
@@ -70,6 +71,14 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
             return R.fail("该评论已有申诉记录,无法重复申诉");
         }
 
+        // 如果orderId为空,从OrderReview中获取
+        if (commentAppeal.getOrderId() == null) {
+            OrderReview orderReview = orderReviewMapper.selectById(commentAppeal.getCommentId());
+            if (orderReview != null && orderReview.getOrderId() != null) {
+                commentAppeal.setOrderId(orderReview.getOrderId());
+            }
+        }
+
         // 设置默认值
         commentAppeal.setStatus(0); // 待处理
         if (commentAppeal.getDeleteFlag() == null) {
@@ -81,9 +90,18 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
         if (result) {
             log.info("提交申诉成功,id={}", commentAppeal.getId());
             
+            // 更新订单表的申诉状态为2(申诉中)
+            if (commentAppeal.getOrderId() != null) {
+                LambdaUpdateWrapper<LawyerConsultationOrder> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+                lambdaUpdateWrapper.eq(LawyerConsultationOrder::getId, commentAppeal.getOrderId())
+                        .set(LawyerConsultationOrder::getIsAppealed, 2);
+                lawyerConsultationOrderMapper.update(null, lambdaUpdateWrapper);
+                log.info("更新订单申诉状态成功,orderId={}, isAppealed=2", commentAppeal.getOrderId());
+            }
+
             // 发送通知给评价用户,告知其评价被申诉了
             sendSubmitAppealNotification(commentAppeal);
-            
+
             return R.data(commentAppeal, "申诉提交成功");
         } else {
             return R.fail("申诉提交失败");
@@ -173,21 +191,21 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
         try {
             // 查询律师用户信息
             LambdaQueryWrapper<LawyerUser> lawyerUser = new LambdaQueryWrapper<>();
-            lawyerUser.eq(LawyerUser :: getId, appeal.getLawyerUserId());
+            lawyerUser.eq(LawyerUser::getId, appeal.getLawyerUserId());
             LawyerUser lifeUser = lawyerUserMapper.selectOne(lawyerUser);
             if (lifeUser == null) {
                 log.warn("评价用户不存在,userId={}", lifeUser.getId());
                 return;
             }
             LambdaQueryWrapper<OrderReview> orderReviewLambdaQueryWrapper = new LambdaQueryWrapper<>();
-            orderReviewLambdaQueryWrapper.eq(OrderReview ::  getId, appeal.getCommentId());
+            orderReviewLambdaQueryWrapper.eq(OrderReview::getId, appeal.getCommentId());
             OrderReview orderReview = orderReviewMapper.selectOne(orderReviewLambdaQueryWrapper);
             String orderNumber = "";
-            if(orderReview != null){
+            if (orderReview != null) {
                 orderNumber = orderReview.getOrderNumber();
             }
             String receiverId = "user_" + lifeUser.getPhone();
-            String message = String.format("您提交的差评申诉信息,订单编号为"+ orderNumber +",已提交至平台审核,1-3个工作日会发送您审核结果,请注意查收。");
+            String message = String.format("您提交的差评申诉信息,订单编号为" + orderNumber + ",已提交至平台审核,1-3个工作日会发送您审核结果,请注意查收。");
 
             LifeNotice lifeNotice = new LifeNotice();
             lifeNotice.setReceiverId(receiverId);
@@ -253,7 +271,7 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
             }
 
             String receiverId = "user_" + lifeUser.getUserPhone();
-            String message = String.format("您对订单编号为"+ orderReview.getOrderNumber() +"的评价,律师已进行申诉,经核实,您的评价不实,平台已删除此条评价及回复。");
+            String message = String.format("您对订单编号为" + orderReview.getOrderNumber() + "的评价,律师已进行申诉,经核实,您的评价不实,平台已删除此条评价及回复。");
 
             LifeNotice lifeNotice = new LifeNotice();
             lifeNotice.setReceiverId(receiverId);
@@ -296,9 +314,9 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
             // 律师的接收ID格式可能是 "lawyer_" + phone 或其他格式,需要根据实际情况调整
             String receiverId = "lawyer_" + lawyerUser.getPhone();
             String title = isSuccess ? "申诉成功通知" : "申诉失败通知";
-            String message = isSuccess 
-                    ? String.format("您的编号"+ orderReview.getOrderNumber() +"的订单,提交的差评申诉信息,经核实,评价内容不实,平台已删除此条评价。")
-                    : String.format("您的编号"+ orderReview.getOrderNumber() +"的订单,提交的差评申诉信息,经核实,评价内容属实。失败原因:"+ reviewReasons +"。");
+            String message = isSuccess
+                    ? String.format("您的编号" + orderReview.getOrderNumber() + "的订单,提交的差评申诉信息,经核实,评价内容不实,平台已删除此条评价。")
+                    : String.format("您的编号" + orderReview.getOrderNumber() + "的订单,提交的差评申诉信息,经核实,评价内容属实。失败原因:" + reviewReasons + "。");
 
             LifeNotice lifeNotice = new LifeNotice();
             lifeNotice.setReceiverId(receiverId);
@@ -347,8 +365,8 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
 
     @Override
     public R<IPage<CommentAppealVo>> getAppealPage(Integer pageNum, Integer pageSize, Integer status,
-                                                     String orderNumber, String userName, String userPhone, String lawyerName, String lawyerPhone,
-                                                     String startTime, String endTime) {
+                                                   String orderNumber, String userName, String userPhone, String lawyerName, String lawyerPhone,
+                                                   String startTime, String endTime) {
         log.info("CommentAppealServiceImpl.getAppealPage?pageNum={}, pageSize={}, status={}, orderNumber={}, userName={}, userPhone={}, lawyerName={}, lawyerPhone={}, startTime={}, endTime={}",
                 pageNum, pageSize, status, orderNumber, userName, userPhone, lawyerName, lawyerPhone, startTime, endTime);
 
@@ -526,11 +544,11 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
                 pageNum, pageSize, status, lawyerUserId);
         List<CommentAppealVo> appealList = new ArrayList<>();
         //status 3 查全部
-        if(status ==3){
-            appealList  = baseMapper.getAppealHistoryList(null, lawyerUserId);
-        }else{
+        if (status == 3) {
+            appealList = baseMapper.getAppealHistoryList(null, lawyerUserId);
+        } else {
             // 查询申诉历史列表
-            appealList  = baseMapper.getAppealHistoryList(status, lawyerUserId);
+            appealList = baseMapper.getAppealHistoryList(status, lawyerUserId);
         }
 
         // 处理数据转换(图片列表等)
@@ -539,7 +557,7 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
         }
 
         ListToPage.setPage(appealList, pageNum, pageSize);
-        
+
         return appealList;
     }
 }

+ 2 - 1
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/LawyerConsultationOrderServiceImpl.java

@@ -454,6 +454,7 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
         order.setAlipayNo(lawyerConsultationOrder.getAlipayNo());
         order.setOrderStr(lawyerConsultationOrder.getOrderStr());
         order.setPlaceId(lawyerConsultationOrder.getPlaceId());
+        order.setPayType(lawyerConsultationOrder.getPayType());
 
         // 设置订单状态
         order.setOrderStatus(0); // 待支付
@@ -559,7 +560,7 @@ public class LawyerConsultationOrderServiceImpl extends ServiceImpl<LawyerConsul
 //                .withNano(0);
 //        order.setValidityPeriod(Date.from(validityDateTime.atZone(ZoneId.systemDefault()).toInstant()));
 //        boolean result = this.updateById(order);
-        int result = consultationOrderMapper.updateOrder(order);
+        Integer result = consultationOrderMapper.updateOrder(order);
 
         if (result > 0) {
             return R.data(order);

+ 8 - 0
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/OrderExpirationServiceImpl.java

@@ -181,6 +181,14 @@ public class OrderExpirationServiceImpl implements OrderExpirationService, Comma
 
                 // 處理訂單退款
                 String refundResult = aliController.processRefund(order.getAlipayNo(), new BigDecimal(order.getOrderAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString(), refundReason, "");
+
+                // 微信/支付宝退款
+                /*paramMap.put("payType", "1".equals(order.getPayType()) ? PaymentEnum.ALIPAY.getType() : PaymentEnum.WECHAT_PAY.getType());
+                paramMap.put("outTradeNo", order.getAlipayNo());
+                paramMap.put("refundReason", refundReason);
+                paramMap.put("refundAmount", new BigDecimal(order.getOrderAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
+                R refunds = alienStoreFeign.paymentRefunds(paramMap);*/
+
                 if ("调用成功".equals(refundResult)) {
                     log.info("訂單退款成功,訂單no: {}", orderNo);
 

+ 30 - 1
alien-lawyer/src/main/java/shop/alien/lawyer/service/impl/OrderReviewServiceImpl.java

@@ -128,7 +128,7 @@ public class OrderReviewServiceImpl extends ServiceImpl<OrderReviewMapper, Order
             log.info("创建评价成功,评价ID={}", review.getId());
             // 更新律师评分
             updateLawyerServiceScore(review.getLawyerUserId());
-            return R.data(review, "评价成功");
+            return R.data(review, "提交成功");
         } else {
             log.error("创建评价失败");
             return R.fail("创建评价失败");
@@ -661,5 +661,34 @@ public class OrderReviewServiceImpl extends ServiceImpl<OrderReviewMapper, Order
             return R.fail("获取统计数据失败");
         }
     }
+
+    @Override
+    public R<OrderReviewVo> getOrderEvaluation(Integer orderId) {
+        log.info("OrderReviewServiceImpl.getOrderEvaluation?orderId={}", orderId);
+
+        if (orderId == null) {
+            return R.fail("订单ID不能为空");
+        }
+
+        OrderReviewVo reviewVo = orderReviewMapper.getOrderEvaluation(orderId);
+        if (reviewVo == null) {
+            return R.fail("该订单暂无评价");
+        }
+
+        // 处理评价图片:从JSON字符串解析为List
+        if (reviewVo.getReviewImagesJson() != null && !reviewVo.getReviewImagesJson().trim().isEmpty()) {
+            try {
+                List<String> images = JSON.parseArray(reviewVo.getReviewImagesJson(), String.class);
+                reviewVo.setReviewImages(images != null ? images : new ArrayList<>());
+            } catch (Exception e) {
+                log.warn("解析评价图片失败:{}", e.getMessage());
+                reviewVo.setReviewImages(new ArrayList<>());
+            }
+        } else {
+            reviewVo.setReviewImages(new ArrayList<>());
+        }
+
+        return R.data(reviewVo);
+    }
 }
 

+ 35 - 0
alien-store/src/main/java/shop/alien/store/controller/SecondAiTaskController.java

@@ -0,0 +1,35 @@
+package shop.alien.store.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import shop.alien.entity.result.R;
+import shop.alien.store.service.SecondAiTaskService;
+
+/**
+ * second_ai_task 控制器(占位)
+ */
+@Api(tags = "二期-AI任务")
+@Slf4j
+@RestController
+@CrossOrigin
+@RequestMapping("/second/ai/task")
+@RequiredArgsConstructor
+public class SecondAiTaskController {
+
+    private final SecondAiTaskService secondAiTaskService;
+
+    @ApiOperation("AI任务模块占位")
+    @GetMapping("/ping")
+    public R<String> ping() {
+        log.info("SecondAiTaskController.ping");
+        return R.success("second_ai_task ready");
+    }
+}
+
+

+ 62 - 0
alien-store/src/main/java/shop/alien/store/controller/StoreMenuController.java

@@ -122,4 +122,66 @@ public class StoreMenuController {
         log.info("StoreRecommendController.getMenuLikeStatus?userId={}&menuId={}", userId, menuId);
         return R.data(storeMenuService.getMenuLikeStatus(userId, menuId));
     }
+
+    /**
+     * 获取菜单(用户端)
+     * <p>
+     * 根据门店ID获取菜单列表,支持按菜品类型、菜单类型筛选,并可查询用户点赞状态
+     * </p>
+     *
+     * @param storeId      门店ID,必填,必须大于0
+     * @param dishType     菜品类型,可选,0:非推荐, 1:推荐
+     * @param phoneId      用户手机号,可选,用于查询点赞状态
+     * @param dishMenuType 菜单类型,可选,1-菜单,2-酒水
+     * @return 统一返回结果,包含菜单列表
+     * @throws IllegalArgumentException 当门店ID为空或小于等于0时抛出
+     */
+    @ApiOperation("获取菜单(用户端)")
+    @ApiOperationSupport(order = 9)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "dishType", value = "菜品类型, 0:(推荐+非推荐), 1:推荐", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "phoneId", value = "用户手机号", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "dishMenuType", value = "菜单类型:1-菜单,2-酒水", dataType = "Integer", paramType = "query")
+    })
+    @GetMapping("/getClientMenuByStoreId")
+    public R<List<StoreMenuVo>> getClientMenuByStoreId(
+            @RequestParam(value = "storeId", required = true) Integer storeId,
+            @RequestParam(value = "dishType", required = false) Integer dishType,
+            @RequestParam(value = "phoneId", required = false) String phoneId,
+            @RequestParam(value = "dishMenuType", required = false) Integer dishMenuType) {
+        // 记录请求入参
+        log.info("获取用户端菜单,入参:storeId={}, dishType={}, phoneId={}, dishMenuType={}", 
+                storeId, dishType, phoneId, dishMenuType);
+        
+        // 参数校验
+        if (storeId == null || storeId <= 0) {
+            log.warn("获取用户端菜单失败,门店ID无效:storeId={}", storeId);
+            return R.fail("门店ID不能为空且必须大于0");
+        }
+        
+        try {
+            // 调用服务层获取菜单列表
+            List<StoreMenuVo> menuList = storeMenuService.getClientMenuByStoreId(
+                    storeId, dishType, phoneId, dishMenuType);
+            
+            // 记录返回结果
+            log.info("获取用户端菜单成功,门店ID:{},返回菜单数量:{}", 
+                    storeId, menuList != null ? menuList.size() : 0);
+            
+            return R.data(menuList);
+        } catch (Exception e) {
+            log.error("获取用户端菜单异常,门店ID:{},异常信息:{}", storeId, e.getMessage(), e);
+            return R.fail("获取菜单失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperation("获取门店菜单详情(用户端)")
+    @ApiOperationSupport(order = 4)
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "菜单ID", dataType = "Integer", paramType = "query")})
+    @GetMapping("/getClientMenuInfoById")
+    public R<StoreMenuVo> getClientMenuInfoById(Integer id) {
+        log.info("StoreRecommendController.getClientMenuInfoById?id={}", id);
+        return R.data(storeMenuService.getClientMenuInfoById(id));
+    }
 }

+ 92 - 5
alien-store/src/main/java/shop/alien/store/controller/StoreOfficialAlbumController.java

@@ -1,14 +1,13 @@
 package shop.alien.store.controller;
 
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiOperationSupport;
-import io.swagger.annotations.ApiSort;
+import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.StoreOfficialAlbum;
+import shop.alien.entity.store.vo.StoreAlbumNameVo;
+import shop.alien.entity.store.vo.StoreOfficialAlbumImgVo;
 import shop.alien.entity.store.vo.StoreOfficialAlbumVo;
 import shop.alien.store.service.StoreOfficialAlbumService;
 
@@ -51,7 +50,7 @@ public class StoreOfficialAlbumController {
     @ApiOperation("删除官方相册")
     @ApiOperationSupport(order = 3)
     @PostMapping("/deleteOfficialAlbum")
-    public  R<Boolean> deleteOfficialAlbum(@RequestBody List<StoreOfficialAlbum> storeOfficialAlbumList) {
+    public R<Boolean> deleteOfficialAlbum(@RequestBody List<StoreOfficialAlbum> storeOfficialAlbumList) {
         log.info("StoreOfficialAlbumController.deleteOfficialAlbum");
         int result = storeOfficialAlbumService.deleteOfficialAlbum(storeOfficialAlbumList);
         if (result > 0) {
@@ -59,4 +58,92 @@ public class StoreOfficialAlbumController {
         }
         return R.fail("失败");
     }
+
+    /**
+     * 获取官方相册图片列表(客户端)
+     * <p>
+     * 根据门店ID和相册名称查询官方相册中的图片列表
+     * 查询条件:imgType = 2(官方相册),通过 business_id 关联到 store_official_album 表,按 albumName 筛选
+     * </p>
+     *
+     * @param storeId   门店ID,必填,必须大于0
+     * @param albumName 相册名称,可选。例如:酒水、餐食、环境、全部等。当为null或空字符串时,查询全部
+     * @return 统一返回结果,包含图片列表和总数
+     * @throws IllegalArgumentException 当门店ID为空或小于等于0时抛出
+     */
+    @ApiOperation("获取官方相册图片列表(客户端)")
+    @ApiOperationSupport(order = 4)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "albumName", value = "相册名称,例如:酒水、餐食、环境、全部等。不传或传空字符串时查询全部", dataType = "String", paramType = "query")
+    })
+    @GetMapping("/getOfficialAlbumImgList")
+    public R<StoreOfficialAlbumImgVo> getOfficialAlbumImgList(
+            @RequestParam(value = "storeId", required = true) Integer storeId,
+            @RequestParam(value = "albumName", required = false) String albumName) {
+        // 记录请求入参
+        log.info("获取官方相册图片列表,入参:storeId={}, albumName={}", storeId, albumName);
+
+        // 参数校验
+        if (storeId == null || storeId <= 0) {
+            log.warn("获取官方相册图片列表失败,门店ID无效:storeId={}", storeId);
+            return R.fail("门店ID不能为空且必须大于0");
+        }
+
+        try {
+            // 调用服务层获取图片列表
+            StoreOfficialAlbumImgVo result = storeOfficialAlbumService.getOfficialAlbumImgList(storeId, albumName);
+
+            // 记录返回结果
+            log.info("获取官方相册图片列表成功,门店ID:{},相册名称:{},返回图片数量:{}", 
+                    storeId, albumName, result.getTotalCount());
+
+            return R.data(result);
+        } catch (Exception e) {
+            log.error("获取官方相册图片列表异常,门店ID:{},异常信息:{}", storeId, e.getMessage(), e);
+            return R.fail("获取图片列表失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 获取官方相册名称列表(客户端)
+     * <p>
+     * 根据门店ID查询所有可用的相册名称列表,用于前端展示筛选选项
+     * 返回每个相册名称及其对应的图片数量
+     * </p>
+     *
+     * @param storeId 门店ID,必填,必须大于0
+     * @return 统一返回结果,包含相册名称列表和每个相册的图片数量
+     * @throws IllegalArgumentException 当门店ID为空或小于等于0时抛出
+     */
+    @ApiOperation("获取官方相册名称列表(客户端)")
+    @ApiOperationSupport(order = 5)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getAlbumNameList")
+    public R<List<StoreAlbumNameVo>> getAlbumNameList(
+            @RequestParam(value = "storeId", required = true) Integer storeId) {
+        // 记录请求入参
+        log.info("获取官方相册名称列表,入参:storeId={}", storeId);
+
+        // 参数校验
+        if (storeId == null || storeId <= 0) {
+            log.warn("获取官方相册名称列表失败,门店ID无效:storeId={}", storeId);
+            return R.fail("门店ID不能为空且必须大于0");
+        }
+
+        try {
+            // 调用服务层获取相册名称列表
+            List<StoreAlbumNameVo> result = storeOfficialAlbumService.getAlbumNameList(storeId);
+
+            // 记录返回结果
+            log.info("获取官方相册名称列表成功,门店ID:{},返回相册数量:{}", storeId, result.size());
+
+            return R.data(result);
+        } catch (Exception e) {
+            log.error("获取官方相册名称列表异常,门店ID:{},异常信息:{}", storeId, e.getMessage(), e);
+            return R.fail("获取相册名称列表失败:" + e.getMessage());
+        }
+    }
 }

+ 12 - 0
alien-store/src/main/java/shop/alien/store/service/SecondAiTaskService.java

@@ -0,0 +1,12 @@
+package shop.alien.store.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.store.SecondAiTask;
+
+/**
+ * second_ai_task 服务接口
+ */
+public interface SecondAiTaskService extends IService<SecondAiTask> {
+}
+
+

+ 25 - 0
alien-store/src/main/java/shop/alien/store/service/StoreMenuService.java

@@ -79,5 +79,30 @@ public interface StoreMenuService extends IService<StoreMenu> {
      * @return boolean
      */
     boolean getMenuLikeStatus(String userId, Integer menuId);
+
+    /**
+     * 获取门店菜单(客户端)
+     * <p>
+     * 根据门店ID查询菜单列表,支持按菜品类型和菜单类型筛选。
+     * 当查询推荐菜且提供用户手机号时,会批量查询并设置用户的点赞状态。
+     * 最终结果按排序字段升序排列。
+     * </p>
+     *
+     * @param storeId      门店ID,必填,必须大于0
+     * @param dishType     菜品类型,可选,0:非推荐, 1:推荐。当为0时,查询条件中不包含菜品类型限制
+     * @param phoneId      用户手机号,可选,用于查询用户对推荐菜的点赞状态
+     * @param dishMenuType 菜单类型,可选,1-菜单,2-酒水
+     * @return 菜单列表,按排序字段升序排列,如果查询结果为空则返回空列表
+     * @throws IllegalArgumentException 当门店ID为空或小于等于0时抛出
+     */
+    List<StoreMenuVo> getClientMenuByStoreId(Integer storeId, Integer dishType, String phoneId, Integer dishMenuType);
+
+    /**
+     * 获取菜品详情
+     *
+     * @param id 菜品id
+     * @return StoreMenuVo
+     */
+    StoreMenuVo getClientMenuInfoById(Integer id);
 }
 

+ 24 - 0
alien-store/src/main/java/shop/alien/store/service/StoreOfficialAlbumService.java

@@ -13,4 +13,28 @@ public interface StoreOfficialAlbumService extends IService<StoreOfficialAlbum>
     StoreOfficialAlbum createOrUpdateOfficialAlbum(StoreOfficialAlbum storeOfficialAlbum);
     List<StoreOfficialAlbumVo> getOfficialAlbumList(String storeId);
     int deleteOfficialAlbum(List<StoreOfficialAlbum> storeOfficialAlbumList);
+    
+    /**
+     * 获取官方相册图片列表(客户端)
+     * <p>
+     * 根据门店ID和相册名称查询官方相册中的图片列表
+     * 查询条件:imgType = 2(官方相册),通过 business_id 关联到 store_official_album 表,按 albumName 筛选
+     * </p>
+     *
+     * @param storeId   门店ID,必填
+     * @param albumName 相册名称,可选。例如:酒水、餐食、环境、全部等。当为null或空字符串时,查询全部
+     * @return 图片列表和总数
+     */
+    shop.alien.entity.store.vo.StoreOfficialAlbumImgVo getOfficialAlbumImgList(Integer storeId, String albumName);
+
+    /**
+     * 获取官方相册名称列表(客户端)
+     * <p>
+     * 根据门店ID查询所有可用的相册名称列表,用于前端展示筛选选项
+     * </p>
+     *
+     * @param storeId 门店ID,必填
+     * @return 相册名称列表,包含相册名称和图片数量
+     */
+    List<shop.alien.entity.store.vo.StoreAlbumNameVo> getAlbumNameList(Integer storeId);
 }

+ 18 - 0
alien-store/src/main/java/shop/alien/store/service/impl/SecondAiTaskServiceImpl.java

@@ -0,0 +1,18 @@
+package shop.alien.store.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import shop.alien.entity.store.SecondAiTask;
+import shop.alien.mapper.SecondAiTaskMapper;
+import shop.alien.store.service.SecondAiTaskService;
+
+/**
+ * second_ai_task 服务实现
+ */
+@Service
+@RequiredArgsConstructor
+public class SecondAiTaskServiceImpl extends ServiceImpl<SecondAiTaskMapper, SecondAiTask> implements SecondAiTaskService {
+}
+
+

+ 147 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StoreMenuServiceImpl.java

@@ -48,6 +48,26 @@ public class StoreMenuServiceImpl extends ServiceImpl<StoreMenuMapper, StoreMenu
 
     private final LifeGroupBuyThaliMapper lifeGroupBuyThaliMapper;
 
+    /**
+     * 菜品类型:非推荐
+     */
+    private static final Integer DISH_TYPE_NON_RECOMMEND = 0;
+
+    /**
+     * 菜品类型:推荐
+     */
+    private static final Integer DISH_TYPE_RECOMMEND = 1;
+
+    /**
+     * 点赞状态:未点赞
+     */
+    private static final Integer LIKE_STATUS_NO = 0;
+
+    /**
+     * 点赞状态:已点赞
+     */
+    private static final Integer LIKE_STATUS_YES = 1;
+
 
     /**
      * 获取门店菜单
@@ -303,4 +323,131 @@ public class StoreMenuServiceImpl extends ServiceImpl<StoreMenuMapper, StoreMenu
     public boolean getMenuLikeStatus(String userId, Integer menuId) {
         return lifeLikeRecordMapper.selectCount(new QueryWrapper<LifeLikeRecord>().eq("dianzan_id", userId).eq("huifu_id", menuId).eq("delete_flag", 0)) > 0;
     }
+
+    /**
+     * 获取门店菜单(客户端)
+     * <p>
+     * 根据门店ID查询菜单列表,支持按菜品类型和菜单类型筛选。
+     * 当查询推荐菜且提供用户手机号时,会批量查询并设置用户的点赞状态。
+     * 最终结果按排序字段升序排列。
+     * </p>
+     *
+     * @param storeId      门店ID,必填,必须大于0
+     * @param dishType     菜品类型,可选,0:全部, 1:推荐
+     * @param phoneId      用户手机号,可选,用于查询用户对推荐菜的点赞状态
+     * @param dishMenuType 菜单类型,可选,1-菜单,2-酒水
+     * @return 菜单列表,按排序字段升序排列,如果查询结果为空则返回空列表
+     */
+    @Override
+    public List<StoreMenuVo> getClientMenuByStoreId(Integer storeId, Integer dishType, String phoneId, Integer dishMenuType) {
+        log.info("开始获取用户端菜单,门店ID:{},菜品类型:{},用户手机号:{},菜单类型:{}", 
+                storeId, dishType, phoneId, dishMenuType);
+        
+        // 参数校验
+        if (storeId == null || storeId <= 0) {
+            log.warn("获取用户端菜单失败,门店ID无效:{}", storeId);
+            throw new IllegalArgumentException("门店ID不能为空且必须大于0");
+        }
+        
+        // 处理菜品类型参数:当dishType为0时,转换为null以查询所有类型
+        Integer queryDishType = (DISH_TYPE_NON_RECOMMEND.equals(dishType)) ? null : dishType;
+        
+        // 查询菜单列表
+        List<StoreMenuVo> menuList = storeMenuMapper.getClientMenuByStoreId(storeId, queryDishType, dishMenuType);
+        
+        // 如果查询结果为空,直接返回空列表
+        if (CollectionUtils.isEmpty(menuList)) {
+            log.info("获取用户端菜单完成,门店ID:{},未查询到菜单数据", storeId);
+            return menuList;
+        }
+        
+        log.info("获取用户端菜单,门店ID:{},查询到菜单数量:{}", storeId, menuList.size());
+        
+        // 如果是推荐菜且有用户标识,批量查询并设置点赞状态
+        if (DISH_TYPE_RECOMMEND.equals(dishType) && StringUtils.isNotEmpty(phoneId)) {
+            setLikeStatusForMenuList(menuList, phoneId);
+        } else {
+            // 非推荐菜或未提供用户手机号时,设置默认未点赞状态
+            menuList.forEach(item -> item.setIsLike(LIKE_STATUS_NO));
+        }
+        
+        // 按排序字段升序排序
+        List<StoreMenuVo> sortedMenuList = menuList.stream()
+                .sorted(Comparator.comparing(StoreMenuVo::getSort, Comparator.nullsLast(Integer::compareTo)))
+                .collect(Collectors.toList());
+        
+        log.info("获取用户端菜单完成,门店ID:{},返回菜单数量:{}", storeId, sortedMenuList.size());
+        
+        return sortedMenuList;
+    }
+
+    /**
+     * 批量设置菜单的点赞状态
+     * <p>
+     * 根据用户手机号和菜单ID列表,批量查询点赞记录,并设置每个菜单的点赞状态
+     * </p>
+     *
+     * @param menuList 菜单列表
+     * @param phoneId  用户手机号
+     */
+    private void setLikeStatusForMenuList(List<StoreMenuVo> menuList, String phoneId) {
+        if (CollectionUtils.isEmpty(menuList) || StringUtils.isEmpty(phoneId)) {
+            return;
+        }
+        
+        log.debug("开始批量查询点赞状态,用户手机号:{},菜单数量:{}", phoneId, menuList.size());
+        
+        // 将菜单ID转换为String集合,用于查询点赞记录
+        Set<String> menuIdStrSet = menuList.stream()
+                .map(item -> String.valueOf(item.getId()))
+                .filter(id -> id != null && !"null".equals(id))
+                .collect(Collectors.toSet());
+        
+        if (menuIdStrSet.isEmpty()) {
+            log.warn("菜单ID集合为空,无法查询点赞状态");
+            menuList.forEach(item -> item.setIsLike(LIKE_STATUS_NO));
+            return;
+        }
+        
+        // 批量查询点赞记录
+        LambdaQueryWrapper<LifeLikeRecord> likeQuery = new LambdaQueryWrapper<>();
+        likeQuery.eq(LifeLikeRecord::getDianzanId, phoneId)
+                .in(LifeLikeRecord::getHuifuId, menuIdStrSet);
+        List<LifeLikeRecord> likeRecordList = lifeLikeRecordMapper.selectList(likeQuery);
+        
+        // 构建已点赞的菜单ID集合
+        Set<String> likedMenuIdSet = likeRecordList.stream()
+                .map(LifeLikeRecord::getHuifuId)
+                .filter(id -> id != null)
+                .collect(Collectors.toSet());
+        
+        log.debug("查询到点赞记录数量:{},已点赞菜单数量:{}", 
+                likeRecordList.size(), likedMenuIdSet.size());
+        
+        // 设置点赞状态
+        menuList.forEach(item -> {
+            if (item.getId() == null) {
+                item.setIsLike(LIKE_STATUS_NO);
+                return;
+            }
+            
+            String menuIdStr = String.valueOf(item.getId());
+            if (likedMenuIdSet.contains(menuIdStr)) {
+                item.setIsLike(LIKE_STATUS_YES);
+            } else {
+                item.setIsLike(LIKE_STATUS_NO);
+            }
+        });
+    }
+
+    /**
+     * 获取菜品详情
+     *
+     * @param id 菜品id
+     * @return StoreMenuVo
+     */
+    @Override
+    public StoreMenuVo getClientMenuInfoById(Integer id) {
+        return storeMenuMapper.getClientMenuInfoById(id);
+    }
 }

+ 181 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StoreOfficialAlbumServiceImpl.java

@@ -1,14 +1,19 @@
 package shop.alien.store.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import shop.alien.entity.store.StoreImg;
 import shop.alien.entity.store.StoreOfficialAlbum;
+import shop.alien.entity.store.vo.StoreAlbumDetailVo;
+import shop.alien.entity.store.vo.StoreAlbumNameVo;
+import shop.alien.entity.store.vo.StoreOfficialAlbumImgVo;
 import shop.alien.entity.store.vo.StoreOfficialAlbumVo;
 import shop.alien.mapper.StoreImgMapper;
 import shop.alien.mapper.StoreOfficialAlbumMapper;
@@ -16,8 +21,10 @@ import shop.alien.store.service.StoreOfficialAlbumService;
 import shop.alien.store.util.CommonConstant;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
+@Slf4j
 @Transactional
 @Service
 @RequiredArgsConstructor
@@ -97,4 +104,178 @@ public class StoreOfficialAlbumServiceImpl extends ServiceImpl<StoreOfficialAlbu
         storeImgMapper.delete(wrapper);
         return CommonConstant.ERROR_CODE_VALID_PARAMS;
     }
+
+    /**
+     * 获取官方相册图片列表(客户端)
+     * <p>
+     * 根据门店ID和相册名称查询官方相册中的图片列表
+     * 查询条件:imgType = 2(官方相册),通过 business_id 关联到 store_official_album 表,按 albumName 筛选
+     * </p>
+     *
+     * @param storeId   门店ID,必填
+     * @param albumName 相册名称,可选。例如:酒水、餐食、环境、全部等。当为null或空字符串时,查询全部
+     * @return 图片列表和总数
+     */
+    @Override
+    public StoreOfficialAlbumImgVo getOfficialAlbumImgList(Integer storeId, String albumName) {
+        log.info("开始获取官方相册图片列表,门店ID:{},相册名称:{}", storeId, albumName);
+
+        // 参数校验
+        if (storeId == null || storeId <= 0) {
+            log.warn("获取官方相册图片列表失败,门店ID无效:{}", storeId);
+            throw new IllegalArgumentException("门店ID不能为空且必须大于0");
+        }
+
+        // 先查询符合条件的官方相册ID列表
+        LambdaQueryWrapper<StoreOfficialAlbum> albumQueryWrapper = new LambdaQueryWrapper<>();
+        albumQueryWrapper.eq(StoreOfficialAlbum::getStoreId, storeId)
+                .eq(StoreOfficialAlbum::getDeleteFlag, CommonConstant.DELETE_FLAG_UNDELETE);
+
+        // 如果指定了相册名称,添加筛选条件
+        if (StringUtils.isNotBlank(albumName)) {
+            albumQueryWrapper.eq(StoreOfficialAlbum::getAlbumName, albumName);
+        }
+
+        List<StoreOfficialAlbum> albumList = storeOfficialAlbumMapper.selectList(albumQueryWrapper);
+
+        // 如果相册列表为空,直接返回空结果
+        if (CollectionUtils.isEmpty(albumList)) {
+            log.info("获取官方相册图片列表,门店ID:{},未查询到符合条件的相册", storeId);
+            StoreOfficialAlbumImgVo result = new StoreOfficialAlbumImgVo();
+            result.setImgList(Collections.emptyList());
+            result.setTotalCount(0);
+            return result;
+        }
+
+        // 提取相册ID列表
+        List<Integer> albumIds = albumList.stream()
+                .map(StoreOfficialAlbum::getId)
+                .collect(Collectors.toList());
+
+        log.debug("查询到符合条件的相册数量:{},相册ID列表:{}", albumList.size(), albumIds);
+
+        // 查询这些相册下的所有图片(imgType = 2 表示官方相册)
+        LambdaQueryWrapper<StoreImg> imgQueryWrapper = new LambdaQueryWrapper<>();
+        imgQueryWrapper.eq(StoreImg::getStoreId, storeId)
+                .eq(StoreImg::getImgType, CommonConstant.STORE_IMG_ALBUM) // imgType = 2 表示官方相册
+                .in(StoreImg::getBusinessId, albumIds) // business_id 关联到相册ID
+                .eq(StoreImg::getDeleteFlag, CommonConstant.DELETE_FLAG_UNDELETE)
+                .orderByAsc(StoreImg::getImgSort);
+
+        List<StoreImg> imgList = storeImgMapper.selectList(imgQueryWrapper);
+
+        // 构建返回结果
+        StoreOfficialAlbumImgVo result = new StoreOfficialAlbumImgVo();
+        result.setImgList(imgList);
+        result.setTotalCount(imgList.size());
+
+        log.info("获取官方相册图片列表完成,门店ID:{},相册名称:{},返回图片数量:{}", 
+                storeId, albumName, result.getTotalCount());
+
+        return result;
+    }
+
+    /**
+     * 获取官方相册名称列表(客户端)
+     * <p>
+     * 根据门店ID查询所有可用的相册名称列表,用于前端展示筛选选项
+     * 返回每个相册名称及其对应的图片数量
+     * </p>
+     *
+     * @param storeId 门店ID,必填
+     * @return 相册名称列表,包含相册名称和图片数量
+     */
+    @Override
+    public List<StoreAlbumNameVo> getAlbumNameList(Integer storeId) {
+        log.info("开始获取官方相册名称列表,门店ID:{}", storeId);
+
+        // 参数校验
+        if (storeId == null || storeId <= 0) {
+            log.warn("获取官方相册名称列表失败,门店ID无效:{}", storeId);
+            throw new IllegalArgumentException("门店ID不能为空且必须大于0");
+        }
+
+        // 查询该门店下所有未删除的官方相册
+        LambdaQueryWrapper<StoreOfficialAlbum> albumQueryWrapper = new LambdaQueryWrapper<>();
+        albumQueryWrapper.eq(StoreOfficialAlbum::getStoreId, storeId)
+                .eq(StoreOfficialAlbum::getDeleteFlag, CommonConstant.DELETE_FLAG_UNDELETE)
+                .isNotNull(StoreOfficialAlbum::getAlbumName)
+                .ne(StoreOfficialAlbum::getAlbumName, "");
+
+        List<StoreOfficialAlbum> albumList = storeOfficialAlbumMapper.selectList(albumQueryWrapper);
+
+        // 如果相册列表为空,直接返回空列表
+        if (CollectionUtils.isEmpty(albumList)) {
+            log.info("获取官方相册名称列表,门店ID:{},未查询到相册", storeId);
+            return Collections.emptyList();
+        }
+
+        // 提取相册ID列表
+        List<Integer> albumIds = albumList.stream()
+                .map(StoreOfficialAlbum::getId)
+                .collect(Collectors.toList());
+
+        // 查询这些相册下的所有图片(imgType = 2 表示官方相册)
+        LambdaQueryWrapper<StoreImg> imgQueryWrapper = new LambdaQueryWrapper<>();
+        imgQueryWrapper.eq(StoreImg::getStoreId, storeId)
+                .eq(StoreImg::getImgType, CommonConstant.STORE_IMG_ALBUM) // imgType = 2 表示官方相册
+                .in(StoreImg::getBusinessId, albumIds) // business_id 关联到相册ID
+                .eq(StoreImg::getDeleteFlag, CommonConstant.DELETE_FLAG_UNDELETE);
+
+        List<StoreImg> imgList = storeImgMapper.selectList(imgQueryWrapper);
+
+        // 构建相册ID到相册名称的映射
+        Map<Integer, String> albumIdToNameMap = albumList.stream()
+                .collect(Collectors.toMap(
+                        StoreOfficialAlbum::getId,
+                        StoreOfficialAlbum::getAlbumName,
+                        (existing, replacement) -> existing // 如果有重复的ID,保留第一个
+                ));
+
+        // 按相册名称分组统计图片数量
+        Map<String, Long> albumNameCountMap = imgList.stream()
+                .filter(img -> img.getBusinessId() != null && albumIdToNameMap.containsKey(img.getBusinessId()))
+                .collect(Collectors.groupingBy(
+                        img -> albumIdToNameMap.get(img.getBusinessId()),
+                        Collectors.counting()
+                ));
+
+        // 转换为返回VO列表
+        List<StoreAlbumNameVo> result = albumNameCountMap.entrySet().stream()
+                .map(entry -> {
+                    StoreAlbumNameVo vo = new StoreAlbumNameVo();
+                    vo.setAlbumName(entry.getKey());
+                    vo.setImgCount(entry.getValue().intValue());
+                    return vo;
+                })
+                .sorted((a, b) -> {
+                    // 按图片数量降序排序,如果数量相同则按名称排序
+                    int countCompare = Integer.compare(b.getImgCount(), a.getImgCount());
+                    if (countCompare != 0) {
+                        return countCompare;
+                    }
+                    return a.getAlbumName().compareTo(b.getAlbumName());
+                })
+                .collect(Collectors.toList());
+
+        log.info("获取官方相册名称列表完成,门店ID:{},返回相册数量:{}", storeId, result.size());
+
+        return result;
+    }
+
+    /**
+     * 将StoreImg转换为StoreImgInfo
+     *
+     * @param img 图片实体
+     * @return 图片信息VO
+     */
+    private StoreAlbumDetailVo.StoreImgInfo convertToImgInfo(StoreImg img) {
+        StoreAlbumDetailVo.StoreImgInfo info = new StoreAlbumDetailVo.StoreImgInfo();
+        info.setId(img.getId());
+        info.setImgUrl(img.getImgUrl());
+        info.setImgDescription(img.getImgDescription());
+        info.setImgSort(img.getImgSort());
+        info.setImgType(img.getImgType());
+        return info;
+    }
 }

+ 47 - 1
alien-store/src/main/java/shop/alien/store/strategy/payment/impl/AlipayPaymentStrategyImpl.java

@@ -10,8 +10,10 @@ import com.alipay.api.DefaultAlipayClient;
 import com.alipay.api.domain.AlipayTradeAppPayModel;
 import com.alipay.api.domain.AlipayTradeRefundModel;
 import com.alipay.api.request.AlipayTradeAppPayRequest;
+import com.alipay.api.request.AlipayTradeQueryRequest;
 import com.alipay.api.request.AlipayTradeRefundRequest;
 import com.alipay.api.response.AlipayTradeAppPayResponse;
+import com.alipay.api.response.AlipayTradeQueryResponse;
 import com.alipay.api.response.AlipayTradeRefundResponse;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -189,7 +191,51 @@ public class AlipayPaymentStrategyImpl implements PaymentStrategy {
 
     @Override
     public R<Object> searchOrderByOutTradeNoPath(String transactionId) throws Exception {
-        return null;
+        try {
+            AlipayClient alipayClient = new DefaultAlipayClient(setAlipayConfig(null));
+            // 2. 构造查询请求
+            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
+
+            // 设置biz_content(JSON格式)
+            JSONObject bizContent = new JSONObject();
+            if (StringUtils.isNotBlank(transactionId)) {
+                bizContent.put("out_trade_no", transactionId);
+            }
+//            if (StringUtils.isNotBlank(tradeNo)) {
+//                bizContent.put("trade_no", tradeNo);
+//            }
+            request.setBizContent(bizContent.toJSONString());
+
+            // 3. 调用接口并获取响应
+            AlipayTradeQueryResponse response = alipayClient.certificateExecute(request);
+            if (response.isSuccess()) {
+                // 4. 解析支付状态
+                String tradeStatus = response.getTradeStatus();
+                log.info("订单查询成功,支付状态:" + tradeStatus);
+
+                // 支付状态说明:
+                // WAIT_BUYER_PAY:等待买家付款
+                // TRADE_CLOSED:交易关闭(超时未支付/已取消)
+                // TRADE_SUCCESS:支付成功(即时到账/普通转账)
+                // TRADE_FINISHED:交易完成(不可退款的场景,如即时到账)
+                if ("TRADE_SUCCESS".equals(tradeStatus)) {
+                    return R.success("支付成功");
+                } else if ("TRADE_CLOSED".equals(tradeStatus)) {
+                    return R.fail("交易已关闭");
+                } else if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
+                    return R.fail("等待买家付款");
+                } else if ("TRADE_FINISHED".equals(tradeStatus)) {
+                    return R.success("交易完成");
+                }
+                return R.success("订单状态:" + tradeStatus);
+            } else {
+                return R.fail("订单查询失败:" + response.getMsg() + "(" + response.getSubMsg() + ")");
+            }
+        } catch (AlipayApiException e) {
+            log.error("支付宝订单查询异常", e);
+            return R.fail("查询异常:" + e.getMessage());
+        }
+
     }
 
     @Override

+ 25 - 5
alien-store/src/main/java/shop/alien/store/strategy/payment/impl/WeChatPaymentStrategyImpl.java

@@ -18,8 +18,11 @@ import javax.annotation.PostConstruct;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
 import java.security.PrivateKey;
 import java.security.PublicKey;
+import java.security.Signature;
+import java.util.Base64;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -128,8 +131,8 @@ public class WeChatPaymentStrategyImpl implements PaymentStrategy {
             privateKeyPath = privateLinuxKeyPath;
             wechatPayPublicKeyFilePath = wechatLinuxPayPublicKeyFilePath;
         }
-        this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyPath);
-        this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
+       // this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyPath);
+        //this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
     }
 
     @Override
@@ -200,6 +203,22 @@ public class WeChatPaymentStrategyImpl implements PaymentStrategy {
             result.put("appId", appId);
             result.put("mchId", mchId);
             result.put("outTradeNo", request.outTradeNo);
+            // 生成sign
+//            appId
+
+//            随机字符串
+//            prepay_id
+            long timestamp = System.currentTimeMillis() / 1000; // 时间戳
+            String nonce = WXPayUtility.createNonce(32); // 随机字符串
+            String prepayId = response.prepayId;
+            String message = String.format("%s\n%s\n%s\n%s\n", appId, timestamp, nonce, prepayId);
+//            String sign = WXPayUtility.sign(message, sha256withRSA, privateKey);
+            Signature sign = Signature.getInstance("SHA256withRSA");
+            sign.initSign(privateKey);
+            sign.update(message.getBytes(StandardCharsets.UTF_8));
+            result.put("sign", Base64.getEncoder().encodeToString(sign.sign()));
+            result.put("timestamp", String.valueOf(timestamp));
+            result.put("nonce", nonce);
             return R.data(result);
         } catch (WXPayUtility.ApiException e) {
             log.error("微信支付预支付失败,状态码:{},错误信息:{}", e.getErrorCode(), e.getMessage());
@@ -235,7 +254,7 @@ public class WeChatPaymentStrategyImpl implements PaymentStrategy {
         CreateRequest request = new CreateRequest();
         // 微信支付订单号和商户订单号必须二选一,不能同时为空,查询的时候使用的是商户订单号
         //request.transactionId = "1217752501201407033233368018";
-        request.outTradeNo = UniqueRandomNumGenerator.generateUniqueCode(19);
+        request.outTradeNo = params.get("outTradeNo");
         // 退款订单号
         request.outRefundNo = UniqueRandomNumGenerator.generateUniqueCode(19);
         // 退款原因
@@ -246,7 +265,7 @@ public class WeChatPaymentStrategyImpl implements PaymentStrategy {
         //request.fundsAccount = ReqFundsAccount.AVAILABLE;
         // 金额信息
         request.amount = new AmountReq();
-        request.amount.refund = 888L;
+        request.amount.refund = new BigDecimal(params.get("refundAmount")).multiply(new BigDecimal(100)).longValue();
         // 退款出资账户及金额 目前不需要,需要的时候再看
         /*
         request.amount.from = new ArrayList<>();
@@ -257,7 +276,7 @@ public class WeChatPaymentStrategyImpl implements PaymentStrategy {
             request.amount.from.add(fromItem);
         };*/
         // 订单总金额
-        request.amount.total = 888L;
+        request.amount.total = new BigDecimal(params.get("totalAmount")).multiply(new BigDecimal(100)).longValue();
         // 退款币种 目前默认人民币 CNY
         request.amount.currency = "CNY";
         // 退款商品信息 目前不需要,需要的时候再看
@@ -275,6 +294,7 @@ public class WeChatPaymentStrategyImpl implements PaymentStrategy {
         };*/
         try {
             Refund response = refundRun(request);
+            String refundReslut = "";
             // TODO: 请求成功,继续业务逻辑
             System.out.println(response);
         } catch (WXPayUtility.ApiException e) {

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

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

+ 78 - 0
alien-util/src/main/java/shop/alien/util/ai/AiAuthTokenUtil.java

@@ -0,0 +1,78 @@
+package shop.alien.util.ai;
+
+import com.alibaba.fastjson2.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.*;
+import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * AI 服务鉴权配置
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class AiAuthTokenUtil {
+
+    private final RestTemplate restTemplate;
+
+    @Value("${third-party-login.base-url:http://192.168.2.250:9000/ai/user-auth-core/api/v1/auth/login}")
+    private String loginUrl;
+
+    @Value("${third-party-user-name.base-url:UdUser}")
+    private String userName;
+
+    @Value("${third-party-pass-word.base-url:123456}")
+    private String passWord;
+
+    /**
+     * 登录 AI 服务,获取 token
+     *
+     * @return accessToken
+     */
+    public String getAccessToken() {
+        log.info("登录Ai服务获取token...{}", loginUrl);
+        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+        formData.add("username", userName);
+        formData.add("password", passWord);
+
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
+
+        ResponseEntity<String> response;
+        try {
+            log.info("请求Ai服务登录接口===================>");
+            response = restTemplate.postForEntity(loginUrl, requestEntity, String.class);
+        } catch (Exception e) {
+            log.error("请求AI服务登录接口失败", e);
+            return null;
+        }
+
+        if (response != null && response.getStatusCode() == HttpStatus.OK) {
+            String body = response.getBody();
+            log.info("请求Ai服务登录成功 postForEntity.getBody()\t{}", body);
+            if (StringUtils.hasText(body)) {
+                JSONObject jsonObject = JSONObject.parseObject(body);
+                if (jsonObject != null) {
+                    JSONObject dataJson = jsonObject.getJSONObject("data");
+                    if (dataJson != null) {
+                        return dataJson.getString("access_token");
+                    }
+                }
+            }
+            log.warn("AI服务登录响应解析失败 body: {}", body);
+            return null;
+        }
+
+        log.error("请求AI服务 登录接口失败 http状态:{}", response != null ? response.getStatusCode() : null);
+        return null;
+    }
+}
+
+