Commit 5dcb3db5d7ae8c205a7f2f61354211c7604b8f54

Authored by YunaiV
1 parent 888c4882

mall + pay:

1. 优化订单管理的接口实现
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
... ... @@ -56,31 +56,20 @@ public class PayOrderController {
56 56 return success(PayOrderConvert.INSTANCE.convert(payOrderService.getOrder(id)));
57 57 }
58 58  
59   - // TODO 芋艿:看看怎么优化下;
60 59 @GetMapping("/get-detail")
61 60 @Operation(summary = "获得支付订单详情")
62 61 @Parameter(name = "id", description = "编号", required = true, example = "1024")
63 62 @PreAuthorize("@ss.hasPermission('pay:order:query')")
64 63 public CommonResult<PayOrderDetailsRespVO> getOrderDetail(@RequestParam("id") Long id) {
65 64 PayOrderDO order = payOrderService.getOrder(id);
66   - if (ObjectUtil.isNull(order)) {
67   - return success(new PayOrderDetailsRespVO());
  65 + if (order == null) {
  66 + return success(null);
68 67 }
69 68  
70   - PayAppDO appDO = appService.getApp(order.getAppId());
71   - PayChannelEnum channelEnum = PayChannelEnum.getByCode(order.getChannelCode());
72   -
73   - // TODO @aquan:文案,都是前端 format;
74   - PayOrderDetailsRespVO respVO = PayOrderConvert.INSTANCE.orderDetailConvert(order);
75   - respVO.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
76   - respVO.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
77   -
78   - PayOrderExtensionDO extensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
79   - if (ObjectUtil.isNotNull(extensionDO)) {
80   - respVO.setPayOrderExtension(PayOrderConvert.INSTANCE.orderDetailExtensionConvert(extensionDO));
81   - }
82   -
83   - return success(respVO);
  69 + // 拼接返回
  70 + PayAppDO app = appService.getApp(order.getAppId());
  71 + PayOrderExtensionDO orderExtension = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
  72 + return success(PayOrderConvert.INSTANCE.convert(order, orderExtension, app));
84 73 }
85 74  
86 75 @PostMapping("/submit")
... ... @@ -90,6 +79,7 @@ public class PayOrderController {
90 79 return success(respVO);
91 80 }
92 81  
  82 + // TODO 芋艿:优化
93 83 @GetMapping("/page")
94 84 @Operation(summary = "获得支付订单分页")
95 85 @PreAuthorize("@ss.hasPermission('pay:order:query')")
... ... @@ -116,6 +106,7 @@ public class PayOrderController {
116 106 return success(new PageResult<>(pageList, pageResult.getTotal()));
117 107 }
118 108  
  109 + // TODO 芋艿:优化
119 110 @GetMapping("/export-excel")
120 111 @Operation(summary = "导出支付订单Excel")
121 112 @PreAuthorize("@ss.hasPermission('pay:order:export')")
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderDetailsRespVO.java
... ... @@ -13,32 +13,30 @@ import java.time.LocalDateTime;
13 13 @ToString(callSuper = true)
14 14 public class PayOrderDetailsRespVO extends PayOrderBaseVO {
15 15  
16   - @Schema(description = "支付订单编号")
  16 + @Schema(description = "支付订单编号", required = true, example = "1024")
17 17 private Long id;
18 18  
19   - @Schema(description = "应用名称")
  19 + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
20 20 private String appName;
21 21  
22   - @Schema(description = "渠道编号名称")
23   - private String channelCodeName;
24   -
25   - @Schema(description = "创建时间")
  22 + @Schema(description = "创建时间", required = true)
26 23 private LocalDateTime createTime;
27 24  
28 25 /**
29 26 * 支付订单扩展
30 27 */
31   - private PayOrderExtension payOrderExtension;
  28 + private PayOrderExtension extension;
32 29  
33 30 @Data
34 31 @Schema(description = "支付订单扩展")
35 32 public static class PayOrderExtension {
36 33  
37   - @Schema(description = "支付订单号")
  34 + @Schema(description = "支付订单号", required = true, example = "1024")
38 35 private String no;
39 36  
40 37 @Schema(description = "支付异步通知的内容")
41 38 private String channelNotifyData;
  39 +
42 40 }
43 41  
44 42 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
6 6 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
7 7 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
8 8 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
  9 +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
9 10 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
10 11 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
11 12 import org.mapstruct.Mapper;
... ... @@ -30,9 +31,16 @@ public interface PayOrderConvert {
30 31  
31 32 PayOrderRespDTO convert2(PayOrderDO order);
32 33  
33   - PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean);
34   -
35   - PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);
  34 + default PayOrderDetailsRespVO convert(PayOrderDO order, PayOrderExtensionDO orderExtension, PayAppDO app) {
  35 + PayOrderDetailsRespVO respVO = convertDetail(order);
  36 + respVO.setExtension(convert(orderExtension));
  37 + if (app != null) {
  38 + respVO.setAppName(app.getName());
  39 + }
  40 + return respVO;
  41 + }
  42 + PayOrderDetailsRespVO convertDetail(PayOrderDO bean);
  43 + PayOrderDetailsRespVO.PayOrderExtension convert(PayOrderExtensionDO bean);
36 44  
37 45 List<PayOrderRespVO> convertList(List<PayOrderDO> list);
38 46  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
... ... @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Pair;
5 5 import cn.hutool.core.util.ObjectUtil;
6 6 import cn.hutool.core.util.RandomUtil;
7 7 import cn.hutool.core.util.StrUtil;
  8 +import cn.hutool.extra.spring.SpringUtil;
8 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 10 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
10 11 import cn.iocoder.yudao.framework.pay.config.PayProperties;
... ... @@ -161,7 +162,7 @@ public class PayOrderServiceImpl implements PayOrderService {
161 162  
162 163 // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
163 164 if (unifiedOrderResp != null) {
164   - notifyPayOrder(channel, unifiedOrderResp);
  165 + getSelf().notifyPayOrder(channel, unifiedOrderResp);
165 166 // 如有渠道错误码,则抛出业务异常,提示用户
166 167 if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
167 168 throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
... ... @@ -234,11 +235,17 @@ public class PayOrderServiceImpl implements PayOrderService {
234 235 // 校验支付渠道是否有效
235 236 PayChannelDO channel = channelService.validPayChannel(channelId);
236 237 // 更新支付订单为已支付
237   - TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify));
  238 + TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyPayOrder(channel, notify));
238 239 }
239 240  
240   - // TODO 芋艿:事务问题
241   - private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) {
  241 + /**
  242 + * 通知并更新订单的支付结果
  243 + *
  244 + * @param channel 支付渠道
  245 + * @param notify 通知
  246 + */
  247 + @Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
  248 + public void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) {
242 249 // 情况一:支付成功的回调
243 250 if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
244 251 notifyOrderSuccess(channel, notify);
... ... @@ -396,4 +403,13 @@ public class PayOrderServiceImpl implements PayOrderService {
396 403 }
397 404 }
398 405  
  406 + /**
  407 + * 获得自身的代理对象,解决 AOP 生效问题
  408 + *
  409 + * @return 自己
  410 + */
  411 + private PayOrderServiceImpl getSelf() {
  412 + return SpringUtil.getBean(getClass());
  413 + }
  414 +
