feat: 接入支付宝沙箱电脑网站支付功能

1. 新增支付宝支付相关接口、实体类与配置类
2. 后端新增支付宝服务实现与支付回调接口
3. 前端替换模拟支付为跳转支付宝支付流程
4. 优化订单支付提示与支付完成跳转逻辑
5. 删除本地Maven配置文件
This commit is contained in:
sparksfly 2026-08-01 22:47:19 +08:00
parent f3fac48ad6
commit 004745fd65
13 changed files with 3054 additions and 68 deletions

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>C:\Users\OrBit-0297\.m2\repository</localRepository>
</settings>

View File

@ -24,6 +24,7 @@
<s3.version>2.44.4</s3.version>
<minio.version>9.0.0</minio.version>
<aliyun-oss.version>3.18.5</aliyun-oss.version>
<alipay.version>4.40.918.ALL</alipay.version>
<tencent-cos.version>5.6.269</tencent-cos.version>
<weixin-java.version>4.8.3.B</weixin-java.version>
<mapstruct.version>1.6.3</mapstruct.version>
@ -142,6 +143,13 @@
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>${alipay.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<dependencyManagement>

View File

@ -0,0 +1,38 @@
package com.snack.server.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 支付宝沙箱配置
*/
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AlipayProperties {
/** 支付宝开放平台应用 ID */
private String appId;
/** 应用私钥PKCS8 */
private String appPrivateKey;
/** 支付宝公钥 */
private String alipayPublicKey;
/** 异步通知地址(可只配域名,代码自动拼接 /api/payment/alipay/notify */
private String notifyUrl;
/** 支付完成同步返回地址(完整 URL */
private String returnUrl;
/** 网关地址沙箱https://openapi.alipaydev.com/gateway.do */
private String gateway = "https://openapi.alipaydev.com/gateway.do";
/** 签名算法 */
private String signType = "RSA2";
/** 字符集 */
private String charset = "utf-8";
}

View File

@ -6,6 +6,7 @@ import com.snack.server.common.Result;
import com.snack.server.module.order.dto.req.OrderPageReq;
import com.snack.server.module.order.dto.req.OrderSubmitReq;
import com.snack.server.module.order.entity.Order;
import com.snack.server.module.order.service.AlipayService;
import com.snack.server.module.order.service.OrderService;
import com.snack.server.module.order.vo.OrderDetailVO;
import io.swagger.v3.oas.annotations.Operation;
@ -27,6 +28,7 @@ import java.util.Map;
public class OrderController {
private final OrderService orderService;
private final AlipayService alipayService;
@Operation(summary = "提交订单")
@SaCheckLogin
@ -58,6 +60,13 @@ public class OrderController {
return Result.ok();
}
@Operation(summary = "获取支付宝电脑网站支付链接")
@SaCheckLogin
@GetMapping("/{id}/pay-url")
public Result<Map<String, String>> payUrl(@Parameter(description = "订单 ID") @PathVariable Long id) {
return Result.ok(Map.of("payUrl", alipayService.createPagePayUrl(id)));
}
@Operation(summary = "取消订单")
@SaCheckLogin
@PostMapping("/{id}/cancel")

View File

@ -1,77 +1,59 @@
package com.snack.server.module.order.controller;
import cn.hutool.core.util.StrUtil;
import com.snack.server.common.Result;
import com.snack.server.module.order.service.OrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.snack.server.module.order.service.AlipayService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.Map;
/**
* 支付宝 / 微信支付回调沙箱版
* 支付宝回调电脑网站支付
*
* 真实生产
* 1. 支付宝 POST 异步通知到 /api/payment/alipay/notify
* 2. 校验 sign 签名
* 3. 解析 out_trade_no订单号trade_no支付宝交易号
* 4. 调用 OrderService.handlePaySuccess()
* 5. 返回 "success" / "fail" 给支付宝
*
* 沙箱测试手动调用
* POST /api/payment/alipay/notify
* ?orderId=1&payChannel=alipay&payTradeNo=20260601xxxx
* 1. 支付成功后支付宝 POST 异步通知 /api/payment/alipay/notify
* 2. 服务端验签后更新订单状态返回 "success" 给支付宝
* 3. 用户支付完成同步跳转 /api/payment/alipay/return再重定向到前端
*/
@Slf4j
@Tag(name = "支付回调(沙箱测试)")
@RestController
@RequestMapping("/api/payment")
@RequiredArgsConstructor
public class PaymentNotifyController {
private final OrderService orderService;
private final AlipayService alipayService;
/**
* 支付宝支付成功异步通知
* 支付宝支付成功异步通知必须返回纯文本 success / fail
*/
@Operation(summary = "支付宝支付成功回调(沙箱测试用)")
@PostMapping("/alipay/notify")
public Result<String> alipayNotify(
@RequestParam Long orderId,
@RequestParam(required = false, defaultValue = "alipay") String payChannel,
@RequestParam(required = false) String payTradeNo) {
if (orderId == null) {
return Result.fail(400, "orderId 不能为空");
}
if (StrUtil.isBlank(payTradeNo)) {
payTradeNo = "ALIPAY-MOCK-" + System.currentTimeMillis();
}
log.info("收到支付宝支付回调 orderId={} payTradeNo={}", orderId, payTradeNo);
boolean ok = orderService.handlePaySuccess(orderId, payChannel, payTradeNo);
// 支付宝要求返回纯文本 "success" / "fail" body 输出
return ok ? Result.ok("success") : Result.fail("fail");
public String alipayNotify(@RequestParam Map<String, String> params) {
log.info("收到支付宝支付异步通知 out_trade_no={} trade_status={}",
params.get("out_trade_no"), params.get("trade_status"));
return alipayService.handleNotify(params);
}
/**
* 支付宝退款成功异步通知
* 支付宝退款异步通知必须返回纯文本 success / fail
*/
@Operation(summary = "支付宝退款成功回调(沙箱测试用)")
@PostMapping("/alipay/refund/notify")
public Result<String> alipayRefundNotify(
@RequestParam Long orderId,
@RequestParam(required = false) String refundTradeNo) {
if (orderId == null) {
return Result.fail(400, "orderId 不能为空");
}
if (StrUtil.isBlank(refundTradeNo)) {
refundTradeNo = "RF-MOCK-" + System.currentTimeMillis();
}
log.info("收到支付宝退款回调 orderId={} refundTradeNo={}", orderId, refundTradeNo);
boolean ok = orderService.handleRefundSuccess(orderId, refundTradeNo);
return ok ? Result.ok("success") : Result.fail("fail");
public String alipayRefundNotify(@RequestParam Map<String, String> params) {
log.info("收到支付宝退款异步通知 out_trade_no={}", params.get("out_trade_no"));
return alipayService.handleRefundNotify(params);
}
/**
* 支付宝电脑网站支付同步返回用户支付后从支付宝跳回
*/
@GetMapping("/alipay/return")
public void alipayReturn(@RequestParam Map<String, String> params,
HttpServletResponse response) throws IOException {
String redirectUrl = alipayService.handleReturn(params);
response.sendRedirect(redirectUrl);
}
}

View File

@ -0,0 +1,41 @@
package com.snack.server.module.order.service;
import java.util.Map;
/**
* 支付宝支付服务电脑网站支付沙箱
*/
public interface AlipayService {
/**
* 生成电脑网站支付跳转链接
*
* @param orderId 订单 ID
* @return 支付宝支付页面 URL
*/
String createPagePayUrl(Long orderId);
/**
* 处理支付宝支付异步通知
*
* @param params 支付宝回调参数
* @return 支付宝要求返回的 "success" / "fail"
*/
String handleNotify(Map<String, String> params);
/**
* 处理支付宝支付同步返回验签后跳转前端
*
* @param params 支付宝返回参数
* @return 前端跳转地址
*/
String handleReturn(Map<String, String> params);
/**
* 处理支付宝退款异步通知
*
* @param params 支付宝回调参数
* @return 支付宝要求返回的 "success" / "fail"
*/
String handleRefundNotify(Map<String, String> params);
}

View File

@ -0,0 +1,193 @@
package com.snack.server.module.order.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.snack.server.common.ResultCode;
import com.snack.server.config.AlipayProperties;
import com.snack.server.exception.BusinessException;
import com.snack.server.module.order.entity.Order;
import com.snack.server.module.order.enums.OrderStatusEnum;
import com.snack.server.module.order.enums.PayChannelEnum;
import com.snack.server.module.order.mapper.OrderMapper;
import com.snack.server.module.order.service.AlipayService;
import com.snack.server.module.order.service.OrderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
/**
* 支付宝支付业务实现电脑网站支付沙箱
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AlipayServiceImpl implements AlipayService {
private static final String NOTIFY_PATH = "/api/payment/alipay/notify";
private final AlipayProperties alipayProperties;
private final OrderMapper orderMapper;
private final OrderService orderService;
@Override
public String createPagePayUrl(Long orderId) {
Order order = orderMapper.selectById(orderId);
if (order == null) {
throw new BusinessException(ResultCode.ORDER_NOT_EXIST);
}
if (!Objects.equals(order.getUserId(), StpUtil.getLoginIdAsLong())) {
throw new BusinessException(1000, "订单不存在或无权访问");
}
if (!Objects.equals(order.getStatus(), OrderStatusEnum.PENDING_PAY.getCode())) {
throw new BusinessException(ResultCode.ORDER_STATUS_ERROR, "当前订单状态不可支付");
}
AlipayClient alipayClient = buildClient();
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setNotifyUrl(fullNotifyUrl());
request.setReturnUrl(alipayProperties.getReturnUrl());
Map<String, Object> bizContent = new LinkedHashMap<>();
bizContent.put("out_trade_no", order.getOrderNo());
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
bizContent.put("total_amount", order.getPayAmount().toPlainString());
bizContent.put("subject", "零食商城-订单" + order.getOrderNo());
bizContent.put("timeout_express", "30m");
request.setBizContent(JSONUtil.toJsonStr(bizContent));
try {
AlipayTradePagePayResponse response = alipayClient.pageExecute(request, "GET");
String payUrl = response.getBody();
if (StrUtil.isBlank(payUrl)) {
throw new BusinessException(1000, "支付宝下单失败,未生成支付链接");
}
log.info("生成支付宝支付链接 orderNo={}", order.getOrderNo());
return payUrl;
} catch (AlipayApiException e) {
log.error("生成支付宝支付链接失败 orderNo={}", order.getOrderNo(), e);
throw new BusinessException(1000, "支付宝下单失败:" + e.getErrMsg());
}
}
@Override
public String handleNotify(Map<String, String> params) {
if (!rsaCheck(params)) {
log.warn("支付宝异步通知签名校验失败");
return "fail";
}
String tradeStatus = params.get("trade_status");
if (!"TRADE_SUCCESS".equals(tradeStatus) && !"TRADE_FINISHED".equals(tradeStatus)) {
log.info("支付宝异步通知忽略状态 trade_status={}", tradeStatus);
return "success";
}
String orderNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
if (StrUtil.isBlank(orderNo) || StrUtil.isBlank(tradeNo)) {
return "fail";
}
Order order = findOrderByNo(orderNo);
if (order == null) {
log.warn("支付宝异步通知订单不存在 orderNo={}", orderNo);
return "fail";
}
String totalAmount = params.get("total_amount");
if (StrUtil.isNotBlank(totalAmount)
&& new BigDecimal(totalAmount).compareTo(order.getPayAmount()) != 0) {
log.warn("支付宝异步通知金额不一致 orderNo={} notify={} order={}",
orderNo, totalAmount, order.getPayAmount());
return "fail";
}
// 幂等处理已支付订单直接返回 success避免支付宝重复通知
if (Objects.equals(order.getStatus(), OrderStatusEnum.PENDING_SHIP.getCode())) {
return "success";
}
boolean ok = orderService.handlePaySuccess(
order.getId(), PayChannelEnum.ALIPAY.getCode(), tradeNo);
return ok ? "success" : "fail";
}
@Override
public String handleReturn(Map<String, String> params) {
if (!rsaCheck(params)) {
throw new BusinessException(1000, "支付宝返回参数校验失败");
}
String orderNo = params.get("out_trade_no");
String base = StrUtil.removeSuffix(alipayProperties.getReturnUrl(), "/");
return StrUtil.isBlank(orderNo) ? base : base + "?pay=success&orderNo=" + orderNo;
}
@Override
public String handleRefundNotify(Map<String, String> params) {
if (!rsaCheck(params)) {
log.warn("支付宝退款异步通知签名校验失败");
return "fail";
}
String orderNo = params.get("out_trade_no");
if (StrUtil.isBlank(orderNo)) {
return "fail";
}
Order order = findOrderByNo(orderNo);
if (order == null) {
return "fail";
}
if (Objects.equals(order.getStatus(), OrderStatusEnum.REFUNDED.getCode())) {
return "success";
}
String tradeNo = params.get("trade_no");
boolean ok = orderService.handleRefundSuccess(
order.getId(), StrUtil.blankToDefault(tradeNo, "RF-" + order.getOrderNo()));
return ok ? "success" : "fail";
}
private AlipayClient buildClient() {
return new DefaultAlipayClient(
alipayProperties.getGateway(),
alipayProperties.getAppId(),
alipayProperties.getAppPrivateKey(),
"json",
alipayProperties.getCharset(),
alipayProperties.getAlipayPublicKey(),
alipayProperties.getSignType());
}
private String fullNotifyUrl() {
String base = alipayProperties.getNotifyUrl();
if (StrUtil.isBlank(base)) {
throw new BusinessException(1000, "支付宝回调地址未配置");
}
return StrUtil.removeSuffix(base, "/") + NOTIFY_PATH;
}
private boolean rsaCheck(Map<String, String> params) {
try {
return AlipaySignature.rsaCheckV1(
params,
alipayProperties.getAlipayPublicKey(),
alipayProperties.getCharset(),
alipayProperties.getSignType());
} catch (AlipayApiException e) {
log.warn("支付宝签名校验异常:{}", e.getMessage());
return false;
}
}
private Order findOrderByNo(String orderNo) {
return orderMapper.selectOne(
new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, orderNo));
}
}

View File

@ -104,3 +104,16 @@ snack:
seckill:
# 抢购用户限购记录在 Redis 中的过期时间(秒)—— 用于活动结束后清理
record-ttl-seconds: 86400
alipay:
appId: 9021000129648617
# 沙箱网关
gateway: https://openapi.alipaydev.com/gateway.do
# 应用私钥
appPrivateKey: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFR2RFzPaCeO0o8ajYOnvSLgekKJ1RKiqUPx2Yw5olXvHIBzEn3Amkyy0SRIQDjoAXdvAsKkOFXLMbEHEAEkCOJLfm5/RQP9hY7jaCrLBV4rH/uJsFkHInPJmUXwOZk7CYdPS5vivW82LqXb8qFpYOETr/6dB074X2smk1r8hISm01TPDsGYr/z5ry8t+JtMTKkPioO32OvaG0ZeksPnHGdgZFoFboaVkOM/jbFSnURlhtVfw6RxnQWMSL7zrtDreLJjJ6CyZI4dEaUcJFyb77QVb+jbDmBhO9/1ul1n65jjRD1YgRyhZg8B9+nvCj7nM60R82PbD0ZzA16R/mW9xfAgMBAAECggEAWx2PHYH99OLfPoLm5f+VAs1JsDMl/b/I7LF9/PmSr2H7r9RKisthFODWT1Kf2nithqjjYrKefvECtCRS3KKReFVTLu3A9HOYe/KB8LbLts8+QQrFZruBTcf6cwGzSvJgpPmXslY4L044SGDGEy1dXt/sbRhTtD6QlBFw8F/g1CniuT+dwGZ5NjEa4HnlB7V0AYXL1hjAn4eKEkR8bzCnHY4g0PM582bqoJv7M6/I93uGAK9BPG6LhsIA54xvYaFcgkiqPFM6GYr1nCGGtK6W1eKh/oCtpIskR94SaUqTxQ4C/TGK+EXNDfgT9pcb28/5pUwiaUDNGsG2sQ0nVxIpkQKBgQD+XLkXQZemoz+YQJ4DtYeHSz88TReYzQKLia5Bt6eqkRuE8bDJ6oG6/dGniv1rh7OWCWvE1BTaOvjQPjw78si0nkJ9MHagZbnHyQE7cGpvXMZrTULsiacC6iH9fGA5+g7pW6/+wM9wED3dvjv4IztykQzxOG4DAEEDidVVErRxOQKBgQDGjJNZ7IH/LuGDzclUwemzeJ9jtJcWSjmY4zixU/wN2iVUavtotC6PBanLJVtsVdJWtSn2E34E+ptJWPHeoIzRAPUo+BrtC53W74CgOJwvBz9oAhbctUUaSp0L0zzmnFmHjcYVbL87pIr2wNNmoOPOk1bCTqvtODMef9iNe45yVwKBgAs6cp05MwWTHUKOT6tgPwxU4QS7bng7TIp2WG/kOI2J/EoBFUnEhVeIztFzjD5L7jyIS+6TYhxEECm5JZWL4RpABjVah1ILS4krMVe7Xadu0/92mKayaOHzDe8Pp3vHsxLQDlPTlRSgUurP8/u/KmejSYv4brrJLxWF5xnrSnXZAoGBAJEfYvyRUBtTCuap3YSkD8tsWSQpdV2Hdz32pxOGDW+aiTqAz64iNP245/hiH8a5m/pghIEmki/VdPdRmchdlU+W4ZrGbffhS8c0W9HATvhY1dGR5WAA5rdm3g8soRD2KsJXr/cs+0H+7Mua+WnEI350Vy/DDQtgzox2abRQITgVAoGBAPV/CRcWAPN1XTXFJMN8GwqndTkQ+Wgc77rE90+4s4kcu7GCaKWYapVDGbpUeAIckoE5uqK5CRgvoiT/ZhlYhSUej4vRrLTr5mD6y9qxW0AN+UiYvkBtRsxgmKMsY7hKIzyf4wEQj5TvN+9UG7ASvQFXVeQAgIhQ3yZ/nHvcrY7y
# 支付宝公钥
alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl54qsMxRkuisHTif0XyMG/ct3+Dx44gC5yj5k729AAJxXd5Y7uFit+FeN805W7ltm0sXB/gFNKsxe0ZJv5N+CO3/GfFtxDZK3FGxgkzH+6isXOI2pl2bOv5jWh/LcyOckA0SAq/p0AUjy0m8/FNJmq321q9SCz8UYSq188iYgawPdUtbuhwUlX2pJTWW25c5qSyNBeiXViODqkeQ9PhBYaEivRa/iY536ypRpEJ8QKcWcfj0INhh7gvDdbCSveRakCAxTkklMtahmkSuUlzVRhAkzhShX+1U2l7tUScimqEzjYJ2FdvhYYRQxjOt054hPug67ptNxPutGhPOI4L8FwIDAQAB
# 回调地址
notifyUrl: http://g2et3x.natappfree.cc
# 返回地址
returnUrl: http://127.0.0.1:5174/user

2674
web-snack/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,11 @@
import { request } from '@/utils/request'
import type { PageResult } from '@/types/common'
import type { OrderDetail, OrderSubmitReq, OrderSubmitResult } from '@/types/order'
import type {
OrderDetail,
OrderPayUrlResult,
OrderSubmitReq,
OrderSubmitResult
} from '@/types/order'
/**
*
@ -39,7 +44,18 @@ export function getOrderDetailApi(id: number) {
}
/**
*
*
* GET /api/orders/{id}/pay-url
*/
export function getOrderPayUrlApi(id: number) {
return request<OrderPayUrlResult>({
url: `/api/orders/${id}/pay-url`,
method: 'GET'
})
}
/**
*
* POST /api/orders/{id}/pay
*/
export function payOrderApi(id: number) {

View File

@ -32,6 +32,11 @@ export interface OrderSubmitResult {
orderNo: string
}
/** 获取支付宝支付链接返回 */
export interface OrderPayUrlResult {
payUrl: string
}
/** 订单(对应后端 OrderDetailVO */
export interface OrderDetail {
id: number

View File

@ -2,7 +2,7 @@
/**
* 确认订单页
*
* 结算购物车中已选中的商品选择收货地址优惠券填写备注提交订单后支持模拟支付
* 结算购物车中已选中的商品选择收货地址优惠券填写备注提交订单后跳转支付宝支付
*/
import { ElMessage } from 'element-plus'
import {
@ -20,7 +20,7 @@ import EmptyState from '@/components/common/EmptyState.vue'
import { getCartApi } from '@/api/cart'
import { getAddressListApi, createAddressApi } from '@/api/address'
import { getMyCouponsApi } from '@/api/coupon'
import { submitOrderApi, payOrderApi } from '@/api/order'
import { submitOrderApi, getOrderPayUrlApi } from '@/api/order'
import type { CartItem } from '@/types/cart'
import type { Address, AddressSaveReq } from '@/types/address'
import type { UserCoupon } from '@/types/coupon'
@ -177,9 +177,12 @@ async function handlePay() {
if (!submitted.value) return
paying.value = true
try {
await payOrderApi(submitted.value.orderId)
ElMessage.success('支付成功')
router.push('/user')
const data = await getOrderPayUrlApi(submitted.value.orderId)
if (data?.payUrl) {
window.location.href = data.payUrl
return
}
ElMessage.warning('支付宝支付链接生成失败')
} catch {
/* 拦截器已提示 */
} finally {

View File

@ -10,7 +10,7 @@
* - 我的优惠券按状态筛选
*/
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
User as UserIcon,
@ -30,7 +30,7 @@ import EmptyState from '@/components/common/EmptyState.vue'
import { useUserStore } from '@/stores/modules/user'
import {
getOrderPageApi,
payOrderApi,
getOrderPayUrlApi,
cancelOrderApi,
receiveOrderApi
} from '@/api/order'
@ -50,6 +50,7 @@ import type { FavoriteItem } from '@/types/favorite'
import type { UserCoupon } from '@/types/coupon'
const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
// ==================== ====================
@ -183,8 +184,8 @@ function onOrderPageChange(page: number) {
async function handlePayOrder(order: OrderDetail) {
try {
await ElMessageBox.confirm('确定支付该订单吗', '提示', {
confirmButtonText: '支付',
await ElMessageBox.confirm('将跳转到支付宝沙箱完成支付,是否继续', '提示', {
confirmButtonText: '支付',
cancelButtonText: '取消',
type: 'info'
})
@ -193,9 +194,12 @@ async function handlePayOrder(order: OrderDetail) {
}
orderActingId.value = order.id
try {
await payOrderApi(order.id)
ElMessage.success('支付成功')
loadOrders()
const data = await getOrderPayUrlApi(order.id)
if (data?.payUrl) {
window.location.href = data.payUrl
return
}
ElMessage.warning('支付宝支付链接生成失败')
} catch {
/* 拦截器已提示 */
} finally {
@ -445,6 +449,12 @@ function onCouponTabChange(name: any) {
onMounted(() => {
loadAddresses()
loadCoupons()
//
if (route.query.pay === 'success') {
activeMenu.value = 'orders'
loadOrders()
ElMessage.success('支付成功')
}
})
</script>