Explorar el Código

chore: auto bump version and changelog [skip ci]

iwt hace 1 semana
padre
commit
8fd64a255f

+ 130 - 26
cfc-backend/src/main/java/com/etotem/cfc/service/MembershipService.java

@@ -788,7 +788,8 @@ public class MembershipService implements MembershipServiceInterface {
             membership.setFamilyId(order.getFamilyId());
             membership.setLevelCode(order.getLevelCode());
             membership.setStartDate(new Date());
-            membership.setEndDate(calculateEndDate(order.getPaymentType(), order.getPeriod()));
+            Date expireTime = calculateEndDate(order.getPaymentType(), order.getPeriod());
+            membership.setEndDate(expireTime);
             membership.setPaymentMethod(payMethod);
             membership.setPaymentStatus("paid");
             membership.setOrderNo(order.getOrderNo());
@@ -796,24 +797,8 @@ public class MembershipService implements MembershipServiceInterface {
             membership.setAmount(order.getAmount());
             membershipMapper.insert(membership);
 
-            // 升级用户等级
-            String fromLevel = adminUser.getMemberLevel() != null ? adminUser.getMemberLevel() : "FREE";
-            Date expireTime = new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000);
-            adminUser.setMemberLevel(order.getLevelCode());
-            adminUser.setMemberExpireTime(expireTime);
-            adminUser.setUpdatedAt(new Date());
-            userMapper.updateById(adminUser);
-
-            // 创建升级记录
-            MemberUpgradeRecord upgradeRecord = new MemberUpgradeRecord();
-            upgradeRecord.setUserId(adminUserId);
-            upgradeRecord.setFromLevel(fromLevel);
-            upgradeRecord.setToLevel(order.getLevelCode());
-            upgradeRecord.setUpgradeType("pay");
-            upgradeRecord.setOrderId(order.getId());
-            upgradeRecord.setExpireTime(expireTime);
-            upgradeRecord.setCreatedAt(new Date());
-            memberUpgradeRecordMapper.insert(upgradeRecord);
+            // 方案B:全家同步会员身份(使用 membership.getEndDate() 统一到期时间,修正原硬编码 365 天 bug)
+            syncMembershipToFamilyMembers(order.getFamilyId(), order.getLevelCode(), expireTime, "pay", order.getId());
 
             // 发放JOIN会员券(按等级匹配grantType=JOIN的券模板)
             try {
@@ -869,6 +854,128 @@ public class MembershipService implements MembershipServiceInterface {
         return members.get(0).getId();
     }
 
+    // ==================== 方案B:家庭会员全量同步辅助方法 ====================
+
+    /**
+     * 方案B:获取家庭当前有效的付费会员记录(未过期、paymentStatus=paid)
+     * @return 有效会员记录,无则返回 null
+     */
+    private FamilyMembership getActiveFamilyMembership(Long familyId) {
+        if (familyId == null) return null;
+        return membershipMapper.selectOne(
+                new LambdaQueryWrapper<FamilyMembership>()
+                        .eq(FamilyMembership::getFamilyId, familyId)
+                        .eq(FamilyMembership::getPaymentStatus, "paid")
+                        .gt(FamilyMembership::getEndDate, new Date())
+                        .orderByDesc(FamilyMembership::getEndDate)
+                        .last("LIMIT 1"));
+    }
+
+    /**
+     * 方案B:将会员身份同步给家庭所有成员(含不可登录成员,即 userId 非空的所有 users 记录)
+     * 用于:会员开通、赠送、试用开通、消费自动升级
+     * @param familyId 家庭ID
+     * @param levelCode 会员等级代码(FAMILY/PREMIUM/LIFETIME等)
+     * @param expireTime 到期时间
+     * @param upgradeType 升级类型:pay/gift/trial/consumption
+     * @param orderId 关联订单ID(可为 null)
+     */
+    private void syncMembershipToFamilyMembers(Long familyId, String levelCode, Date expireTime,
+                                               String upgradeType, Long orderId) {
+        if (familyId == null || levelCode == null || expireTime == null) return;
+        List<User> familyUsers = userMapper.selectList(
+                new LambdaQueryWrapper<User>().eq(User::getFamilyId, familyId));
+        if (familyUsers == null || familyUsers.isEmpty()) return;
+
+        Date now = new Date();
+        for (User u : familyUsers) {
+            String fromLevel = u.getMemberLevel() != null ? u.getMemberLevel() : "FREE";
+            // 只有等级变化或到期时间延长时才写入(避免不必要的降级覆盖)
+            if (levelCode.equals(u.getMemberLevel())
+                    && u.getMemberExpireTime() != null
+                    && u.getMemberExpireTime().after(expireTime)) {
+                continue; // 已有同级更晚到期的会员,跳过
+            }
+            u.setMemberLevel(levelCode);
+            u.setMemberExpireTime(expireTime);
+            u.setUpdatedAt(now);
+            userMapper.updateById(u);
+
+            // 为每个成员创建升级记录
+            MemberUpgradeRecord record = new MemberUpgradeRecord();
+            record.setUserId(u.getId());
+            record.setFromLevel(fromLevel);
+            record.setToLevel(levelCode);
+            record.setUpgradeType(upgradeType);
+            record.setOrderId(orderId);
+            record.setExpireTime(expireTime);
+            record.setCreatedAt(now);
+            memberUpgradeRecordMapper.insert(record);
+        }
+        log.info("家庭会员全量同步完成: familyId={}, levelCode={}, 成员数={}", familyId, levelCode, familyUsers.size());
+    }
+
+    /**
+     * 方案B:将家庭所有成员降级为 FREE(退款、到期、家庭解散时调用)
+     * @param familyId 家庭ID
+     */
+    private void downgradeFamilyMembers(Long familyId) {
+        if (familyId == null) return;
+        List<User> familyUsers = userMapper.selectList(
+                new LambdaQueryWrapper<User>().eq(User::getFamilyId, familyId));
+        if (familyUsers == null || familyUsers.isEmpty()) return;
+
+        Date now = new Date();
+        int downgraded = 0;
+        for (User u : familyUsers) {
+            if (!"FREE".equals(u.getMemberLevel())) {
+                u.setMemberLevel("FREE");
+                u.setMemberExpireTime(null);
+                u.setUpdatedAt(now);
+                userMapper.updateById(u);
+                downgraded++;
+            }
+        }
+        if (downgraded > 0) {
+            log.info("家庭全员降级 FREE: familyId={}, 降级人数={}", familyId, downgraded);
+        }
+    }
+
+    /**
+     * 方案B:新成员加入家庭时,继承家庭现有有效会员身份
+     * 由 FamilyMemberService.addMember() 调用
+     */
+    public void syncMembershipForNewMember(Long userId, Long familyId) {
+        if (userId == null || familyId == null) return;
+        FamilyMembership active = getActiveFamilyMembership(familyId);
+        if (active == null) return; // 家庭无有效会员
+
+        User u = userMapper.selectById(userId);
+        if (u == null) return;
+        String fromLevel = u.getMemberLevel() != null ? u.getMemberLevel() : "FREE";
+        // 只有当前等级更低或到期更早时才同步升级
+        if (active.getLevelCode().equals(u.getMemberLevel())
+                && u.getMemberExpireTime() != null
+                && u.getMemberExpireTime().after(active.getEndDate())) {
+            return;
+        }
+        u.setMemberLevel(active.getLevelCode());
+        u.setMemberExpireTime(active.getEndDate());
+        u.setUpdatedAt(new Date());
+        userMapper.updateById(u);
+
+        MemberUpgradeRecord record = new MemberUpgradeRecord();
+        record.setUserId(userId);
+        record.setFromLevel(fromLevel);
+        record.setToLevel(active.getLevelCode());
+        record.setUpgradeType("family_sync");
+        record.setExpireTime(active.getEndDate());
+        record.setCreatedAt(new Date());
+        memberUpgradeRecordMapper.insert(record);
+
+        log.info("新成员继承家庭会员: userId={}, familyId={}, level={}", userId, familyId, active.getLevelCode());
+    }
+
     // ==================== 会员升级与过期 ====================
 
     /**
@@ -954,8 +1061,7 @@ public class MembershipService implements MembershipServiceInterface {
             membershipMapper.updateById(membership);
         }
 
-        // 降级管理员:若无其他有效付费会员,降级为 FREE
-        Family family = familyMapper.selectById(order.getFamilyId());
+        // 降级管理员:若无其他有效付费会员,降级全家为 FREE
         if (family != null && family.getCreatorId() != null) {
             User adminUser = userMapper.selectById(family.getCreatorId());
             if (adminUser != null && order.getLevelCode().equals(adminUser.getMemberLevel())) {
@@ -966,11 +1072,9 @@ public class MembershipService implements MembershipServiceInterface {
                         .ne(FamilyMembership::getOrderNo, targetOrderNo)
                         .gt(FamilyMembership::getEndDate, new Date()));
                 if (activePaidCount == 0) {
-                    adminUser.setMemberLevel("FREE");
-                    adminUser.setMemberExpireTime(null);
-                    adminUser.setUpdatedAt(new Date());
-                    userMapper.updateById(adminUser);
-                    log.info("会员退款降级管理员: userId={}, familyId={}", adminUser.getId(), order.getFamilyId());
+                    // 方案B:退款后无其他有效会员,全家降级
+                    downgradeFamilyMembers(order.getFamilyId());
+                    log.info("会员退款降级全家: userId={}, familyId={}", adminUser.getId(), order.getFamilyId());
                 }
             }
         }

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-c65cfd4d0a24113cf378625fb3f796abca3ded0e
+e3083bd46d1bb0f416cbc8d03cd5ac006aae318a

+ 2 - 2
cfc-web/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "cfc-web",
-  "version": "1.0.1356",
+  "version": "1.0.1357",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "cfc-web",
-      "version": "1.0.1356",
+      "version": "1.0.1357",
       "dependencies": {
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor-for-vue": "^1.0.2",

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
   "name": "cfc-web",
-  "version": "1.0.1357",
+  "version": "1.0.1358",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

+ 10 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,16 @@
 
 ---
 
+## v1.0.1358 (2026-09-10)
+
+### 文档
+- PROJECT-OVERVIEW 同步关键人拓展章鱼图计划
+- 珍珠图社会连接盘点系统实现计划
+
+### 其他
+- plan: 关键人拓展章鱼图替换实现计划(12任务/全链路)
+
+
 ## v1.0.1357 (2026-09-10)
 
 ### 文档

+ 11 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.1357
+> 当前版本: v1.0.1358
 
 ## 历史版本
 
@@ -8,6 +8,16 @@
 
 ---
 
+## v1.0.1358 (2026-09-10)
+
+### 文档
+- PROJECT-OVERVIEW 同步关键人拓展章鱼图计划
+- 珍珠图社会连接盘点系统实现计划
+
+### 其他
+- plan: 关键人拓展章鱼图替换实现计划(12任务/全链路)
+
+
 ## v1.0.1357 (2026-09-10)
 
 ### 文档