Commit b34801f303773ec8dcdd9d516f606b8a5701b085

Authored by YunaiV
1 parent df702e8d

pay: 接入支付宝 PC 支付的跳转模式

Showing 17 changed files with 262 additions and 158 deletions
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java
1 package cn.iocoder.yudao.framework.pay.core.client.dto.order; 1 package cn.iocoder.yudao.framework.pay.core.client.dto.order;
2 2
  3 +import cn.iocoder.yudao.framework.pay.core.enums.PayDisplayModeEnum;
3 import lombok.Data; 4 import lombok.Data;
4 import org.hibernate.validator.constraints.Length; 5 import org.hibernate.validator.constraints.Length;
5 import org.hibernate.validator.constraints.URL; 6 import org.hibernate.validator.constraints.URL;
@@ -7,6 +8,7 @@ import org.hibernate.validator.constraints.URL; @@ -7,6 +8,7 @@ import org.hibernate.validator.constraints.URL;
7 import javax.validation.constraints.DecimalMin; 8 import javax.validation.constraints.DecimalMin;
8 import javax.validation.constraints.NotEmpty; 9 import javax.validation.constraints.NotEmpty;
9 import javax.validation.constraints.NotNull; 10 import javax.validation.constraints.NotNull;
  11 +import java.awt.*;
10 import java.time.LocalDateTime; 12 import java.time.LocalDateTime;
11 import java.util.Map; 13 import java.util.Map;
12 14
@@ -78,4 +80,13 @@ public class PayOrderUnifiedReqDTO { @@ -78,4 +80,13 @@ public class PayOrderUnifiedReqDTO {
78 */ 80 */
79 private Map<String, String> channelExtras; 81 private Map<String, String> channelExtras;
80 82
  83 + /**
  84 + * 展示模式
  85 + *
  86 + * 如果不传递,则每个支付渠道使用默认的方式
  87 + *
  88 + * 枚举 {@link PayDisplayModeEnum}
  89 + */
  90 + private String displayMode;
  91 +
81 } 92 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/bo/PayOrderSubmitRespBO.java renamed to yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedRespDTO.java
1 -package cn.iocoder.yudao.module.pay.service.order.bo; 1 +package cn.iocoder.yudao.framework.pay.core.client.dto.order;
2 2
  3 +import lombok.AllArgsConstructor;
3 import lombok.Data; 4 import lombok.Data;
4 5
5 -import java.io.Serializable;  
6 -  
7 /** 6 /**
8 - * 支付单提交 Response BO 7 + * 统一下单 Response DTO
  8 + *
  9 + * @author 芋道源码
9 */ 10 */
10 @Data 11 @Data
11 -public class PayOrderSubmitRespBO implements Serializable { 12 +public class PayOrderUnifiedRespDTO {
12 13
13 /** 14 /**
14 - * 支付拓展单的编号 15 + * 展示模式
15 */ 16 */
16 - private Long extensionId;  
17 - 17 + private String displayMode;
18 /** 18 /**
19 - * 调用支付渠道的响应结果 19 + * 展示内容
20 */ 20 */
21 - private Object invokeResponse; 21 + private String displayContent;
22 22
23 } 23 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
@@ -69,6 +69,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -69,6 +69,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
69 this.init(); 69 this.init();
70 } 70 }
71 71
  72 + // TODO 芋艿:后续抽取到工具类里
