瀏覽代碼

mall + pay:
1. 优化订单管理的接口实现

YunaiV 1 年之前
父節點
當前提交
5dcb3db5d7

+ 8 - 17
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 {
         return success(PayOrderConvert.INSTANCE.convert(payOrderService.getOrder(id)));
     }
 
-    // TODO 芋艿:看看怎么优化下;
     @GetMapping("/get-detail")
     @Operation(summary = "获得支付订单详情")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
     @PreAuthorize("@ss.hasPermission('pay:order:query')")
     public CommonResult<PayOrderDetailsRespVO> getOrderDetail(@RequestParam("id") Long id) {
         PayOrderDO order = payOrderService.getOrder(id);
-        if (ObjectUtil.isNull(order)) {
-            return success(new PayOrderDetailsRespVO());
+        if (order == null) {
+            return success(null);
         }
 
-        PayAppDO appDO = appService.getApp(order.getAppId());
-        PayChannelEnum channelEnum = PayChannelEnum.getByCode(order.getChannelCode());
-
-        // TODO @aquan:文案,都是前端 format;
-        PayOrderDetailsRespVO respVO = PayOrderConvert.INSTANCE.orderDetailConvert(order);
-        respVO.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
-        respVO.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
-
-        PayOrderExtensionDO extensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
-        if (ObjectUtil.isNotNull(extensionDO)) {
-            respVO.setPayOrderExtension(PayOrderConvert.INSTANCE.orderDetailExtensionConvert(extensionDO));
-        }
-
-        return success(respVO);
+        // 拼接返回
+        PayAppDO app = appService.getApp(order.getAppId());
+        PayOrderExtensionDO orderExtension = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
+        return success(PayOrderConvert.INSTANCE.convert(order, orderExtension, app));
     }
 
     @PostMapping("/submit")
@@ -90,6 +79,7 @@ public class PayOrderController {
         return success(respVO);
     }
 
+    // TODO 芋艿:优化
     @GetMapping("/page")
     @Operation(summary = "获得支付订单分页")
     @PreAuthorize("@ss.hasPermission('pay:order:query')")
@@ -116,6 +106,7 @@ public class PayOrderController {
         return success(new PageResult<>(pageList, pageResult.getTotal()));
     }
 
+    // TODO 芋艿:优化
     @GetMapping("/export-excel")
     @Operation(summary = "导出支付订单Excel")
     @PreAuthorize("@ss.hasPermission('pay:order:export')")

+ 6 - 8
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;
 @ToString(callSuper = true)
 public class PayOrderDetailsRespVO extends PayOrderBaseVO {
 
-    @Schema(description = "支付订单编号")
+    @Schema(description = "支付订单编号", required = true, example = "1024")
     private Long id;
 
-    @Schema(description = "应用名称")
+    @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
     private String appName;
 
-    @Schema(description = "渠道编号名称")
-    private String channelCodeName;
-
-    @Schema(description = "创建时间")
+    @Schema(description = "创建时间", required = true)
     private LocalDateTime createTime;
 
     /**
      * 支付订单扩展
      */
-    private PayOrderExtension payOrderExtension;
+    private PayOrderExtension extension;
 
     @Data
     @Schema(description = "支付订单扩展")
     public static class PayOrderExtension {
 
-        @Schema(description = "支付订单号")
+        @Schema(description = "支付订单号", required = true, example = "1024")
         private String no;
 
         @Schema(description = "支付异步通知的内容")
         private String channelNotifyData;
+
     }
 
 }

+ 11 - 3
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;
 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
 import org.mapstruct.Mapper;
@@ -30,9 +31,16 @@ public interface PayOrderConvert {
 
     PayOrderRespDTO convert2(PayOrderDO order);
 
-    PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean);
-
-    PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);
+    default PayOrderDetailsRespVO convert(PayOrderDO order, PayOrderExtensionDO orderExtension, PayAppDO app) {
+        PayOrderDetailsRespVO respVO = convertDetail(order);
+        respVO.setExtension(convert(orderExtension));
+        if (app != null) {
+            respVO.setAppName(app.getName());
+        }
+        return respVO;
+    }
+    PayOrderDetailsRespVO convertDetail(PayOrderDO bean);
+    PayOrderDetailsRespVO.PayOrderExtension convert(PayOrderExtensionDO bean);
 
     List<PayOrderRespVO> convertList(List<PayOrderDO> list);
 

+ 20 - 4
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;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
 import cn.iocoder.yudao.framework.pay.config.PayProperties;
