This commit is contained in:
menxipeng
2025-08-03 16:56:44 +08:00
parent d6c5934dba
commit 85375b7f0c
18 changed files with 1627 additions and 282 deletions

View File

@@ -0,0 +1,198 @@
# 订单支付API文档
## 概述
本文档描述了客户端订单支付相关的API接口包括创建订单、支付、退款等完整流程。
## 基础信息
- 基础URL: `/client/order`
- 请求方式: REST API
- 数据格式: JSON
- 认证方式: Token认证
## 订单状态说明
- 1: 已创建 - 订单创建成功,等待支付
- 2: 已支付 - 支付成功,等待服务开始
- 3: 已完成 - 服务完成
- 4: 已退款 - 订单已退款
- 5: 已取消 - 订单已取消
## 支付方式
- aliPay: 支付宝支付
- wechatPay: 微信支付
- applePay: Apple Pay支付
## API接口
### 1. 创建订单
**接口地址**: `POST /client/order/create`
**请求参数**:
```json
{
"orderName": "VIP会员包月",
"amount": 9900,
"payType": "aliPay",
"packageType": "1",
"deviceType": "android"
}
```
**响应示例**:
```json
{
"code": 200,
"msg": "订单创建成功",
"data": {
"id": "uuid",
"orderId": 1706342400000,
"orderName": "VIP会员包月",
"userId": 1,
"amount": 9900,
"payType": "aliPay",
"payStatus": 1,
"packageType": "1",
"deviceType": "android",
"createTime": "2025-01-27 10:00:00"
}
}
```
### 2. 支付订单
**接口地址**: `POST /client/order/pay`
**请求参数**:
```json
{
"orderId": "1706342400000",
"payType": "aliPay",
"deviceType": "android",
"paymentParams": "{}"
}
```
**响应示例**:
```json
{
"code": 200,
"msg": "支付请求成功",
"data": {
"paymentUrl": "https://openapi.alipay.com/gateway.do?",
"orderId": "1706342400000",
"amount": 9900,
"payType": "aliPay"
}
}
```
### 3. 支付回调
**接口地址**: `POST /client/order/callback`
**请求参数**:
- orderId: 订单ID
- tradeNo: 第三方交易号
- payType: 支付方式
**响应示例**:
```json
{
"code": 200,
"msg": "支付完成"
}
```
### 4. 申请退款
**接口地址**: `POST /client/order/refund`
**请求参数**:
```json
{
"orderId": "1706342400000",
"refundAmount": 9900,
"refundReason": "用户申请退款",
"refundType": 1
}
```
**响应示例**:
```json
{
"code": 200,
"msg": "退款申请成功"
}
```
### 5. 查询用户订单列表
**接口地址**: `GET /client/order/list`
**响应示例**:
```json
{
"code": 200,
"msg": "查询成功",
"data": [
{
"id": "uuid",
"orderId": "1706342400000",
"orderName": "VIP会员包月",
"amount": 9900,
"payType": "aliPay",
"payStatus": 2,
"payTime": "2025-01-27 10:05:00",
"startTime": "2025-01-27 10:05:00",
"endTime": "2025-02-27 10:05:00",
"createTime": "2025-01-27 10:00:00"
}
]
}
```
### 6. 查询订单详情
**接口地址**: `GET /client/order/detail/{orderId}`
**响应示例**:
```json
{
"code": 200,
"msg": "查询成功",
"data": {
"id": "uuid",
"orderId": "1706342400000",
"orderName": "VIP会员包月",
"userId": 1,
"amount": 9900,
"payType": "aliPay",
"payStatus": 2,
"payTime": "2025-01-27 10:05:00",
"startTime": "2025-01-27 10:05:00",
"endTime": "2025-02-27 10:05:00",
"tradeNo": "2025012722001234567890",
"createTime": "2025-01-27 10:00:00",
"updateTime": "2025-01-27 10:05:00"
}
}
```
## 错误码说明
- 200: 成功
- 400: 请求参数错误
- 401: 用户未登录
- 403: 权限不足
- 404: 资源不存在
- 500: 服务器内部错误
## 套餐类型说明
- 1: 包月
- 3: 包季度
- 6: 半年
- 12: 一年
## 设备类型说明
- android: Android设备
- ios: iOS设备
## 注意事项
1. 所有金额单位为分
2. 支付回调需要验证签名
3. 退款只能对已支付的订单进行
4. 订单创建后需要在指定时间内完成支付
5. 支付成功后会自动计算服务时间

View File

@@ -75,13 +75,6 @@ public class ActivityInfoController extends BaseController
// @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT)
@PostMapping("/addActivity")
public AjaxResult add(@RequestBody ActivityInfo activityInfo) throws IOException {
// ActivityInfo activityInfo = new ActivityInfo();
// String imgAddr = AliConfig.ossUp("config/" , Objects.requireNonNull(file.getOriginalFilename()), file.getInputStream());
// activityInfo.setImg("");
// activityInfo.setName(name);
// activityInfo.setContent(content);
// activityInfo.setStartTime(DateUtil.parseDateTime(startTime));
// activityInfo.setEndTime(DateUtil.parseDateTime(endTime));
return toAjax(activityInfoService.insertActivityInfo(activityInfo));
}

View File

