Ver Fonte

mall + pay:
1. 优化退款管理的导出实现

YunaiV há 1 ano atrás
pai
commit
721adfbf60

+ 5 - 27
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java

@@ -1,16 +1,13 @@
 package cn.iocoder.yudao.module.pay.controller.admin.refund;
 
 import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
-import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
 import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
 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.refund.PayRefundDO;
 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
@@ -62,8 +59,7 @@ public class PayRefundController {
 
         // 拼接数据
         PayAppDO app = appService.getApp(refund.getAppId());
-        PayOrderDO order = orderService.getOrder(refund.getOrderId());
-        return success(PayRefundConvert.INSTANCE.convert(refund, order, app));
+        return success(PayRefundConvert.INSTANCE.convert(refund, app));
     }
 
     @GetMapping("/page")
@@ -93,29 +89,11 @@ public class PayRefundController {
             return;
         }
 
-        // 处理应用ID数据
-        Map<Long, PayAppDO> appMap = appService.getAppMap(
-                convertList(list, PayRefundDO::getAppId));
-
-        List<PayRefundExcelVO> excelDatum = new ArrayList<>(list.size());
-        // 处理商品名称数据
-        Map<Long, PayOrderDO> orderMap = orderService.getOrderSubjectMap(
-                convertList(list, PayRefundDO::getOrderId));
-
-        list.forEach(c -> {
-            PayAppDO appDO = appMap.get(c.getAppId());
-            PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());
-
-            PayRefundExcelVO excelItem = PayRefundConvert.INSTANCE.excelConvert(c);
-            excelItem.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
-            excelItem.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
-            excelItem.setSubject(orderMap.get(c.getOrderId()).getSubject());
-
-            excelDatum.add(excelItem);
-        });
-
+        // 拼接返回
+        Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(list, PayRefundDO::getAppId));
+        List<PayRefundExcelVO> excelList = PayRefundConvert.INSTANCE.convertList(list, appMap);
         // 导出 Excel
-        ExcelUtils.write(response, "退款订单.xls", "数据", PayRefundExcelVO.class, excelDatum);
+        ExcelUtils.write(response, "退款订单.xls", "数据", PayRefundExcelVO.class, excelList);
     }
 
 }

+ 25 - 38
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExcelVO.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
 
 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert;
 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
 import com.alibaba.excel.annotation.ExcelProperty;
 import lombok.Data;
@@ -19,56 +20,42 @@ public class PayRefundExcelVO {
     @ExcelProperty("支付退款编号")
     private Long id;
 
-    @ExcelProperty("商品名称")
-    private String subject;
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
 
-    @ExcelProperty(value = "应用名称")
-    private String appName;
+    @ExcelProperty(value = "支付金额", converter = MoneyConvert.class)
+    private Integer payPrice;
 
-    @ExcelProperty(value = "渠道编号名称")
-    private String channelCodeName;
+    @ExcelProperty(value = "退款金额", converter = MoneyConvert.class)
+    private Integer refundPrice;
 
-    @ExcelProperty("交易订单号")
-    private String tradeNo;
+    @ExcelProperty("商户退款单号")
+    private String merchantRefundId;
+    @ExcelProperty("退款单号")
+    private String no;
+    @ExcelProperty("渠道退款单号")
+    private String channelRefundNo;
 
-    @ExcelProperty("商户订单编号")
+    @ExcelProperty("商户支付单号")
     private String merchantOrderId;
+    @ExcelProperty("渠道支付单号")
+    private String channelOrderNo;
 
-    @ExcelProperty("商户退款订单号")
-    private String merchantRefundNo;
-
-    @ExcelProperty("异步通知商户地址")
-    private String notifyUrl;
-
-    @DictFormat(DictTypeConstants.REFUND_STATUS)
     @ExcelProperty(value = "退款状态", converter = DictConvert.class)
+    @DictFormat(DictTypeConstants.REFUND_STATUS)
     private Integer status;
 
-    @ExcelProperty("支付金额,单位:元")
-    private String payPrice;
+    @ExcelProperty(value = "退款渠道", converter = DictConvert.class)
+    @DictFormat(DictTypeConstants.CHANNEL_CODE)
+    private String channelCode;
 
-    @ExcelProperty("退款金额,单位:元")
-    private String refundPrice;
+    @ExcelProperty("成功时间")
+    private LocalDateTime successTime;
+
+    @ExcelProperty(value = "支付应用")
+    private String appName;
 
     @ExcelProperty("退款原因")
     private String reason;
 
-    @ExcelProperty("用户付款 IP")
-    private String userIp;
-
-    @ExcelProperty("渠道订单号")
-    private String channelOrderNo;
-
-    @ExcelProperty("渠道退款单号")
-    private String channelRefundNo;
-
-    @ExcelProperty("创建时间")
-    private LocalDateTime createTime;
-
-    @ExcelProperty("退款成功时间")
-    private LocalDateTime successTime;
-
-    @ExcelProperty("退款失效时间")
-    private LocalDateTime expireTime;
-
 }