399 415 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
... ... @@ -137,7 +137,7 @@ public class PayRefundServiceImpl implements PayRefundService {
137 137 .setOutRefundNo(refund.getNo())
138 138 .setNotifyUrl(genChannelRefundNotifyUrl(channel))
139 139 .setReason(reqDTO.getReason());
140   - PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); // TODO 增加一个 channelErrorCode、channelErrorMsg 字段
  140 + PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO);
141 141 // 2.3 处理退款返回
142 142 notifyRefund(channel, refundRespDTO);
143 143  
... ...
yudao-ui-admin/src/views/pay/order/index.vue
... ... @@ -11,7 +11,7 @@
11 11 <el-form-item label="渠道编码" prop="channelCode">
12 12 <el-select v-model="queryParams.channelCode" placeholder="请输入渠道编码" clearable
13 13 @clear="()=>{queryParams.channelCode = null}">
14   - <el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/>
  14 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label" :value="dict.value"/>
15 15 </el-select>
16 16 </el-form-item>
17 17 <el-form-item label="商户订单编号" prop="merchantOrderId">
... ... @@ -24,13 +24,13 @@
24 24 </el-form-item>
25 25 <el-form-item label="支付状态" prop="status">
26 26 <el-select v-model="queryParams.status" placeholder="请选择支付状态" clearable size="small">
27   - <el-option v-for="dict in payOrderDictDatum" :key="parseInt(dict.value)"
  27 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_ORDER_STATUS)" :key="parseInt(dict.value)"
