Bladeren bron

优化退款申请性能,退款申请增加挂起功能

skyline 2 maanden geleden
bovenliggende
commit
9eef84fde9

+ 79 - 1
admin-web/src/views/admin/refund/index.vue

@@ -149,6 +149,22 @@
                 @click="onManualRefundClick(row)">
                 线下退款
               </el-button>
+              <el-button 
+                v-if="row.status==='NEW' && row.isOverdue"  
+                size="small" 
+                plain 
+                type="info" 
+                @click="onSuspendRefundClick(row)">
+                挂起
+              </el-button>
+              <el-button 
+                v-if="row.status==='SUSPENDED'"  
+                size="small" 
+                plain 
+                type="primary" 
+                @click="onCancelSuspendRefundClick(row)">
+                取消挂起
+              </el-button>
             </template>
             <template v-else>
               <div>{{ row[field.prop] }}</div>
@@ -217,7 +233,7 @@ const state = reactive({
       {label: '退款入账账户', prop: 'userReceivedAccount', resizable: true, width: 120},
       {label: '操作人', prop: 'adminUsername', resizable: true, width: 120},
       {
-        label: '操作', prop: 'action', width: 110, align: 'center', fixed: 'right',
+        label: '操作', prop: 'action', width: 180, align: 'center', fixed: 'right',
       }
     ],
   },
@@ -337,6 +353,68 @@ const onManualRefundClick = (row: any) => {
   });
 };
 