@@ -4,6 +4,7 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -22,7 +23,7 @@ import java.util.List;
* @date 2025-08-03
*/
@RestController
@RequestMapping("/back/info")
@RequestMapping("/back/order")
public class OrderInfoController extends BaseController
{
@Autowired
@@ -40,6 +41,18 @@ public class OrderInfoController extends BaseController
return getDataTable(list);
}
/**
* 查询订单详细信息列表
*/
// @PreAuthorize("@ss.hasPermi('system:info:list')")
@GetMapping("/detailList")
public TableDataInfo detailList(OrderInfo orderInfo)
{
startPage();
List<OrderInfoVO> list = orderInfoService.selectOrderInfoVOList(orderInfo);
return getDataTable(list);
}
/**
* 导出【请填写功能名称】列表
*/
@@ -53,6 +66,19 @@ public class OrderInfoController extends BaseController
util.exportExcel(response, list, "【请填写功能名称】数据");
}
/**
* 导出订单详细信息列表
*/
@PreAuthorize("@ss.hasPermi('system:info:export')")
@Log(title = "订单详细信息", businessType = BusinessType.EXPORT)
@PostMapping("/exportDetail")
public void exportDetail(HttpServletResponse response, OrderInfo orderInfo)
{
List<OrderInfoVO> list = orderInfoService.selectOrderInfoVOList(orderInfo);
ExcelUtil<OrderInfoVO> util = new ExcelUtil<OrderInfoVO>(OrderInfoVO.class);
util.exportExcel(response, list, "订单详细信息数据");
}
/**
* 获取【请填写功能名称】详细信息
*/
@@ -95,4 +121,15 @@ public class OrderInfoController extends BaseController
{
return toAjax(orderInfoService.deleteOrderInfoByIds(ids));
}
/**
* 确认出货
*/
@PreAuthorize("@ss.hasPermi('system:info:edit')")
@Log(title = "确认出货", businessType = BusinessType.UPDATE)
@PostMapping("/confirmShipment/{orderId}")
public AjaxResult confirmShipment(@PathVariable String orderId)
{
return orderInfoService.confirmShipment(orderId);
}
}

View File

@@ -1,19 +1,27 @@
package com.ruoyi.web.controller.client;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.dto.OrderCreateRequest;
import com.ruoyi.common.core.domain.dto.PaymentRequest;
import com.ruoyi.common.core.domain.dto.RefundRequest;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.service.IOrderInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* 【请填写功能名称】Controller
* 客户端订单Controller
*
* @author ruoyi
* @date 2025-08-03
* @date 2025-01-27
*/
@RestController
@RequestMapping("/client/order")
@@ -22,13 +30,137 @@ public class ClientOrderInfoController extends BaseController
@Autowired
private IOrderInfoService orderInfoService;
// 创建订单
/**
* 创建订单
*/
@Log(title = "创建订单", businessType = BusinessType.INSERT)
@PostMapping("/create")
public void crateOrder(@RequestBody OrderInfo orderInfo){
orderInfoService.createOrder(orderInfo);
public AjaxResult createOrder(@RequestBody OrderCreateRequest request, HttpServletRequest httpRequest) {
try {
// 获取客户端IP
String clientIp = getClientIp(httpRequest);
request.setClientIp(clientIp);
return orderInfoService.createOrder(request);
} catch (Exception e) {
return AjaxResult.error("创建订单失败: " + e.getMessage());
}
}
/**
* 支付订单
*/
@Log(title = "支付订单", businessType = BusinessType.UPDATE)
@PostMapping("/pay")
public AjaxResult payOrder(@RequestBody PaymentRequest request) {
try {
return orderInfoService.payOrder(request);
} catch (Exception e) {
return AjaxResult.error("支付失败: " + e.getMessage());
}
}
/**
* 支付回调
*/
@PostMapping("/callback")
public AjaxResult paymentCallback(@RequestParam("orderId") String orderId,
@RequestParam("tradeNo") String tradeNo,
@RequestParam("payType") String payType) {
try {
return orderInfoService.completePayment(orderId, tradeNo, payType);
} catch (Exception e) {
return AjaxResult.error("支付回调处理失败: " + e.getMessage());
}
}
/**
* 确认出货
*/
@Log(title = "确认出货", businessType = BusinessType.UPDATE)
@PostMapping("/confirmShipment")
public AjaxResult confirmShipment(@RequestParam("orderId") String orderId) {
try {
return orderInfoService.confirmShipment(orderId);
} catch (Exception e) {
return AjaxResult.error("确认出货失败: " + e.getMessage());
}
}
/**
* 申请退款
*/
@Log(title = "申请退款", businessType = BusinessType.UPDATE)
@PostMapping("/refund")
public AjaxResult refundOrder(@RequestBody RefundRequest request) {
try {
return orderInfoService.refundOrder(request);
} catch (Exception e) {
return AjaxResult.error("退款申请失败: " + e.getMessage());
}
}
/**
* 查询用户订单列表
*/
@GetMapping("/list")
public AjaxResult getUserOrders() {
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
return AjaxResult.error("用户未登录");
}
List<OrderInfo> orders = orderInfoService.selectUserOrders(loginUser.getUserId());
return AjaxResult.success("查询成功", orders);
} catch (Exception e) {
return AjaxResult.error("查询订单失败: " + e.getMessage());
}
}
/**
* 查询订单详情
*/
@GetMapping("/detail/{orderId}")
public AjaxResult getOrderDetail(@PathVariable String orderId) {
try {
OrderInfo orderInfo = orderInfoService.selectOrderByOrderId(orderId);
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查用户权限
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || !loginUser.getUserId().equals(orderInfo.getUserId())) {
return AjaxResult.error("无权限查看此订单");
}
return AjaxResult.success("查询成功", orderInfo);
} catch (Exception e) {
return AjaxResult.error("查询订单详情失败: " + e.getMessage());
}
}
/**
* 获取客户端IP地址
*/
private String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}

View File

