目录
1. 前期准备
1.1 申请沙盒账号
登录支付宝开放平台,注册/登录开发者账号
1.2 获取必要密钥
下载密钥工具生成密钥,获取应用公钥、应用私钥
1.3 下载沙盒环境APP
1. 进入沙盒应用
2. 将上面的“应用公钥”复制到沙箱应用的自定义密钥中,此页面可以获取“AppID、支付宝网关地址”
3. 沙箱账号就是模拟付款的卖家和买家账号,输入账号密码可在付款页面或沙箱工具下载的手机端支付宝沙箱app中进行登录,输入付款密码可完成支付流程
2. 环境配置
2.1 Maven项目依赖配置
pom.xml
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.57.ALL</version>
</dependency>
2.2 配置文件设置
application.yml
# 支付宝沙箱配置
alipay:
app-id: …… # 你的支付宝应用APPID
private-key: …… # 密钥生成工具-应用私钥
public-key: …… # 沙箱应用-自定义密钥-支付宝公钥
gateway-url: https://openapi-sandbox.dl.alipaydev.com/gateway.do # 测试环境使用沙箱网关地址
return-url: http://localhost:8080/payment/return # 支付完成后前端回调页面
notify-url: http://your-domain.com/api/payment/notify # 支付通知接收地址(需外网可访问)
charset: UTF-8 # 编码
sign-type: RSA2 # 签名类型
3.3 外网访问
ngrok http 8080
3.3.1 配置本地hosts
由于localhost无法直接被外网访问,需要使用内网穿透工具或修改hosts文件:
127.0.0.1 yourdomain.com
3.3.2 内网穿透配置(可选)
为了让支付宝服务器能访问localhost的回调接口,可以使用内网穿透工具:
工具1:ngrok:下载并安装ngrok,启动并映射端口:
ngrok http 8080
工具2:花生壳:下载并安装花生壳,注册并购买服务,配置内网映射
3. 部分相关代码
3.1 SQL
CREATE TABLE `payment_order` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '检查报告ID',
`order_id` varchar(255) NOT NULL COMMENT '订单ID (同时也是商户订单号)',
`record_id` int(11) NOT NULL COMMENT '就诊记录ID',
`user_id` int(11) NOT NULL COMMENT '患者ID',
`username` varchar(255) DEFAULT NULL COMMENT '患者',
`drug_id` int(11) NOT NULL COMMENT '药品ID',
`drug_name` varchar(255) DEFAULT NULL COMMENT '药品名称',
`quantity` int(11) NOT NULL COMMENT '购买数量',
`total_amount` int(11) NOT NULL COMMENT '订单总金额',
`subject` varchar(255) DEFAULT NULL COMMENT '订单标题',
`body` varchar(255) DEFAULT NULL COMMENT '订单描述',
`trade_no` varchar(255) DEFAULT NULL COMMENT '支付宝交易号',
`status` varchar(255) DEFAULT NULL COMMENT '订单状态:WAIT_BUYER_PAY (交易创建,等待买家付款);TRADE_CLOSED (未付款交易超时关闭,或支付完成后全额退款);TRADE_SUCCESS (交易支付成功);TRADE_FINISHED (交易结束,不可退款)',
`return_url` varchar(100) DEFAULT NULL COMMENT '支付完成后的前端回调地址',
`create_user` int(11) NOT NULL COMMENT '创建人',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 COMMENT='支付订单表';
3.2 Java
Controller
@RestController
@RequestMapping("/api/payment")
public class PaymentController {
public final static Logger logger = LoggerFactory.getLogger(PaymentController.class);
@Value("${alipay.app-id}")
private String appId;
@Value("${alipay.private-key}")
private String privateKey;
@Value("${alipay.public-key}")
private String aliPayPublicKey;
@Value("${alipay.gateway-url}")
private String gatewayUrl;
@Value("${alipay.return-url}")
private String returnUrl;
@Value("${alipay.notify-url}")
private String notifyUrl;
@Autowired
private IOrderService orderService;
private AlipayClient getAlipayClient() {
return new DefaultAlipayClient(
gatewayUrl, appId, privateKey, "json", "UTF-8",
aliPayPublicKey, "RSA2");
}
// 创建支付订单
@PostMapping("/create")
public Map<String, Object> createPayment(@RequestBody PaymentOrder paymentOrder) {
Map<String, Object> result = new HashMap<>();
try {
// 生成订单号
String outTradeNo = orderService.generateOrderId();
paymentOrder.setOrderId(outTradeNo);
// 保存订单信息到数据库
orderService.saveOrder(paymentOrder);
// 设置回调地址(如果前端传入了自定义returnUrl,则使用前端提供的)
String actualReturnUrl = paymentOrder.getReturnUrl() != null ?
paymentOrder.getReturnUrl() : returnUrl;
// 创建支付宝支付请求
AlipayClient alipayClient = getAlipayClient();
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
// 设置异步通知地址
request.setNotifyUrl(notifyUrl);
// 设置同步返回地址
request.setReturnUrl(actualReturnUrl);
// 设置请求参数
model.setOutTradeNo(outTradeNo);
model.setProductCode("FAST_INSTANT_TRADE_PAY"); // PC场景固定值
model.setTotalAmount(paymentOrder.getTotalAmount().toString());
model.setSubject(paymentOrder.getSubject());
model.setBody(paymentOrder.getBody());
request.setBizModel(model);
// 获取支付表单
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
result.put("success", true);
// 返回支付相关信息
Map<String, Object> data = new HashMap<>();
data.put("orderId", outTradeNo);
data.put("paymentFormHtml", response.getBody()); // 完整的支付表单HTML
result.put("data", data);
result.put("message", "订单创建成功");
} else {
result.put("success", false);
result.put("message", "创建支付订单失败: " + response.getMsg());
}
} catch (AlipayApiException e) {
result.put("success", false);
result.put("message", "支付接口异常: " + e.getMessage());
logger.error("支付接口异常: ", e);
} catch (Exception e) {
result.put("success", false);
result.put("message", "系统异常: " + e.getMessage());
logger.error("系统异常: ", e);
}
return result;
}
// 查询支付状态
@GetMapping("/status/{orderId}")
public Map<String, Object> checkPaymentStatus(@PathVariable String orderId) {
Map<String, Object> result = new HashMap<>();
try {
// 先查询订单数据库记录
PaymentOrder orderInfo = orderService.getOrderById(orderId);
if (orderInfo == null) {
result.put("success", false);
result.put("message", "订单不存在");
return result;
}
// 如果订单已支付,直接返回结果
if ("TRADE_SUCCESS".equals(orderInfo.getStatus()) ||
"TRADE_FINISHED".equals(orderInfo.getStatus())) {
result.put("success", true);
Map<String, Object> data = new HashMap<>();
data.put("status", orderInfo.getStatus());
result.put("data", data);
return result;
}
// 调用支付宝接口查询订单状态
AlipayClient alipayClient = getAlipayClient();
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo(orderId);
request.setBizModel(model);
AlipayTradeQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
// 更新订单状态
String tradeStatus = response.getTradeStatus();
orderService.updateOrderStatus(orderId, tradeStatus, response.getTradeNo());
result.put("success", true);
Map<String, Object> data = new HashMap<>();
data.put("status", tradeStatus);
result.put("data", data);
} else {
result.put("success", false);
result.put("message", "查询订单状态失败: " + response.getMsg());
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "系统异常: " + e.getMessage());
}
return result;
}
// 取消支付
@PostMapping("/cancel/{orderId}")
public Map<String, Object> cancelPayment(@PathVariable String orderId) {
Map<String, Object> result = new HashMap<>();
try {
// 查询订单状态
PaymentOrder orderInfo = orderService.getOrderById(orderId);
if (orderInfo == null) {
result.put("success", false);
result.put("message", "订单不存在");
return result;
}
// 如果已支付,不能取消
if ("TRADE_SUCCESS".equals(orderInfo.getStatus()) ||
"TRADE_FINISHED".equals(orderInfo.getStatus())) {
result.put("success", false);
result.put("message", "订单已支付,无法取消");
return result;
}
// 调用支付宝接口关闭交易
AlipayClient alipayClient = getAlipayClient();
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
AlipayTradeCloseModel model = new AlipayTradeCloseModel();
model.setOutTradeNo(orderId);
request.setBizModel(model);
alipayClient.execute(request);
// 更新订单状态为已取消
orderService.updateOrderStatus(orderId, "TRADE_CLOSED", null);
result.put("success", true);
result.put("message", "订单已取消");
} catch (Exception e) {
result.put("success", false);
result.put("message", "取消订单异常: " + e.getMessage());
}
return result;
}
// 处理支付宝异步通知
@PostMapping("/notify")
public String handlePaymentNotify(@RequestParam Map<String, String> params) {
try {
// 这里需要验证支付宝的通知签名
boolean signVerified = orderService.verifyAlipayNotify(params);
if (signVerified) {
// 验证订单金额等关键信息
String outTradeNo = params.get("outTradeNo");
String tradeStatus = params.get("tradeStatus");
String tradeNo = params.get("tradeNo");
String totalAmount = params.get("total_amount");
PaymentOrder orderInfo = orderService.getOrderById(outTradeNo);
if (orderInfo != null &&
orderInfo.getTotalAmount().toString().equals(totalAmount)) {
if ("TRADE_SUCCESS".equals(tradeStatus) ||
"TRADE_FINISHED".equals(tradeStatus)) {
// 更新订单状态
orderService.updateOrderStatus(outTradeNo, tradeStatus, tradeNo);
}
}
return "success";
} else {
return "fail";
}
} catch (Exception e) {
return "fail";
}
}
// 验证支付结果
@PostMapping("/verify")
public Map<String, Object> verifyPayment(@RequestBody Map<String, String> params) {
Map<String, Object> result = new HashMap<>();
try {
String outTradeNo = params.get("outTradeNo");
String tradeNo = params.get("tradeNo");
String tradeStatus = params.get("tradeStatus");
if (outTradeNo == null || tradeNo == null) {
result.put("success", false);
result.put("message", "缺少必要参数");
return result;
}
// 调用支付宝查询订单接口验证
AlipayClient alipayClient = getAlipayClient();
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo(outTradeNo);
model.setTradeNo(tradeNo);
request.setBizModel(model);
AlipayTradeQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
// 验证状态
if ("TRADE_SUCCESS".equals(response.getTradeStatus()) ||
"TRADE_FINISHED".equals(response.getTradeStatus())) {
// 更新订单状态
orderService.updateOrderStatus(outTradeNo, response.getTradeStatus(), tradeNo);
result.put("success", true);
result.put("message", "支付验证成功");
} else {
result.put("success", false);
result.put("message", "订单未完成支付");
}
} else {
result.put("success", false);
result.put("message", "订单验证失败: " + response.getMsg());
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "验证异常: " + e.getMessage());
}
return result;
}
}
ServiceImpl
/**
* 订单服务实现类
*/
@Service
public class OrderServiceImpl extends ServiceImpl<PaymentOrderMapper, PaymentOrder> implements IOrderService {
@Value("${alipay.public-key}")
private String alipayPublicKey;
@Value("${alipay.charset}")
private String charset;
@Value("${alipay.sign-type}")
private String signType;
@Resource
RecorddruginfoMapper recorddruginfoMapper;
/**
* 生成订单ID - 格式: 年月日时分秒 + 4位随机数
* 例如: 2023102010303012345
*/
@Override
public String generateOrderId() {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String timeStr = format.format(new Date());
// 生成4位随机数
Random random = new Random();
int randomNum = random.nextInt(10000);
String randomStr = String.format("%04d", randomNum);
return timeStr + randomStr;
}
/**
* 保存订单信息
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveOrder(PaymentOrder paymentOrder) {
// 设置初始订单状态为等待支付
paymentOrder.setStatus("WAIT_BUYER_PAY");
paymentOrder.setCreateTime(new Date());
return baseMapper.insert(paymentOrder) > 0;
}
/**
* 根据订单ID查询订单
*/
@Override
public PaymentOrder getOrderById(String orderId) {
return baseMapper.selectOne(new LambdaQueryWrapper<PaymentOrder>().eq(PaymentOrder::getOrderId, orderId));
}
/**
* 更新订单状态
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateOrderStatus(String orderId, String status, String tradeNo) {
PaymentOrder order = baseMapper.selectOne(new LambdaQueryWrapper<PaymentOrder>().eq(PaymentOrder::getOrderId, orderId));
if (order == null) {
return false;
}
order.setStatus(status);
if (tradeNo != null) {
order.setTradeNo(tradeNo);
}
order.setUpdateTime(new Date());
boolean flag = baseMapper.updateById(order) > 0;
if (flag && "TRADE_SUCCESS".equals(status)) {
Recorddruginfo recorddruginfo = recorddruginfoMapper.selectById(order.getRecordId());
if (null != recorddruginfo) {
recorddruginfo.setActualNum(recorddruginfo.getActualNum() + order.getQuantity());
recorddruginfo.setDistributeStatus(0);
recorddruginfoMapper.updateById(recorddruginfo);
}
}
return flag;
}
/**
* 验证支付宝异步通知签名
*/
@Override
public boolean verifyAlipayNotify(Map<String, String> params) {
try {
return AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
charset,
signType
);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class PaymentOrder implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "订单ID (同时也是商户订单号)")
private String orderId;
@ApiModelProperty(value = "就诊记录ID")
private Integer recordId;
@ApiModelProperty(value = "用户ID")
private Integer userId;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "药品ID")
private Integer drugId;
@ApiModelProperty(value = "药品名称")
private String drugName;
@ApiModelProperty(value = "购买数量")
private Integer quantity;
@ApiModelProperty(value = "订单总金额")
private BigDecimal totalAmount;
@ApiModelProperty(value = "订单标题")
private String subject;
@ApiModelProperty(value = "订单描述")
private String body;
@ApiModelProperty(value = "支付宝交易号")
private String tradeNo;
/**
* 订单状态
* WAIT_BUYER_PAY (交易创建,等待买家付款)
* TRADE_CLOSED (未付款交易超时关闭,或支付完成后全额退款)
* TRADE_SUCCESS (交易支付成功)
* TRADE_FINISHED (交易结束,不可退款)
*/
@ApiModelProperty(value = "订单状态")
private String status;
@ApiModelProperty(value = "支付完成后的前端回调地址")
private String returnUrl;
@ApiModelProperty(value = "创建时间")
private Integer createUser;
@ApiModelProperty(value = "创建时间")
private Date createTime;
@ApiModelProperty(value = "更新时间")
private Date updateTime;
}
3.3 Vue
<template>
……
<el-dialog title="购买" :visible.sync="dialogVisible" width="35%">
<el-form v-if="!isPaying && !paymentVisible">
<el-form-item label="请输入加购数量">
<el-input v-model.number="addBuyNum" @input="calculate"></el-input>
</el-form-item>
<el-form-item>
<span>共计:{{ totalPrice }} 元</span>
</el-form-item>
</el-form>
<div v-if="isPaying && !paymentVisible" class="payment-loading">
<el-progress type="circle" :percentage="paymentProgress"></el-progress>
<p>正在创建订单,请稍后...</p>
</div>
<div v-if="paymentVisible" class="payment-iframe-container">
<div v-if="paymentQrCode" class="payment-qrcode">
<img :src="paymentQrCode" alt="支付二维码" />
<p>请使用支付宝扫码支付</p>
</div>
<div v-else-if="paymentFormHtml" v-html="paymentFormHtml"></div>
<iframe v-else-if="paymentUrl" :src="paymentUrl" frameborder="0" width="100%" height="500px"></iframe>
</div>
<div slot="footer" class="dialog-footer">
<template v-if="!isPaying && !paymentVisible">
<el-button :disabled="disabledBuyConfirmButton" round class="bg16d" @click="doSubmit">确定</el-button>
<el-button round @click="closeBuyDialog">取 消</el-button>
</template>
<template v-if="paymentVisible">
<el-button type="primary" round @click="checkPaymentStatus">检查支付状态</el-button>
<el-button round @click="cancelPayment">取消支付</el-button>
</template>
</div>
</el-dialog>
……
</template>
<script>
import axios from 'axios' // 确保项目中已安装并导入axios
export default {
data() {
return {
userSearchKeyWord: '',
pageIndex: 1,
pageSize: 10,
total: 0,
tableData: [], // 分页记录
dialogVisible: false,
currentRow: {},
addBuyNum: 0,
totalPrice: 0.0,
disabledBuyConfirmButton: true,
isPaying: false, // 支付状态标识
paymentProgress: 0, // 支付进度
paymentVisible: false, // 是否显示支付界面
paymentUrl: '', // 支付链接URL
paymentFormHtml: '', // 支付表单HTML
paymentQrCode: '', // 支付二维码图片
orderId: '', // 订单ID
progressInterval: null, // 进度条定时器
paymentCheckInterval: null, // 支付状态检查定时器
};
},
watch: {
$route() {
const index = window.location.href.lastIndexOf('/');
this.url = window.location.href.substring(index + 1);
}
},
created() {
this.doSearch();
this.checkPaymentCallback();
},
beforeDestroy() {
// 清除所有定时器
if (this.progressInterval) {
clearInterval(this.progressInterval);
}
if (this.paymentCheckInterval) {
clearInterval(this.paymentCheckInterval);
}
},
methods: {
// 检查URL中是否包含支付回调参数
checkPaymentCallback() {
const queryParams = new URLSearchParams(window.location.search);
const outTradeNo = queryParams.get('out_trade_no');
const tradeNo = queryParams.get('trade_no');
const tradeStatus = queryParams.get('tradeStatus');
// 如果包含这些参数,说明是从支付宝回调回来的
if (outTradeNo && tradeNo) {
// 验证支付状态
this.verifyPayment(outTradeNo, tradeNo, tradeStatus);
}
},
// 验证支付结果
async verifyPayment(outTradeNo, tradeNo, tradeStatus) {
try {
const response = await axios.post('/api/payment/verify', {
outTradeNo: outTradeNo,
tradeNo: tradeNo,
tradeStatus: tradeStatus
});
console.log("verifyPayment0");
if (response.success) {
this.$message.success('支付验证成功!');
// 清除URL中的查询参数(避免刷新重复处理)
window.history.replaceState({}, document.title, window.location.pathname);
// 支付成功
clearInterval(this.paymentCheckInterval);
// 刷新数据列表
this.doSearch();
} else {
this.$message.error('支付验证失败:' + response.message);
}
} catch (error) {
console.error('支付验证异常:', error);
this.$message.error('支付验证发生错误,请联系客服');
}
},
// 查询
async doSearch() {
this.loading = true;
const res = await request.page({
pageSize: this.pageSize,
pageIndex: this.pageIndex,
userId: this.$store.getters.getUserInfo.id,
userSearchKeyWord: this.userSearchKeyWord,
});
this.tableData = res.records;
this.total = res.total;
this.pageSize = res.pageSize;
this.pageIndex = res.pageIndex;
this.loading = false;
},
closeBuyDialog() {
this.dialogVisible = false;
this.addBuyNum = 0;
this.totalPrice = 0.0;
this.isPaying = false;
this.paymentVisible = false;
this.paymentUrl = '';
this.paymentFormHtml = '';
this.paymentQrCode = '';
this.orderId = '';
this.doSearch();
// 清除定时器
if (this.progressInterval) {
clearInterval(this.progressInterval);
this.progressInterval = null;
}
if (this.paymentCheckInterval) {
clearInterval(this.paymentCheckInterval);
this.paymentCheckInterval = null;
}
},
// 搜索框清空
clearSearchValue() {
this.userSearchKeyWord = '';
this.doSearch();
},
// 分页功能
handleSizeChange(val) {
this.pageSize = val;
this.doSearch();
},
handleCurrentChange(val) {
this.pageIndex = val;
this.doSearch();
},
checkedRow(row) {
this.dialogVisible = true;
this.currentRow = row;
this.addBuyNum = 0;
this.totalPrice = 0.0;
this.disabledBuyConfirmButton = true;
},
calculate(addBuyNum) {
this.disabledBuyConfirmButton = true;
let totalActualNum = Number(addBuyNum) + Number(this.currentRow.actualNum);
if (addBuyNum <= 0 || totalActualNum > this.currentRow.adviceNum) {
this.$message({
type: 'error',
message: '加购数量为空或超过限制请重新输入,操作失败!'
});
} else {
this.totalPrice = (addBuyNum * this.currentRow.price).toFixed(2);
this.disabledBuyConfirmButton = false;
}
},
async doSubmit() {
this.$confirm('请确认是否购买并支付 ' + this.totalPrice + ' 元?', '确认支付', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.startPayment();
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消支付'
});
});
},
// 开始支付流程
startPayment() {
this.isPaying = true;
this.paymentProgress = 0;
// 使用定时器模拟进度增加
this.progressInterval = setInterval(() => {
if (this.paymentProgress < 90) {
this.paymentProgress += 10;
}
}, 300);
// 调用后端创建订单接口
this.createPaymentOrder();
},
// 创建支付订单
async createPaymentOrder() {
try {
// 构建订单信息
const orderData = {
userId: this.$store.getters.getUserInfo.id,
username: this.$store.getters.getUserInfo.username,
recordId: this.currentRow.id,
drugId: this.currentRow.drugId,
drugName: this.currentRow.drugName,
quantity: this.addBuyNum,
totalAmount: this.totalPrice,
subject: `购买药品: ${this.currentRow.drugName}`,
body: `购买${this.addBuyNum}个${this.currentRow.drugName},单价${this.currentRow.price}元`,
// 客户端支付完成后的回调地址
returnUrl: window.location.origin + window.location.pathname,
createUser: this.$store.getters.getUserInfo.id,
};
// 调用后端接口创建订单并获取支付信息
const response = await axios.post('/api/payment/create', orderData);
if (response.success) {
// 清除进度条定时器
clearInterval(this.progressInterval);
this.paymentProgress = 100;
// 设置订单ID
this.orderId = response.data.orderId;
// 处理支付方式 - 这是关键部分
setTimeout(() => {
this.isPaying = false;
if (response.data.payUrl) {
// 方式1: 直接跳转到支付宝支付页面
window.location.href = response.data.payUrl;
} else if (response.data.paymentFormHtml) {
// 方式2: 显示支付表单并自动提交
this.paymentVisible = true;
this.paymentFormHtml = response.data.paymentFormHtml;
// 关键代码: 自动提交表单
setTimeout(() => {
// 创建临时div存放表单
const div = document.createElement('div');
div.innerHTML = this.paymentFormHtml;
document.body.appendChild(div);
// 获取并提交表单
const form = div.getElementsByTagName('form')[0];
if (form) {
form.submit();
}
// 移除临时div
setTimeout(() => {
document.body.removeChild(div);
}, 100);
}, 10);
}
}, 500);
} else {
this.handlePaymentError(response.message || '创建订单失败');
}
} catch (error) {
console.error('创建支付订单异常:', error);
this.handlePaymentError('支付系统异常,请稍后再试');
}
},
// 开始定时检查支付状态
startPaymentStatusCheck() {
this.paymentCheckInterval = setInterval(() => {
this.checkPaymentStatus();
}, 5000); // 每5秒检查一次
},
// 检查支付状态
async checkPaymentStatus() {
try {
const response = await axios.get(`/api/payment/status/${this.orderId}`);
if (response.success) {
const status = response.status;
if (status === 'TRADE_SUCCESS' || status === 'TRADE_FINISHED') {
// 支付成功
clearInterval(this.paymentCheckInterval);
this.handlePaymentSuccess();
} else if (status === 'TRADE_CLOSED') {
// 交易关闭
clearInterval(this.paymentCheckInterval);
this.$message.warning('订单已关闭或取消');
this.closeBuyDialog();
}
}
} catch (error) {
console.error('检查支付状态异常:', error);
}
},
// 取消支付
async cancelPayment() {
try {
await axios.post(`/api/payment/cancel/${this.orderId}`);
this.$message.info('已取消支付');
this.closeBuyDialog();
} catch (error) {
console.error('取消支付异常:', error);
this.$message.error('取消支付失败,请稍后再试');
}
},
// 处理支付成功
async handlePaymentSuccess() {
this.$message.success('支付成功!');
// 更新药品购买信息
try {
const result = await request.edit({
id: this.currentRow.id,
actualNum: Number(this.currentRow.actualNum) + Number(this.addBuyNum),
distributeStatus: 0, // 待配送状态
});
if (!result) {
this.$message.error('更新药品购买信息失败');
} else {
this.$message.success('药品购买成功,等待配送');
}
} catch (error) {
console.error('更新药品信息异常:', error);
this.$message.error('更新药品信息失败');
}
// 关闭对话框并刷新列表
this.closeBuyDialog();
},
// 处理支付错误
handlePaymentError(message) {
// 清除进度定时器
if (this.progressInterval) {
clearInterval(this.progressInterval);
this.progressInterval = null;
}
this.isPaying = false;
this.$message.error(message);
},
},
};
</script>
<style lang="scss">
……
.payment-loading {
text-align: center;
padding: 20px 0;
p {
margin-top: 15px;
color: #606266;
}
}
.payment-iframe-container {
min-height: 200px;
.payment-qrcode {
text-align: center;
padding: 20px;
img {
max-width: 200px;
max-height: 200px;
}
p {
margin-top: 10px;
color: #606266;
}
}
}
}
</style>
4. 效果图
购买药品前
购买石膏
准备跳转支付页面
支付宝沙箱手机app可扫码完成付款,或者页面输入买家账号信息完成付款,两种均可
输入付款密码生成付款订单并跳转回购买页面
购买药品后显示购买数量,切换“待配送”状态
手机沙箱app查看付款详情