28 28 :label="dict.label" :value="parseInt(dict.value)"/>
29 29 </el-select>
30 30 </el-form-item>
31 31 <el-form-item label="退款状态" prop="refundStatus">
32 32 <el-select v-model="queryParams.refundStatus" placeholder="请选择退款状态" clearable>
33   - <el-option v-for="dict in payOrderRefundDictDatum" :key="parseInt(dict.value)"
  33 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_ORDER_REFUND_STATUS)" :key="parseInt(dict.value)"
34 34 :label="dict.label" :value="parseInt(dict.value)"/>
35 35 </el-select>
36 36 </el-form-item>
... ... @@ -102,6 +102,7 @@
102 102 </template>
103 103  
104 104 </el-table-column>
  105 + <!-- TODO 芋艿:要放开 -->
105 106 <!-- <el-table-column label="退款状态" align="center" prop="refundStatus">-->
106 107 <!-- <template v-slot="scope">-->
107 108 <!-- <span>{{ getDictDataLabel(DICT_TYPE.PAY_ORDER_REFUND_STATUS, scope.row.refundStatus) }}</span>-->
... ... @@ -124,7 +125,7 @@
124 125 </el-table-column>
125 126 <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
126 127 <template v-slot="scope">
127   - <el-button size="mini" type="text" icon="el-icon-search" @click="handleQueryDetails(scope.row)"
  128 + <el-button size="mini" type="text" icon="el-icon-search" @click="handleDetail(scope.row)"
128 129 v-hasPermi="['pay:order:query']">查看详情
129 130 </el-button>
130 131 </template>
... ... @@ -134,7 +135,7 @@
134 135 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
135 136 @pagination="getList"/>
136 137  
137   - <!-- 对话框(添加 / 修改) -->
  138 + <!-- 对话框(详情) -->
138 139 <el-dialog title="订单详情" :visible.sync="open" width="50%">
139 140 <el-descriptions :column="2" label-class-name="desc-label">
140 141 <el-descriptions-item label="应用名称">{{ orderDetail.appName }}</el-descriptions-item>
... ... @@ -149,8 +150,8 @@
149 150 <el-tag class="tag-purple" size="small">{{ orderDetail.channelOrderNo }}</el-tag>
150 151 </el-descriptions-item>
151 152 <el-descriptions-item label="支付订单号">
152   - <el-tag v-if="orderDetail.payOrderExtension.no !== ''" class="tag-pink" size="small">
153   - {{ orderDetail.payOrderExtension.no }}
  153 + <el-tag v-if="orderDetail.extension.no !== ''" class="tag-pink" size="small">
  154 + {{ orderDetail.extension.no }}
154 155 </el-tag>
155 156 </el-descriptions-item>
156 157 <el-descriptions-item label="金额">
... ... @@ -176,7 +177,9 @@
176 177 </el-descriptions>
177 178 <el-divider></el-divider>
178 179 <el-descriptions :column="2" label-class-name="desc-label">
179   - <el-descriptions-item label="支付渠道">{{ orderDetail.channelCodeName }}</el-descriptions-item>
  180 + <el-descriptions-item label="支付渠道">
  181 + <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="orderDetail.channelCode" />
  182 + </el-descriptions-item>
180 183 <el-descriptions-item label="支付IP">{{ orderDetail.userIp }}</el-descriptions-item>
181 184 <el-descriptions-item label="退款状态">
182 185 <dict-tag :type="DICT_TYPE.PAY_ORDER_REFUND_STATUS" :value="orderDetail.refundStatus" />
... ... @@ -194,7 +197,7 @@
194 197 {{ orderDetail.body }}
195 198 </el-descriptions-item>
196 199 <el-descriptions-item label="支付通道异步回调内容">
197   - {{ orderDetail.payOrderExtension.channelNotifyData }}
  200 + {{ orderDetail.extension.channelNotifyData }}
