فهرست منبع

用户,红娘精品课程对接支付功能

YH_0525 1 ماه پیش
والد
کامیت
6e90d4ddcb

+ 152 - 41
LiangZhiYUMao/pages/courses/detail.vue

@@ -80,25 +80,35 @@
 <script>
 	import api from '@/utils/api.js'
 	import { DEFAULT_IMAGES } from '@/config/index.js'
+	import userAuth from '@/utils/userAuth.js'
 
 	export default {
 		data() {
 			return {
 				courseId: null,
 				course: {},
-				DEFAULT_IMAGES
+				DEFAULT_IMAGES,
+				gatewayURL: 'http://localhost:8083',
+				currentUserId: null,
+				isPurchased: false
 			}
 		},
 
 		onLoad(options) {
 			console.log('精品课程详情页面加载, 参数:', options)
 			
+			// 获取当前用户ID
+			this.currentUserId = userAuth.getUserId()
+			console.log('当前用户ID:', this.currentUserId)
+			
 			if (options.id) {
 				this.courseId = options.id
 				console.log('课程ID:', this.courseId)
 				// 根据ID设置对应的课程数据
 				this.setCourseDataById(this.courseId)
 				this.loadCourseDetail()
+				// 检查是否已购买
+				this.checkPurchaseStatus()
 			} else {
 				console.log('未传入课程ID,使用默认数据')
 			}
@@ -132,8 +142,11 @@
 					console.log('尝试从API加载课程详情:', this.courseId)
 					const data = await api.course.getDetail(this.courseId)
 					if (data) {
-						this.course = data
-						console.log('API课程详情加载成功')
+						this.course = {
+							...data,
+							purchase_status: 0  // 初始化为未购买,由 checkPurchaseStatus 判断
+						}
+						console.log('API课程详情加载成功, purchase_status:', this.course.purchase_status)
 					} else {
 						console.log('API返回空数据,使用默认课程详情')
 					}
@@ -148,10 +161,28 @@
 				}
 			},
 