@@ -1,62 +1,62 @@
package com.ruoyi.common.config;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* 描述:
*
* @author menxipeng by 2023/12/15
*/
@Getter
@Component
public class AliPayConfig {
@Value("${alipay.gateway}")
private String aliPayGateway;
@Value("${alipay.appid}")
private String aliPayAppid;
@Value("${alipay.privateKey}")
private String aliPayPrivateKey;
@Value("${alipay.publicKey}")
private String aliPayPublicKey;
@Value("${alipay.merchantCertPath}")
private String merchantCertPath;
@Value("${alipay.alipayCertPath}")
private String alipayCertPath;
@Value("${alipay.alipayRootCertPath}")
private String alipayRootCertPath;
@Value("${alipay.notifyUrl}")
private String aliPayNotifyUrl;
@Value("${alipay.authUrl}")
private String aliPayAuthUrl;
@Value("${alipay.timeout}")
private Integer aliTimeOut;
@Bean
public void init() {
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi.alipay.com";
config.signType = "RSA2";
config.appId = aliPayAppid;
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
config.merchantPrivateKey = aliPayPrivateKey;
//注证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径优先从文件系统中加载加载失败后会继续尝试从CLASS_PATH中加载
config.merchantCertPath = merchantCertPath;
config.alipayCertPath = alipayCertPath;
config.alipayRootCertPath = alipayRootCertPath;
//注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
//可设置异步通知接收服务地址(可选)
config.notifyUrl = aliPayNotifyUrl;
Factory.setOptions(config);
}
}
//package com.ruoyi.common.config;
//
//import com.alipay.easysdk.factory.Factory;
//import com.alipay.easysdk.kernel.Config;
//import lombok.Getter;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.context.annotation.Bean;
//import org.springframework.stereotype.Component;
//
///**
// * 描述:
// *
// * @author menxipeng by 2023/12/15
// */
//@Getter
//@Component
//public class AliPayConfig {
//
// @Value("${alipay.gateway}")
// private String aliPayGateway;
// @Value("${alipay.appid}")
// private String aliPayAppid;
// @Value("${alipay.privateKey}")
// private String aliPayPrivateKey;
// @Value("${alipay.publicKey}")
// private String aliPayPublicKey;
// @Value("${alipay.merchantCertPath}")
// private String merchantCertPath;
// @Value("${alipay.alipayCertPath}")
// private String alipayCertPath;
// @Value("${alipay.alipayRootCertPath}")
// private String alipayRootCertPath;
// @Value("${alipay.notifyUrl}")
// private String aliPayNotifyUrl;
// @Value("${alipay.authUrl}")
// private String aliPayAuthUrl;
// @Value("${alipay.timeout}")
// private Integer aliTimeOut;
//
//
// @Bean
// public void init() {
// Config config = new Config();
// config.protocol = "https";
// config.gatewayHost = "openapi.alipay.com";
// config.signType = "RSA2";
//
// config.appId = aliPayAppid;
// // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
// config.merchantPrivateKey = aliPayPrivateKey;
// //注证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径优先从文件系统中加载加载失败后会继续尝试从CLASS_PATH中加载
// config.merchantCertPath = merchantCertPath;
// config.alipayCertPath = alipayCertPath;
// config.alipayRootCertPath = alipayRootCertPath;
// //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
// //可设置异步通知接收服务地址(可选)
// config.notifyUrl = aliPayNotifyUrl;
//
// Factory.setOptions(config);
// }
//
//}

View File