@@ -161,7 +162,7 @@ public class PayOrderServiceImpl implements PayOrderService {
 
         // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功
         if (unifiedOrderResp != null) {
-            notifyPayOrder(channel, unifiedOrderResp);
+            getSelf().notifyPayOrder(channel, unifiedOrderResp);
             // 如有渠道错误码,则抛出业务异常,提示用户
             if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
                 throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
@@ -234,11 +235,17 @@ public class PayOrderServiceImpl implements PayOrderService {
         // 校验支付渠道是否有效
         PayChannelDO channel = channelService.validPayChannel(channelId);
         // 更新支付订单为已支付
-        TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify));
+        TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyPayOrder(channel, notify));
     }
 
-    // TODO 芋艿:事务问题
-    private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) {
+    /**
+     * 通知并更新订单的支付结果
+     *
+     * @param channel 支付渠道
+     * @param notify 通知
+     */
+    @Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效
+    public void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) {
         // 情况一:支付成功的回调
         if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
             notifyOrderSuccess(channel, notify);
@@ -396,4 +403,13 @@ public class PayOrderServiceImpl implements PayOrderService {
         }
     }
 
+    /**
+     * 获得自身的代理对象,解决 AOP 生效问题
+     *
+     * @return 自己
+     */
+    private PayOrderServiceImpl getSelf() {
+        return SpringUtil.getBean(getClass());
+    }
+
 }

+ 1 - 1
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 {
                 .setOutRefundNo(refund.getNo())
                 .setNotifyUrl(genChannelRefundNotifyUrl(channel))
                 .setReason(reqDTO.getReason());
-        PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); // TODO 增加一个 channelErrorCode、channelErrorMsg 字段
+        PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO);
         // 2.3 处理退款返回
         notifyRefund(channel, refundRespDTO);
 

+ 27 - 76
yudao-ui-admin/src/views/pay/order/index.vue

@@ -11,7 +11,7 @@
       <el-form-item label="渠道编码" prop="channelCode">
         <el-select v-model="queryParams.channelCode" placeholder="请输入渠道编码" clearable
                    @clear="()=>{queryParams.channelCode = null}">
-          <el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/>
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label" :value="dict.value"/>
         </el-select>
       </el-form-item>
       <el-form-item label="商户订单编号" prop="merchantOrderId">
@@ -24,13 +24,13 @@
       </el-form-item>
       <el-form-item label="支付状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="请选择支付状态" clearable size="small">
-          <el-option v-for="dict in payOrderDictDatum" :key="parseInt(dict.value)"
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_ORDER_STATUS)" :key="parseInt(dict.value)"
                      :label="dict.label" :value="parseInt(dict.value)"/>
         </el-select>
       </el-form-item>
       <el-form-item label="退款状态" prop="refundStatus">
         <el-select v-model="queryParams.refundStatus" placeholder="请选择退款状态" clearable>
-          <el-option v-for="dict in payOrderRefundDictDatum" :key="parseInt(dict.value)"
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_ORDER_REFUND_STATUS)" :key="parseInt(dict.value)"
                      :label="dict.label" :value="parseInt(dict.value)"/>
         </el-select>
       </el-form-item>
@@ -102,6 +102,7 @@
         </template>
 
       </el-table-column>
+      <!-- TODO 芋艿:要放开 -->
 <!--      <el-table-column label="退款状态" align="center" prop="refundStatus">-->
 <!--        <template v-slot="scope">-->
 <!--          <span>{{ getDictDataLabel(DICT_TYPE.PAY_ORDER_REFUND_STATUS, scope.row.refundStatus) }}</span>-->
@@ -124,7 +125,7 @@
       </el-table-column>
       <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
         <template v-slot="scope">
-          <el-button size="mini" type="text" icon="el-icon-search" @click="handleQueryDetails(scope.row)"
+          <el-button size="mini" type="text" icon="el-icon-search" @click="handleDetail(scope.row)"
                      v-hasPermi="['pay:order:query']">查看详情
           </el-button>
         </template>
@@ -134,7 +135,7 @@
     <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
                 @pagination="getList"/>
 
-    <!-- 对话框(添加 / 修改) -->
+    <!-- 对话框(详情) -->
     <el-dialog title="订单详情" :visible.sync="open" width="50%">
       <el-descriptions :column="2" label-class-name="desc-label">
         <el-descriptions-item label="应用名称">{{ orderDetail.appName }}</el-descriptions-item>
@@ -149,8 +150,8 @@
           <el-tag class="tag-purple" size="small">{{ orderDetail.channelOrderNo }}</el-tag>
         </el-descriptions-item>
         <el-descriptions-item label="支付订单号">
-          <el-tag v-if="orderDetail.payOrderExtension.no !== ''" class="tag-pink" size="small">
-            {{ orderDetail.payOrderExtension.no }}
+          <el-tag v-if="orderDetail.extension.no !== ''" class="tag-pink" size="small">
+            {{ orderDetail.extension.no }}
           </el-tag>
         </el-descriptions-item>
         <el-descriptions-item label="金额">