+ 13 - 41
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.pay.convert.refund;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
@@ -13,8 +14,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
-import java.math.BigDecimal;
-import java.math.RoundingMode;
+import java.util.List;
 import java.util.Map;
 
 @Mapper
@@ -23,9 +23,8 @@ public interface PayRefundConvert {
     PayRefundConvert INSTANCE = Mappers.getMapper(PayRefundConvert.class);
 
 
-    default PayRefundDetailsRespVO convert(PayRefundDO refund, PayOrderDO order, PayAppDO app) {
-        PayRefundDetailsRespVO respVO = convert(refund)
-                .setOrder(convert(order));
+    default PayRefundDetailsRespVO convert(PayRefundDO refund, PayAppDO app) {
+        PayRefundDetailsRespVO respVO = convert(refund);
         if (app != null) {
             respVO.setAppName(app.getName());
         }
@@ -41,44 +40,17 @@ public interface PayRefundConvert {
     }
     PageResult<PayRefundPageItemRespVO> convertPage(PageResult<PayRefundDO> page);
 
-    /**
-     * 退款订单DO 转 导出excel VO
-     *
-     * @param bean 退款订单DO
-     * @return 导出 excel VO
-     */
-    default PayRefundExcelVO excelConvert(PayRefundDO bean) {
-        if (bean == null) {
-            return null;
-        }
-
-        PayRefundExcelVO payRefundExcelVO = new PayRefundExcelVO();
-
-        payRefundExcelVO.setId(bean.getId());
-        payRefundExcelVO.setTradeNo(bean.getNo());
-        payRefundExcelVO.setMerchantOrderId(bean.getMerchantOrderId());
-        // TODO 芋艿:晚点在改
-//        payRefundExcelVO.setMerchantRefundNo(bean.getMerchantRefundNo());
-        payRefundExcelVO.setNotifyUrl(bean.getNotifyUrl());
-        payRefundExcelVO.setStatus(bean.getStatus());
-        payRefundExcelVO.setReason(bean.getReason());
-        payRefundExcelVO.setUserIp(bean.getUserIp());
-        payRefundExcelVO.setChannelOrderNo(bean.getChannelOrderNo());
-        payRefundExcelVO.setChannelRefundNo(bean.getChannelRefundNo());
-        payRefundExcelVO.setSuccessTime(bean.getSuccessTime());
-        payRefundExcelVO.setCreateTime(bean.getCreateTime());
-
-        BigDecimal multiple = new BigDecimal(100);
-        payRefundExcelVO.setPayPrice(BigDecimal.valueOf(bean.getPayPrice())
-                .divide(multiple, 2, RoundingMode.HALF_UP).toString());
-        payRefundExcelVO.setRefundPrice(BigDecimal.valueOf(bean.getRefundPrice())
-                .divide(multiple, 2, RoundingMode.HALF_UP).toString());
-
-        return payRefundExcelVO;
-    }
-
     PayRefundDO convert(PayRefundCreateReqDTO bean);
 
     PayRefundRespDTO convert02(PayRefundDO bean);
 
+    default List<PayRefundExcelVO> convertList(List<PayRefundDO> list, Map<Long, PayAppDO> appMap) {
+        return CollectionUtils.convertList(list, order -> {
+            PayRefundExcelVO excelVO = convertExcel(order);
+            MapUtils.findAndThen(appMap, order.getAppId(), app -> excelVO.setAppName(app.getName()));
+            return excelVO;
+        });
+    }
+    PayRefundExcelVO convertExcel(PayRefundDO bean);
+
 }

+ 0 - 22
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.pay.service.order;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
@@ -13,9 +12,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
 
 import javax.validation.Valid;
 import javax.validation.constraints.NotEmpty;
-import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 
 /**
  * 支付订单 Service 接口
@@ -65,25 +62,6 @@ public interface PayOrderService {
      */
     List<PayOrderDO> getOrderList(PayOrderExportReqVO exportReqVO);
 
-    /**
-     * 获得支付订单列表
-     *
-     * @param ids 订单 ID 集合
-     * @return 支付订单列表
-     */
-    List<PayOrderDO> getOrderList(Collection<Long> ids);
-
-    /**
-     * 获得支付订单 Map
-     *
-     * @param ids 订单 ID 集合
-     * @return 支付订单 Map 集合
-     */
-    default Map<Long, PayOrderDO> getOrderSubjectMap(Collection<Long> ids) {
-        List<PayOrderDO> list = getOrderList(ids);
-        return CollectionUtils.convertMap(list, PayOrderDO::getId);
-    }
-
     /**
      * 创建支付单
      *

+ 0 - 6
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java

@@ -41,7 +41,6 @@ import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
-import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 
@@ -102,11 +101,6 @@ public class PayOrderServiceImpl implements PayOrderService {
         return orderMapper.selectList(exportReqVO);
     }
 
-    @Override
-    public List<PayOrderDO> getOrderList(Collection<Long> ids) {
-        return orderMapper.selectBatchIds(ids);
-    }
-
     @Override
     public Long createOrder(PayOrderCreateReqDTO reqDTO) {
         // 校验 App

+ 1 - 2
yudao-ui-admin/src/views/pay/order/index.vue

@@ -127,7 +127,7 @@
           <el-tag size="small">{{ orderDetail.merchantOrderId }}</el-tag>
         </el-descriptions-item>
         <el-descriptions-item label="支付单号">
-          <el-tag type="warning" v-if="orderDetail.no">{{ orderDetail.no }}</el-tag>
+          <el-tag type="warning" size="small" v-if="orderDetail.no">{{ orderDetail.no }}</el-tag>
         </el-descriptions-item>
       </el-descriptions>
       <el-descriptions :column="2" label-class-name="desc-label">
@@ -278,7 +278,6 @@ export default {
         this.open = true;
       });
     },
-
     /** 导出按钮操作 */
     handleExport() {
       // 处理查询参数

+ 46 - 32
yudao-ui-admin/src/views/pay/refund/index.vue

@@ -78,7 +78,7 @@
             <el-tag size="mini">商户</el-tag> {{scope.row.merchantRefundId}}
           </p>
           <p class="order-font">
-            <el-tag size="mini" type="warning">支付</el-tag> {{scope.row.no}}
+            <el-tag size="mini" type="warning">退款</el-tag> {{scope.row.no}}
           </p>
           <p class="order-font" v-if="scope.row.channelRefundNo">
             <el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelRefundNo}}
@@ -110,6 +110,11 @@
           <span>{{ parseTime(scope.row.successTime) }}</span>
         </template>
       </el-table-column>
+      <el-table-column label="支付应用" align="center" prop="successTime" width="100">
+        <template v-slot="scope">
+          <span>{{ scope.row.appName }}</span>
+        </template>
+      </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)"
@@ -122,64 +127,75 @@
     <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
                 @pagination="getList"/>
 