@@ -0,0 +1,80 @@
package com.ruoyi.common.core.domain.dto;
import java.io.Serializable;
/**
* 订单创建请求DTO
*
* @author ruoyi
* @date 2025-01-27
*/
public class OrderCreateRequest implements Serializable {
private static final long serialVersionUID = 1L;
/** 订单名称 */
private String orderName;
/** 金额(分) */
private Long amount;
/** 支付方式 aliPay/wechatPay/applePay */
private String payType;
/** 套餐类型 1包月 3包季度 6半年 12一年 */
private String packageType;
/** 设备类型 android/ios */
private String deviceType;
/** 客户端IP */
private String clientIp;
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Long getAmount() {
return amount;
}
public void setAmount(Long amount) {
this.amount = amount;
}
public String getPayType() {
return payType;
}
public void setPayType(String payType) {
this.payType = payType;
}
public String getPackageType() {
return packageType;
}
public void setPackageType(String packageType) {
this.packageType = packageType;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getClientIp() {
return clientIp;
}
public void setClientIp(String clientIp) {
this.clientIp = clientIp;
}
}

View File

@@ -0,0 +1,124 @@
package com.ruoyi.common.core.domain.dto;
import java.io.Serializable;
/**
* 支付请求DTO
*
* @author ruoyi
* @date 2025-01-27
*/
public class PaymentRequest implements Serializable {
private static final long serialVersionUID = 1L;
/** 订单ID */
private String orderId;
/** 支付方式 aliPay/wechatPay/applePay */
private String payType;
/** 设备类型 android/ios */
private String deviceType;
/** 商品标题 */
private String subject;
/** 商品描述 */
private String body;
/** 附加数据 */
private String attach;
/** 用户openid(微信支付专用) */
private String openid;
/** 商户标识符(Apple Pay专用) */
private String merchantIdentifier;
/** 支付令牌(Apple Pay专用) */
private String paymentToken;
/** 订单超时时间(分钟) */
private Integer timeoutMinutes;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getPayType() {
return payType;
}
public void setPayType(String payType) {
this.payType = payType;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getMerchantIdentifier() {
return merchantIdentifier;
}
public void setMerchantIdentifier(String merchantIdentifier) {
this.merchantIdentifier = merchantIdentifier;
}
public String getPaymentToken() {
return paymentToken;
}
public void setPaymentToken(String paymentToken) {
this.paymentToken = paymentToken;
}
public Integer getTimeoutMinutes() {
return timeoutMinutes;
}
public void setTimeoutMinutes(Integer timeoutMinutes) {
this.timeoutMinutes = timeoutMinutes;
}
}

View File

@@ -0,0 +1,58 @@
package com.ruoyi.common.core.domain.dto;
import java.io.Serializable;
/**
* 退款请求DTO
*
* @author ruoyi
* @date 2025-01-27
*/
public class RefundRequest implements Serializable {
private static final long serialVersionUID = 1L;
/** 订单ID */
private String orderId;
/** 退款金额(分) */
private Long refundAmount;
/** 退款原因 */
private String refundReason;
/** 退款方式 1全额退款 2部分退款 */
private Integer refundType;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Long getRefundAmount() {
return refundAmount;
}
public void setRefundAmount(Long refundAmount) {
this.refundAmount = refundAmount;
}
public String getRefundReason() {
return refundReason;
}
public void setRefundReason(String refundReason) {
this.refundReason = refundReason;
}
public Integer getRefundType() {
return refundType;
}
public void setRefundType(Integer refundType) {
this.refundType = refundType;
}
}

View File

@@ -0,0 +1,127 @@
package com.ruoyi.common.core.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import java.math.BigDecimal;
import java.util.Date;
/**
* 订单信息VO
*
* @author ruoyi
* @date 2025-01-27
*/
public class OrderInfoVO {
/** 订单号 */
@Excel(name = "订单号")
private Long orderId;
/** 用户昵称 */
@Excel(name = "用户昵称")
private String userNickname;
/** 套餐名称 */
@Excel(name = "套餐名称")
private String packageName;
/** 支付金额(元) */
@Excel(name = "支付金额(元)")
private BigDecimal amountYuan;
/** 支付方式 */
@Excel(name = "支付方式")
private String payTypeName;
/** 开通时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "开通时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/** 到期时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "到期时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/** 订单状态 */
@Excel(name = "订单状态")
private String statusName;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public String getUserNickname() {
return userNickname;
}
public void setUserNickname(String userNickname) {
this.userNickname = userNickname;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public BigDecimal getAmountYuan() {
return amountYuan;
}
public void setAmountYuan(BigDecimal amountYuan) {
this.amountYuan = amountYuan;
}
public String getPayTypeName() {
return payTypeName;
}
public void setPayTypeName(String payTypeName) {
this.payTypeName = payTypeName;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getStatusName() {
return statusName;
}
public void setStatusName(String statusName) {
this.statusName = statusName;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}

View File

@@ -0,0 +1,41 @@
package com.ruoyi.common.enums;
/**
* 订单状态枚举
*
* @author ruoyi
* @date 2025-01-27
*/
public enum OrderStatus {
CREATED(1L, "已创建"),
PAID(2L, "已支付"),
COMPLETED(3L, "已完成"),
REFUNDED(4L, "已退款"),
CANCELLED(5L, "已取消");
private final Long code;
private final String description;
OrderStatus(Long code, String description) {
this.code = code;
this.description = description;
}
public Long getCode() {
return code;
}
public String getDescription() {
return description;
}
public static OrderStatus getByCode(Long code) {
for (OrderStatus status : values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
}

View File

@@ -1,6 +1,7 @@
package com.ruoyi.system.mapper;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import java.util.List;
@@ -59,4 +60,20 @@ public interface OrderInfoMapper
* @return 结果
*/
public int deleteOrderInfoByIds(String[] ids);
/**
* 根据订单号查询订单
*
* @param orderId 订单号
* @return 订单信息
*/
public OrderInfo selectOrderByOrderId(String orderId);
/**
* 查询订单列表(包含用户信息和套餐信息)
*
* @param orderInfo 查询条件
* @return 订单列表
*/
public List<OrderInfoVO> selectOrderInfoVOList(OrderInfo orderInfo);
}

View File

@@ -2,6 +2,10 @@ package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.dto.OrderCreateRequest;
import com.ruoyi.common.core.domain.dto.PaymentRequest;
import com.ruoyi.common.core.domain.dto.RefundRequest;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import java.util.List;
@@ -61,5 +65,69 @@ public interface IOrderInfoService
*/
public int deleteOrderInfoById(String id);
AjaxResult createOrder(OrderInfo orderInfo);
/**
* 创建订单
*
* @param request 订单创建请求
* @return 结果
*/
AjaxResult createOrder(OrderCreateRequest request);
/**
* 支付订单
*
* @param request 支付请求
* @return 结果
*/
AjaxResult payOrder(PaymentRequest request);
/**
* 完成支付(支付回调)
*
* @param orderId 订单ID
* @param tradeNo 第三方交易号
* @param payType 支付方式
* @return 结果
*/
AjaxResult completePayment(String orderId, String tradeNo, String payType);
/**
* 确认出货
*
* @param orderId 订单ID
* @return 结果
*/
AjaxResult confirmShipment(String orderId);
/**
* 申请退款
*
* @param request 退款请求
* @return 结果
*/
AjaxResult refundOrder(RefundRequest request);
/**
* 查询用户订单列表
*
* @param userId 用户ID
* @return 订单列表
*/
List<OrderInfo> selectUserOrders(Long userId);
/**
* 查询订单详情
*
* @param orderId 订单ID
* @return 订单详情
*/
OrderInfo selectOrderByOrderId(String orderId);
/**
* 查询订单列表(包含用户信息和套餐信息)
*
* @param orderInfo 查询条件
* @return 订单列表
*/
List<OrderInfoVO> selectOrderInfoVOList(OrderInfo orderInfo);
}

View File

@@ -1,16 +1,24 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.dto.OrderCreateRequest;
import com.ruoyi.common.core.domain.dto.PaymentRequest;
import com.ruoyi.common.core.domain.dto.RefundRequest;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.entity.PayStatusEnum;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.OrderInfoMapper;
import com.ruoyi.system.service.IOrderInfoService;
import com.ruoyi.system.util.PaymentUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.*;
/**
* 【请填写功能名称】Service业务层处理
@@ -24,6 +32,9 @@ public class OrderInfoServiceImpl implements IOrderInfoService
@Autowired
private OrderInfoMapper orderInfoMapper;
@Autowired
private PaymentUtil paymentUtil;
/**
* 查询【请填写功能名称】
*
@@ -99,13 +110,272 @@ public class OrderInfoServiceImpl implements IOrderInfoService
}
@Override
public AjaxResult createOrder(OrderInfo orderInfo) {
LoginUser userInfo = SecurityUtils.getLoginUser();
if (userInfo != null){
//orderInfo.setPayStatus();
@Transactional
public AjaxResult createOrder(OrderCreateRequest request) {
try {
// 参数校验
if (StringUtils.isEmpty(request.getOrderName()) || request.getAmount() == null || request.getAmount() <= 0) {
return AjaxResult.error("订单信息不完整");
}
return null;
// 获取当前用户
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
return AjaxResult.error("用户未登录");
}
// 创建订单
OrderInfo orderInfo = new OrderInfo();
orderInfo.setId(UUID.randomUUID().toString().replace("-", ""));
orderInfo.setOrderId(System.currentTimeMillis()); // 使用时间戳作为订单号
orderInfo.setOrderName(request.getOrderName());
orderInfo.setUserId(loginUser.getUserId());
orderInfo.setAmount(request.getAmount());
orderInfo.setPayType(request.getPayType());
orderInfo.setPackageType(request.getPackageType());
orderInfo.setDeviceType(request.getDeviceType());
orderInfo.setClientIp(request.getClientIp());
orderInfo.setPayStatus(PayStatusEnum.CREATE.status); // 1-创建订单
orderInfo.setIdDel(0L);
orderInfo.setVersion(1L);
orderInfo.setCreateTime(DateUtils.getNowDate());
// 保存订单
int result = insertOrderInfo(orderInfo);
if (result > 0) {
return AjaxResult.success("订单创建成功", orderInfo);
} else {
return AjaxResult.error("订单创建失败");
}
} catch (Exception e) {
return AjaxResult.error("订单创建异常: " + e.getMessage());
}
}
@Override
@Transactional
public AjaxResult payOrder(PaymentRequest request) {
try {
// 参数校验
if (StringUtils.isEmpty(request.getOrderId())) {
return AjaxResult.error("订单ID不能为空");
}
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(request.getOrderId());
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.CREATE.getStatus()) {
return AjaxResult.error("订单状态不正确");
}
// 检查用户权限
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || !loginUser.getUserId().equals(orderInfo.getUserId())) {
return AjaxResult.error("无权限操作此订单");
}
// 调用第三方支付接口
Map<String, Object> paymentResult = processPayment(orderInfo, request);
return AjaxResult.success("支付请求成功", paymentResult);
} catch (Exception e) {
return AjaxResult.error("支付异常: " + e.getMessage());
}
}
@Override
@Transactional
public AjaxResult completePayment(String orderId, String tradeNo, String payType) {
try {
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(orderId);
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.CREATE.getStatus()) {
return AjaxResult.error("订单状态不正确");
}
// 更新订单状态
orderInfo.setPayStatus(PayStatusEnum.PENDING.getStatus()); // 2-待出货
orderInfo.setPayTime(DateUtils.getNowDate());
orderInfo.setTradeNo(tradeNo);
orderInfo.setCallTime(DateUtils.getNowDate());
orderInfo.setCallbackContent("支付成功回调");
orderInfo.setUpdateTime(DateUtils.getNowDate());
// 计算服务时间
calculateServiceTime(orderInfo);
// 保存订单
int result = updateOrderInfo(orderInfo);
if (result > 0) {
return AjaxResult.success("支付完成");
} else {
return AjaxResult.error("支付完成处理失败");
}
} catch (Exception e) {
return AjaxResult.error("支付完成处理异常: " + e.getMessage());
}
}
@Override
@Transactional
public AjaxResult refundOrder(RefundRequest request) {
try {
// 参数校验
if (StringUtils.isEmpty(request.getOrderId()) || request.getRefundAmount() == null || request.getRefundAmount() <= 0) {
return AjaxResult.error("退款信息不完整");
}
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(request.getOrderId());
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.PENDING.getStatus() && orderInfo.getPayStatus() != PayStatusEnum.WAIT_REFUND.getStatus()) {
return AjaxResult.error("订单状态不允许退款");
}
// 检查退款金额
if (request.getRefundAmount() > orderInfo.getAmount()) {
return AjaxResult.error("退款金额不能大于订单金额");
}
// 检查是否已退款
if (orderInfo.getRefundAmount() != null && orderInfo.getRefundAmount() > 0) {
return AjaxResult.error("订单已退款");
}
// 调用第三方退款接口
boolean refundResult = paymentUtil.processRefund(orderInfo.getOrderId().toString(), request.getRefundAmount(), orderInfo.getPayType());
if (!refundResult) {
return AjaxResult.error("第三方退款失败");
}
// 更新订单退款信息
orderInfo.setRefundAmount(request.getRefundAmount());
orderInfo.setRefundTime(DateUtils.getNowDate());
orderInfo.setUpdateTime(DateUtils.getNowDate());
// 如果是全额退款,更新订单状态
if (request.getRefundAmount().equals(orderInfo.getAmount())) {
orderInfo.setPayStatus(PayStatusEnum.REFUND.getStatus()); // 4-已退款
}
// 保存订单
int result = updateOrderInfo(orderInfo);
if (result > 0) {
return AjaxResult.success("退款申请成功");
} else {
return AjaxResult.error("退款申请失败");
}
} catch (Exception e) {
return AjaxResult.error("退款异常: " + e.getMessage());
}
}
@Override
public List<OrderInfo> selectUserOrders(Long userId) {
OrderInfo orderInfo = new OrderInfo();
orderInfo.setUserId(userId);
orderInfo.setIdDel(0L);
return orderInfoMapper.selectOrderInfoList(orderInfo);
}
@Override
public OrderInfo selectOrderByOrderId(String orderId) {
return orderInfoMapper.selectOrderByOrderId(orderId);
}
@Override
public List<OrderInfoVO> selectOrderInfoVOList(OrderInfo orderInfo) {
return orderInfoMapper.selectOrderInfoVOList(orderInfo);
}
@Override
@Transactional
public AjaxResult confirmShipment(String orderId) {
try {
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(orderId);
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.PENDING.getStatus()) {
return AjaxResult.error("订单状态不正确,只有已支付的订单才能确认出货");
}
// 更新订单状态为已完成
orderInfo.setPayStatus(PayStatusEnum.COMPLETE.getStatus()); // 3-已完成
orderInfo.setUpdateTime(DateUtils.getNowDate());
// 保存订单
int result = updateOrderInfo(orderInfo);
if (result > 0) {
return AjaxResult.success("确认出货成功");
} else {
return AjaxResult.error("确认出货失败");
}
} catch (Exception e) {
return AjaxResult.error("确认出货异常: " + e.getMessage());
}
}
/**
* 处理支付过程
*/
private Map<String, Object> processPayment(OrderInfo orderInfo, PaymentRequest request) {
// 根据支付方式调用相应的支付接口
switch (request.getPayType()) {
case "aliPay":
return paymentUtil.processAliPay(orderInfo, request);
case "wechatPay":
return paymentUtil.processWechatPay(orderInfo, request);
case "applePay":
return paymentUtil.processApplePay(orderInfo, request);
default:
Map<String, Object> errorResult = new HashMap<>();
errorResult.put("error", "不支持的支付方式");
return errorResult;
}
}
/**
* 计算服务时间
*/
private void calculateServiceTime(OrderInfo orderInfo) {
Date now = DateUtils.getNowDate();
orderInfo.setStartTime(now);
// 根据套餐类型计算结束时间
String packageType = orderInfo.getPackageType();
if ("1".equals(packageType)) {
// 包月
orderInfo.setEndTime(DateUtils.addMonths(now, 1));
} else if ("3".equals(packageType)) {
// 包季度
orderInfo.setEndTime(DateUtils.addMonths(now, 3));
} else if ("6".equals(packageType)) {
// 半年
orderInfo.setEndTime(DateUtils.addMonths(now, 6));
} else if ("12".equals(packageType)) {
// 一年
orderInfo.setEndTime(DateUtils.addMonths(now, 12));
}
}
}

View File

@@ -0,0 +1,195 @@
package com.ruoyi.system.util;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.dto.PaymentRequest;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 支付工具类
*
* @author ruoyi
* @date 2025-01-27
*/
@Component
public class PaymentUtil {
/**
* 处理支付宝支付
*/
public Map<String, Object> processAliPay(OrderInfo orderInfo, PaymentRequest request) {
Map<String, Object> result = new HashMap<>();
// TODO: 调用支付宝SDK进行支付
// 这里只是模拟返回支付参数
// 构建支付宝支付参数
Map<String, Object> aliPayParams = new HashMap<>();
aliPayParams.put("out_trade_no", orderInfo.getOrderId().toString());
aliPayParams.put("total_amount", orderInfo.getAmount() / 100.0);
aliPayParams.put("subject", StringUtils.isNotEmpty(request.getSubject()) ? request.getSubject() : orderInfo.getOrderName());
aliPayParams.put("body", StringUtils.isNotEmpty(request.getBody()) ? request.getBody() : "购买VIP会员服务");
aliPayParams.put("timeout_express", (request.getTimeoutMinutes() != null ? request.getTimeoutMinutes() : 30) + "m");
aliPayParams.put("product_code", "QUICK_WAP_WAY");
result.put("paymentUrl", "https://openapi.alipay.com/gateway.do?");
result.put("orderId", orderInfo.getOrderId());
result.put("amount", orderInfo.getAmount());
result.put("payType", "aliPay");
result.put("params", aliPayParams);
return result;
}
/**
* 处理微信支付
*/
public Map<String, Object> processWechatPay(OrderInfo orderInfo, PaymentRequest request) {
Map<String, Object> result = new HashMap<>();
// TODO: 调用微信支付SDK进行支付
// 这里只是模拟返回支付参数
// 构建微信支付参数
Map<String, Object> wechatPayParams = new HashMap<>();
wechatPayParams.put("out_trade_no", orderInfo.getOrderId().toString());
wechatPayParams.put("total_fee", orderInfo.getAmount());
wechatPayParams.put("body", StringUtils.isNotEmpty(request.getBody()) ? request.getBody() : orderInfo.getOrderName());
wechatPayParams.put("attach", StringUtils.isNotEmpty(request.getAttach()) ? request.getAttach() : "VIP会员服务");
if (StringUtils.isNotEmpty(request.getOpenid())) {
wechatPayParams.put("openid", request.getOpenid());
}
result.put("prepayId", "wx_prepay_id_" + System.currentTimeMillis());
result.put("orderId", orderInfo.getOrderId());
result.put("amount", orderInfo.getAmount());
result.put("payType", "wechatPay");
result.put("params", wechatPayParams);
return result;
}
/**
* 处理Apple Pay支付
*/
public Map<String, Object> processApplePay(OrderInfo orderInfo, PaymentRequest request) {
Map<String, Object> result = new HashMap<>();
// TODO: 调用Apple Pay SDK进行支付
// 这里只是模拟返回支付参数
// 构建Apple Pay支付参数
Map<String, Object> applePayParams = new HashMap<>();
applePayParams.put("orderId", orderInfo.getOrderId().toString());
applePayParams.put("amount", orderInfo.getAmount() / 100.0);
applePayParams.put("currency", "CNY");
applePayParams.put("merchantIdentifier", StringUtils.isNotEmpty(request.getMerchantIdentifier()) ?
request.getMerchantIdentifier() : "merchant.com.example");
if (StringUtils.isNotEmpty(request.getPaymentToken())) {
applePayParams.put("paymentToken", request.getPaymentToken());
}
result.put("paymentToken", "apple_payment_token_" + System.currentTimeMillis());
result.put("orderId", orderInfo.getOrderId());
result.put("amount", orderInfo.getAmount());
result.put("payType", "applePay");
result.put("params", applePayParams);
return result;
}
/**
* 验证支付回调
*/
public boolean verifyPaymentCallback(String orderId, String tradeNo, String payType, String signature) {
// TODO: 根据不同的支付方式验证回调签名
// 这里只是模拟验证
if (StringUtils.isEmpty(orderId) || StringUtils.isEmpty(tradeNo) || StringUtils.isEmpty(payType)) {
return false;
}
// 验证签名逻辑
switch (payType) {
case "aliPay":
return verifyAliPayCallback(signature);
case "wechatPay":
return verifyWechatPayCallback(signature);
case "applePay":
return verifyApplePayCallback(signature);
default:
return false;
}
}
/**
* 验证支付宝回调
*/
private boolean verifyAliPayCallback(String signature) {
// TODO: 实现支付宝回调验证
return true;
}
/**
* 验证微信支付回调
*/
private boolean verifyWechatPayCallback(String signature) {
// TODO: 实现微信支付回调验证
return true;
}
/**
* 验证Apple Pay回调
*/
private boolean verifyApplePayCallback(String signature) {
// TODO: 实现Apple Pay回调验证
return true;
}
/**
* 处理退款
*/
public boolean processRefund(String orderId, Long refundAmount, String payType) {
// TODO: 根据不同的支付方式调用相应的退款接口
switch (payType) {
case "aliPay":
return processAliPayRefund(orderId, refundAmount);
case "wechatPay":
return processWechatPayRefund(orderId, refundAmount);
case "applePay":
return processApplePayRefund(orderId, refundAmount);
default:
return false;
}
}
/**
* 处理支付宝退款
*/
private boolean processAliPayRefund(String orderId, Long refundAmount) {
// TODO: 调用支付宝退款接口
return true;
}
/**
* 处理微信支付退款
*/
private boolean processWechatPayRefund(String orderId, Long refundAmount) {
// TODO: 调用微信支付退款接口
return true;
}
/**
* 处理Apple Pay退款
*/
private boolean processApplePayRefund(String orderId, Long refundAmount) {
// TODO: 调用Apple Pay退款接口
return true;
}
}

View File

@@ -151,4 +151,70 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{id}
</foreach>
</delete>
<select id="selectOrderByOrderId" parameterType="String" resultMap="OrderInfoResult">
<include refid="selectOrderInfoVo"/>
where order_id = #{orderId} and id_del = 0
</select>
<resultMap type="OrderInfoVO" id="OrderInfoVOResult">
<result property="orderId" column="order_id" />
<result property="userNickname" column="user_nickname" />
<result property="packageName" column="package_name" />
<result property="amountYuan" column="amount_yuan" />
<result property="payTypeName" column="pay_type_name" />
<result property="startTime" column="start_time" />
<result property="endTime" column="end_time" />
<result property="statusName" column="status_name" />
<result property="createTime" column="create_time" />
</resultMap>
<select id="selectOrderInfoVOList" parameterType="OrderInfo" resultMap="OrderInfoVOResult">
SELECT
o.order_id,
su.nickname as user_nickname,
CASE
WHEN o.package_type = '1' THEN '包月'
WHEN o.package_type = '3' THEN '包季度'
WHEN o.package_type = '6' THEN '半年'
WHEN o.package_type = '12' THEN '一年'
ELSE '未知套餐'
END as package_name,
ROUND(o.amount / 100.0, 2) as amount_yuan,
CASE
WHEN o.pay_type = 'aliPay' THEN '支付宝'
WHEN o.pay_type = 'wechatPay' THEN '微信支付'
WHEN o.pay_type = 'applePay' THEN 'Apple Pay'
ELSE '未知支付方式'
END as pay_type_name,
o.start_time,
o.end_time,
CASE
WHEN o.pay_status = 1 THEN '待支付'
WHEN o.pay_status = 2 THEN '待出货'
WHEN o.pay_status = 3 THEN '待退款'
WHEN o.pay_status = 4 THEN '已退款'
WHEN o.pay_status = 5 THEN '已完成'
ELSE '未知状态'
END as status_name,
o.create_time
FROM order_info o
LEFT JOIN shop_user su ON o.user_id = su.user_id
<where>
o.id_del = 0
<if test="orderId != null "> and o.order_id = #{orderId}</if>
<if test="orderName != null and orderName != ''"> and o.order_name like concat('%', #{orderName}, '%')</if>
<if test="userId != null "> and o.user_id = #{userId}</if>
<if test="amount != null "> and o.amount = #{amount}</if>
<if test="payType != null and payType != ''"> and o.pay_type = #{payType}</if>
<if test="payTime != null "> and o.pay_time = #{payTime}</if>
<if test="payStatus != null "> and o.pay_status = #{payStatus}</if>
<if test="startTime != null "> and o.start_time = #{startTime}</if>
<if test="endTime != null "> and o.end_time = #{endTime}</if>
<if test="packageType != null and packageType != ''"> and o.package_type = #{packageType}</if>
<if test="clientIp != null and clientIp != ''"> and o.client_ip = #{clientIp}</if>
<if test="deviceType != null and deviceType != ''"> and o.device_type = #{deviceType}</if>
</where>
ORDER BY o.create_time DESC
</select>
</mapper>

View File

@@ -0,0 +1,61 @@
import request from '@/utils/request'
// 查询订单列表
export function listOrderInfo(query) {
return request({
url: '/back/order/detailList',
method: 'get',
params: query
})
}
// 查询订单详细
export function getOrderInfo(id) {
return request({
url: '/back/order/' + id,
method: 'get'
})
}
// 新增订单
export function addOrderInfo(data) {
return request({
url: '/back/order',
method: 'post',
data: data
})
}
// 修改订单
export function updateOrderInfo(data) {
return request({
url: '/back/order',
method: 'put',
data: data
})
}
// 删除订单
export function delOrderInfo(id) {
return request({
url: '/back/order/' + id,
method: 'delete'
})
}
// 确认出货
export function confirmShipment(orderId) {
return request({
url: '/back/order/confirmShipment/' + orderId,
method: 'post'
})
}
// 导出订单
export function exportOrderInfo(query) {
return request({
url: '/back/order/exportDetail',
method: 'post',
data: query
})
}

View File

@@ -1,9 +1,9 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="120px">
<el-form-item label="订单号" prop="orderNumber">
<el-form-item label="订单号" prop="orderId">
<el-input
v-model="queryParams.orderNumber"
v-model="queryParams.orderId"
placeholder="请输入订单号查找"
clearable
style="width: 200px"
@@ -20,8 +20,8 @@
/>
</el-select>
</el-form-item>
<el-form-item label="选择状态" prop="status">
<el-select v-model="queryParams.status" placeholder="选择状态" clearable style="width: 150px">
<el-form-item label="选择状态" prop="payStatus">
<el-select v-model="queryParams.payStatus" placeholder="选择状态" clearable style="width: 150px">
<el-option
v-for="item in statusOptions"
:key="item.value"
@@ -40,49 +40,36 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="memberList">
<el-table-column label="订单号" align="center" prop="orderNumber" :show-overflow-tooltip="true" />
<el-table-column label="套餐名称" align="center" prop="packageName" :show-overflow-tooltip="true" />
<el-table v-loading="loading" :data="orderList">
<el-table-column label="订单号" align="center" prop="orderId" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" prop="userNickname" :show-overflow-tooltip="true" />
<el-table-column label="金额" align="center" prop="amount" width="100">
<el-table-column label="套餐名称" align="center" prop="packageName" :show-overflow-tooltip="true" />
<el-table-column label="金额" align="center" prop="amountYuan" width="100">
<template slot-scope="scope">
<span>¥{{ scope.row.amount }}</span>
<span>¥{{ scope.row.amountYuan }}</span>
</template>
</el-table-column>
<el-table-column label="支付方式" align="center" prop="paymentMethod" width="120" />
<el-table-column label="开通时间" align="center" prop="activationTime" width="160">
<el-table-column label="支付方式" align="center" prop="payTypeName" width="120" />
<el-table-column label="开通时间" align="center" prop="startTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.activationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
<span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="到期时间" align="center" prop="expirationTime" width="160">
<el-table-column label="到期时间" align="center" prop="endTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.expirationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
<span>{{ parseTime(scope.row.endTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100">
<el-table-column label="状态" align="center" prop="statusName" width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'" size="mini">
{{ scope.row.status === 1 ? '正常' : '已过期' }}
<el-tag :type="getStatusType(scope.row.statusName)" size="mini">
{{ scope.row.statusName }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
<el-table-column label="创建时间" align="center" prop="createTime" width="160">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['member:member:edit']"
>编辑</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['member:member:remove']"
>删除</el-button>
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
</el-table>
@@ -95,71 +82,12 @@
@pagination="getList"
/>
<!-- 添加或修改会员记录对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="订单号" prop="orderNumber" required>
<el-input v-model="form.orderNumber" placeholder="请输入订单号" />
</el-form-item>
<el-form-item label="套餐名称" prop="packageName" required>
<el-select v-model="form.packageName" placeholder="请选择套餐" style="width: 100%">
<el-option
v-for="item in packageOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="用户昵称" prop="userNickname" required>
<el-input v-model="form.userNickname" placeholder="请输入用户昵称" />
</el-form-item>
<el-form-item label="金额" prop="amount" required>
<el-input-number v-model="form.amount" :precision="2" :step="0.01" :min="0" style="width: 100%" />
</el-form-item>
<el-form-item label="支付方式" prop="paymentMethod" required>
<el-select v-model="form.paymentMethod" placeholder="请选择支付方式" style="width: 100%">
<el-option label="微信支付" value="微信支付" />
<el-option label="支付宝支付" value="支付宝支付" />
<el-option label="app store" value="app store" />
<el-option label="其他" value="其他" />
</el-select>
</el-form-item>
<el-form-item label="开通时间" prop="activationTime" required>
<el-date-picker
v-model="form.activationTime"
type="datetime"
placeholder="选择开通时间"
style="width: 100%"
value-format="yyyy-MM-dd HH:mm:ss"
/>
</el-form-item>
<el-form-item label="到期时间" prop="expirationTime" required>
<el-date-picker
v-model="form.expirationTime"
type="datetime"
placeholder="选择到期时间"
style="width: 100%"
value-format="yyyy-MM-dd HH:mm:ss"
/>
</el-form-item>
<el-form-item label="状态" prop="status" required>
<el-select v-model="form.status" placeholder="请选择状态" style="width: 100%">
<el-option label="正常" :value="1" />
<el-option label="已过期" :value="0" />
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listMember, getMember, delMember, addMember, updateMember } from "@/api/member/member";
import { listOrderInfo } from "@/api/system/orderInfo";
export default {
name: "Member",
@@ -168,37 +96,27 @@ export default {
loading: true,
showSearch: true,
total: 0,
memberList: [],
title: "",
open: false,
orderList: [],
queryParams: {
pageNum: 1,
pageSize: 10,
orderNumber: null,
orderId: null,
packageType: null,
status: null
},
form: {},
rules: {
orderNumber: [{ required: true, message: "订单号不能为空", trigger: "blur" }],
packageName: [{ required: true, message: "套餐名称不能为空", trigger: "change" }],
userNickname: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
amount: [{ required: true, message: "金额不能为空", trigger: "blur" }],
paymentMethod: [{ required: true, message: "支付方式不能为空", trigger: "change" }],
activationTime: [{ required: true, message: "开通时间不能为空", trigger: "change" }],
expirationTime: [{ required: true, message: "到期时间不能为空", trigger: "change" }],
status: [{ required: true, message: "状态不能为空", trigger: "change" }]
payStatus: null
},
packageOptions: [
{ label: '连续包月', value: '连续包月' },
{ label: '年卡会员', value: '年卡会员' },
{ label: '季卡会员', value: '季卡会员' },
{ label: '月卡会员', value: '月卡会员' },
{ label: '周卡会员', value: '周卡会员' }
{ label: '包月', value: '1' },
{ label: '包季度', value: '3' },
{ label: '半年', value: '6' },
{ label: '一年', value: '12' }
],
statusOptions: [
{ label: '已过期', value: 0 },
{ label: '正常', value: 1 }
{ label: '待支付', value: 1 },
{ label: '待出货', value: 2 },
{ label: '待退款', value: 3 },
{ label: '已退款', value: 4 },
{ label: '已完成', value: 5 }
]
};
},
@@ -206,82 +124,42 @@ export default {
this.getList();
},
methods: {
/** 查询订单列表 */
getList() {
this.loading = true;
listMember(this.queryParams).then(response => {
this.memberList = response.rows;
listOrderInfo(this.queryParams).then(response => {
this.orderList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
id: null,
orderNumber: null,
packageName: null,
userNickname: null,
amount: null,
paymentMethod: null,
activationTime: null,
expirationTime: null,
status: 1
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleAdd() {
this.reset();
this.open = true;
this.title = "新增会员记录";
},
handleUpdate(row) {
this.reset();
const id = row.id || this.ids
getMember(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "编辑会员记录";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateMember(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addMember(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
/** 获取状态标签类型 */
getStatusType(statusName) {
switch (statusName) {
case '待支付':
return 'warning';
case '待出货':
return 'primary';
case '待退款':
return 'info';
case '已退款':
return 'danger';
case '已完成':
return 'success';
default:
return 'info';
}
}
});
},
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除会员记录编号为"' + ids + '"的数据项?').then(function() {
return delMember(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
}
};
</script>

View File

@@ -10,8 +10,8 @@ const CompressionPlugin = require('compression-webpack-plugin')
const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
// const baseUrl = 'http://localhost:8080' // 后端接口
const baseUrl = 'http://60.205.107.210:8080' // 后端接口
// const baseUrl = 'http://192.168.31.239:8081' // 后端接口
// const baseUrl = 'http://60.205.107.210:8080' // 后端接口
const baseUrl = 'http://192.168.31.239:8080' // 后端接口
const port = process.env.port || process.env.npm_config_port || 80 // 端口