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

feat: AdminController 增加终身会员概览统计、候选人查询与审核授予接口

Xiaogang Liao 2 месяцев назад
Родитель
Сommit
e2aec338e3

+ 140 - 3
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminController.java

@@ -12,6 +12,8 @@ import org.springframework.util.DigestUtils;
 
 import java.util.Date;
 
+import java.text.SimpleDateFormat;
+
 import io.swagger.v3.oas.annotations.Operation;
 import org.springframework.web.bind.annotation.*;
 
@@ -71,6 +73,13 @@ public class AdminController {
     @Resource
     private AssessmentOrderMapper assessmentOrderMapper;
 
+    @Resource
+    private LifetimeStatsMapper lifetimeStatsMapper;
+
+    // 终身会员达标阈值(分)
+    private static final long LIFETIME_CONSUME_THRESHOLD = 100_000_000L;  // 消费 ≥ 100万元
+    private static final long LIFETIME_SALES_THRESHOLD = 200_000_000L;    // 销售 ≥ 200万元
+
     // 用户管理
     @PostMapping("/users")
     public Result<Page<User>> getUsers(@RequestBody Map<String, Object> params) {
@@ -1059,6 +1068,10 @@ public class AdminController {
         Long totalFamilyMemberships = familyMembershipMapper.selectCount(null);
         overview.put("totalFamilyMemberships", totalFamilyMemberships);
 
+        // 终身会员数
+        Long lifetimeCount = userMapper.selectCount(new LambdaQueryWrapper<User>().eq(User::getMemberLevel, "LIFETIME"));
+        overview.put("lifetimeCount", lifetimeCount);
+
         return Result.success(overview);
     }
 
@@ -1066,14 +1079,138 @@ public class AdminController {
     public Result<Page<MemberUpgradeRecord>> getUpgradeRecords(@RequestBody Map<String, Object> params) {
         int page = params.get("page") != null ? ((Number) params.get("page")).intValue() : 1;
         int size = params.get("size") != null ? ((Number) params.get("size")).intValue() : 10;
+        String toLevel = params.get("toLevel") != null ? params.get("toLevel").toString() : null;
+
+        LambdaQueryWrapper<MemberUpgradeRecord> wrapper = new LambdaQueryWrapper<>();
+        if (toLevel != null && !toLevel.isEmpty()) {
+            wrapper.eq(MemberUpgradeRecord::getToLevel, toLevel);
+        }
+        wrapper.orderByDesc(MemberUpgradeRecord::getCreatedAt);
 
         Page<MemberUpgradeRecord> pageParam = new Page<>(page, size);
-        Page<MemberUpgradeRecord> result = memberUpgradeRecordMapper.selectPage(pageParam,
-                new LambdaQueryWrapper<MemberUpgradeRecord>()
-                        .orderByDesc(MemberUpgradeRecord::getCreatedAt));
+        Page<MemberUpgradeRecord> result = memberUpgradeRecordMapper.selectPage(pageParam, wrapper);
         return Result.success(result);
     }
 
+    /**
+     * 终身会员候选人列表:365天滚动消费/销售额,返回达标用户
+     */
+    @PostMapping("/membership/lifetime-candidates")
+    public Result<Map<String, Object>> getLifetimeCandidates(@RequestBody(required = false) Map<String, Object> params) {
+        String cutoff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
+                .format(new Date(System.currentTimeMillis() - 365L * 24 * 60 * 60 * 1000));
+
+        List<Map<String, Object>> consumption = lifetimeStatsMapper.selectConsumptionSummary(cutoff);
+        List<Map<String, Object>> sales = lifetimeStatsMapper.selectSalesSummary(cutoff);
+
+        Map<Long, Long> consumeMap = new HashMap<>();
+        for (Map<String, Object> row : consumption) {
+            Number uid = (Number) row.get("userId");
+            Number amt = (Number) row.get("totalAmount");
+            if (uid != null) consumeMap.put(uid.longValue(), amt == null ? 0L : amt.longValue());
+        }
+        Map<Long, Long> salesMap = new HashMap<>();
+        for (Map<String, Object> row : sales) {
+            Number uid = (Number) row.get("userId");
+            Number amt = (Number) row.get("totalAmount");
+            if (uid != null) salesMap.put(uid.longValue(), amt == null ? 0L : amt.longValue());
+        }
+
+        // 达标类型:consumption | sales | both
+        Map<Long, String> typeMap = new HashMap<>();
+        for (Long uid : consumeMap.keySet()) {
+            if (consumeMap.get(uid) >= LIFETIME_CONSUME_THRESHOLD) {
+                typeMap.put(uid, "consumption");
+            }
+        }
+        for (Long uid : salesMap.keySet()) {
+            if (salesMap.get(uid) >= LIFETIME_SALES_THRESHOLD) {
+                String prev = typeMap.get(uid);
+                typeMap.put(uid, prev == null ? "sales" : "both");
+            }
+        }
+
+        List<Map<String, Object>> candidates = new ArrayList<>();
+        for (Map.Entry<Long, String> entry : typeMap.entrySet()) {
+            User user = userMapper.selectById(entry.getKey());
+            if (user == null || "LIFETIME".equals(user.getMemberLevel())) {
+                continue;  // 已授予或用户不存在,跳过
+            }
+            Map<String, Object> item = new HashMap<>();
+            item.put("userId", entry.getKey());
+            item.put("nickname", user.getNickname());
+            item.put("consumptionAmount", consumeMap.getOrDefault(entry.getKey(), 0L));
+            item.put("salesAmount", salesMap.getOrDefault(entry.getKey(), 0L));
+            item.put("qualifiedType", entry.getValue());
+            candidates.add(item);
+        }
+        // 按消费额降序
+        candidates.sort((a, b) -> Long.compare(
+                ((Number) b.get("consumptionAmount")).longValue(),
+                ((Number) a.get("consumptionAmount")).longValue()));
+
+        // 分页(overall 量可控,内存分页即可)
+        int current = params != null && params.get("page") != null ? ((Number) params.get("page")).intValue() : 1;
+        int size = params != null && params.get("size") != null ? ((Number) params.get("size")).intValue() : 20;
+        int from = Math.min((current - 1) * size, candidates.size());
+        int to = Math.min(from + size, candidates.size());
+
+        Map<String, Object> data = new HashMap<>();
+        data.put("records", candidates.subList(from, to));
+        data.put("total", (long) candidates.size());
+        data.put("page", current);
+        data.put("size", size);
+        return Result.success(data);
+    }
+
+    /**
+     * 审核授予终身会员
+     */
+    @PostMapping("/membership/lifetime-grant")
+    public Result<Void> grantLifetime(@RequestBody Map<String, Object> params,
+                                      @RequestAttribute("userId") Long adminUserId,
+                                      @RequestAttribute("role") String role) {
+        if (!"admin".equals(role)) {
+            return Result.error("无权限");
+        }
+        if (params.get("userId") == null) {
+            return Result.error("参数缺失: userId");
+        }
+        Long targetUserId = ((Number) params.get("userId")).longValue();
+        String remark = params.get("remark") != null ? params.get("remark").toString() : "";
+
+        User user = userMapper.selectById(targetUserId);
+        if (user == null) {
+            return Result.error("用户不存在");
+        }
+        if ("LIFETIME".equals(user.getMemberLevel())) {
+            return Result.error("该用户已是终身会员");
+        }
+        String fromLevel = user.getMemberLevel() != null ? user.getMemberLevel() : "FREE";
+
+        // 1. 升级用户为 LIFETIME(memberExpireTime=null 永久有效)
+        user.setMemberLevel("LIFETIME");
+        user.setMemberExpireTime(null);
+        user.setUpdatedAt(new Date());
+        userMapper.updateById(user);
+
+        // 2. 写入升级记录 upgradeType='lifetime'
+        MemberUpgradeRecord record = new MemberUpgradeRecord();
+        record.setUserId(targetUserId);
+        record.setFromLevel(fromLevel);
+        record.setToLevel("LIFETIME");
+        record.setUpgradeType("lifetime");
+        record.setApproveUserId(adminUserId);
+        record.setApproveStatus("approved");
+        record.setApproveTime(new Date());
+        record.setApproveRemark(remark != null && !remark.isEmpty()
+                ? remark : "平台终身会员:管理员审核授予");
+        record.setCreatedAt(new Date());
+        memberUpgradeRecordMapper.insert(record);
+
+        return Result.success();
+    }
+
     // ========== 测评待分配规划师 ==========
 
     @PostMapping("/assessment/pending-list")