72 protected Double calculateAmount(Integer amount) { 73 protected Double calculateAmount(Integer amount) {
73 return amount / 100.0; 74 return amount / 100.0;
74 } 75 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; 1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2
  3 +import cn.hutool.core.lang.Pair;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.core.util.ObjectUtil;
3 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
4 import cn.hutool.http.Method; 7 import cn.hutool.http.Method;
  8 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 9 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
6 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; 10 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 11 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
  12 +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
8 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; 13 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
9 -import com.alibaba.fastjson.JSONObject; 14 +import cn.iocoder.yudao.framework.pay.core.enums.PayDisplayModeEnum;
10 import com.alipay.api.AlipayApiException; 15 import com.alipay.api.AlipayApiException;
11 import com.alipay.api.domain.AlipayTradePagePayModel; 16 import com.alipay.api.domain.AlipayTradePagePayModel;
12 import com.alipay.api.request.AlipayTradePagePayRequest; 17 import com.alipay.api.request.AlipayTradePagePayRequest;
13 import com.alipay.api.response.AlipayTradePagePayResponse; 18 import com.alipay.api.response.AlipayTradePagePayResponse;
14 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
15 20
  21 +import java.util.HashMap;
  22 +import java.util.Objects;
  23 +
16 24
17 /** 25 /**
18 * 支付宝【PC网站支付】的 PayClient 实现类 26 * 支付宝【PC网站支付】的 PayClient 实现类
@@ -28,35 +36,72 @@ public class AlipayPcPayClient extends AbstractAlipayClient { @@ -28,35 +36,72 @@ public class AlipayPcPayClient extends AbstractAlipayClient {
28 } 36 }
29 37
30 @Override 38 @Override
31 - public PayCommonResult<AlipayTradePagePayResponse> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {  
32 - // 构建 AlipayTradePagePayModel 请求 39 + public PayCommonResult<PayOrderUnifiedRespDTO> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
  40 + // 1.1 构建 AlipayTradePagePayModel 请求
33 AlipayTradePagePayModel model = new AlipayTradePagePayModel(); 41 AlipayTradePagePayModel model = new AlipayTradePagePayModel();
34 - // 构建 AlipayTradePagePayRequest 42 + // ① 通用的参数
  43 + model.setOutTradeNo(reqDTO.getMerchantOrderId());
  44 + model.setSubject(reqDTO.getSubject());
  45 + model.setTotalAmount(String.valueOf(calculateAmount(reqDTO.getAmount())));
  46 + model.setProductCode("FAST_INSTANT_TRADE_PAY"); // 销售产品码. 目前电脑支付场景下仅支持 FAST_INSTANT_TRADE_PAY
  47 + // ② 个性化的参数
  48 + // 参考 https://www.pingxx.com/api/支付渠道 extra 参数说明.html 的 alipay_pc_direct 部分
  49 + model.setQrPayMode(MapUtil.getStr(reqDTO.getChannelExtras(), "qr_pay_mode"));
  50 + model.setQrcodeWidth(MapUtil.getLong(reqDTO.getChannelExtras(), "qr_code_width"));
  51 + // ③ 支付宝 PC 支付有多种展示模式,因此这里需要计算
  52 + String displayMode = getDisplayMode(reqDTO.getDisplayMode(), model.getQrPayMode());
  53 +
  54 + // 1.2 构建 AlipayTradePagePayRequest 请求
35 AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); 55 AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
36 request.setBizModel(model); 56 request.setBizModel(model);
37 - JSONObject bizContent = new JSONObject();  
38 - // 参数说明可查看: https://opendocs.alipay.com/open/028r8t?scene=22  
39 - bizContent.put("out_trade_no", reqDTO.getMerchantOrderId());  
40 - bizContent.put("subject", reqDTO.getSubject());  
41 - bizContent.put("total_amount", calculateAmount(reqDTO.getAmount()));  
42 - bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); // 销售产品码. 目前电脑支付场景下仅支持 FAST_INSTANT_TRADE_PAY  
43 - // PC扫码支付的方式:支持前置模式和跳转模式。4: 订单码-可定义宽度的嵌入式二维码  
44 -// bizContent.put("qr_pay_mode", "4");  
45 - // 自定义二维码宽度  
46 -// bizContent.put("qrcode_width", "150");  
47 - request.setBizContent(bizContent.toJSONString());  
48 request.setNotifyUrl(reqDTO.getNotifyUrl()); 57 request.setNotifyUrl(reqDTO.getNotifyUrl());
49 - request.setReturnUrl("");  
50 - // 执行请求 58 + request.setReturnUrl(""); // TODO 芋艿,待搞
  59 +
  60 + // 2.1 执行请求
51 AlipayTradePagePayResponse response; 61 AlipayTradePagePayResponse response;
52 try { 62 try {
53 - response = client.pageExecute(request, Method.GET.name()); 63 + if (Objects.equals(displayMode, PayDisplayModeEnum.FORM.getMode())) {
  64 + response = client.pageExecute(request, Method.POST.name()); // 需要特殊使用 POST 请求
  65 + } else {
  66 + response = client.pageExecute(request, Method.GET.name());
  67 + }
54 } catch (AlipayApiException e) { 68 } catch (AlipayApiException e) {
55 log.error("[unifiedOrder][request({}) 发起支付失败]", JsonUtils.toJsonString(reqDTO), e); 69 log.error("[unifiedOrder][request({}) 发起支付失败]", JsonUtils.toJsonString(reqDTO), e);
56 return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping); 70 return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping);
57 } 71 }
  72 + // 1. form
  73 + // 2. url
  74 + // 3. code
  75 + // 4. code url
  76 +
  77 + // 2.2 处理结果
58 System.out.println(response.getBody()); 78 System.out.println(response.getBody());
  79 + PayOrderUnifiedRespDTO respDTO = new PayOrderUnifiedRespDTO()
  80 + .setDisplayMode(displayMode).setDisplayContent(response.getBody());
59 // 响应为表单格式,前端可嵌入响应的页面或关闭当前支付窗口 81 // 响应为表单格式,前端可嵌入响应的页面或关闭当前支付窗口
60 - return PayCommonResult.build(StrUtil.blankToDefault(response.getCode(),"10000") ,response.getMsg(), response, codeMapping); 82 + return PayCommonResult.build(StrUtil.blankToDefault(response.getCode(),"10000"),
  83 + response.getMsg(), respDTO, codeMapping);
61 } 84 }
  85 +
  86 + /**
  87 + * 获得最终的支付 UI 展示模式
  88 + *
  89 + * @param displayMode 前端传递的 UI 展示模式
  90 + * @param qrPayMode 前端传递的二维码模式
  91 + * @return 最终的支付 UI 展示模式
  92 + */
  93 + private String getDisplayMode(String displayMode, String qrPayMode) {
  94 + // 1.1 支付宝二维码的前置模式
  95 + if (StrUtil.equalsAny(qrPayMode, "0", "1", "3", "4")) {
  96 + return PayDisplayModeEnum.IFRAME.getMode();
  97 + }
  98 + // 1.2 支付宝二维码的跳转模式
  99 + if (StrUtil.equals(qrPayMode, "2")) {
  100 + return PayDisplayModeEnum.URL.getMode();
  101 + }
  102 + // 2. 前端传递了 UI 展示模式
  103 + return displayMode != null ? displayMode :
  104 + PayDisplayModeEnum.URL.getMode(); // 模式使用 URL 跳转
  105 + }
  106 +
62 } 107 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayDisplayModeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.pay.core.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 支付 UI 展示模式
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum PayDisplayModeEnum {
  14 +
  15 + URL("url"), // Redirect 跳转链接的方式
  16 + IFRAME("iframe"), // IFrame 内嵌链接的方式
  17 + FORM("form"), // HTML 表单提交
  18 + QR_CODE("qr_code"), // 二维码的文字内容
  19 + QR_CODE_URL("qr_code_url"), // 二维码的图片链接
  20 + ;
  21 +
  22 + /**
  23 + * 展示模式
  24 + */
  25 + private final String mode;
  26 +
  27 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
@@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.pay.controller.admin.order; @@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.pay.controller.admin.order;
2 2
3 import cn.hutool.core.collection.CollectionUtil; 3 import cn.hutool.core.collection.CollectionUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  9 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  10 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
5 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; 11 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
6 -import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;  
7 -import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;  
8 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; 12 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
9 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO; 13 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO;
10 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayMerchantDO; 14 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayMerchantDO;
@@ -14,16 +18,9 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService; @@ -14,16 +18,9 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService;
14 import cn.iocoder.yudao.module.pay.service.merchant.PayMerchantService; 18 import cn.iocoder.yudao.module.pay.service.merchant.PayMerchantService;
15 import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService; 19 import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;
16 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 20 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
17 -import cn.iocoder.yudao.framework.common.pojo.CommonResult;  
18 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
19 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
20 -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;  
21 -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;  
22 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;  
23 -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO;  
24 -import io.swagger.v3.oas.annotations.tags.Tag;  
25 -import io.swagger.v3.oas.annotations.Parameter;  
26 import io.swagger.v3.oas.annotations.Operation; 21 import io.swagger.v3.oas.annotations.Operation;
  22 +import io.swagger.v3.oas.annotations.Parameter;
  23 +import io.swagger.v3.oas.annotations.tags.Tag;
27 import org.springframework.security.access.prepost.PreAuthorize; 24 import org.springframework.security.access.prepost.PreAuthorize;
28 import org.springframework.validation.annotation.Validated; 25 import org.springframework.validation.annotation.Validated;
29 import org.springframework.web.bind.annotation.*; 26 import org.springframework.web.bind.annotation.*;
@@ -94,10 +91,9 @@ public class PayOrderController { @@ -94,10 +91,9 @@ public class PayOrderController {
94 91
95 @PostMapping("/submit") 92 @PostMapping("/submit")
96 @Operation(summary = "提交支付订单") 93 @Operation(summary = "提交支付订单")
97 - public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {  
98 - PayOrderSubmitRespBO respDTO = payOrderService.submitPayOrder(  
99 - PayOrderConvert.INSTANCE.convert(reqVO, getClientIP()));  
100 - return success(new AppPayOrderSubmitRespVO(respDTO.getInvokeResponse())); 94 + public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
  95 + PayOrderSubmitRespVO respVO = payOrderService.submitPayOrder(reqVO, getClientIP());
  96 + return success(respVO);
101 } 97 }
102 98
103 @GetMapping("/page") 99 @GetMapping("/page")
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitReqVO.java
@@ -6,11 +6,11 @@ import lombok.experimental.Accessors; @@ -6,11 +6,11 @@ import lombok.experimental.Accessors;
6 6
7 import javax.validation.constraints.NotEmpty; 7 import javax.validation.constraints.NotEmpty;
8 import javax.validation.constraints.NotNull; 8 import javax.validation.constraints.NotNull;
  9 +import java.awt.*;
9 import java.util.Map; 10 import java.util.Map;
10 11
11 @Schema(description = "管理后台 - 支付订单提交 Request VO") 12 @Schema(description = "管理后台 - 支付订单提交 Request VO")
12 @Data 13 @Data
13 -@Accessors(chain = true)  
14 public class PayOrderSubmitReqVO { 14 public class PayOrderSubmitReqVO {
15 15
16 @Schema(description = "支付单编号", required = true, example = "1024") 16 @Schema(description = "支付单编号", required = true, example = "1024")
@@ -24,4 +24,6 @@ public class PayOrderSubmitReqVO { @@ -24,4 +24,6 @@ public class PayOrderSubmitReqVO {
24 @Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数") 24 @Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数")
25 private Map<String, String> channelExtras; 25 private Map<String, String> channelExtras;
26 26
  27 + @Schema(description = "展示模式", example = "url") // 参见 {@link PayDisplayModeEnum} 枚举。如果不传递,则每个支付渠道使用默认的方式
  28 + private String displayMode;
27 } 29 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitRespVO.java
@@ -9,15 +9,12 @@ import lombok.experimental.Accessors; @@ -9,15 +9,12 @@ import lombok.experimental.Accessors;
9 9
10 @Schema(description = "管理后台 - 支付订单提交 Response VO") 10 @Schema(description = "管理后台 - 支付订单提交 Response VO")
11 @Data 11 @Data
12 -@Accessors(chain = true)  
13 -@Builder  
14 -@NoArgsConstructor  
15 -@AllArgsConstructor  
16 public class PayOrderSubmitRespVO { 12 public class PayOrderSubmitRespVO {
17 13
18 - /**  
19 - * 调用支付渠道的响应结果  
20 - */  
21 - private Object invokeResponse; 14 + @Schema(description = "展示模式", required = true, example = "url") // 参见 PayDisplayModeEnum 枚举
  15 + private String displayMode;
  16 +
  17 + @Schema(description = "展示内容", required = true)
  18 + private String displayContent;
22 19
23 } 20 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java
1 package cn.iocoder.yudao.module.pay.controller.app.order; 1 package cn.iocoder.yudao.module.pay.controller.app.order;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
4 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; 5 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
5 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; 6 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
6 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; 7 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
7 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 8 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
8 -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO;  
9 import io.swagger.v3.oas.annotations.Operation; 9 import io.swagger.v3.oas.annotations.Operation;
10 import io.swagger.v3.oas.annotations.tags.Tag; 10 import io.swagger.v3.oas.annotations.tags.Tag;
11 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
@@ -33,9 +33,8 @@ public class AppPayOrderController { @@ -33,9 +33,8 @@ public class AppPayOrderController {
33 @PostMapping("/submit") 33 @PostMapping("/submit")
34 @Operation(summary = "提交支付订单") 34 @Operation(summary = "提交支付订单")
35 public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) { 35 public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) {
36 - PayOrderSubmitRespBO respDTO = orderService.submitPayOrder(  
37 - PayOrderConvert.INSTANCE.convert(reqVO, getClientIP()));  
38 - return success(new AppPayOrderSubmitRespVO(respDTO.getInvokeResponse())); 36 + PayOrderSubmitRespVO respVO = orderService.submitPayOrder(reqVO, getClientIP());
  37 + return success(PayOrderConvert.INSTANCE.convert3(respVO));
39 } 38 }
40 39
41 } 40 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitReqVO.java
1 package cn.iocoder.yudao.module.pay.controller.app.order.vo; 1 package cn.iocoder.yudao.module.pay.controller.app.order.vo;
2 2
  3 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
3 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.experimental.Accessors; 6 import lombok.experimental.Accessors;
@@ -10,18 +11,5 @@ import java.util.Map; @@ -10,18 +11,5 @@ import java.util.Map;
10 11
11 @Schema(description = "用户 APP - 支付订单提交 Request VO") 12 @Schema(description = "用户 APP - 支付订单提交 Request VO")
12 @Data 13 @Data
13 -@Accessors(chain = true)  
14 -public class AppPayOrderSubmitReqVO {  
15 -  
16 - @Schema(description = "支付单编号", required = true, example = "1024")  
17 - @NotNull(message = "支付单编号不能为空")  
18 - private Long id;  
19 -  
20 - @Schema(description = "支付渠道", required = true, example = "wx_pub")  
21 - @NotEmpty(message = "支付渠道不能为空")  
22 - private String channelCode;  
23 -  
24 - @Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数")  
25 - private Map<String, String> channelExtras;  
26 - 14 +public class AppPayOrderSubmitReqVO extends PayOrderSubmitReqVO {
27 } 15 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitRespVO.java
1 package cn.iocoder.yudao.module.pay.controller.app.order.vo; 1 package cn.iocoder.yudao.module.pay.controller.app.order.vo;
2 2
  3 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
3 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.AllArgsConstructor; 5 import lombok.AllArgsConstructor;
5 import lombok.Builder; 6 import lombok.Builder;
@@ -9,15 +10,6 @@ import lombok.experimental.Accessors; @@ -9,15 +10,6 @@ import lombok.experimental.Accessors;
9 10
10 @Schema(description = "用户 APP - 支付订单提交 Response VO") 11 @Schema(description = "用户 APP - 支付订单提交 Response VO")
11 @Data 12 @Data
12 -@Accessors(chain = true)  
13 -@Builder  
14 -@NoArgsConstructor  
15 -@AllArgsConstructor  
16 -public class AppPayOrderSubmitRespVO {  
17 -  
18 - /**  
19 - * 调用支付渠道的响应结果  
20 - */  
21 - private Object invokeResponse; 13 +public class AppPayOrderSubmitRespVO extends PayOrderSubmitRespVO {
22 14
23 } 15 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java
@@ -2,13 +2,14 @@ package cn.iocoder.yudao.module.pay.convert.order; @@ -2,13 +2,14 @@ package cn.iocoder.yudao.module.pay.convert.order;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
  5 +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
5 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; 6 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
6 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; 7 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
7 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; 8 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
8 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; 9 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
  10 +import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
9 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 11 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
10 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; 12 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
11 -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO;  
12 import org.mapstruct.Mapper; 13 import org.mapstruct.Mapper;
13 import org.mapstruct.Mapping; 14 import org.mapstruct.Mapping;
14 import org.mapstruct.factory.Mappers; 15 import org.mapstruct.factory.Mappers;
@@ -29,6 +30,8 @@ public interface PayOrderConvert { @@ -29,6 +30,8 @@ public interface PayOrderConvert {
29 30
30 PayOrderRespVO convert(PayOrderDO bean); 31 PayOrderRespVO convert(PayOrderDO bean);
31 32
  33 + PayOrderRespDTO convert2(PayOrderDO order);
  34 +
32 PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean); 35 PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean);
33 36
34 PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean); 37 PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);
@@ -86,18 +89,15 @@ public interface PayOrderConvert { @@ -86,18 +89,15 @@ public interface PayOrderConvert {
86 return payOrderExcelVO; 89 return payOrderExcelVO;
87 } 90 }
88 91
89 -  
90 PayOrderDO convert(PayOrderCreateReqDTO bean); 92 PayOrderDO convert(PayOrderCreateReqDTO bean);
91 93
92 @Mapping(target = "id", ignore = true) 94 @Mapping(target = "id", ignore = true)
93 - PayOrderExtensionDO convert(PayOrderSubmitReqBO bean);  
94 -  
95 - PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqBO bean); 95 + PayOrderExtensionDO convert(PayOrderSubmitReqVO bean, String userIp);
96 96
97 - PayOrderRespDTO convert2(PayOrderDO bean); 97 + PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqVO reqVO);
98 98
99 - PayOrderSubmitReqBO convert(AppPayOrderSubmitReqVO bean, String userIp); 99 + PayOrderSubmitRespVO convert(PayOrderUnifiedRespDTO bean);
100 100
101 - PayOrderSubmitReqBO convert(PayOrderSubmitReqVO bean, String userIp); 101 + AppPayOrderSubmitRespVO convert3(PayOrderSubmitRespVO bean);
102 102
103 } 103 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
1 package cn.iocoder.yudao.module.pay.service.order; 1 package cn.iocoder.yudao.module.pay.service.order;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
3 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO; 5 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
  6 +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
4 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; 7 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
5 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; 8 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
6 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
7 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 9 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
  10 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
8 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 11 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
9 -import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;  
10 -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO;  
11 -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO;  
12 12
13 import javax.validation.Valid; 13 import javax.validation.Valid;
  14 +import javax.validation.constraints.NotEmpty;
14 import java.util.Collection; 15 import java.util.Collection;
15 import java.util.List; 16 import java.util.List;
16 import java.util.Map; 17 import java.util.Map;
@@ -81,10 +82,12 @@ public interface PayOrderService { @@ -81,10 +82,12 @@ public interface PayOrderService {
81 * 提交支付 82 * 提交支付
82 * 此时,会发起支付渠道的调用 83 * 此时,会发起支付渠道的调用
83 * 84 *
84 - * @param reqDTO 提交请求 85 + * @param reqVO 提交请求
  86 + * @param userIp 提交 IP
85 * @return 提交结果 87 * @return 提交结果
86 */ 88 */
87 - PayOrderSubmitRespBO submitPayOrder(@Valid PayOrderSubmitReqBO reqDTO); 89 + PayOrderSubmitRespVO submitPayOrder(@Valid PayOrderSubmitReqVO reqVO,
  90 + @NotEmpty(message = "提交 IP 不能为空") String userIp);
88 91
89 /** 92 /**
90 * 通知支付单成功 93 * 通知支付单成功
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
@@ -12,10 +12,13 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; @@ -12,10 +12,13 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
12 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO; 12 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
13 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; 13 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
14 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 14 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
  15 +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
15 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 16 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
16 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; 17 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
17 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; 18 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
18 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; 19 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
  20 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
  21 +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
19 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; 22 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
20 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO; 23 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO;
21 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO; 24 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO;
@@ -31,8 +34,6 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService; @@ -31,8 +34,6 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService;
31 import cn.iocoder.yudao.module.pay.service.merchant.PayChannelService; 34 import cn.iocoder.yudao.module.pay.service.merchant.PayChannelService;
32 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; 35 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
33 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; 36 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
34 -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO;  
35 -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO;  
36 import lombok.extern.slf4j.Slf4j; 37 import lombok.extern.slf4j.Slf4j;
37 import org.springframework.stereotype.Service; 38 import org.springframework.stereotype.Service;
38 import org.springframework.transaction.annotation.Transactional; 39 import org.springframework.transaction.annotation.Transactional;
@@ -126,22 +127,22 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -126,22 +127,22 @@ public class PayOrderServiceImpl implements PayOrderService {
126 } 127 }
127 128
128 @Override 129 @Override
129 - public PayOrderSubmitRespBO submitPayOrder(PayOrderSubmitReqBO reqBO) { 130 + public PayOrderSubmitRespVO submitPayOrder(PayOrderSubmitReqVO reqVO, String userIp) {
130 // 1. 获得 PayOrderDO ,并校验其是否存在 131 // 1. 获得 PayOrderDO ,并校验其是否存在
131 - PayOrderDO order = validatePayOrderCanSubmit(reqBO.getId()); 132 + PayOrderDO order = validatePayOrderCanSubmit(reqVO.getId());
132 // 1.2 校验支付渠道是否有效 133 // 1.2 校验支付渠道是否有效
133 - PayChannelDO channel = validatePayChannelCanSubmit(order.getAppId(), reqBO.getChannelCode()); 134 + PayChannelDO channel = validatePayChannelCanSubmit(order.getAppId(), reqVO.getChannelCode());
134 PayClient client = payClientFactory.getPayClient(channel.getId()); 135 PayClient client = payClientFactory.getPayClient(channel.getId());
135 136
136 // 2. 插入 PayOrderExtensionDO 137 // 2. 插入 PayOrderExtensionDO
137 - PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqBO) 138 + PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp)
138 .setOrderId(order.getId()).setNo(generateOrderExtensionNo()) 139 .setOrderId(order.getId()).setNo(generateOrderExtensionNo())
139 .setChannelId(channel.getId()).setChannelCode(channel.getCode()) 140 .setChannelId(channel.getId()).setChannelCode(channel.getCode())
140 .setStatus(PayOrderStatusEnum.WAITING.getStatus()); 141 .setStatus(PayOrderStatusEnum.WAITING.getStatus());
141 orderExtensionMapper.insert(orderExtension); 142 orderExtensionMapper.insert(orderExtension);
142 143
143 // 3. 调用三方接口 144 // 3. 调用三方接口
144 - PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqBO) 145 + PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqVO)
145 // 商户相关的字段 146 // 商户相关的字段
146 .setMerchantOrderId(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性! 147 .setMerchantOrderId(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性!
147 .setSubject(order.getSubject()).setBody(order.getBody()) 148 .setSubject(order.getSubject()).setBody(order.getBody())
@@ -152,10 +153,11 @@ public class PayOrderServiceImpl implements PayOrderService { @@ -152,10 +153,11 @@ public class PayOrderServiceImpl implements PayOrderService {
152 CommonResult<?> unifiedOrderResult = client.unifiedOrder(unifiedOrderReqDTO); 153 CommonResult<?> unifiedOrderResult = client.unifiedOrder(unifiedOrderReqDTO);
153 unifiedOrderResult.checkError(); 154 unifiedOrderResult.checkError();
154 155
  156 + PayOrderUnifiedRespDTO xx = (PayOrderUnifiedRespDTO) unifiedOrderResult.getData();
  157 +
155 // TODO 轮询三方接口,是否已经支付的任务 158 // TODO 轮询三方接口,是否已经支付的任务
156 // 返回成功 159 // 返回成功
157 - return new PayOrderSubmitRespBO().setExtensionId(orderExtension.getId())  
158 - .setInvokeResponse(unifiedOrderResult.getData()); 160 + return PayOrderConvert.INSTANCE.convert(xx);
159 } 161 }
160 162
161 private PayOrderDO validatePayOrderCanSubmit(Long id) { 163 private PayOrderDO validatePayOrderCanSubmit(Long id) {
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/bo/PayOrderSubmitReqBO.java deleted
1 -package cn.iocoder.yudao.module.pay.service.order.bo;  
2 -  
3 -import lombok.Data;  
4 -import lombok.experimental.Accessors;  
5 -  
6 -import javax.validation.constraints.NotEmpty;  
7 -import javax.validation.constraints.NotNull;  
8 -import java.io.Serializable;  
9 -import java.util.Map;  
10 -  
11 -/**  
12 - * 支付单提交 Request BO  
13 - */  
14 -@Data  
15 -@Accessors(chain = true)  
16 -public class PayOrderSubmitReqBO implements Serializable {  
17 -  
18 - /**  
19 - * 支付单编号  
20 - */  
21 - @NotNull(message = "支付单编号不能为空")  
22 - private Long id;  
23 -  
24 - /**  
25 - * 支付渠道  
26 - */  
27 - @NotEmpty(message = "支付渠道不能为空")  
28 - private String channelCode;  
29 -  
30 - /**  
31 - * 用户 IP  
32 - */  
33 - @NotEmpty(message = "用户 IP 不能为空")  
34 - private String userIp;  
35 -  
36 - /**  
37 - * 支付渠道的额外参数  
38 - */  
39 - private Map<String, String> channelExtras;  
40 -  
41 -}  
yudao-ui-admin/src/utils/constants.js
@@ -151,6 +151,18 @@ export const PayChannelEnum = { @@ -151,6 +151,18 @@ export const PayChannelEnum = {
151 } 151 }
152 152
153 /** 153 /**
  154 + * 支付的展示模式每局
  155 + */
  156 +export const PayDisplayModeEnum = {
  157 + URL: {
  158 + "mode": "url",
  159 + },
  160 + IFRAME: {
  161 + "mode": "iframe",
  162 + },
  163 +}
  164 +
  165 +/**
154 * 支付类型枚举 166 * 支付类型枚举
155 */ 167 */
156 export const PayType = { 168 export const PayType = {
yudao-ui-admin/src/views/pay/order/submit.vue
@@ -12,7 +12,6 @@ @@ -12,7 +12,6 @@
12 </el-descriptions> 12 </el-descriptions>
13 </el-card> 13 </el-card>
14 14
15 -  
16 <!-- 支付选择框 --> 15 <!-- 支付选择框 -->
17 <el-card style="margin-top: 10px" v-loading="submitLoading" element-loading-text="提交支付中..."> 16 <el-card style="margin-top: 10px" v-loading="submitLoading" element-loading-text="提交支付中...">
18 <!-- 支付宝 --> 17 <!-- 支付宝 -->
@@ -42,12 +41,18 @@ @@ -42,12 +41,18 @@
42 </div> 41 </div>
43 </el-card> 42 </el-card>
44 43
45 - <!-- 支付二维码 --> 44 + <!-- 展示形式:二维码 -->
46 <el-dialog :title="qrCode.title" :visible.sync="qrCode.visible" width="350px" append-to-body 45 <el-dialog :title="qrCode.title" :visible.sync="qrCode.visible" width="350px" append-to-body
47 :close-on-press-escape="false"> 46 :close-on-press-escape="false">
48 <qrcode-vue :value="qrCode.url" size="310" level="H" /> 47 <qrcode-vue :value="qrCode.url" size="310" level="H" />
49 </el-dialog> 48 </el-dialog>
50 49
  50 + <!-- 展示形式:iframe -->
  51 + <el-dialog :title="iframe.title" :visible.sync="iframe.visible" width="800px" height="800px" append-to-body
  52 + :close-on-press-escape="false">
  53 + <iframe :src="iframe.url" width="100%" />
  54 + </el-dialog>
  55 +
51 <!-- 阿里支付 --> 56 <!-- 阿里支付 -->
52 <div ref="alipayWap" v-html="alipayHtml.value" /> 57 <div ref="alipayWap" v-html="alipayHtml.value" />
53 58
@@ -57,7 +62,7 @@ @@ -57,7 +62,7 @@
57 import QrcodeVue from 'qrcode.vue' 62 import QrcodeVue from 'qrcode.vue'
58 import { DICT_TYPE, getDictDatas } from "@/utils/dict"; 63 import { DICT_TYPE, getDictDatas } from "@/utils/dict";
59 import { getOrder, submitOrder } from '@/api/pay/order'; 64 import { getOrder, submitOrder } from '@/api/pay/order';
60 -import { PayChannelEnum, PayOrderStatusEnum } from "@/utils/constants"; 65 +import {PayChannelEnum, PayDisplayModeEnum, PayOrderStatusEnum} from "@/utils/constants";
61 66
62 export default { 67 export default {
63 name: "PayOrderSubmit", 68 name: "PayOrderSubmit",
@@ -83,11 +88,16 @@ export default { @@ -83,11 +88,16 @@ export default {
83 mock: require("@/assets/images/pay/icon/mock.svg"), 88 mock: require("@/assets/images/pay/icon/mock.svg"),
84 }, 89 },
85 submitLoading: false, // 提交支付的 loading 90 submitLoading: false, // 提交支付的 loading
86 - qrCode: { // 支付二维码 91 + qrCode: { // 展示形式:二维码
87 url: '', 92 url: '',
88 title: '', 93 title: '',
89 visible: false, 94 visible: false,
90 }, 95 },
  96 + iframe: { // 展示形式:iframe
  97 + url: '',
  98 + title: '',
  99 + visible: false
  100 + },
91 interval: undefined, // 定时任务,轮询是否完成支付 101 interval: undefined, // 定时任务,轮询是否完成支付
92 alipayHtml: '' // 阿里支付的 HTML 102 alipayHtml: '' // 阿里支付的 HTML
93 }; 103 };
@@ -146,21 +156,65 @@ export default { @@ -146,21 +156,65 @@ export default {
146 this.submitLoading = true 156 this.submitLoading = true
147 submitOrder({ 157 submitOrder({
148 id: this.id, 158 id: this.id,
149 - channelCode: channelCode 159 + channelCode: channelCode,
  160 + ...this.buildSubmitParam(channelCode)
150 }).then(response => { 161 }).then(response => {
151 - const invokeResponse = response.data.invokeResponse  
152 - // 不同的支付,调用不同的策略  
153 - if (channelCode === PayChannelEnum.ALIPAY_QR.code) {  
154 - this.submitAfterAlipayQr(invokeResponse)  
155 - } else if (channelCode === PayChannelEnum.ALIPAY_PC.code  
156 - || channelCode === PayChannelEnum.ALIPAY_WAP.code) {  
157 - this.submitAfterAlipayPc(invokeResponse) 162 + const data = response.data
  163 + if (data.displayMode === 'iframe') {
  164 + this.displayIFrame(channelCode, data)
  165 + } else if (data.displayMode === 'url') {
  166 + this.displayUrl(channelCode, data)
158 } 167 }
  168 + // 不同的支付,调用不同的策略
  169 + // if (channelCode === PayChannelEnum.ALIPAY_QR.code) {
  170 + // this.submitAfterAlipayQr(invokeResponse)
  171 + // } else if (channelCode === PayChannelEnum.ALIPAY_PC.code
  172 + // || channelCode === PayChannelEnum.ALIPAY_WAP.code) {
  173 + // this.submitAfterAlipayPc(invokeResponse)
  174 + // }
159 175
160 // 打开轮询任务 176 // 打开轮询任务
161 this.createQueryInterval() 177 this.createQueryInterval()
162 }) 178 })
163 }, 179 },
  180 + /** 构建提交支付的额外参数 */
  181 + buildSubmitParam(channelCode) {
  182 + // 支付宝网页支付时,有多种展示形态
  183 + if (channelCode === PayChannelEnum.ALIPAY_PC.code) {
  184 + // 情况【前置模式】:将二维码前置到商户的订单确认页的模式。需要商户在自己的页面中以 iframe 方式请求支付宝页面。具体支持的枚举值有以下几种:
  185 + // 0:订单码-简约前置模式,对应 iframe 宽度不能小于 600px,高度不能小于 300px
  186 + // return {
  187 + // "channelExtras": {
  188 + // "qr_pay_mode": "0"
  189 + // }
  190 + // }
  191 + // 1:订单码-前置模式,对应iframe 宽度不能小于 300px,高度不能小于 600px
  192 + // return {
  193 + // "channelExtras": {
  194 + // "qr_pay_mode": "1"
  195 + // }
  196 + // }
  197 + // 3:订单码-迷你前置模式,对应 iframe 宽度不能小于 75px,高度不能小于 75px
  198 + // return {
  199 + // "channelExtras": {
  200 + // "qr_pay_mode": "3"
  201 + // }
  202 + // }
  203 + // 4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小
  204 + // return {
  205 + // "channelExtras": {
  206 + // "qr_pay_mode": "2"
  207 + // }
  208 + // }
  209 + // 情况【跳转模式】:跳转模式下,用户的扫码界面是由支付宝生成的,不在商户的域名下。支持传入的枚举值有
  210 + return {
  211 + "channelExtras": {
  212 + "qr_pay_mode": "2"
  213 + }
  214 + }
  215 + }
  216 + return {}
  217 + },
164 /** 提交支付后(支付宝扫码支付) */ 218 /** 提交支付后(支付宝扫码支付) */
165 submitAfterAlipayQr(invokeResponse) { 219 submitAfterAlipayQr(invokeResponse) {
166 this.qrCode = { 220 this.qrCode = {
@@ -170,6 +224,19 @@ export default { @@ -170,6 +224,19 @@ export default {
170 } 224 }
171 this.submitLoading = false 225 this.submitLoading = false
172 }, 226 },
  227 + displayIFrame(channelCode, data) {
  228 + // this.iframe = {
  229 + // title: '支付窗口',
  230 + // url: data.displayContent,
  231 + // visible: true
  232 + // }
  233 + window.open(data.displayContent)
  234 + },
  235 + /** 提交支付后,URL 的展示形式 */
  236 + displayUrl(channelCode, data) {
  237 + window.open(data.displayContent)
  238 + this.submitLoading = false
  239 + },
173 /** 提交支付后(支付宝 PC 网站支付) */ 240 /** 提交支付后(支付宝 PC 网站支付) */
174 submitAfterAlipayPc(invokeResponse) { 241 submitAfterAlipayPc(invokeResponse) {
175 // 渲染支付页面 242 // 渲染支付页面
@@ -188,6 +255,9 @@ export default { @@ -188,6 +255,9 @@ export default {
188 }, 255 },
189 /** 轮询查询任务 */ 256 /** 轮询查询任务 */
190 createQueryInterval() { 257 createQueryInterval() {
  258 + if (!this.interval) {
  259 + return
  260 + }
191 this.interval = setInterval(() => { 261 this.interval = setInterval(() => {
192 getOrder(this.id).then(response => { 262 getOrder(this.id).then(response => {
193 // 已支付 263 // 已支付