Pārlūkot izejas kodu

优化银河订单预支付信息返回

zoujiajian 5 stundas atpakaļ
vecāks
revīzija
fadae1f5b1

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/OrderDetailView.java

@@ -4,6 +4,7 @@ import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.DbIgnore;
 import com.ejlchina.searcher.bean.SearchBean;
 import com.cyksj.model.views.MultiQuantityOrderTicketView;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -25,6 +26,8 @@ public class OrderDetailView {
 	/**
 	 * 订单id
 	 */
+	/** 订单 id 仅后端使用, 不返回给用户端(用户端用 orderNo) */
+	@JsonIgnore
 	@DbField("o.id")
 	private Long id;
 

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonSearchView.java

@@ -27,6 +27,8 @@ import java.util.List;
 		"left join goods_don g on g.id = o.goods_id " +
 		"left join order_don_transport odt on odt.order_id = o.id")
 public class OrderDonSearchView {
+	/** 订单 id 仅后端使用, 不返回给用户端(用户端用 orderNo) */
+	@JsonIgnore
 	@DbField("o.id")
 	private Long id;
 

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonView.java

@@ -28,6 +28,8 @@ import java.util.List;
 		where = "ocr.id is null")
 public class OrderDonView {
 
+    /** 订单 id 仅后端使用, 不返回给用户端(用户端用 orderNo) */
+    @JsonIgnore
     @DbField("o.id")
     private Long id;
 

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/RenewUpgradeOrderDonView.java

@@ -22,6 +22,8 @@ import java.util.Date;
         " left join goods_don_sku sku on o.sku_id = sku.id")
 public class RenewUpgradeOrderDonView {
 
+    /** 订单 id 仅后端使用, 不返回给用户端(用户端用 orderNo) */
+    @JsonIgnore
     @DbField("o.id")
     private Long id;
 

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/UpgradeOrderDetailView.java

@@ -7,6 +7,7 @@ import com.cyksj.model.entity.UpgradeOrderDon;
 import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.DbIgnore;
 import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -26,6 +27,8 @@ public class UpgradeOrderDetailView {
 	/**
 	 * 订单id
 	 */
+	/** 订单 id 仅后端使用, 不返回给用户端(用户端用 orderNo) */
+	@JsonIgnore
 	@DbField("o.id")
 	private Long id;
 

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/UpgradeOrderDonSearchView.java

@@ -3,6 +3,7 @@ package com.cyksj.model.manage.views;
 import com.cyksj.model.entity.UpgradeOrderDon;
 import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -21,9 +22,14 @@ import java.util.Date;
 		"left join goods_don g on g.id = up.goods_id " +
 		"left join goods_don_sku gs on gs.id = o.sku_id ")
 public class UpgradeOrderDonSearchView {
+	/** 订单 id 仅后端使用, 不返回给用户端(用户端用 orderNo) */
+	@JsonIgnore
 	@DbField("o.id")
 	private Long id;
 
+	@DbField("o.order_no")
+	private String orderNo;
+
 	@DbField("up.name")
 	private String name;
 

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/UpgradeOrderDonView.java

@@ -22,6 +22,8 @@ import java.util.Date;
         "left join goods_don_sku sku on o.sku_id = sku.id ")
 public class UpgradeOrderDonView {
 
+    /** 订单 id 仅后端使用, 不返回给用户端(用户端用 orderNo) */
+    @JsonIgnore
     @DbField("o.id")
     private Long id;
 

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/request/AlipayOrderDonReq.java

@@ -17,6 +17,12 @@ public class AlipayOrderDonReq {
 	@NotNull
 	private Long orderId;
 
+	/**
+	 * 订单号: /applets/order 下普通订单/套餐订单的支付宝接口只认这个字段(由后端换成 orderId),
+	 * 其他订单类型(注册/VIP/Spotify/批发/镜像店铺)仍用 orderId
+	 */
+	private String orderNo;
+
 	/**
 	 *  1、手机网页支付 2、电脑网页支付
 	 */

+ 2 - 2
netflix-service/src/main/java/com/cyksj/service/pay/impl/AliPayCommonServiceImpl.java

@@ -226,8 +226,8 @@ public class AliPayCommonServiceImpl implements AliPayCommonService {
 		Boolean isWx = Optional.ofNullable(re.getIsWx()).orElse(false);
 		if (ZfbProductCode.MOBILE_WEB.getProductCode().equals(productCode) && !isWx) {
 			if (is_bdPost) {
-				//页面 拼接订单号,前端从url获取订单id.
-				returnUrl = String.format("%s%s", envCommonService.getDomain(), BaseZfbConfig.SUCCESS_URL) + orderDon.getId();
+				//页面 拼接订单号, 前端从url获取订单号(用户端不再暴露订单 id)
+				returnUrl = String.format("%s%s", envCommonService.getDomain(), BaseZfbConfig.SUCCESS_URL) + orderDon.getOrderNo();
 			} else {
 				if (StrUtil.isEmpty(returnUrl)) {
 					//默认跳转页

+ 2 - 1
netflix-web/src/main/java/com/cyksj/web/controller/codex/CodexController.java

@@ -178,7 +178,8 @@ public class CodexController {
         long userId = StpUserUtil.getLoginIdAsLong();
         payReq.setUserId(userId);
         OrderDon orderDon = orderDonService.deductSubmitOrder(payReq);
-        return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
+        // 用户端不返回订单 id, 前端用 orderNo 支付
+        return GatewayResponse.SUCCESS.newBuilder().toResult(com.cyksj.web.util.OrderIdHider.hide(orderDon));
     }
 
     /**

+ 2 - 1
netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java

@@ -179,7 +179,8 @@ public class GroupRelationController {
         payRequest.setIp(ip);
 
         OrderDon orderDon = orderDonService.renewal(payRequest);
-        return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
+        // 用户端不返回订单 id, 前端用 orderNo 支付
+        return GatewayResponse.SUCCESS.newBuilder().toResult(com.cyksj.web.util.OrderIdHider.hide(orderDon));
     }
 
     /**

+ 148 - 60
netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java

@@ -184,7 +184,7 @@ public class OrderController {
 
         OrderDon orderDon = orderDonService.submit(payRequest);
 
-        return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(hideOrderId(orderDon));
     }
 
     /**
@@ -206,30 +206,33 @@ public class OrderController {
 
         UpgradeOrderDon orderDon = orderDonService.submitUpgrade(payRequest);
 
-        return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(hideOrderId(orderDon));
     }
 
-    /**
-     * 0元订单确认
-     */
-    @PostMapping("/post/order/status/{orderId}")
+    /*
+     * 0元订单确认 / 套餐0元订单确认 —— 已停用(2026-10-23)
+     * 前端(web-yinhe2 源码、dist、后台)均无调用; 0元订单在下单时已直接完成:
+     * OrderDonServiceImpl.submit / submitUpgrade 中 money == 0 时调用 unifiedHandler*OrderNotify。
+     * service 层 zeroOrderConfirm / zeroUpgradeOrderConfirm 保留未删, 如需恢复取消下面注释即可。
+     *
+    @PostMapping("/post/order/status/{orderNo}")
     @Deprecated
-    public Result<String> zeroOrderConfirm(@PathVariable Long orderId) {
+    public Result<String> zeroOrderConfirm(@PathVariable String orderNo) {
+        Long orderId = resolveOrderId(orderNo);
         authorizePayment(orderId, false);
         orderDonService.zeroOrderConfirm(orderId);
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
-    /**
-     * 套餐0元订单确认
-     */
-    @PostMapping("/post/upgrade/order/status/{orderId}")
+    @PostMapping("/post/upgrade/order/status/{orderNo}")
     @Deprecated
-    public Result<String> zeroUpgradeOrderConfirm(@PathVariable Long orderId) {
+    public Result<String> zeroUpgradeOrderConfirm(@PathVariable String orderNo) {
+        Long orderId = resolveUpgradeOrderId(orderNo);
         authorizePayment(orderId, true);
         orderDonService.zeroUpgradeOrderConfirm(orderId);
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
+    */
 
 
     /**
@@ -251,6 +254,56 @@ public class OrderController {
         }
     }
 
+    /**
+     * 用户端只认订单号, 不再接收/返回订单 id(防止按自增 id 遍历)
+     */
+    private static final java.util.regex.Pattern ORDER_NO_PATTERN = java.util.regex.Pattern.compile("^[0-9A-Za-z_-]{1,64}$");
+
+    private static final String ORDER_NOT_FOUND = "订单不存在或无权操作";
+
+    /**
+     * 订单号 -> 订单 id; 只做映射, 归属校验仍由各接口原有逻辑负责
+     */
+    private Long resolveOrderId(String orderNo) {
+        String no = StrUtil.trim(orderNo);
+        if (StrUtil.isEmpty(no) || !ORDER_NO_PATTERN.matcher(no).matches()) {
+            throw BusinessRuntimeException.getInstance(ORDER_NOT_FOUND);
+        }
+        OrderDon order = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
+                .select(OrderDon::getId)
+                .eq(OrderDon::getOrderNo, no)
+                .last("limit 1"));
+        if (order == null) {
+            throw BusinessRuntimeException.getInstance(ORDER_NOT_FOUND);
+        }
+        return order.getId();
+    }
+
+    /**
+     * 套餐订单号 -> 套餐订单 id
+     */
+    private Long resolveUpgradeOrderId(String orderNo) {
+        String no = StrUtil.trim(orderNo);
+        if (StrUtil.isEmpty(no) || !ORDER_NO_PATTERN.matcher(no).matches()) {
+            throw BusinessRuntimeException.getInstance(ORDER_NOT_FOUND);
+        }
+        UpgradeOrderDon order = paymentUpgradeMapper.selectOne(Wrappers.lambdaQuery(UpgradeOrderDon.class)
+                .select(UpgradeOrderDon::getId)
+                .eq(UpgradeOrderDon::getOrderNo, no)
+                .last("limit 1"));
+        if (order == null) {
+            throw BusinessRuntimeException.getInstance(ORDER_NOT_FOUND);
+        }
+        return order.getId();
+    }
+
+    /**
+     * 下单接口返回前去掉订单 id, 前端用 orderNo(返回副本, 不改原对象)
+     */
+    private static <T extends BaseEntity> T hideOrderId(T order) {
+        return com.cyksj.web.util.OrderIdHider.hide(order);
+    }
+
     @FunctionalInterface
     private interface PaymentCall<T> { T run() throws Exception; }
 
@@ -286,8 +339,9 @@ public class OrderController {
             throw BusinessRuntimeException.getInstance("支付请求过于频繁,请稍后重试");
     }
 
-    @PostMapping("/post/pay/{orderId}")
-    public Result<H5JsPayParams> pay(@PathVariable Long orderId) throws Exception {
+    @PostMapping("/post/pay/{orderNo}")
+    public Result<H5JsPayParams> pay(@PathVariable String orderNo) throws Exception {
+        Long orderId = resolveOrderId(orderNo);
         authorizePayment(orderId, false);
         final String methodName = "吊起微信支付";
         log.info("{}[start] orderId:{}",methodName,orderId);
@@ -301,8 +355,9 @@ public class OrderController {
      * 调用生成订单之后
      * 微信网页预下单获取交易链接生成二维码
      */
-    @PostMapping("/get/wx/orderQrCode/{orderId}")
-    public Result<String> createUnifiedOrderQr(@PathVariable Long orderId) throws Exception {
+    @PostMapping("/get/wx/orderQrCode/{orderNo}")
+    public Result<String> createUnifiedOrderQr(@PathVariable String orderNo) throws Exception {
+        Long orderId = resolveOrderId(orderNo);
         authorizePayment(orderId, false);
         //预下单
         H5JsPayParams payParams = invokePayment(orderId, () -> orderDonService.wxPcWebPay(orderId, "NATIVE"));
@@ -385,7 +440,8 @@ public class OrderController {
      * 手机支付
 	 */
 	@PostMapping("/post/pay/zfb")
-    public Result<String> aliPay(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
+    public Result<String> aliPay(@RequestBody AlipayOrderDonReq re) throws Exception {
+        re.setOrderId(resolveOrderId(re.getOrderNo()));
         authorizePayment(re.getOrderId(), false);
         AliPayParams aliPayParams = invokePayment(re.getOrderId(), () -> orderDonService.aliPay(re, ZfbProductCode.MOBILE_WEB.getProductCode(), null));
 //        response.setContentType("text/html;charset=" + BaseZfbConfig.charset);
@@ -400,7 +456,8 @@ public class OrderController {
      * 套餐支付宝支付
      */
     @PostMapping("/post/pay/upgrade/zfb")
-    public Result<String> aliPayUpgrade(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
+    public Result<String> aliPayUpgrade(@RequestBody AlipayOrderDonReq re) throws Exception {
+        re.setOrderId(resolveUpgradeOrderId(re.getOrderNo()));
         authorizePayment(re.getOrderId(), true);
         AliPayParams aliPayParams = invokePayment(re.getOrderId(), () -> orderDonService.aliPayUpgrade(re, ZfbProductCode.MOBILE_WEB.getProductCode(),null));
         return GatewayResponse.SUCCESS.newBuilder().toResult(aliPayParams.getBody());
@@ -412,7 +469,8 @@ public class OrderController {
      * pc网页内嵌二维码
      */
     @PostMapping("/get/zfb/orderQrCode")
-    public Result<String> zfbWebQrCode(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
+    public Result<String> zfbWebQrCode(@RequestBody AlipayOrderDonReq re) throws Exception {
+        re.setOrderId(resolveOrderId(re.getOrderNo()));
         authorizePayment(re.getOrderId(), false);
         AliPayParams aliPayParams = invokePayment(re.getOrderId(), () -> orderDonService.aliPay(re, ZfbProductCode.PC_WEB.getProductCode(), BaseZfbConfig.qrPayMode_orderCode));
 //        response.setContentType("text/html;charset=" + BaseZfbConfig.charset);
@@ -428,7 +486,8 @@ public class OrderController {
      * pc网页内嵌二维码
      */
     @PostMapping("/get/zfb/upgrade/orderQrCode")
-    public Result<String> zfbWebQrCodeUpgrade(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
+    public Result<String> zfbWebQrCodeUpgrade(@RequestBody AlipayOrderDonReq re) throws Exception {
+        re.setOrderId(resolveUpgradeOrderId(re.getOrderNo()));
         authorizePayment(re.getOrderId(), true);
         AliPayParams aliPayParams = invokePayment(re.getOrderId(), () -> orderDonService.aliPayUpgrade(re, ZfbProductCode.PC_WEB.getProductCode(), BaseZfbConfig.qrPayMode_orderCode));
 //        response.setContentType("text/html;charset=" + BaseZfbConfig.charset);
@@ -444,7 +503,8 @@ public class OrderController {
      * pc网页跳转二维码
      */
     @PostMapping("/get/zfb/orderRedirect")
-    public Result<String> zfbWebRedirectQrCode(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
+    public Result<String> zfbWebRedirectQrCode(@RequestBody AlipayOrderDonReq re) throws Exception {
+        re.setOrderId(resolveOrderId(re.getOrderNo()));
         authorizePayment(re.getOrderId(), false);
         AliPayParams aliPayParams = invokePayment(re.getOrderId(), () -> orderDonService.aliPay(re, ZfbProductCode.PC_WEB.getProductCode(), BaseZfbConfig.qrPayMode_redirect));
         return GatewayResponse.SUCCESS.newBuilder().toResult(aliPayParams.getBody());
@@ -578,11 +638,11 @@ public class OrderController {
     /**
      * 获取订单详情
      */
-    @GetMapping("/get/{orderId}")
-    public Result<OrderDetailView> detail(@PathVariable Long orderId, Boolean isNoLogin) {
+    @GetMapping("/get/{orderNo}")
+    public Result<OrderDetailView> detail(@PathVariable String orderNo, Boolean isNoLogin) {
         Long userId = StpUserUtil.getLoginIdAsLong();
 
-        OrderDetailView detail = orderDonService.getDetail(orderId, userId);
+        OrderDetailView detail = orderDonService.getDetail(resolveOrderId(orderNo), userId);
 
         return GatewayResponse.SUCCESS.newBuilder().toResult(detail);
     }
@@ -590,19 +650,17 @@ public class OrderController {
     /**
      * 取消订单
      */
-    @GetMapping("/get/close/{orderId}")
-    public Result<String> closeOrder(@PathVariable Long orderId) {
+    @GetMapping("/get/close/{orderNo}")
+    public Result<String> closeOrder(@PathVariable String orderNo) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        orderDonService.closeOrder(orderId, userId);
+        orderDonService.closeOrder(resolveOrderId(orderNo), userId);
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
-    @GetMapping("/get/order/status/{orderId}")
-    public Result<OrderDonSearchView> getOrderStatusById(@PathVariable Long orderId) {
+    @GetMapping("/get/order/status/{orderNo}")
+    public Result<OrderDonSearchView> getOrderStatusById(@PathVariable String orderNo) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        if (orderId < 1) {
-            throw BusinessRuntimeException.getInstance("订单不存在");
-        }
+        Long orderId = resolveOrderId(orderNo);
         OrderDonSearchView orderDonView = beanSearcher.searchFirst(OrderDonSearchView.class, MapUtils.builder()
                 .put("orderId", String.format("where id = %s and user_id = %s", orderId, userId))
                 .build());
@@ -640,12 +698,10 @@ public class OrderController {
     /**
      * 查询套餐订单支付状态
      */
-    @GetMapping("/get/upgrade/order/status/{orderId}")
-    public Result<UpgradeOrderDonSearchView> getUpgradeOrderStatusById(@PathVariable Long orderId) {
+    @GetMapping("/get/upgrade/order/status/{orderNo}")
+    public Result<UpgradeOrderDonSearchView> getUpgradeOrderStatusById(@PathVariable String orderNo) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        if (orderId < 1) {
-            throw BusinessRuntimeException.getInstance("订单不存在");
-        }
+        Long orderId = resolveUpgradeOrderId(orderNo);
         UpgradeOrderDonSearchView orderDonView = beanSearcher.searchFirst(UpgradeOrderDonSearchView.class, MapUtils.builder()
                 .put("orderId", String.format("where id = %s and user_id = %s", orderId, userId))
                 .build());
@@ -655,10 +711,28 @@ public class OrderController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(orderDonView);
     }
 
+    /**
+     * 按订单号批量查询订单
+     * 原来免登录 + 按 id 查任意订单(可遍历全站订单), 现改为: 必须登录, 按订单号查, 只返回本人(含绑定账号)的订单
+     */
     @PostMapping("/get/noLogin/order")
-    public Result<List<OrderDonView>> getSearchResult(@RequestBody List<Long> orderIds) {
+    public Result<List<OrderDonView>> getSearchResult(@RequestBody List<String> orderNos) {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        List<String> nos = orderNos == null ? Collections.emptyList() : orderNos.stream()
+                .map(StrUtil::trim)
+                .filter(no -> StrUtil.isNotEmpty(no) && ORDER_NO_PATTERN.matcher(no).matches())
+                .distinct()
+                .limit(50)
+                .collect(Collectors.toList());
+        List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
+        if (nos.isEmpty() || CollUtil.isEmpty(userIds)) {
+            // 声明为 List, 避免 ArrayList 同时匹配 toResult 的 Serializable/Collection 重载产生歧义
+            List<OrderDonView> empty = Collections.emptyList();
+            return GatewayResponse.SUCCESS.newBuilder().toResult(empty);
+        }
         List<OrderDonView> orderDonViews = beanSearcher.searchAll(OrderDonView.class, MapUtils.builder()
-                .field(OrderDonView::getId, orderIds).op(Operator.InList)
+                .field(OrderDonView::getOrderNo, nos).op(Operator.InList)
+                .field(OrderDonView::getUserId, userIds).op(Operator.InList)
                 .orderBy(OrderDonView::getId).desc().build());
         return GatewayResponse.SUCCESS.newBuilder().toResult(orderDonViews);
     }
@@ -753,8 +827,9 @@ public class OrderController {
     /**
      * paypal支付
      */
-    @PostMapping("/paypal/pay/{orderId}")
-    public Result<String> paypalPay(@PathVariable Long orderId,String successUrl) throws Exception {
+    @PostMapping("/paypal/pay/{orderNo}")
+    public Result<String> paypalPay(@PathVariable String orderNo,String successUrl) throws Exception {
+        Long orderId = resolveOrderId(orderNo);
         authorizePayment(orderId, false);
         final String methodName = "paypal支付";
         log.info("{}[start] orderId:{}",methodName,orderId);
@@ -780,9 +855,10 @@ public class OrderController {
     /**
      * stripe支付
      */
-    @PostMapping("/stripe/pay/{orderId}")
-    public Result<String> stripePay(@PathVariable Long orderId,String successUrl) throws Exception {
+    @PostMapping("/stripe/pay/{orderNo}")
+    public Result<String> stripePay(@PathVariable String orderNo,String successUrl) throws Exception {
         final String methodName = "stripe支付";
+        Long orderId = resolveOrderId(orderNo);
         authorizePayment(orderId, false);
         log.info("{}[start] orderId:{}",methodName,orderId);
         String payUrl = invokePayment(orderId, () -> stripeService.checkOutStripe(orderId, successUrl));
@@ -901,11 +977,12 @@ public class OrderController {
     /**
      * 获取套餐订单详情
      */
-    @GetMapping("/get/upgrade/{orderId}")
-    public Result<UpgradeOrderDetailView> upgradeOrderDetail(@PathVariable Long orderId) {
-        Long userId = StpUserUtil.getUserIdAfterLogin();
+    @GetMapping("/get/upgrade/{orderNo}")
+    public Result<UpgradeOrderDetailView> upgradeOrderDetail(@PathVariable String orderNo) {
+        // 原来用 getUserIdAfterLogin(): 未登录时 userId=null, service 不加用户过滤, 任何人都能查任意套餐订单; 改为必须登录
+        Long userId = StpUserUtil.getLoginIdAsLong();
 
-        UpgradeOrderDetailView detail = orderDonService.getUpgradeOrderDetail(orderId, userId);
+        UpgradeOrderDetailView detail = orderDonService.getUpgradeOrderDetail(resolveUpgradeOrderId(orderNo), userId);
 
         return GatewayResponse.SUCCESS.newBuilder().toResult(detail);
     }
@@ -913,10 +990,10 @@ public class OrderController {
     /**
      * 取消套餐订单
      */
-    @GetMapping("/get/close/upgrade/{orderId}")
-    public Result<String> closeUpgradeOrder(@PathVariable Long orderId) {
+    @GetMapping("/get/close/upgrade/{orderNo}")
+    public Result<String> closeUpgradeOrder(@PathVariable String orderNo) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        orderDonService.closeUpgradeOrder(orderId, userId);
+        orderDonService.closeUpgradeOrder(resolveUpgradeOrderId(orderNo), userId);
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
@@ -970,7 +1047,7 @@ public class OrderController {
 
         OrderDon orderDon = orderDonService.submitRenewUpgrade(payRequest);
 
-        return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(hideOrderId(orderDon));
     }
 
     /**
@@ -981,7 +1058,7 @@ public class OrderController {
         long userId = StpUserUtil.getLoginIdAsLong();
         payRequest.setUserId(userId);
         OrderDon orderDon = orderDonService.ccDeductSubmitOrder(payRequest);
-        return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(hideOrderId(orderDon));
     }
 
     /**
@@ -1049,16 +1126,16 @@ public class OrderController {
         String ip = ServletUtil.getClientIP(request);
         orderPayRequest.setIp(ip);
         OrderDon orderDon = orderDonService.userBenefitsSubmit(orderPayRequest);
-        return GatewayResponse.SUCCESS.newBuilder().toResult(orderDon);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(hideOrderId(orderDon));
     }
 
     /**
      * 是否是实物可选多张车票权益记录
      */
-    @GetMapping("/get/combo/optional/ticket/record/{orderId}")
-    public Result<UserPayEquipmentAvailableBenefits> getComboOptionalTicketRecord(@PathVariable Long orderId) {
+    @GetMapping("/get/combo/optional/ticket/record/{orderNo}")
+    public Result<UserPayEquipmentAvailableBenefits> getComboOptionalTicketRecord(@PathVariable String orderNo) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        UserPayEquipmentAvailableBenefits userPayEquipmentAvailableBenefits = orderDonService.getComboOptionalTicketRecord(userId, orderId);
+        UserPayEquipmentAvailableBenefits userPayEquipmentAvailableBenefits = orderDonService.getComboOptionalTicketRecord(userId, resolveOrderId(orderNo));
         return GatewayResponse.SUCCESS.newBuilder().toResult(userPayEquipmentAvailableBenefits);
     }
 
@@ -1080,8 +1157,9 @@ public class OrderController {
     /**
      * paypalV2支付
      */
-    @PostMapping("/paypalV2/pay/{orderId}")
-    public Result<String> paypalV2Pay(@PathVariable Long orderId,String successUrl) throws Exception {
+    @PostMapping("/paypalV2/pay/{orderNo}")
+    public Result<String> paypalV2Pay(@PathVariable String orderNo,String successUrl) throws Exception {
+        Long orderId = resolveOrderId(orderNo);
         authorizePayment(orderId, false);
         final String methodName = "paypal支付";
         log.info("{}[start] orderId:{}",methodName,orderId);
@@ -1106,8 +1184,18 @@ public class OrderController {
     /**
      * 领取GPT镜像天卡
      */
-    @PostMapping("/receive/gptMirror/dayCard/{orderId}")
-    public Result<String> receiveGptMirrorDayCard(@PathVariable Long orderId) throws Exception {
+    @PostMapping("/receive/gptMirror/dayCard/{orderNo}")
+    public Result<String> receiveGptMirrorDayCard(@PathVariable String orderNo) throws Exception {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        Long orderId = resolveOrderId(orderNo);
+        // 原来没有归属校验, 登录用户可拿别人的订单领天卡; 只允许本人(含绑定账号)的订单
+        OrderDon order = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
+                .select(OrderDon::getId, OrderDon::getUserId)
+                .eq(OrderDon::getId, orderId));
+        List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
+        if (order == null || CollUtil.isEmpty(userIds) || !userIds.contains(order.getUserId())) {
+            throw BusinessRuntimeException.getInstance(ORDER_NOT_FOUND);
+        }
         orderDonService.receiveGptMirrorDayCard(orderId);
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }

+ 17 - 1
netflix-web/src/main/java/com/cyksj/web/controller/user/UserController.java

@@ -225,8 +225,24 @@ public class UserController {
      * 用户已有实物权益 可选车票
      */
     @GetMapping("/get/available/benefits/tickets")
-    public Result<List<UserAvailableGoodsTicketView>> getAvailableBenefitsTickets(Long orderId, String customId, Integer cmt) {
+    public Result<List<UserAvailableGoodsTicketView>> getAvailableBenefitsTickets(String orderNo, String customId, Integer cmt) {
         Long userId = StpUserUtil.getLoginIdAsLong();
+        // 用户端改用订单号; 不传订单号时与原来不传 orderId 行为一致(查本人全部可领权益)
+        Long orderId = null;
+        String no = StrUtil.trim(orderNo);
+        if (StrUtil.isNotEmpty(no)) {
+            if (!no.matches("^[0-9A-Za-z_-]{1,64}$")) {
+                throw BusinessRuntimeException.getInstance("订单不存在或无权操作");
+            }
+            OrderDon order = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
+                    .select(OrderDon::getId)
+                    .eq(OrderDon::getOrderNo, no)
+                    .last("limit 1"));
+            if (order == null) {
+                throw BusinessRuntimeException.getInstance("订单不存在或无权操作");
+            }
+            orderId = order.getId();
+        }
         List<UserAvailableGoodsTicketView> tickets = userRealOrderBenefitsService.getAvailableBenefitsTickets(userId, orderId, customId, cmt);
         return GatewayResponse.SUCCESS.newBuilder().toResult(tickets);
     }

+ 25 - 0
netflix-web/src/main/java/com/cyksj/web/util/OrderIdHider.java

@@ -0,0 +1,25 @@
+package com.cyksj.web.util;
+
+import com.cyksj.model.entity.BaseEntity;
+import org.springframework.beans.BeanUtils;
+
+/**
+ * 用户端下单接口返回前去掉订单 id(用户端只用订单号)。
+ * 返回副本, 不修改 service 返回的原对象, 避免影响仍持有该对象的后续逻辑。
+ */
+public final class OrderIdHider {
+
+    private OrderIdHider() {
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends BaseEntity> T hide(T order) {
+        if (order == null) {
+            return null;
+        }
+        T copy = (T) BeanUtils.instantiateClass(order.getClass());
+        BeanUtils.copyProperties(order, copy);
+        copy.setId(null);
+        return copy;
+    }
+}