feat(payment): 初始化支付模块基础功能
- 添加订单号生成工具类 OrderIdGenerator - 定义订单状态枚举 OrderStatus - 实现OSS文件上传服务接口及阿里云OSS实现 - 添加支付常量类 PaymentConstants - 创建支付控制器 PaymentController 支持下单、查单和收银台页面 - 新增支付记录实体类 PaymentRecord 用于存储回调和查询记录
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
package com.mtkj.mtpay.controller;
|
||||
|
||||
import com.mtkj.mtpay.common.Result;
|
||||
import com.mtkj.mtpay.common.ResultCode;
|
||||
import com.mtkj.mtpay.dto.request.CheckoutRequestDTO;
|
||||
import com.mtkj.mtpay.entity.PaymentOrder;
|
||||
import com.mtkj.mtpay.service.PaymentOrderService;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 支付控制器
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/payment")
|
||||
@RequiredArgsConstructor
|
||||
public class PaymentController {
|
||||
|
||||
private final PaymentOrderService paymentOrderService;
|
||||
|
||||
/**
|
||||
* 创建支付订单
|
||||
*/
|
||||
@PostMapping("/checkout")
|
||||
public ResponseEntity<Result<Map<String, Object>>> checkout(@Valid @RequestBody CheckoutRequestDTO request) {
|
||||
log.info("收到创建支付订单请求,商户订单号: {}", request.getMerchantTransactionId());
|
||||
|
||||
PaymentOrder order = paymentOrderService.createPaymentOrder(request);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("merchantTransactionId", order.getMerchantTransactionId());
|
||||
data.put("token", order.getToken());
|
||||
data.put("paymentUrl", order.getPaymentUrl());
|
||||
data.put("status", order.getStatus());
|
||||
|
||||
return ResponseEntity.ok(Result.success("订单创建成功", data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单状态
|
||||
*/
|
||||
@GetMapping("/order/{merchantTransactionId}")
|
||||
public ResponseEntity<Result<Map<String, Object>>> getOrder(@PathVariable String merchantTransactionId) {
|
||||
log.info("查询订单状态,商户订单号: {}", merchantTransactionId);
|
||||
|
||||
Optional<PaymentOrder> orderOpt = paymentOrderService.findByMerchantTransactionId(merchantTransactionId);
|
||||
|
||||
if (orderOpt.isPresent()) {
|
||||
PaymentOrder order = orderOpt.get();
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("merchantTransactionId", order.getMerchantTransactionId());
|
||||
data.put("transactionId", order.getTransactionId() != null ? order.getTransactionId() : "");
|
||||
data.put("status", order.getStatus());
|
||||
data.put("amount", order.getAmount());
|
||||
data.put("currency", order.getCurrency());
|
||||
data.put("createTime", order.getCreateTime());
|
||||
data.put("token", order.getToken());
|
||||
data.put("paymentUrl", order.getPaymentUrl());
|
||||
|
||||
return ResponseEntity.ok(Result.success(data));
|
||||
} else {
|
||||
return ResponseEntity.ok(Result.fail(ResultCode.ORDER_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收银台页面HTML
|
||||
* 返回包含SDK初始化的HTML页面
|
||||
*/
|
||||
@GetMapping("/checkout/page")
|
||||
public ResponseEntity<String> getCheckoutPage(@RequestParam String token) {
|
||||
log.info("获取收银台页面,token: {}", token);
|
||||
|
||||
String html = generateCheckoutPage(token);
|
||||
return ResponseEntity.ok()
|
||||
.header("Content-Type", "text/html;charset=UTF-8")
|
||||
.body(html);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成收银台页面HTML
|
||||
*/
|
||||
private String generateCheckoutPage(String token) {
|
||||
return """
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>PingPong支付收银台</title>
|
||||
<style>
|
||||
#ufo-container {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="ufo-container"></div>
|
||||
<script src="https://pay-cdn.pingpongx.com/production/static/sdk/1.2.0/ppPay.min.js"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
let client = new ppPay({
|
||||
lang: 'zh',
|
||||
root: '#ufo-container',
|
||||
manul: false,
|
||||
located: true,
|
||||
showPrice: true,
|
||||
bill: true,
|
||||
mode: 'sandbox',
|
||||
menu: false,
|
||||
base: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
fontSize: '14px',
|
||||
backgroundColor: '#fff',
|
||||
showHeader: true,
|
||||
showHeaderLabel: true,
|
||||
headerLabelFont: "支付",
|
||||
headerColor: '#333333',
|
||||
headerSize: '16px',
|
||||
headerBackgroundColor: '#fff',
|
||||
headerPadding: '20px',
|
||||
btnSize: '100%',
|
||||
btnColor: '#fff',
|
||||
btnFontSize: '14px',
|
||||
btnPaddingX: '20px',
|
||||
btnPaddingY: '10px',
|
||||
btnBackgroundColor: '#1fa0e8',
|
||||
btnBorderRadius: '4px',
|
||||
btnMarginTop: '20px'
|
||||
}
|
||||
});
|
||||
|
||||
let sdkConfig = {
|
||||
token: '%s'
|
||||
};
|
||||
|
||||
client.createPayment(sdkConfig);
|
||||
|
||||
function setPPPayPropWin() {
|
||||
let winWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||
let winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
|
||||
let ufoContainer = document.getElementById('ufo-container');
|
||||
|
||||
if (winWidth >= 500) {
|
||||
let clientW = Math.floor(winWidth / 3);
|
||||
clientW = clientW >= 500 ? clientW : 500;
|
||||
ufoContainer.style.width = clientW + 'px';
|
||||
} else {
|
||||
ufoContainer.style.width = winWidth + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
setPPPayPropWin();
|
||||
window.addEventListener('resize', setPPPayPropWin);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
""".formatted(token);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user