-    <!-- 对话框(添加 / 修改) -->
+    <!-- 对话框(详情) -->
     <el-dialog title="退款订单详情" :visible.sync="open" width="700px" append-to-body>
       <el-descriptions :column="2" label-class-name="desc-label">
-        <el-descriptions-item label="应用名称">{{ refundDetail.appName }}</el-descriptions-item>
-        <el-descriptions-item label="商品名称">{{ refundDetail.subject }}</el-descriptions-item>
+        <el-descriptions-item label="商户退款单号">
+          <el-tag size="small">{{ refundDetail.merchantRefundId }}</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="渠道退款单号">
+          <el-tag type="success" size="small" v-if="refundDetail.channelRefundNo">{{ refundDetail.channelRefundNo }}</el-tag>
+        </el-descriptions-item>
       </el-descriptions>
-      <el-divider></el-divider>
       <el-descriptions :column="2" label-class-name="desc-label">
-        <el-descriptions-item label="商户退款单号">
-          <el-tag  size="mini">{{ refundDetail.merchantRefundNo }}</el-tag>
+        <el-descriptions-item label="商户支付单号">
+          <el-tag size="small">{{ refundDetail.merchantOrderId }}</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="渠道支付单号">
+          <el-tag type="success" size="small">{{ refundDetail.channelOrderNo }}</el-tag>
         </el-descriptions-item>
-        <el-descriptions-item label="商户订单号">{{ refundDetail.merchantOrderId }}</el-descriptions-item>
-        <el-descriptions-item label="交易订单号">{{ refundDetail.tradeNo }}</el-descriptions-item>
       </el-descriptions>
-      <el-divider></el-divider>
+      <el-descriptions :column="2" label-class-name="desc-label">
+        <el-descriptions-item label="应用编号">{{ refundDetail.appId }}</el-descriptions-item>
+        <el-descriptions-item label="应用名称">{{ refundDetail.appName }}</el-descriptions-item>
+      </el-descriptions>
       <el-descriptions :column="2" label-class-name="desc-label">
         <el-descriptions-item label="支付金额">