198 201 </el-descriptions-item>
199 202 </el-descriptions>
200 203 </el-dialog>
... ... @@ -204,34 +207,6 @@
204 207 <script>
205 208 import { getOrderDetail, getOrderPage, exportOrderExcel } from "@/api/pay/order";
206 209 import { DICT_TYPE, getDictDatas } from "@/utils/dict";
207   -import { getNowDateTime} from "@/utils/ruoyi";
208   -
209   -const defaultOrderDetail = {
210   - appName: '',
211   - channelCodeName: '',
212   - subject: '',
213   - merchantOrderId: null,
214   - channelOrderNo: '',
215   - body: '',
216   - price: null,
217   - channelFeeRate: null,
218   - channelFeePrice: null,
219   - userIp: '',
220   - status: null,
221   - notifyUrl: '',
222   - notifyStatus: null,
223   - refundStatus: null,
224   - refundTimes: '',
225   - refundPrice: null,
226   - createTime: '',
227   - successTime: '',
228   - notifyTime: '',
229   - expireTime: '',
230   - payOrderExtension: {
231   - channelNotifyData: '',
232   - no: ''
233   - }
234   -};
235 210  
236 211 export default {
237 212 name: "PayOrder",
... ... @@ -278,47 +253,24 @@ export default {
278 253 notifyTime: [],
279 254 createTime: []
280 255 },
281   - // 商户加载遮罩层
282   - merchantLoading: false,
283   - // 商户列表集合
284   - merchantList: null,
  256 +
285 257 // 支付应用列表集合
286   - appList: null,
287   - // 支付渠道编码字典数据集合
288   - payChannelCodeDictDatum: getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE),
  258 + appList: [],
289 259 // 订单回调商户状态字典数据集合
290 260 payOrderNotifyDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_NOTIFY_STATUS),
291   - // 订单状态字典数据集合
292   - payOrderDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_STATUS),
293   - // 订单退款状态字典数据集合
294   - payOrderRefundDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_REFUND_STATUS),
295   - orderDetail: JSON.parse(JSON.stringify(defaultOrderDetail)),
  261 +
  262 + // 订单详情
  263 + orderDetail: {
  264 + extension: {}
  265 + },
296 266 };
297 267 },
298 268 created() {
299   - // 初始化默认时间
300   - this.initTime();
301 269 this.getList();
302   - this.handleGetMerchantListByName(null);
303 270 },
304 271 methods: {
305   - initTime(){
306   - this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")];
307   - },
308 272 /** 查询列表 */
309 273 getList() {
310   - // 判断选择的日期是否超过了一个月
311   - let oneMonthTime = 31 * 24 * 3600 * 1000;
312   - if (this.queryParams.createTime == null){
313   - this.initTime();
314   - } else {
315   - let minDateTime = new Date(this.queryParams.createTime[0]).getTime();
316   - let maxDateTime = new Date(this.queryParams.createTime[1]).getTime()
317   - if (maxDateTime - minDateTime > oneMonthTime) {
318   - this.$message.error('时间范围最大为 31 天!');
319   - return false;
320   - }
321   - }
322 274 this.loading = true;
323 275 // 执行查询
324 276 getOrderPage(this.queryParams).then(response => {
... ... @@ -339,23 +291,22 @@ export default {
339 291 /** 重置按钮操作 */
340 292 resetQuery() {
341 293 this.resetForm("queryForm");
342   - this.initTime();
343 294 this.handleQuery();
344 295 },
345   - /**
346   - * 查看订单详情
347   - */
348   - handleQueryDetails(row) {
349   - this.orderDetail = JSON.parse(JSON.stringify(defaultOrderDetail));
  296 + /** 详情按钮操作 */
  297 + handleDetail(row) {
  298 + this.orderDetail = {};
350 299 getOrderDetail(row.id).then(response => {
  300 + // 设置值
351 301 this.orderDetail = response.data;
352   - if (response.data.payOrderExtension === null) {
353   - this.orderDetail.payOrderExtension = Object.assign(defaultOrderDetail.payOrderExtension, {});
  302 + if (!this.orderDetail.extension) {
  303 + this.orderDetail.extension = {}
354 304 }
  305 + // 弹窗打开
355 306 this.open = true;
356 307 });
357   -
358 308 },
  309 +
359 310 /** 导出按钮操作 */
360 311 handleExport() {
361 312 // 处理查询参数
... ...