@@ -176,7 +177,9 @@
       </el-descriptions>
       <el-divider></el-divider>
       <el-descriptions :column="2" label-class-name="desc-label">
-        <el-descriptions-item label="支付渠道">{{ orderDetail.channelCodeName }}</el-descriptions-item>
+        <el-descriptions-item label="支付渠道">
+          <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="orderDetail.channelCode" />
+        </el-descriptions-item>
         <el-descriptions-item label="支付IP">{{ orderDetail.userIp }}</el-descriptions-item>
         <el-descriptions-item label="退款状态">
           <dict-tag :type="DICT_TYPE.PAY_ORDER_REFUND_STATUS" :value="orderDetail.refundStatus" />
@@ -194,7 +197,7 @@
           {{ orderDetail.body }}
         </el-descriptions-item>
         <el-descriptions-item label="支付通道异步回调内容">
-          {{ orderDetail.payOrderExtension.channelNotifyData }}
+          {{ orderDetail.extension.channelNotifyData }}
         </el-descriptions-item>
       </el-descriptions>
     </el-dialog>
@@ -204,34 +207,6 @@
 <script>
 import { getOrderDetail, getOrderPage, exportOrderExcel } from "@/api/pay/order";
 import { DICT_TYPE, getDictDatas } from "@/utils/dict";
-import { getNowDateTime} from "@/utils/ruoyi";
-
-const defaultOrderDetail = {
-  appName: '',
-  channelCodeName: '',
-  subject: '',
-  merchantOrderId: null,
-  channelOrderNo: '',
-  body: '',
-  price: null,
-  channelFeeRate: null,
-  channelFeePrice: null,
-  userIp: '',
-  status: null,
-  notifyUrl: '',
-  notifyStatus: null,
-  refundStatus: null,
-  refundTimes: '',
-  refundPrice: null,
-  createTime: '',
-  successTime: '',
-  notifyTime: '',
-  expireTime: '',
-  payOrderExtension: {
-    channelNotifyData: '',
-    no: ''
-  }
-};
 
 export default {
   name: "PayOrder",
@@ -278,47 +253,24 @@ export default {
         notifyTime: [],
         createTime: []
       },
-      // 商户加载遮罩层
-      merchantLoading: false,
-      // 商户列表集合
-      merchantList: null,
+
       // 支付应用列表集合
-      appList: null,
-      // 支付渠道编码字典数据集合
-      payChannelCodeDictDatum: getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE),
+      appList: [],
       // 订单回调商户状态字典数据集合
       payOrderNotifyDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_NOTIFY_STATUS),
-      // 订单状态字典数据集合
-      payOrderDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_STATUS),
-      // 订单退款状态字典数据集合
-      payOrderRefundDictDatum: getDictDatas(DICT_TYPE.PAY_ORDER_REFUND_STATUS),
-      orderDetail: JSON.parse(JSON.stringify(defaultOrderDetail)),
+
+      // 订单详情
+      orderDetail: {
+        extension: {}
+      },
     };
   },
   created() {
-    // 初始化默认时间
-    this.initTime();
     this.getList();
-    this.handleGetMerchantListByName(null);
   },
   methods: {
-    initTime(){
-      this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")];
-    },
     /** 查询列表 */
     getList() {
-      // 判断选择的日期是否超过了一个月
-      let oneMonthTime = 31 * 24 * 3600 * 1000;
-      if (this.queryParams.createTime == null){
-        this.initTime();
-      } else {
-        let minDateTime = new Date(this.queryParams.createTime[0]).getTime();
-        let maxDateTime = new Date(this.queryParams.createTime[1]).getTime()
-        if (maxDateTime - minDateTime > oneMonthTime) {
-          this.$message.error('时间范围最大为 31 天!');
-          return false;
-        }
-      }
       this.loading = true;
       // 执行查询
       getOrderPage(this.queryParams).then(response => {
@@ -339,23 +291,22 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
-      this.initTime();
       this.handleQuery();
     },
-    /**
-     * 查看订单详情
-     */
-    handleQueryDetails(row) {
-      this.orderDetail = JSON.parse(JSON.stringify(defaultOrderDetail));
+    /** 详情按钮操作 */
+    handleDetail(row) {
+      this.orderDetail = {};
       getOrderDetail(row.id).then(response => {
+        // 设置值
         this.orderDetail = response.data;
-        if (response.data.payOrderExtension === null) {
-          this.orderDetail.payOrderExtension = Object.assign(defaultOrderDetail.payOrderExtension, {});
+        if (!this.orderDetail.extension) {
+          this.orderDetail.extension = {}
         }
+        // 弹窗打开
         this.open = true;
       });
-
     },
+
     /** 导出按钮操作 */
     handleExport() {
       // 处理查询参数