Просмотр исходного кода

fix(cf): 修复最终审查问题(幂等唯一索引兜底 + NPE判空 + delete参数校验 + 前端路由/时间格式)

Sisyphus 2 месяцев назад
Родитель
Сommit
45c60d6899

+ 8 - 0
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -10187,5 +10187,13 @@ public class DatabaseInitializer implements CommandLineRunner {
         } catch (Exception e) {
             log.warn("referral_tree.uk_parent_child 已存在: {}", e.getMessage());
         }
+
+        // 迁移284: cf_transfer_record 加 (ref_type, ref_id) 唯一索引(幂等兜底,防止并发 earn 重复发放)
+        try {
+            jdbcTemplate.execute("ALTER TABLE cf_transfer_record ADD UNIQUE KEY uk_ref_type_id (ref_type, ref_id)");
+            log.info("cf_transfer_record 已添加 uk_ref_type_id 唯一索引");
+        } catch (Exception e) {
+            log.warn("cf_transfer_record.uk_ref_type_id 已存在: {}", e.getMessage());
+        }
     }
 }

+ 3 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminCfRateTierController.java

@@ -43,7 +43,9 @@ public class AdminCfRateTierController {
 
     @PostMapping("/delete")
     public Result<String> delete(@RequestBody Map<String, Object> params) {
-        Long id = ((Number) params.get("id")).longValue();
+        Object idObj = params.get("id");
+        if (idObj == null) return Result.error("id 不能为空");
+        Long id = ((Number) idObj).longValue();
         cfRateTierMapper.deleteById(id);
         return Result.success("已删除");
     }

+ 4 - 1
cfc-backend/src/main/java/com/etotem/cfc/service/AssessmentOrderService.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.etotem.cfc.common.OrderNoGenerator;
 import com.etotem.cfc.entity.AssessmentOrder;
 import com.etotem.cfc.entity.AssessmentAppointment;
+import com.etotem.cfc.entity.User;
 import com.etotem.cfc.mapper.AssessmentOrderMapper;
 import com.etotem.cfc.mapper.AssessmentAppointmentMapper;
 import com.etotem.cfc.mapper.UserMapper;
@@ -80,8 +81,10 @@ public class AssessmentOrderService extends ServiceImpl<AssessmentOrderMapper, A
         order.setUpdatedAt(new Date());
         boolean updated = this.updateById(order);
         if (updated) {
+            User buyer = userMapper.selectById(order.getUserId());
+            Long buyerFamilyId = (buyer != null) ? buyer.getFamilyId() : null;
             cfCommissionService.settle(order.getId(), "assessment", order.getUserId(),
-                    userMapper.selectById(order.getUserId()).getFamilyId(),
+                    buyerFamilyId,
                     order.getActualPrice() != null ? order.getActualPrice().intValue() : 0, null);
         }
         return updated;

+ 3 - 2
cfc-backend/src/main/java/com/etotem/cfc/service/MembershipService.java

@@ -784,8 +784,9 @@ public class MembershipService implements MembershipServiceInterface {
             }
 
             // 结算佣金(推荐人分润)
-            cfCommissionService.settleReferrerOnly(order.getId(), "membership", adminUserId,
-                    userMapper.selectById(adminUserId).getFamilyId(), order.getAmount());
+            User buyer = userMapper.selectById(adminUserId);
+            Long buyerFamilyId = (buyer != null) ? buyer.getFamilyId() : null;
+            cfCommissionService.settleReferrerOnly(order.getId(), "membership", adminUserId, buyerFamilyId, order.getAmount());
 
             log.info("会员开通完成: orderNo={}, levelCode={}, amount={}, fromLevel={}",
                     order.getOrderNo(), order.getLevelCode(), order.getAmount(), fromLevel);

+ 2 - 1
cfc-backend/src/main/resources/schema.sql

@@ -5336,5 +5336,6 @@ CREATE TABLE IF NOT EXISTS cf_transfer_record (
     created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
     INDEX idx_from (from_user_id),
     INDEX idx_to (to_user_id),
-    INDEX idx_family (family_id)
+    INDEX idx_family (family_id),
+    UNIQUE KEY uk_ref_type_id (ref_type, ref_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值流转记录';

+ 4 - 1
cfc-frontend/pages/promotion/commission.vue

@@ -124,7 +124,10 @@ export default {
       if (!time) return ''
       var d = parseDate(time)
       if (!d) return ''
-      return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0')
+      return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0') + ' ' +
+             String(d.getHours()).padStart(2, '0') + ':' +
+             String(d.getMinutes()).padStart(2, '0') + ':' +
+             String(d.getSeconds()).padStart(2, '0')
     }
   }
 }

+ 0 - 1
cfc-frontend/utils/api.js

@@ -1833,7 +1833,6 @@ export const getCommissionBalance = () => {
 export const getCfRate = () => request('/api/commission/cf/rate', 'POST')
 export const getCfSummary = () => request('/api/commission/cf/summary', 'POST')
 export const getCfList = (page, size) => request('/api/commission/cf/list', 'POST', { page, size })
-export const getFamilyCoupons = (page, size) => request('/api/coupon/family/list', 'POST', { page, size })
 // CF 转让
 export const sendCfTransfer = (toUserId, amount) => request('/api/cf/transfer/send', 'POST', { toUserId, amount })
 export const getCfTransferList = (page, size) => request('/api/cf/transfer/list', 'POST', { page, size })