mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	mall + pay:
1. 修复支付宝沙箱地址的调整 2. 收银台的前端 URL 支付走整个网页跳转 3. 收银台的支付成功后,增加 returnUrl 回跳 4. 修复 PayNotifyTask 首次通知时,可能会失败的情况;原因:租户未传递;
This commit is contained in:
		@@ -18,15 +18,6 @@ import java.util.Set;
 | 
			
		||||
@Data
 | 
			
		||||
public class AlipayPayClientConfig implements PayClientConfig {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 网关地址 - 线上
 | 
			
		||||
     */
 | 
			
		||||
    public static final String SERVER_URL_PROD = "https://openapi.alipay.com/gateway.do";
 | 
			
		||||
    /**
 | 
			
		||||
     * 网关地址 - 沙箱
 | 
			
		||||
     */
 | 
			
		||||
    public static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 公钥类型 - 公钥模式
 | 
			
		||||
     */
 | 
			
		||||
@@ -43,8 +34,9 @@ public class AlipayPayClientConfig implements PayClientConfig {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 网关地址
 | 
			
		||||
     * 1. {@link #SERVER_URL_PROD}
 | 
			
		||||
     * 2. {@link #SERVER_URL_SANDBOX}
 | 
			
		||||
     *
 | 
			
		||||
     * 1. <a href="https://openapi.alipay.com/gateway.do">生产环境</a>
 | 
			
		||||
     * 2. <a href="https://openapi-sandbox.dl.alipaydev.com/gateway.do">沙箱环境</a>
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "网关地址不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
 | 
			
		||||
    private String serverUrl;
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,8 @@ import java.io.FileNotFoundException;
 | 
			
		||||
@Disabled
 | 
			
		||||
public class PayClientFactoryImplIntegrationTest {
 | 
			
		||||
 | 
			
		||||
    private static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do";
 | 
			
		||||
 | 
			
		||||
    private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -79,7 +81,7 @@ public class PayClientFactoryImplIntegrationTest {
 | 
			
		||||
        // 创建配置
 | 
			
		||||
        AlipayPayClientConfig config = new AlipayPayClientConfig();
 | 
			
		||||
        config.setAppId("2021000118634035");
 | 
			
		||||
        config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX);
 | 
			
		||||
        config.setServerUrl(SERVER_URL_SANDBOX);
 | 
			
		||||
        config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
 | 
			
		||||
        config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8=");
 | 
			
		||||
        config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB");
 | 
			
		||||
@@ -103,7 +105,7 @@ public class PayClientFactoryImplIntegrationTest {
 | 
			
		||||
        // 创建配置
 | 
			
		||||
        AlipayPayClientConfig config = new AlipayPayClientConfig();
 | 
			
		||||
        config.setAppId("2021000118634035");
 | 
			
		||||
        config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX);
 | 
			
		||||
        config.setServerUrl(SERVER_URL_SANDBOX);
 | 
			
		||||
        config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
 | 
			
		||||
        config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8=");
 | 
			
		||||
        config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB");
 | 
			
		||||
 
 | 
			
		||||
@@ -82,9 +82,9 @@ public class TenantUtils {
 | 
			
		||||
     * 将多租户编号,添加到 header 中
 | 
			
		||||
     *
 | 
			
		||||
     * @param headers HTTP 请求 headers
 | 
			
		||||
     * @param tenantId 租户编号
 | 
			
		||||
     */
 | 
			
		||||
    public static void addTenantHeader(Map<String, String> headers) {
 | 
			
		||||
        Long tenantId = TenantContextHolder.getTenantId();
 | 
			
		||||
    public static void addTenantHeader(Map<String, String> headers, Long tenantId) {
 | 
			
		||||
        if (tenantId != null) {
 | 
			
		||||
            headers.put(HEADER_TENANT_ID, tenantId.toString());
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.pay.dal.dataobject.notify;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 | 
			
		||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
 | 
			
		||||
@@ -25,7 +25,7 @@ import java.time.LocalDateTime;
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Accessors(chain = true)
 | 
			
		||||
public class PayNotifyTaskDO extends BaseDO {
 | 
			
		||||
public class PayNotifyTaskDO extends TenantBaseDO {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知频率,单位为秒。
 | 
			
		||||
 
 | 
			
		||||
@@ -24,10 +24,11 @@ import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.context.annotation.Lazy;
 | 
			
		||||
import org.springframework.scheduling.annotation.Async;
 | 
			
		||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.transaction.annotation.Transactional;
 | 
			
		||||
import org.springframework.transaction.support.TransactionSynchronization;
 | 
			
		||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import javax.validation.Valid;
 | 
			
		||||
@@ -86,6 +87,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
 | 
			
		||||
    private PayNotifyServiceImpl self;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public void createPayNotifyTask(PayNotifyTaskCreateReqDTO reqDTO) {
 | 
			
		||||
        PayNotifyTaskDO task = new PayNotifyTaskDO();
 | 
			
		||||
        task.setType(reqDTO.getType()).setDataId(reqDTO.getDataId());
 | 
			
		||||
@@ -105,8 +107,13 @@ public class PayNotifyServiceImpl implements PayNotifyService {
 | 
			
		||||
        // 执行插入
 | 
			
		||||
        payNotifyTaskMapper.insert(task);
 | 
			
		||||
 | 
			
		||||
        // 异步直接发起任务。虽然会有定时任务扫描,但是会导致延迟
 | 
			
		||||
        self.executeNotifyAsync(task);
 | 
			
		||||
        // 必须在事务提交后,在发起任务,否则 PayNotifyTaskDO 还没入库,就提前回调接入的业务
 | 
			
		||||
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void afterCommit() {
 | 
			
		||||
                executeNotify(task);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -121,7 +128,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
 | 
			
		||||
        CountDownLatch latch = new CountDownLatch(tasks.size());
 | 
			
		||||
        tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> {
 | 
			
		||||
            try {
 | 
			
		||||
                executeNotifySync(task);
 | 
			
		||||
                executeNotify(task);
 | 
			
		||||
            } finally {
 | 
			
		||||
                latch.countDown();
 | 
			
		||||
            }
 | 
			
		||||
@@ -150,22 +157,12 @@ public class PayNotifyServiceImpl implements PayNotifyService {
 | 
			
		||||
        log.error("[awaitExecuteNotify][任务未处理完,总任务数({}) 剩余任务数({})]", size, latch.getCount());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 异步执行单个支付通知
 | 
			
		||||
     *
 | 
			
		||||
     * @param task 通知任务
 | 
			
		||||
     */
 | 
			
		||||
    @Async
 | 
			
		||||
    public void executeNotifyAsync(PayNotifyTaskDO task) {
 | 
			
		||||
        self.executeNotifySync(task); // 使用 self,避免事务不发起
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 同步执行单个支付通知
 | 
			
		||||
     *
 | 
			
		||||
     * @param task 通知任务
 | 
			
		||||
     */
 | 
			
		||||
    public void executeNotifySync(PayNotifyTaskDO task) {
 | 
			
		||||
    public void executeNotify(PayNotifyTaskDO task) {
 | 
			
		||||
        // 分布式锁,避免并发问题
 | 
			
		||||
        payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
 | 
			
		||||
            // 校验,当前任务是否已经被通知过
 | 
			
		||||
@@ -178,12 +175,12 @@ public class PayNotifyServiceImpl implements PayNotifyService {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 执行通知
 | 
			
		||||
            self.executeNotify(dbTask);
 | 
			
		||||
            self.executeNotify0(dbTask);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Transactional
 | 
			
		||||
    public void executeNotify(PayNotifyTaskDO task) {
 | 
			
		||||
    public void executeNotify0(PayNotifyTaskDO task) {
 | 
			
		||||
        // 发起回调
 | 
			
		||||
        CommonResult<?> invokeResult = null;
 | 
			
		||||
        Throwable invokeException = null;
 | 
			
		||||
@@ -223,7 +220,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
 | 
			
		||||
        }
 | 
			
		||||
        // 拼接 header 参数
 | 
			
		||||
        Map<String, String> headers = new HashMap<>();
 | 
			
		||||
        TenantUtils.addTenantHeader(headers);
 | 
			
		||||
        TenantUtils.addTenantHeader(headers, task.getTenantId());
 | 
			
		||||
 | 
			
		||||
        // 发起请求
 | 
			
		||||
        try (HttpResponse response = HttpUtil.createPost(task.getNotifyUrl())
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,8 @@ import static org.junit.jupiter.api.Assertions.*;
 | 
			
		||||
@Import({PayChannelServiceImpl.class})
 | 
			
		||||
public class PayChannelServiceTest extends BaseDbUnitTest {
 | 
			
		||||
 | 
			
		||||
    private static final String ALIPAY_SERVER_URL = "https://openapi.alipay.com/gateway.do";
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private PayChannelServiceImpl channelService;
 | 
			
		||||
 | 
			
		||||
@@ -106,7 +108,6 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
 | 
			
		||||
        assertPojoEquals(reqVO, channel, "config");
 | 
			
		||||
        // 关于config 对象应该拿出来重新对比
 | 
			
		||||
        assertPojoEquals(payClientConfig, channel.getConfig());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@@ -291,7 +292,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
 | 
			
		||||
 | 
			
		||||
    public AlipayPayClientConfig getPublicKeyConfig() {
 | 
			
		||||
        return new AlipayPayClientConfig()
 | 
			
		||||
                .setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD)
 | 
			
		||||
                .setServerUrl(ALIPAY_SERVER_URL)
 | 
			
		||||
                .setAppId("APP00001")
 | 
			
		||||
                .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
 | 
			
		||||
                .setMode(AlipayPayClientConfig.MODE_PUBLIC_KEY)
 | 
			
		||||
@@ -304,7 +305,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
 | 
			
		||||
 | 
			
		||||
    public AlipayPayClientConfig getCertificateConfig() {
 | 
			
		||||
        return new AlipayPayClientConfig()
 | 
			
		||||
                .setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD)
 | 
			
		||||
                .setServerUrl(ALIPAY_SERVER_URL)
 | 
			
		||||
                .setAppId("APP00001")
 | 
			
		||||
                .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
 | 
			
		||||
                .setMode(AlipayPayClientConfig.MODE_CERTIFICATE)
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,9 @@ export default {
 | 
			
		||||
        return router.push(lastPath || '/');
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof obj === "function") {
 | 
			
		||||
      return store.dispatch('tagsView/delView', router.currentRoute).then(obj);
 | 
			
		||||
    }
 | 
			
		||||
    return store.dispatch('tagsView/delView', obj);
 | 
			
		||||
  },
 | 
			
		||||
  // 关闭所有tab页签
 | 
			
		||||
 
 | 
			
		||||
@@ -41,17 +41,17 @@
 | 
			
		||||
          </el-radio-group>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <div v-if="form.aliPayConfig.mode === 1">
 | 
			
		||||
          <el-form-item label-width="180px" label="商户私钥" prop="aliPayConfig.privateKey">
 | 
			
		||||
          <el-form-item label-width="180px" label="应用私钥" prop="aliPayConfig.privateKey">
 | 
			
		||||
            <el-input type="textarea" :autosize="{minRows: 8, maxRows: 8}" v-model="form.aliPayConfig.privateKey"
 | 
			
		||||
                      placeholder="请输入商户私钥" clearable :style="{width: '100%'}">
 | 
			
		||||
                      placeholder="请输入应用私钥" clearable :style="{width: '100%'}">
 | 
			
		||||
            </el-input>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
          <el-form-item label-width="180px" label="支付宝公钥字符串" prop="aliPayConfig.alipayPublicKey">
 | 
			
		||||
          <el-form-item label-width="180px" label="支付宝公钥" prop="aliPayConfig.alipayPublicKey">
 | 
			
		||||
            <el-input
 | 
			
		||||
              type="textarea"
 | 
			
		||||
              :autosize="{minRows: 8, maxRows: 8}"
 | 
			
		||||
              v-model="form.aliPayConfig.alipayPublicKey"
 | 
			
		||||
              placeholder="请输入支付宝公钥字符串" clearable
 | 
			
		||||
              placeholder="请输入支付宝公钥" clearable
 | 
			
		||||
              :style="{width: '100%'}">
 | 
			
		||||
            </el-input>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
 
 | 
			
		||||
@@ -48,15 +48,6 @@
 | 
			
		||||
      <qrcode-vue :value="qrCode.url" size="310" level="L" />
 | 
			
		||||
    </el-dialog>
 | 
			
		||||
 | 
			
		||||
    <!-- 展示形式:IFrame -->
 | 
			
		||||
    <el-dialog :title="iframe.title" :visible.sync="iframe.visible" width="800px" height="800px" append-to-body
 | 
			
		||||
               :close-on-press-escape="false">
 | 
			
		||||
      <iframe :src="iframe.url" width="100%" />
 | 
			
		||||
    </el-dialog>
 | 
			
		||||
 | 
			
		||||
    <!-- 展示形式:Form -->
 | 
			
		||||
    <div ref="formRef" v-html="form.value" />
 | 
			
		||||
 | 
			
		||||
    <!-- 展示形式:BarCode 条形码 -->
 | 
			
		||||
    <el-dialog :title="barCode.title" :visible.sync="barCode.visible" width="500px" append-to-body
 | 
			
		||||
               :close-on-press-escape="false">
 | 
			
		||||
@@ -146,14 +137,6 @@ export default {
 | 
			
		||||
        title: '',
 | 
			
		||||
        visible: false,
 | 
			
		||||
      },
 | 
			
		||||
      iframe: { // 展示形式:iframe
 | 
			
		||||
        url: '',
 | 
			
		||||
        title: '',
 | 
			
		||||
        visible: false
 | 
			
		||||
      },
 | 
			
		||||
      form: { // 展示形式:form
 | 
			
		||||
        html: '',
 | 
			
		||||
      },
 | 
			
		||||
      barCode: { // 展示形式:条形码
 | 
			
		||||
        channelCode: '',
 | 
			
		||||
        value: '',
 | 
			
		||||
@@ -175,21 +158,24 @@ export default {
 | 
			
		||||
      // 1.1 未传递订单编号
 | 
			
		||||
      if (!this.id) {
 | 
			
		||||
        this.$message.error('未传递支付单号,无法查看对应的支付信息');
 | 
			
		||||
        this.goBackToList();
 | 
			
		||||
        this.goReturnUrl('cancel');
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      getOrder(this.id).then(response => {
 | 
			
		||||
        // 1.2 无法查询到支付信息
 | 
			
		||||
        if (!response.data) {
 | 
			
		||||
          this.$message.error('支付订单不存在,请检查!');
 | 
			
		||||
          this.goBackToList();
 | 
			
		||||
          this.goReturnUrl('cancel');
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        // 1.3 订单已支付
 | 
			
		||||
        // TODO 芋艿:已支付
 | 
			
		||||
        if (response.data.status !== PayOrderStatusEnum.WAITING.status) {
 | 
			
		||||
          this.$message.error('支付订单不处于待支付状态,请检查!');
 | 
			
		||||
          this.goBackToList();
 | 
			
		||||
        // 1.3 如果已支付、或者已关闭,则直接跳转
 | 
			
		||||
        if (response.data.status === PayOrderStatusEnum.SUCCESS.status) {
 | 
			
		||||
          this.$message.success('支付成功');
 | 
			
		||||
          this.goReturnUrl('success');
 | 
			
		||||
          return;
 | 
			
		||||
        } else if (response.data.status === PayOrderStatusEnum.CLOSED.status) {
 | 
			
		||||
          this.$message.error('无法支付,原因:订单已关闭');
 | 
			
		||||
          this.goReturnUrl('close');
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -218,15 +204,12 @@ export default {
 | 
			
		||||
      submitOrder({
 | 
			
		||||
        id: this.id,
 | 
			
		||||
        channelCode: channelCode,
 | 
			
		||||
        returnUrl: location.href, // 支付成功后,支付渠道跳转回当前页;再由当前页,跳转回 {@link returnUrl} 对应的地址
 | 
			
		||||
        ...this.buildSubmitParam(channelCode)
 | 
			
		||||
      }).then(response => {
 | 
			
		||||
        const data = response.data
 | 
			
		||||
        if (data.displayMode === PayDisplayModeEnum.IFRAME.mode) {
 | 
			
		||||
          this.displayIFrame(channelCode, data)
 | 
			
		||||
        } else if (data.displayMode === PayDisplayModeEnum.URL.mode) {
 | 
			
		||||
        if (data.displayMode === PayDisplayModeEnum.URL.mode) {
 | 
			
		||||
          this.displayUrl(channelCode, data)
 | 
			
		||||
        } else if (data.displayMode === PayDisplayModeEnum.FORM.mode) {
 | 
			
		||||
          this.displayForm(channelCode, data)
 | 
			
		||||
        } else if (data.displayMode === PayDisplayModeEnum.QR_CODE.mode) {
 | 
			
		||||
          this.displayQrCode(channelCode, data)
 | 
			
		||||
        }
 | 
			
		||||
@@ -239,53 +222,7 @@ export default {
 | 
			
		||||
    },
 | 
			
		||||
    /** 构建提交支付的额外参数 */
 | 
			
		||||
    buildSubmitParam(channelCode) {
 | 
			
		||||
      // ① 支付宝 PC 支付时,有多种展示形态
 | 
			
		||||
      if (channelCode === PayChannelEnum.ALIPAY_PC.code) {
 | 
			
		||||
        // 情况【前置模式】:将二维码前置到商户的订单确认页的模式。需要商户在自己的页面中以 iframe 方式请求支付宝页面。具体支持的枚举值有以下几种:
 | 
			
		||||
        // 0:订单码-简约前置模式,对应 iframe 宽度不能小于 600px,高度不能小于 300px
 | 
			
		||||
        // return {
 | 
			
		||||
        //   "channelExtras": {
 | 
			
		||||
        //     "qr_pay_mode": "0"
 | 
			
		||||
        //   }
 | 
			
		||||
        // }
 | 
			
		||||
        // 1:订单码-前置模式,对应iframe 宽度不能小于 300px,高度不能小于 600px
 | 
			
		||||
        // return {
 | 
			
		||||
        //   "channelExtras": {
 | 
			
		||||
        //     "qr_pay_mode": "1"
 | 
			
		||||
        //   }
 | 
			
		||||
        // }
 | 
			
		||||
        // 3:订单码-迷你前置模式,对应 iframe 宽度不能小于 75px,高度不能小于 75px
 | 
			
		||||
        // return {
 | 
			
		||||
        //   "channelExtras": {
 | 
			
		||||
        //     "qr_pay_mode": "3"
 | 
			
		||||
        //   }
 | 
			
		||||
        // }
 | 
			
		||||
        // 4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小
 | 
			
		||||
        // return {
 | 
			
		||||
        //   "channelExtras": {
 | 
			
		||||
        //     "qr_pay_mode": "4"
 | 
			
		||||
        //   }
 | 
			
		||||
        // }
 | 
			
		||||
        // 情况【跳转模式】:跳转模式下,用户的扫码界面是由支付宝生成的,不在商户的域名下。支持传入的枚举值有
 | 
			
		||||
        return {
 | 
			
		||||
          "channelExtras": {
 | 
			
		||||
            "qr_pay_mode": "2"
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        // 情况【表单模式】:直接提交当前页面到支付宝
 | 
			
		||||
        // return {
 | 
			
		||||
        //   displayMode: PayDisplayModeEnum.FORM.mode
 | 
			
		||||
        // }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // ② 支付宝 Wap 支付时,引导手机扫码支付
 | 
			
		||||
      if (channelCode === PayChannelEnum.ALIPAY_WAP.code) {
 | 
			
		||||
        return {
 | 
			
		||||
          displayMode: PayDisplayModeEnum.QR_CODE.mode
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // ③ 支付宝 BarCode 支付时,需要传递 authCode 条形码
 | 
			
		||||
      // ① 支付宝 BarCode 支付时,需要传递 authCode 条形码
 | 
			
		||||
      if (channelCode === PayChannelEnum.ALIPAY_BAR.code) {
 | 
			
		||||
        return {
 | 
			
		||||
          "channelExtras": {
 | 
			
		||||
@@ -295,37 +232,12 @@ export default {
 | 
			
		||||
      }
 | 
			
		||||
      return {}
 | 
			
		||||
    },
 | 
			
		||||
    /** 提交支付后,IFrame 内置 URL 的展示形式 */
 | 
			
		||||
    displayIFrame(channelCode, data) {
 | 
			
		||||
      // TODO 芋艿:目前有点奇怪,支付宝总是会显示“支付环境存在风险”
 | 
			
		||||
      this.iframe = {
 | 
			
		||||
        title: '支付窗口',
 | 
			
		||||
        url: data.displayContent,
 | 
			
		||||
        visible: true
 | 
			
		||||
      }
 | 
			
		||||
      this.submitLoading = false
 | 
			
		||||
    },
 | 
			
		||||
    /** 提交支付后,URL 的展示形式 */
 | 
			
		||||
    displayUrl(channelCode, data) {
 | 
			
		||||
      // window.open(data.displayContent)window
 | 
			
		||||
      // window.open(data.displayContent)
 | 
			
		||||
      location.href = data.displayContent
 | 
			
		||||
      this.submitLoading = false
 | 
			
		||||
    },
 | 
			
		||||
    /** 提交支付后,Form 的展示形式 */
 | 
			
		||||
    displayForm(channelCode, data) {
 | 
			
		||||
      // 渲染支付页面
 | 
			
		||||
      this.form = {
 | 
			
		||||
        value: data.displayContent
 | 
			
		||||
      }
 | 
			
		||||
      // 防抖避免重复支付
 | 
			
		||||
      this.$nextTick(() => {
 | 
			
		||||
        // 提交支付表单
 | 
			
		||||
        this.$refs.formRef.children[0].submit();
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
          this.submitLoading = false
 | 
			
		||||
        }, 1000);
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    /** 提交支付后(支付宝扫码支付) */
 | 
			
		||||
    displayQrCode(channelCode, data) {
 | 
			
		||||
      let title = '请使用手机浏览器“扫一扫”';
 | 
			
		||||
@@ -354,13 +266,13 @@ export default {
 | 
			
		||||
          if (response.data.status === PayOrderStatusEnum.SUCCESS.status) {
 | 
			
		||||
            this.clearQueryInterval();
 | 
			
		||||
            this.$message.success('支付成功!');
 | 
			
		||||
            this.goBackToList();
 | 
			
		||||
            this.goReturnUrl();
 | 
			
		||||
          }
 | 
			
		||||
          // 已取消
 | 
			
		||||
          if (response.data.status === PayOrderStatusEnum.CLOSED.status) {
 | 
			
		||||
            this.clearQueryInterval();
 | 
			
		||||
            this.$message.error('支付已关闭!');
 | 
			
		||||
            this.goBackToList();
 | 
			
		||||
            this.goReturnUrl();
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }, 1000 * 2)
 | 
			
		||||
@@ -377,14 +289,34 @@ export default {
 | 
			
		||||
      clearInterval(this.interval)
 | 
			
		||||
      this.interval = undefined
 | 
			
		||||
    },
 | 
			
		||||
    /** 回到列表 **/
 | 
			
		||||
    goBackToList() {
 | 
			
		||||
    /**
 | 
			
		||||
     * 回到业务的 URL
 | 
			
		||||
     *
 | 
			
		||||
     * @param payResult 支付结果
 | 
			
		||||
     *                  ① success:支付成功
 | 
			
		||||
     *                  ② cancel:取消支付
 | 
			
		||||
     *                  ③ close:支付已关闭
 | 
			
		||||
     */
 | 
			
		||||
    goReturnUrl(payResult) {
 | 
			
		||||
      // 未配置的情况下,只能关闭
 | 
			
		||||
      if (!this.returnUrl) {
 | 
			
		||||
        this.$tab.closePage();
 | 
			
		||||
      this.$router.go(-1);
 | 
			
		||||
      // TODO 芋艿:需要优化;
 | 
			
		||||
      // this.$router.push({
 | 
			
		||||
      //   path: this.returnUrl
 | 
			
		||||
      // });
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const url = this.returnUrl.indexOf('?') >= 0
 | 
			
		||||
        ? this.returnUrl + '&payResult=' + payResult
 | 
			
		||||
        : this.returnUrl + '?payResult=' + payResult
 | 
			
		||||
      // 如果有配置,且是 http 开头,则浏览器跳转
 | 
			
		||||
      if (this.returnUrl.indexOf('http') === 0) {
 | 
			
		||||
        location.href = url;
 | 
			
		||||
      } else {
 | 
			
		||||
        this.$tab.closePage(() => {
 | 
			
		||||
          this.$router.push({
 | 
			
		||||
            path: url
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user