-          {{ parseFloat(refundDetail.payPrice / 100).toFixed(2) }}
+          <el-tag type="success" size="small">¥{{ (refundDetail.payPrice / 100.0).toFixed(2) }}</el-tag>
         </el-descriptions-item>
-        <el-descriptions-item label="退款金额" size="mini">
-          <el-tag class="tag-purple" size="mini">{{ parseFloat(refundDetail.refundPrice / 100).toFixed(2) }}</el-tag>
+        <el-descriptions-item label="退款金额">
+          <el-tag size="mini" type="danger">¥{{ (refundDetail.refundPrice / 100.0).toFixed(2) }}</el-tag>
         </el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions :column="2" label-class-name="desc-label">
         <el-descriptions-item label="退款状态">
           <dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="refundDetail.status" />
         </el-descriptions-item>
+        <el-descriptions-item label="退款时间">{{ parseTime(refundDetail.successTime) }}</el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions :column="2" label-class-name="desc-label">
         <el-descriptions-item label="创建时间">{{ parseTime(refundDetail.createTime) }}</el-descriptions-item>
-        <el-descriptions-item label="退款成功时间">{{ parseTime(refundDetail.successTime) }}</el-descriptions-item>
-        <el-descriptions-item label="退款失效时间">{{ parseTime(refundDetail.expireTime) }}</el-descriptions-item>
         <el-descriptions-item label="更新时间">{{ parseTime(refundDetail.updateTime) }}</el-descriptions-item>
       </el-descriptions>
-      <el-divider></el-divider>
+      <!-- 分割线 -->
+      <el-divider />
       <el-descriptions :column="2" label-class-name="desc-label">
-        <el-descriptions-item label="支付渠道">
-          {{ refundDetail.channelCodeName }}
+        <el-descriptions-item label="退款渠道">
+          <dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="refundDetail.channelCode" />
         </el-descriptions-item>
-        <el-descriptions-item label="支付IP" size="mini">
-          {{refundDetail.userIp}}
-        </el-descriptions-item>
-        <el-descriptions-item label="回调地址">{{ refundDetail.notifyUrl }}</el-descriptions-item>
+        <el-descriptions-item label="退款原因">{{ refundDetail.reason }}</el-descriptions-item>
+      </el-descriptions>
+      <el-descriptions :column="2" label-class-name="desc-label">
+        <el-descriptions-item label="退款 IP">{{ refundDetail.userIp }}</el-descriptions-item>
+        <el-descriptions-item label="通知 URL">{{ refundDetail.notifyUrl }}</el-descriptions-item>
       </el-descriptions>
+      <!-- 分割线 -->
       <el-divider></el-divider>
       <el-descriptions :column="2" label-class-name="desc-label">
-        <el-descriptions-item label="渠道订单号">{{ refundDetail.channelOrderNo }}</el-descriptions-item>
-        <el-descriptions-item label="渠道退款单号">{{ refundDetail.channelRefundNo }}</el-descriptions-item>
         <el-descriptions-item label="渠道错误码">{{refundDetail.channelErrorCode}}</el-descriptions-item>
         <el-descriptions-item label="渠道错误码描述">{{refundDetail.channelErrorMsg}}</el-descriptions-item>
       </el-descriptions>
-      <br>
       <el-descriptions :column="1" label-class-name="desc-label" direction="vertical" border>
-        <el-descriptions-item label="渠道额外参数">{{ refundDetail.channelExtras }}</el-descriptions-item>
-        <el-descriptions-item label="退款原因">{{ refundDetail.reason }}</el-descriptions-item>
+        <el-descriptions-item label="支付通道异步回调内容">
+          {{ refundDetail.channelNotifyData }}
+        </el-descriptions-item>
       </el-descriptions>
     </el-dialog>
   </div>
 </template>
 
 <script>
-import {getRefundPage, exportRefundExcel, getRefund} from "@/api/pay/refund";
+import { getRefundPage, exportRefundExcel, getRefund } from "@/api/pay/refund";
 import { getAppList } from "@/api/pay/app";
 
 export default {
@@ -213,7 +229,7 @@ export default {
         createTime: []
       },
       // 支付应用列表集合
-      appList: null,
+      appList: [],
       // 退款订单详情
       refundDetail: {},
     };
@@ -263,9 +279,7 @@ export default {
         this.$download.excel(response, '退款订单.xls');
       }).catch(() => {});
     },
-    /**
-     * 查看订单详情
-     */
+    /** 详情按钮操作 */
     handleQueryDetails(row) {
       this.refundDetail = {};
       getRefund(row.id).then(response => {