+			// 检查购买状态
+			async checkPurchaseStatus() {
+				if (!this.currentUserId || !this.courseId) return
+				
+				try {
+					const purchased = await api.courseOrder.checkPurchased(this.currentUserId, this.courseId)
+					console.log('检查购买状态结果:', purchased, typeof purchased)
+					// 只有明确返回 true 时才设置为已购买
+					if (purchased === true) {
+						this.isPurchased = true
+						this.course.purchase_status = 1
+					}
+				} catch (error) {
+					console.log('检查购买状态失败:', error)
+					// 失败时不改变购买状态,默认为未购买
+				}
+			},
+			
 			// 处理购买
 			handlePurchase() {
 				// 检查是否已购买
-				if (this.course.purchase_status === 1) {
+				if (this.course.purchase_status === 1 || this.isPurchased) {
 					uni.showToast({
 						title: '您已购买过此课程',
 						icon: 'none'
@@ -159,49 +190,129 @@
 					return
 				}
 				
+				// 检查是否登录
+				if (!this.currentUserId) {
+					uni.showModal({
+						title: '提示',
+						content: '请先登录后再购买课程',
+						confirmText: '去登录',
+						success: (res) => {
+							if (res.confirm) {
+								uni.navigateTo({
+									url: '/pages/page3/page3'
+								})
+							}
+						}
+					})
+					return
+				}
+				
 				uni.showModal({
 					title: '确认购买',
 					content: `确认购买"${this.course.name}"课程吗?\n价格:¥${this.course.price}`,
-					success: async (res) => {
+					success: (res) => {
 						if (res.confirm) {
-							try {
-								console.log('尝试购买课程:', this.courseId)
-								// await api.course.purchase(this.courseId, {})
-								
-								// 模拟购买成功
-								uni.showToast({
-									title: '购买成功!',
-									icon: 'success'
-								})
-								
-								// 更新购买状态
-								this.course.purchase_status = 1
-								this.course.student_count = (this.course.student_count || 0) + 1
-								
-								setTimeout(() => {
-									uni.showModal({
-										title: '购买成功',
-										content: '您已成功购买此课程,现在可以开始学习了!',
-										showCancel: false,
-										confirmText: '开始学习',
-										success: (modalRes) => {
-											if (modalRes.confirm) {
-												// TODO: 跳转到课程学习页面
-												uni.showToast({
-													title: '学习功能开发中',
-													icon: 'none'
-												})
-											}
+							this.requestPay()
+						}
+					}
+				})
+			},
+			
+			// 请求支付参数并调起微信支付
+			requestPay() {
+				uni.showLoading({
+					title: '处理中...'
+				})
+				
+				uni.request({
+					url: this.gatewayURL + '/api/course-order/purchase',
+					method: 'POST',
+					data: {
+						userId: this.currentUserId,
+						courseId: parseInt(this.courseId),
+						courseName: this.course.name,
+						price: this.course.price
+					},
+					header: {
+						'content-type': 'application/json',
+						'token': uni.getStorageSync('token')
+					},
+					success: (res) => {
+						uni.hideLoading()
+						
+						if (res.data && res.data.code === 200) {
+							const payParams = res.data.data
+							this.callWxPay(payParams)
+						} else {
+							uni.showToast({
+								title: res.data?.message || res.data?.msg || '获取支付参数失败',
+								icon: 'none'
+							})
+						}
+					},
+					fail: (err) => {
+						uni.hideLoading()
+						console.error('请求支付参数失败:', err)
+						uni.showToast({
+							title: '网络请求失败',
+							icon: 'none'
+						})
+					}
+				})
+			},
+			
+			// 调起微信支付
+			callWxPay(payParams) {
+				uni.requestPayment({
+					provider: 'wxpay',
+					timeStamp: payParams.timeStamp,
+					nonceStr: payParams.nonceStr,
+					package: payParams.package,
+					signType: payParams.signType,
+					paySign: payParams.paySign,
+					success: (payResult) => {
+						if (payResult.errMsg === 'requestPayment:ok') {
+							uni.showToast({
+								title: '购买成功!',
+								icon: 'success',
+								duration: 2000
+							})
+							
+							// 更新购买状态
+							this.course.purchase_status = 1
+							this.isPurchased = true
+							this.course.student_count = (this.course.student_count || 0) + 1
+							
+							setTimeout(() => {
+								uni.showModal({
+									title: '购买成功',
+									content: '您已成功购买此课程,现在可以开始学习了!',
+									showCancel: false,
+									confirmText: '开始学习',
+									success: (modalRes) => {
+										if (modalRes.confirm) {
+											uni.showToast({
+												title: '学习功能开发中',
+												icon: 'none'
+											})
 										}
-									})
-								}, 1500)
-							} catch (error) {
-								console.error('购买失败:', error)
-								uni.showToast({
-									title: '购买失败,请重试',
-									icon: 'none'
+									}
 								})
-							}
+							}, 2000)
+						}
+					},
+					fail: (payError) => {
+						console.error('支付失败:', payError)
+						if (payError.errMsg.includes('cancel')) {
+							uni.showToast({
+								title: '已取消支付',
+								icon: 'none'
+							})
+						} else {
+							uni.showToast({
+								title: `支付失败:${payError.errMsg}`,
+								icon: 'none'
+							})
 						}
 					}
 				})

+ 16 - 0
LiangZhiYUMao/pages/matchmaker-workbench/index.vue

@@ -310,6 +310,22 @@ export default {
 				uni.navigateTo({
 					url: '/pages/matchmaker-workbench/mine'
 				})
+			},
+			// 打开退出工作台确认弹窗
+			openExitPopup() {
+				uni.showModal({
+					title: '退出红娘工作台',
+					content: '确定要退出红娘工作台吗?',
+					confirmText: '确定',
+					cancelText: '取消',
+					success: (res) => {
+						if (res.confirm) {
+							uni.reLaunch({
+								url: '/pages/index/index'
+							})
+						}
+					}
+				})
 			}
 		}
 	}

+ 23 - 1
LiangZhiYUMao/utils/api.js

@@ -244,7 +244,7 @@ export default {
       method: 'GET'
     }),
     
-    // 购买课程
+    // 购买课程(旧接口-模拟)
     purchase: (courseId, data) => request({ 
       url: `/course/purchase/${courseId}`, 
       method: 'POST', 
@@ -252,6 +252,28 @@ export default {
     })
   },
 
+  // 课程订单相关(微信支付)
+  courseOrder: {
+    // 购买课程(获取微信支付参数)
+    purchase: (data) => request({
+      url: '/course-order/purchase',
+      method: 'POST',
+      data
+    }),
+    
+    // 检查是否已购买课程
+    checkPurchased: (userId, courseId) => request({
+      url: `/course-order/check?userId=${userId}&courseId=${courseId}`,
+      method: 'GET'
+    }),
+    
+    // 获取已购买的课程列表
+    getPurchasedCourses: (userId) => request({
+      url: `/course-order/purchased?userId=${userId}`,
+      method: 'GET'
+    })
+  },
+
   // 红娘相关
     matchmaker: {
         // 获取红娘列表

+ 11 - 3
gateway/src/main/resources/application.yml

@@ -161,13 +161,21 @@ spring:
           filters:
             - StripPrefix=1
         
-        # 课程服务路由(admin服务)
+        # 课程服务路由(homePage服务)
         - id: course-route
-          uri: http://localhost:8088
+          uri: http://localhost:8081
           predicates:
             - Path=/api/course/**
           filters:
-            - StripPrefix=1
+            - StripPrefix=0
+        
+        # 课程订单服务路由(Essential服务-微信支付)
+        - id: course-order-route
+          uri: http://localhost:1005
+          predicates:
+            - Path=/api/course-order/**
+          filters:
+            - StripPrefix=0
 
         # 首页服务路由(兜底路由)
         - id: homepage-route

+ 6 - 0
service/Essential/pom.xml

@@ -94,5 +94,11 @@
             <artifactId>minio</artifactId>
             <version>8.5.2</version>
         </dependency>
+        <dependency>
+            <groupId>com.zhentao</groupId>
+            <artifactId>dynamic</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 </project>

+ 92 - 0
service/Essential/src/main/java/com/zhentao/controller/CourseOrderController.java

@@ -0,0 +1,92 @@
+package com.zhentao.controller;
+
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.zhentao.common.Result;
+import com.zhentao.dto.CoursePurchaseRequest;
+import com.zhentao.service.CourseOrderService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 课程订单控制器
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/course-order")
+public class CourseOrderController {
+
+    @Autowired
+    private CourseOrderService courseOrderService;
+
+    /**
+     * 购买课程(获取支付参数)
+     */
+    @PostMapping("/purchase")
+    public Result<Map<String, Object>> purchaseCourse(@RequestBody CoursePurchaseRequest request) {
+        try {
+            Map<String, Object> payParams = courseOrderService.purchaseCourse(
+                    request.getUserId(),
+                    request.getCourseId(),
+                    request.getCourseName(),
+                    request.getPrice()
+            );
+            return Result.success(payParams);
+        } catch (RuntimeException e) {
+            return Result.error(e.getMessage());
+        } catch (WxPayException e) {
+            log.error("微信支付下单失败", e);
+            return Result.error("支付下单失败:" + e.getMessage());
+        } catch (Exception e) {
+            log.error("课程购买失败", e);
+            return Result.error("课程购买失败");
+        }
+    }
+
+    /**
+     * 微信支付回调
+     */
+    @PostMapping("/notify")
+    public String handlePayNotify(@RequestBody String notifyData) {
+        log.info("收到课程支付回调:{}", notifyData);
+        try {
+            return courseOrderService.handlePayNotify(notifyData);
+        } catch (WxPayException e) {
+            log.error("处理课程支付回调失败", e);
+            return "处理支付回调失败";
+        }
+    }
+
+    /**
+     * 检查用户是否已购买课程
+     */
+    @GetMapping("/check")
+    public Result<Boolean> checkPurchased(
+            @RequestParam Long userId,
+            @RequestParam Integer courseId) {
+        try {
+            boolean purchased = courseOrderService.checkPurchased(userId, courseId);
+            return Result.success(purchased);
+        } catch (Exception e) {
+            log.error("检查购买状态失败", e);
+            return Result.error("检查购买状态失败");
+        }
+    }
+
+    /**
+     * 获取用户已购买的课程ID列表
+     */
+    @GetMapping("/purchased")
+    public Result<List<Integer>> getPurchasedCourses(@RequestParam Long userId) {
+        try {
+            List<Integer> courseIds = courseOrderService.getPurchasedCourseIds(userId);
+            return Result.success(courseIds);
+        } catch (Exception e) {
+            log.error("获取已购买课程失败", e);
+            return Result.error("获取已购买课程失败");
+        }
+    }
+}

+ 30 - 0
service/Essential/src/main/java/com/zhentao/dto/CoursePurchaseRequest.java

@@ -0,0 +1,30 @@
+package com.zhentao.dto;
+
+import lombok.Data;
+
+/**
+ * 课程购买请求DTO
+ */
+@Data
+public class CoursePurchaseRequest {
+    
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    
+    /**
+     * 课程ID
+     */
+    private Integer courseId;
+    
+    /**
+     * 课程名称
+     */
+    private String courseName;
+    
+    /**
+     * 课程价格
+     */
+    private Double price;
+}

+ 81 - 0
service/Essential/src/main/java/com/zhentao/entity/CourseOrder.java

@@ -0,0 +1,81 @@
+package com.zhentao.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 课程订单实体
+ */
+@Data
+@TableName("course_orders")
+public class CourseOrder implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    
+    /**
+     * 订单ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+    
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    
+    /**
+     * 课程ID
+     */
+    private Integer courseId;
+    
+    /**
+     * 课程名称
+     */
+    private String courseName;
+    
+    /**
+     * 订单号
+     */
+    private String orderNo;
+    
+    /**
+     * 支付金额
+     */
+    private BigDecimal paymentAmount;
+    
+    /**
+     * 支付方式
+     */
+    private String paymentMethod;
+    
+    /**
+     * 支付时间
+     */
+    private LocalDateTime paymentTime;
+    
+    /**
+     * 订单状态:0-待支付,1-已支付,2-已取消,3-已退款
+     */
+    private Integer status;
+    
+    /**
+     * 微信支付交易号
+     */
+    private String transactionId;
+    
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+    
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 34 - 0
service/Essential/src/main/java/com/zhentao/mapper/CourseOrderMapper.java

@@ -0,0 +1,34 @@
+package com.zhentao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zhentao.entity.CourseOrder;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 课程订单Mapper
+ */
+@Mapper
+public interface CourseOrderMapper extends BaseMapper<CourseOrder> {
+    
+    /**
+     * 根据订单号查询订单
+     */
+    @Select("SELECT * FROM course_orders WHERE order_no = #{orderNo}")
+    CourseOrder selectByOrderNo(@Param("orderNo") String orderNo);
+    
+    /**
+     * 查询用户已购买的课程ID列表
+     */
+    @Select("SELECT course_id FROM course_orders WHERE user_id = #{userId} AND status = 1")
+    List<Integer> selectPurchasedCourseIds(@Param("userId") Long userId);
+    
+    /**
+     * 检查用户是否已购买某课程
+     */
+    @Select("SELECT COUNT(*) FROM course_orders WHERE user_id = #{userId} AND course_id = #{courseId} AND status = 1")
+    int checkPurchased(@Param("userId") Long userId, @Param("courseId") Integer courseId);
+}

+ 48 - 0
service/Essential/src/main/java/com/zhentao/service/CourseOrderService.java

@@ -0,0 +1,48 @@
+package com.zhentao.service;
+
+import com.github.binarywang.wxpay.exception.WxPayException;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 课程订单服务接口
+ */
+public interface CourseOrderService {
+    
+    /**
+     * 购买课程(创建订单并获取支付参数)
+     * 
+     * @param userId 用户ID
+     * @param courseId 课程ID
+     * @param courseName 课程名称
+     * @param price 课程价格
+     * @return 微信支付参数
+     */
+    Map<String, Object> purchaseCourse(Long userId, Integer courseId, String courseName, Double price) throws WxPayException;
+    
+    /**
+     * 处理微信支付回调
+     * 
+     * @param notifyData 回调数据
+     * @return 处理结果
+     */
+    String handlePayNotify(String notifyData) throws WxPayException;
+    
+    /**
+     * 检查用户是否已购买课程
+     * 
+     * @param userId 用户ID
+     * @param courseId 课程ID
+     * @return 是否已购买
+     */
+    boolean checkPurchased(Long userId, Integer courseId);
+    
+    /**
+     * 获取用户已购买的课程ID列表
+     * 
+     * @param userId 用户ID
+     * @return 课程ID列表
+     */
+    List<Integer> getPurchasedCourseIds(Long userId);
+}

+ 191 - 0
service/Essential/src/main/java/com/zhentao/service/impl/CourseOrderServiceImpl.java

@@ -0,0 +1,191 @@
+package com.zhentao.service.impl;
+
+import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+import com.github.binarywang.wxpay.util.SignUtils;
+import com.zhentao.entity.CourseOrder;
+import com.zhentao.entity.Wx;
+import com.zhentao.pojo.Users;
+import com.zhentao.mapper.CourseOrderMapper;
+import com.zhentao.service.CourseOrderService;
+import com.zhentao.service.UsersService;
+import com.zhentao.service.WxService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.RandomUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 课程订单服务实现
+ */
+@Slf4j
+@Service
+public class CourseOrderServiceImpl implements CourseOrderService {
+
+    @Autowired
+    private CourseOrderMapper courseOrderMapper;
+
+    @Autowired
+    private UsersService usersService;
+
+    @Autowired
+    private WxService wxService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> purchaseCourse(Long userId, Integer courseId, String courseName, Double price) throws WxPayException {
+        // 1. 检查是否已购买
+        if (checkPurchased(userId, courseId)) {
+            throw new RuntimeException("您已购买过此课程");
+        }
+
+        // 2. 生成订单号
+        String orderNo = generateOrderNo();
+        LocalDateTime now = LocalDateTime.now();
+
+        // 3. 创建待支付订单
+        CourseOrder order = new CourseOrder();
+        order.setUserId(userId);
+        order.setCourseId(courseId);
+        order.setCourseName(courseName);
+        order.setOrderNo(orderNo);
+        order.setPaymentAmount(BigDecimal.valueOf(price));
+        order.setPaymentMethod("微信支付");
+        order.setStatus(0); // 待支付
+        order.setCreateTime(now);
+        courseOrderMapper.insert(order);
+
+        // 4. 构建微信支付请求
+        WxPayUnifiedOrderRequest payRequest = buildWxPayRequest(orderNo, courseName, price, userId);
+        WxPayUnifiedOrderResult wxPayResult = createWxPayOrder(payRequest);
+
+        // 5. 生成前端调起支付的参数
+        Map<String, Object> payParams = generatePayParams(wxPayResult, price);
+        payParams.put("orderNo", orderNo);
+        return payParams;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String handlePayNotify(String notifyData) throws WxPayException {
+        // 1. 解析回调数据并验证签名
+        WxPayConfig payConfig = getWxPayConfig();
+        WxPayService wxPayService = new WxPayServiceImpl();
+        wxPayService.setConfig(payConfig);
+
+        WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(notifyData);
+        String orderNo = notifyResult.getOutTradeNo();
+        String transactionId = notifyResult.getTransactionId();
+
+        // 2. 查询待支付订单
+        CourseOrder order = courseOrderMapper.selectByOrderNo(orderNo);
+        if (order == null || order.getStatus() != 0) {
+            log.warn("课程订单不存在或已处理:{}", orderNo);
+            return WxPayNotifyResponse.fail("订单不存在或已处理");
+        }
+
+        // 3. 验证支付金额
+        int totalFee = order.getPaymentAmount().multiply(new BigDecimal("100")).intValue();
+        if (Integer.parseInt(String.valueOf(notifyResult.getTotalFee())) != totalFee) {
+            log.warn("课程订单金额不一致:{},实际支付:{}", orderNo, notifyResult.getTotalFee());
+            return WxPayNotifyResponse.fail("金额不一致");
+        }
+
+        // 4. 更新订单状态为已支付
+        order.setStatus(1);
+        order.setPaymentTime(LocalDateTime.now());
+        order.setTransactionId(transactionId);
+        order.setUpdateTime(LocalDateTime.now());
+        courseOrderMapper.updateById(order);
+
+        log.info("课程购买成功:用户{},课程{},订单{}", order.getUserId(), order.getCourseId(), orderNo);
+        return WxPayNotifyResponse.success("处理成功");
+    }
+
+    @Override
+    public boolean checkPurchased(Long userId, Integer courseId) {
+        return courseOrderMapper.checkPurchased(userId, courseId) > 0;
+    }
+
+    @Override
+    public List<Integer> getPurchasedCourseIds(Long userId) {
+        return courseOrderMapper.selectPurchasedCourseIds(userId);
+    }
+
+    private String generateOrderNo() {
+        return "COURSE" + System.currentTimeMillis() + RandomUtils.nextInt(1000, 9999);
+    }
+
+    private WxPayUnifiedOrderRequest buildWxPayRequest(String orderNo, String courseName, Double price, Long userId) {
+        Users user = usersService.getById(userId);
+        if (user == null || user.getWechatOpenid() == null) {
+            throw new RuntimeException("用户微信信息未绑定");
+        }
+
+        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
+        request.setOutTradeNo(orderNo);
+        request.setBody("课程购买-" + courseName);
+        request.setTotalFee(BigDecimal.valueOf(price).multiply(new BigDecimal("100")).intValue());
+        request.setSpbillCreateIp("127.0.0.1");
+        request.setNotifyUrl("https://mini.workervip.com/api/course-order/notify");
+        request.setTradeType("JSAPI");
+        request.setOpenid(user.getWechatOpenid());
+        return request;
+    }
+
+    private WxPayUnifiedOrderResult createWxPayOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
+        WxPayService wxPayService = new WxPayServiceImpl();
+        wxPayService.setConfig(getWxPayConfig());
+        return wxPayService.unifiedOrder(request);
+    }
+
+    private Map<String, Object> generatePayParams(WxPayUnifiedOrderResult wxPayResult, Double price) {
+        Wx wxConfig = wxService.list().get(0);
+        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
+        String nonceStr = RandomStringUtils.randomAlphanumeric(32);
+        String prepayId = wxPayResult.getPrepayId();
+
+        Map<String, String> signParams = new HashMap<>();
+        signParams.put("appId", wxConfig.getAppId());
+        signParams.put("timeStamp", timeStamp);
+        signParams.put("nonceStr", nonceStr);
+        signParams.put("package", "prepay_id=" + prepayId);
+        signParams.put("signType", "MD5");
+
+        String paySign = SignUtils.createSign(signParams, "7f633cbabd894b4d213bc6edffe3b119");
+
+        Map<String, Object> payParams = new HashMap<>();
+        payParams.put("appId", wxConfig.getAppId());
+        payParams.put("timeStamp", timeStamp);
+        payParams.put("nonceStr", nonceStr);
+        payParams.put("package", "prepay_id=" + prepayId);
+        payParams.put("signType", "MD5");
+        payParams.put("paySign", paySign);
+        payParams.put("totalFee", BigDecimal.valueOf(price).multiply(new BigDecimal("100")).intValue());
+        return payParams;
+    }
+
+    private WxPayConfig getWxPayConfig() {
+        Wx wxConfig = wxService.list().get(0);
+        WxPayConfig payConfig = new WxPayConfig();
+        payConfig.setAppId(wxConfig.getAppId());
+        payConfig.setMchId(wxConfig.getMchId());
+        payConfig.setMchKey("7f633cbabd894b4d213bc6edffe3b119");
+        payConfig.setNotifyUrl("https://mini.workervip.com/api/course-order/notify");
+        return payConfig;
+    }
+}

+ 9 - 0
service/Essential/src/main/resources/application.yml

@@ -70,6 +70,9 @@ minio:
   access-key: minioadmin
   secret-key: minioadmin
   bucket-name: user-feedback
+  accessKey: minioadmin
+  secretKey: minioadmin
+  bucketName: dynamic-comments
 
 # 头像本地存储配置
 avatar:
@@ -78,6 +81,12 @@ avatar:
   url:
     prefix: http://localhost:8083/avatars/  # 访问URL前缀(通过网关)
 
+# 动态媒体配置(dynamic模块依赖)
+dynamic:
+  media:
+    upload:
+      path: D:/dynamic-media/
+
 wx:
   pay:
     appId: wx3e90d662a801266e       # 替换为你的小程序AppID