+// 挂起退款申请
+const onSuspendRefundClick = (row: any) => {
+  Msg.confirm(
+    `<div style="line-height: 2; font-size: 14px;">` +
+    `<div style="font-weight: bold; color: #909399; font-size: 15px; margin-bottom: 10px;">【挂起退款申请】</div>` +
+    `<div style="margin: 8px 0;"><span style="color: #606266;">用户手机:</span><span style="font-weight: 500;">${row.mobilePhone}</span></div>` +
+    `<div style="margin: 8px 0;"><span style="color: #606266;">退款金额:</span><span style="font-weight: 500; color: #F56C6C;">${u.fmt.fmtMoney(row.refund)}</span></div>` +
+    `<div style="margin: 8px 0;"><span style="color: #606266;">充值时间:</span><span style="font-weight: 500;">${row.rechargeTime ? row.rechargeTime.replace('T', ' ') : '无'}</span></div>` +
+    `<div style="margin: 15px 0; padding: 10px; background-color: #F4F4F5; border-radius: 4px; border-left: 3px solid #909399;">` +
+    `<div style="color: #909399; margin-bottom: 5px;">该订单已超过365天退款时限</div>` +
+    `<div style="color: #909399;">挂起后可在方便时统一处理</div>` +
+    `</div>` +
+    `</div>`,
+    '挂起确认',
+    {
+      confirmButtonText: '确认挂起',
+      cancelButtonText: '取消',
+      type: 'info'
+    }
+  ).then(() => {
+    $get(`/finance/suspendRefund/${row.refundLogId}`).then((res: any) => {
+      Msg.message(`挂起成功`)
+      loadData(true)
+    }).catch(e => {
+      console.error(e)
+      Msg.message(`操作失败:${e.message}`, 'error')
+    })
+  }).catch(() => {
+    // 用户取消操作
+  });
+};
+
+// 取消挂起退款申请
+const onCancelSuspendRefundClick = (row: any) => {
+  Msg.confirm(
+    `<div style="line-height: 2; font-size: 14px;">` +
+    `<div style="font-weight: bold; color: #409EFF; font-size: 15px; margin-bottom: 10px;">【取消挂起】</div>` +
+    `<div style="margin: 8px 0;"><span style="color: #606266;">用户手机:</span><span style="font-weight: 500;">${row.mobilePhone}</span></div>` +
+    `<div style="margin: 8px 0;"><span style="color: #606266;">退款金额:</span><span style="font-weight: 500; color: #F56C6C;">${u.fmt.fmtMoney(row.refund)}</span></div>` +
+    `<div style="margin: 15px 0; padding: 10px; background-color: #ECF5FF; border-radius: 4px; border-left: 3px solid #409EFF;">` +
+    `<div style="color: #409EFF;">取消挂起后,退款状态将恢复为"新申请"</div>` +
+    `</div>` +
+    `</div>`,
+    '取消挂起确认',
+    {
+      confirmButtonText: '确认取消挂起',
+      cancelButtonText: '取消',
+      type: 'primary'
+    }
+  ).then(() => {
+    $get(`/finance/cancelSuspendRefund/${row.refundLogId}`).then((res: any) => {
+      Msg.message(`取消挂起成功`)
+      loadData(true)
+    }).catch(e => {
+      console.error(e)
+      Msg.message(`操作失败:${e.message}`, 'error')
+    })
+  }).catch(() => {
+    // 用户取消操作
+  });
+};
+
 
 const handleTableSelectionChange = (selection: any) => {
   console.log("handleTableSelectionChange>>", selection)

+ 14 - 0
admin/src/main/java/com/kym/admin/controller/FinanceController.java

@@ -81,6 +81,20 @@ public class FinanceController {
         return R.success();
     }
 
+    @SysLog("挂起退款申请")
+    @GetMapping("/suspendRefund/{refundLogId}")
+    R<?> suspendRefund(@PathVariable("refundLogId") long refundLogId) {
+        wxPayService.suspendRefund(refundLogId);
+        return R.success();
+    }
+
+    @SysLog("取消挂起退款申请")
+    @GetMapping("/cancelSuspendRefund/{refundLogId}")
+    R<?> cancelSuspendRefund(@PathVariable("refundLogId") long refundLogId) {
+        wxPayService.cancelSuspendRefund(refundLogId);
+        return R.success();
+    }
+
     @GetMapping("/getUserTitle/{applyId}")
     Object getUserTitle(@PathVariable String applyId) {
         return wxPayService.userTitle(applyId);

+ 1 - 1
admin/src/main/resources/static/index.html

@@ -9,7 +9,7 @@
     <link rel="icon" href="./assets/logo.46850193.png"/>
     <title>快与慢运营管理平台</title>
 
-  <script type="module" crossorigin src="./assets/index.569521c2.js"></script>
+  <script type="module" crossorigin src="./assets/index.76a47322.js"></script>
   <link rel="modulepreload" crossorigin href="./assets/vue.6ae8aee9.js">
   <link rel="stylesheet" href="./assets/index.63d29cea.css">
 </head>

+ 2 - 1
entity/src/main/java/com/kym/entity/miniapp/RefundLog.java

@@ -27,6 +27,7 @@ public class RefundLog extends BaseEntity {
     public static final String STATUS_退款处理中 = "PROCESSING";
     public static final String STATUS_退款异常 = "ABNORMAL";
     public static final String STATUS_退款已申请 = "NEW";
+    public static final String STATUS_挂起 = "SUSPENDED";
 
     private static final long serialVersionUID = 1L;
 
@@ -71,7 +72,7 @@ public class RefundLog extends BaseEntity {
     private LocalDateTime successTime;
 
     /**
-     * 退款状态:SUCCESS:退款成功 CLOSED:退款关闭 PROCESSING:退款处理中 ABNORMAL:退款异常  NEW:已申请(自定义)
+     * 退款状态:SUCCESS:退款成功 CLOSED:退款关闭 PROCESSING:退款处理中 ABNORMAL:退款异常  NEW:已申请(自定义) SUSPENDED:挂起
      */
     private String status;
 

+ 8 - 18
mapper/src/main/resources/mappers/miniapp/RefundLogMapper.xml

@@ -57,10 +57,10 @@
     <select id="listRefundLog" resultMap="RefundVoMap" parameterType="com.kym.entity.admin.queryParams.CommonQueryParam">
         SELECT
             t1.id,
-            t4.user_id,
-            t4.mobile_phone,
-            t4.balance,
-            t4.frozen_amount,
+            t2.id as user_id,
+            t2.mobile_phone,
+            t3.balance,
+            t3.frozen_amount,
             t1.out_refund_no,
             t1.out_trade_no,
             t1.channel,
@@ -83,22 +83,12 @@
             END as is_overdue
         FROM
             t_refund_log t1
-                LEFT JOIN
-            (SELECT
-                 t2.id user_id,
-                 t2.mobile_phone,
-                 t3.balance,
-                 t3.frozen_amount
-             FROM
-                 t_user t2
-                     LEFT JOIN t_account t3
-                               ON t2.id = t3.user_id) t4
-            ON t1.user_id = t4.user_id
-                LEFT JOIN t_pay_log t5
-                    ON CONVERT(t1.out_trade_no USING utf8mb4) = CONVERT(t5.out_trade_no USING utf8mb4)
+            LEFT JOIN t_user t2 ON t1.user_id = t2.id
+            LEFT JOIN t_account t3 ON t2.id = t3.user_id
+            LEFT JOIN t_pay_log t5 ON t1.out_trade_no COLLATE utf8mb4_general_ci = t5.out_trade_no
         <where>
             <if test="params.mobilePhone != null and params.mobilePhone != ''  ">
-                and t4.mobile_phone = #{params.mobilePhone}
+                and t2.mobile_phone = #{params.mobilePhone}
             </if>
             <if test="params.status != null and params.status !='' ">
                 and t1.status = #{params.status}

+ 4 - 0
service/src/main/java/com/kym/service/wechat/WxPayService.java

@@ -23,6 +23,10 @@ public interface WxPayService {
 
     void manualConfirmRefund(long refundLogId);
 
+    void suspendRefund(long refundLogId);
+
+    void cancelSuspendRefund(long refundLogId);
+
     Refund queryByOutRefundNo(String outRefundNo);
 
     ResponseEntity<Object> wxRefundNotify(HttpServletRequest request);

+ 72 - 0
service/src/main/java/com/kym/service/wechat/impl/WxPayServiceImpl.java

@@ -552,6 +552,78 @@ public class WxPayServiceImpl implements WxPayService {
         LOGGER.info("手动确认退款完成,退款记录ID:{},操作人员:{}", refundLogId, StpUtil.getSession().getString("username"));
     }
 
+    /**
+     * 挂起退款申请(针对超过365天的订单)
+     *
+     * @param refundLogId 退款记录ID
+     */
+    @DS("db-miniapp")
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void suspendRefund(long refundLogId) {
+        var refundLog = refundLogService.getById(refundLogId);
+        if (refundLog == null) {
+            throw new BusinessException("退款记录不存在");
+        }
+
+        if (!RefundLog.STATUS_退款已申请.equals(refundLog.getStatus())) {
+            throw new BusinessException("退款状态不正确,只能挂起已申请状态的退款");
+        }
+
+        var payLog = payLogService.lambdaQuery()
+                .eq(PayLog::getOutTradeNo, refundLog.getOutTradeNo())
+                .eq(PayLog::getTradeState, PayLog.STATUS_充值成功)
+                .one();
+
+        if (payLog == null) {
+            throw new BusinessException("找不到对应的支付记录");
+        }
+
+        LocalDateTime paySuccessTime = payLog.getSuccessTime();
+        boolean isOverdue = paySuccessTime.plusDays(365).isBefore(LocalDateTime.now());
+
+        if (!isOverdue) {
+            throw new BusinessException("该订单未超过365天退款时限,无需挂起");
+        }
+
+        refundLogService.lambdaUpdate()
+                .set(RefundLog::getStatus, RefundLog.STATUS_挂起)
+                .set(RefundLog::getAdminUserId, StpUtil.getLoginIdAsLong())
+                .set(RefundLog::getAdminUsername, StpUtil.getSession().getString("username"))
+                .eq(RefundLog::getId, refundLogId)
+                .update();
+
+        LOGGER.info("挂起退款申请完成,退款记录ID:{},操作人员:{}", refundLogId, StpUtil.getSession().getString("username"));
+    }
+
+    /**
+     * 取消挂起退款申请
+     *
+     * @param refundLogId 退款记录ID
+     */
+    @DS("db-miniapp")
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void cancelSuspendRefund(long refundLogId) {
+        var refundLog = refundLogService.getById(refundLogId);
+        if (refundLog == null) {
+            throw new BusinessException("退款记录不存在");
+        }
+
+        if (!RefundLog.STATUS_挂起.equals(refundLog.getStatus())) {
+            throw new BusinessException("退款状态不正确,只能取消挂起状态的退款");
+        }
+
+        refundLogService.lambdaUpdate()
+                .set(RefundLog::getStatus, RefundLog.STATUS_退款已申请)
+                .set(RefundLog::getAdminUserId, StpUtil.getLoginIdAsLong())
+                .set(RefundLog::getAdminUsername, StpUtil.getSession().getString("username"))
+                .eq(RefundLog::getId, refundLogId)
+                .update();
+
+        LOGGER.info("取消挂起退款申请完成,退款记录ID:{},操作人员:{}", refundLogId, StpUtil.getSession().getString("username"));
+    }
+
     /**
      * 处理退款成功的公共逻辑
      *