Forráskód Böngészése

fix(cf): 财富中心/推广收益改读实时CF账本,修正成员解析取最老家庭

opencode 1 hete
szülő
commit
dfc78e9d3

+ 197 - 13
cfc-backend/src/main/java/com/etotem/cfc/controller/CfBalanceController.java

@@ -5,9 +5,16 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.etotem.cfc.common.Result;
 import com.etotem.cfc.dto.CfBalanceLogVO;
 import com.etotem.cfc.dto.CfBalanceView;
+import com.etotem.cfc.dto.FamilyEarningsMemberDTO;
+import com.etotem.cfc.dto.FamilyEarningsSummaryDTO;
+import com.etotem.cfc.entity.CfBalance;
 import com.etotem.cfc.entity.CfBalanceLog;
 import com.etotem.cfc.entity.FamilyMember;
+import com.etotem.cfc.entity.User;
+import com.etotem.cfc.mapper.CfBalanceLogMapper;
+import com.etotem.cfc.mapper.CfBalanceMapper;
 import com.etotem.cfc.mapper.FamilyMemberMapper;
+import com.etotem.cfc.mapper.UserMapper;
 import com.etotem.cfc.service.CfBalanceService;
 import com.etotem.cfc.service.CouponService;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -17,28 +24,41 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
  * C 端 CF 值查询接口(只读)。
  *
  * <p>个人 CF 值账本为成员维度(family_members.id),本控制器把「登录 userId → memberId」
- * 的解析口径与 {@code CfEarnDispatchService}(F-3a)保持一致:按 user_id 在家庭内匹配,
- * 取最小 id 的一条(LIMIT 1);找不到对应家庭成员时返回明确错误码,不返回空数据。</p>
+ * 的解析口径与 {@code JwtInterceptor} 保持一致:优先使用拦截器按
+ * {@code users.family_id + family_members} 解析出的 {@code currentMemberId},
+ * 仅在缺失时回退到历史口径(user_id 最小一条)。</p>
  *
- * <p>仅提供三个只读接口:余额快照 / 流水分页 / 家庭共享优惠券列表,不提供任何写接口。
- * 余额与流水走统一账本 {@link CfBalanceService};家庭券复用 {@link CouponService#listMyCoupons}
- * (N3 家庭化口径:family_coupon + coupon 联合,家庭内成员共享可见)。</p>
+ * <p>仅提供只读接口:余额快照 / 流水分页 / 周期统计 / 家庭 CF 总览 / 推广类 CF 收益 /
+ * 家庭共享优惠券列表。余额与流水走统一账本 {@link CfBalanceService};
+ * 家庭券复用 {@link CouponService#listMyCoupons}(N3 家庭化口径:family_coupon + coupon 联合)。</p>
  *
- * <p>接口约定见 docs/superpowers/plans/2026-10-24-cf-value-unification-plan.md §七 F-7a。</p>
+ * <p>接口约定见 docs/superpowers/specs/2026-10-25-cf-value-single-source-of-truth.md §5/§6。</p>
  */
 @RestController
 @RequestMapping("/api/cf")
 public class CfBalanceController {
 
+    /** 推广类 CF 收益:推荐注册 F24 + 直接销售奖 F03a + 间接销售奖 F03b + 邀请里程碑 F11 */
+    private static final Set<String> PROMOTION_REF_TYPES = new HashSet<>(Arrays.asList(
+            "referral_register", "F03a", "F03b", "invite_milestone"));
+
     @Resource
     private CfBalanceService cfBalanceService;
 
@@ -48,12 +68,22 @@ public class CfBalanceController {
     @Resource
     private FamilyMemberMapper familyMemberMapper;
 
+    @Resource
+    private CfBalanceMapper cfBalanceMapper;
+
+    @Resource
+    private CfBalanceLogMapper cfBalanceLogMapper;
+
+    @Resource
+    private UserMapper userMapper;
+
     /**
      * 我的 CF 值快照:可用余额 / 冻结 / 累计获得 / 已提现 / 已兑换消费。
      */
     @GetMapping("/balance")
-    public Result<CfBalanceView> balance(@RequestAttribute("userId") Long userId) {
-        Long memberId = resolveMemberId(userId);
+    public Result<CfBalanceView> balance(@RequestAttribute("userId") Long userId,
+                                         @RequestAttribute(value = "currentMemberId", required = false) Long currentMemberId) {
+        Long memberId = resolveMemberId(userId, currentMemberId);
         if (memberId == null) {
             return Result.error(404, "未找到当前用户对应的家庭成员,无法查询 CF 值");
         }
@@ -65,9 +95,10 @@ public class CfBalanceController {
      */
     @GetMapping("/logs")
     public Result<Page<CfBalanceLogVO>> logs(@RequestAttribute("userId") Long userId,
+                                             @RequestAttribute(value = "currentMemberId", required = false) Long currentMemberId,
                                              @RequestParam(defaultValue = "1") Integer page,
                                              @RequestParam(defaultValue = "20") Integer size) {
-        Long memberId = resolveMemberId(userId);
+        Long memberId = resolveMemberId(userId, currentMemberId);
         if (memberId == null) {
             return Result.error(404, "未找到当前用户对应的家庭成员,无法查询 CF 流水");
         }
@@ -80,6 +111,151 @@ public class CfBalanceController {
         return Result.success(vo);
     }
 
+    /**
+     * 我的 CF 周期统计:今日 / 本月获得 + 累计获得(cf_balance.total_earned)。
+     */
+    @GetMapping("/stats")
+    public Result<Map<String, Object>> stats(@RequestAttribute("userId") Long userId,
+                                             @RequestAttribute(value = "currentMemberId", required = false) Long currentMemberId) {
+        Long memberId = resolveMemberId(userId, currentMemberId);
+        if (memberId == null) {
+            return Result.error(404, "未找到当前用户对应的家庭成员,无法查询 CF 统计");
+        }
+        CfBalanceView view = cfBalanceService.getBalance(memberId);
+
+        Calendar cal = Calendar.getInstance();
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        Date startOfDay = cal.getTime();
+        cal.set(Calendar.DAY_OF_MONTH, 1);
+        Date startOfMonth = cal.getTime();
+
+        List<CfBalanceLog> monthLogs = cfBalanceLogMapper.selectList(new LambdaQueryWrapper<CfBalanceLog>()
+                .eq(CfBalanceLog::getMemberId, memberId)
+                .eq(CfBalanceLog::getType, "earn")
+                .ge(CfBalanceLog::getCreatedAt, startOfMonth));
+        int monthEarned = 0;
+        int todayEarned = 0;
+        for (CfBalanceLog log : monthLogs) {
+            int amount = log.getAmount() == null ? 0 : log.getAmount();
+            monthEarned += amount;
+            if (log.getCreatedAt() != null && !log.getCreatedAt().before(startOfDay)) {
+                todayEarned += amount;
+            }
+        }
+
+        Map<String, Object> data = new LinkedHashMap<>();
+        data.put("todayEarned", todayEarned);
+        data.put("monthEarned", monthEarned);
+        data.put("totalEarned", view.getTotalEarned() == null ? 0 : view.getTotalEarned());
+        data.put("available", view.getAvailable() == null ? 0 : view.getAvailable());
+        return Result.success(data);
+    }
+
+    /**
+     * 家庭 CF 总览(成员维度):全家累计 / 可用 / 已提现 / 已兑换 + 成员贡献榜。
+     *
+     * <p>替代已停写的 {@code family_earnings} 旧账本,数据源为 {@code cf_balance}。</p>
+     */
+    @GetMapping("/family-summary")
+    public Result<FamilyEarningsSummaryDTO> familySummary(@RequestAttribute("userId") Long userId,
+                                                          @RequestAttribute(value = "currentMemberId", required = false) Long currentMemberId) {
+        Long memberId = resolveMemberId(userId, currentMemberId);
+        if (memberId == null) {
+            return Result.error(404, "未找到当前用户对应的家庭成员,无法查询家庭 CF 总览");
+        }
+        FamilyMember self = familyMemberMapper.selectById(memberId);
+        Long familyId = self == null ? null : self.getFamilyId();
+
+        FamilyEarningsSummaryDTO summary = new FamilyEarningsSummaryDTO();
+        summary.setFamilyId(familyId);
+
+        List<CfBalance> balances = familyId == null ? Collections.emptyList()
+                : cfBalanceMapper.selectList(new LambdaQueryWrapper<CfBalance>()
+                        .eq(CfBalance::getFamilyId, familyId));
+
+        List<Long> memberIds = balances.stream()
+                .map(CfBalance::getMemberId).filter(id -> id != null)
+                .collect(Collectors.toList());
+        Map<Long, FamilyMember> memberMap = memberIds.isEmpty() ? Collections.emptyMap()
+                : familyMemberMapper.selectBatchIds(memberIds).stream()
+                        .collect(Collectors.toMap(FamilyMember::getId, m -> m, (a, b) -> a));
+
+        List<Long> userIds = balances.stream()
+                .map(CfBalance::getUserId).filter(id -> id != null)
+                .collect(Collectors.toList());
+        Map<Long, User> userMap = userIds.isEmpty() ? Collections.emptyMap()
+                : userMapper.selectBatchIds(userIds).stream()
+                        .collect(Collectors.toMap(User::getId, u -> u, (a, b) -> a));
+
+        long totalEarned = 0L;
+        long available = 0L;
+        long withdrawn = 0L;
+        long exchanged = 0L;
+        List<FamilyEarningsMemberDTO> members = new ArrayList<>();
+        for (CfBalance balance : balances) {
+            long memberTotal = balance.getTotalEarned() == null ? 0L : balance.getTotalEarned();
+            long memberAvailable = balance.getAvailable() == null ? 0L : balance.getAvailable();
+            FamilyMember member = memberMap.get(balance.getMemberId());
+            User user = balance.getUserId() == null ? null : userMap.get(balance.getUserId());
+
+            FamilyEarningsMemberDTO dto = new FamilyEarningsMemberDTO();
+            dto.setUserId(balance.getUserId());
+            dto.setNickname(user != null && user.getNickname() != null ? user.getNickname()
+                    : (member == null ? null : member.getNickname()));
+            dto.setAvatar(user != null && user.getAvatar() != null ? user.getAvatar()
+                    : (member == null ? null : member.getAvatar()));
+            dto.setAllocatedAmount(memberTotal);
+            dto.setAvailableAmount(memberAvailable);
+            dto.setConsumedAmount(Math.max(0L, memberTotal - memberAvailable));
+            dto.setIsAdmin(user != null && Boolean.TRUE.equals(user.getIsFamilyAdmin()));
+            // 新模型无家庭公共池,字段保留兼容前端;家庭内共享通过优惠券 / 成员转让实现
+            dto.setCanUseFamilyBalance(true);
+            members.add(dto);
+
+            totalEarned += memberTotal;
+            available += memberAvailable;
+            withdrawn += balance.getWithdrawn() == null ? 0L : balance.getWithdrawn();
+            exchanged += balance.getExchanged() == null ? 0L : balance.getExchanged();
+        }
+        members.sort((a, b) -> Long.compare(
+                b.getAllocatedAmount() == null ? 0L : b.getAllocatedAmount(),
+                a.getAllocatedAmount() == null ? 0L : a.getAllocatedAmount()));
+
+        summary.setTotalEarned(totalEarned);
+        summary.setAvailableAmount(available);
+        summary.setWithdrawnAmount(withdrawn);
+        summary.setDistributedAmount(exchanged);
+        summary.setMembers(members);
+        return Result.success(summary);
+    }
+
+    /**
+     * 推广类 CF 收益:F24 推荐注册 + F03a 直接销售奖 + F03b 间接销售奖 + F11 邀请里程碑。
+     *
+     * <p>仅统计本人当前成员的 {@code cf_balance_log}(type=earn)。</p>
+     */
+    @GetMapping("/promotion-earnings")
+    public Result<Map<String, Object>> promotionEarnings(@RequestAttribute("userId") Long userId,
+                                                         @RequestAttribute(value = "currentMemberId", required = false) Long currentMemberId) {
+        Long memberId = resolveMemberId(userId, currentMemberId);
+        if (memberId == null) {
+            return Result.error(404, "未找到当前用户对应的家庭成员,无法查询推广收益");
+        }
+        List<CfBalanceLog> logs = cfBalanceLogMapper.selectList(new LambdaQueryWrapper<CfBalanceLog>()
+                .eq(CfBalanceLog::getMemberId, memberId)
+                .eq(CfBalanceLog::getType, "earn")
+                .in(CfBalanceLog::getRefType, PROMOTION_REF_TYPES));
+        int total = logs.stream().mapToInt(log -> log.getAmount() == null ? 0 : log.getAmount()).sum();
+
+        Map<String, Object> data = new LinkedHashMap<>();
+        data.put("totalEarned", total);
+        data.put("refTypes", new ArrayList<>(PROMOTION_REF_TYPES));
+        return Result.success(data);
+    }
+
     /**
      * 家庭共享优惠券列表(N3 口径):按登录用户所属家庭查券实例 + 券模板,
      * 返回券名 / 状态 / 有效期 / 抵扣面额等展示字段,家庭内成员共享可见。
@@ -102,10 +278,18 @@ public class CfBalanceController {
     }
 
     /**
-     * 登录 userId → 家庭成员(family_members.id)。
-     * 口径与 {@code CfEarnDispatchService} 的 resolveMemberId 一致:user_id 匹配 +
-     * 按 id 升序取第一条(LIMIT 1),未命中返回 null。
+     * 登录 userId → 当前家庭成员(family_members.id)。
+     *
+     * <p>优先使用 {@code JwtInterceptor} 按 {@code users.family_id} 解析出的 currentMemberId;
+     * 缺失时回退到历史口径(user_id 匹配 + id 升序 LIMIT 1),保证无家庭用户兼容。</p>
      */
+    private Long resolveMemberId(Long userId, Long currentMemberId) {
+        if (currentMemberId != null && currentMemberId > 0) {
+            return currentMemberId;
+        }
+        return resolveMemberId(userId);
+    }
+
     private Long resolveMemberId(Long userId) {
         if (userId == null || userId <= 0) {
             return null;
@@ -116,4 +300,4 @@ public class CfBalanceController {
                 .last("LIMIT 1"));
         return member == null ? null : member.getId();
     }
-}
+}

+ 3 - 3
cfc-frontend/pages/profile-main/profile.vue

@@ -345,7 +345,7 @@ import {
   getChildren, getFamilyMemberList,
   getTodayTasksByCategory, getChallengeList, getMyMembership,
   verifyPassword, getPointsBalance, getUserInfo,
-  cartCount, getOrderCounts, getReferralSummary,
+  cartCount, getOrderCounts, getCfPromotionEarnings,
   getProfileStats, getMyReferrer, getVendorTeamList, getVendorHierarchyInfo,
   getTeacherInfo, getTeacherPendingTasks, getTeacherUnreadCount,
   getReferralCode, extractReferralCode, getShareQrCode, getEnergySandbox,
@@ -601,9 +601,9 @@ export default {
 
     loadReferralEarnings() {
       var self = this
-      getReferralSummary().then(function(res) {
+      getCfPromotionEarnings().then(function(res) {
         if (res && res.code === 200 && res.data) {
-          self.referralEarnings = res.data.totalEarnings || 0
+          self.referralEarnings = res.data.totalEarned || 0
         }
       }).catch(function() {})
     },

+ 25 - 174
cfc-frontend/pages/promotion/index.vue

@@ -5,19 +5,19 @@
     <view class="family-earnings-card" v-if="familySummary">
       <view class="fe-header">
         <view class="fe-title-row">
-          <text class="fe-title">🏠 家庭公共收益</text>
+          <text class="fe-title">🏠 家庭CF总览</text>
           <text class="fe-badge" v-if="isAdmin">管理员</text>
         </view>
-        <text class="fe-subtitle">家庭成员共同努力的成果</text>
+        <text class="fe-subtitle">家庭成员 CF 贡献与余额</text>
       </view>
       <view class="fe-grid">
         <view class="fe-item">
           <text class="fe-value orange">{{ cfVal(familySummary.totalEarned) }}</text>
-          <text class="fe-label">累计推荐CF</text>
+          <text class="fe-label">家庭累计CF</text>
         </view>
         <view class="fe-item">
           <text class="fe-value blue">{{ cfVal(familySummary.availableAmount) }}</text>
-          <text class="fe-label">可支配CF</text>
+          <text class="fe-label">家庭可用CF</text>
         </view>
         <view class="fe-item">
           <text class="fe-value green">{{ cfVal(familySummary.withdrawnAmount) }}</text>
@@ -25,14 +25,9 @@
         </view>
         <view class="fe-item">
           <text class="fe-value purple">{{ cfVal(familySummary.distributedAmount) }}</text>
-          <text class="fe-label">已分配CF</text>
+          <text class="fe-label">已兑换CF</text>
         </view>
       </view>
-
-      <!-- 管理员操作按钮(仅管理员可见) -->
-      <view class="fe-actions" v-if="isAdmin">
-        <button class="fe-btn fe-btn-distribute" @click="showDistributeSheet = true">分配收益</button>
-      </view>
     </view>
 
     <!-- 成员贡献榜 -->
@@ -54,16 +49,12 @@
           <view class="member-info">
             <text class="member-name">{{ m.nickname || '用户' }}</text>
             <text class="member-role-tag" v-if="m.isAdmin">管理员</text>
-            <text class="member-balance-tag" v-if="m.canUseFamilyBalance">池可用</text>
-            <text class="member-balance-tag disabled-tag" v-else>池关闭</text>
           </view>
           <view class="member-amounts">
-            <text class="member-amount allocated">+{{ cfVal(m.allocatedAmount) }}</text>
-            <text class="member-amount consumed">-{{ cfVal(m.consumedAmount) }}</text>
-            <text class="member-amount available">={{ cfVal(m.availableAmount) }}</text>
+            <text class="member-amount allocated">累计 {{ cfVal(m.allocatedAmount) }}</text>
+            <text class="member-amount consumed">消费 {{ cfVal(m.consumedAmount) }}</text>
+            <text class="member-amount available">可用 {{ cfVal(m.availableAmount) }}</text>
           </view>
-          <!-- 管理员可切换成员池权限 -->
-          <switch v-if="isAdmin && !m.isAdmin" class="member-switch" :checked="m.canUseFamilyBalance" @change="toggleMemberAccess(m)" :color="primaryColor"></switch>
         </view>
       </view>
     </view>
@@ -84,15 +75,15 @@
     <!-- 统计卡片 -->
     <view class="stats-cards">
       <view class="stat-card today-card">
-        <text class="stat-value">{{ stats.todayCommission || 0 }}</text>
+        <text class="stat-value">{{ stats.todayEarned || 0 }}</text>
         <text class="stat-label">今日CF</text>
       </view>
       <view class="stat-card month-card">
-        <text class="stat-value">{{ stats.monthCommission || 0 }}</text>
+        <text class="stat-value">{{ stats.monthEarned || 0 }}</text>
         <text class="stat-label">本月CF</text>
       </view>
       <view class="stat-card total-card">
-        <text class="stat-value">{{ stats.totalCommission || 0 }}</text>
+        <text class="stat-value">{{ stats.totalEarned || 0 }}</text>
         <text class="stat-label">累计CF</text>
       </view>
     </view>
@@ -167,53 +158,26 @@
     <view style="height:40rpx"></view>
     </scroll-view>
 
-    <!-- iOS 修复:position: fixed 不能嵌套在 scroll-view 内,会导致固定定位失效。已移至 scroll-view 后 -->
-    <view class="sheet-mask" v-if="showDistributeSheet" @click="showDistributeSheet = false">
-      <view class="sheet-content" @click.stop>
-        <text class="sheet-title">分配收益</text>
-        <text class="sheet-hint">选择成员并输入分配CF值</text>
-        <picker class="sheet-picker" mode="selector" :range="memberOptions" :value="distributeMemberIdx" @change="onDistributeMemberChange">
-          <text>{{ distributeMemberIdx >= 0 ? memberOptions[distributeMemberIdx] : '选择成员' }}</text>
-        </picker>
-        <input class="sheet-input" type="digit" v-model="distributeAmount" placeholder="输入分配CF值" />
-        <view class="sheet-actions">
-          <button class="sheet-cancel" @click="showDistributeSheet = false">取消</button>
-          <button class="sheet-confirm" @click="doDistribute" :disabled="distributeMemberIdx < 0 || !distributeAmount || distributeAmount <= 0">确认分配</button>
-        </view>
-      </view>
-    </view>
-
   </view>
 </template>
 
 <script>
-import { BrandColors } from '@/utils/brand-colors.js'
-import { getReferralSummary, getCfSummary, getFamilyEarningsSummary, getFamilyEarningsMembers, getFamilyEarningsRecords, distributeToMember, toggleMemberBalance, withdrawFamilyEarnings, getReferralCode, extractReferralCode } from '../../utils/api.js'
+import { getCfBalance, getCfStats, getCfFamilySummary, getReferralCode, extractReferralCode } from '../../utils/api.js'
 import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
   mixins: [fontScaleMixin],
   data() {
     return {
-      primaryColor: BrandColors.primary,
-      totalEarnings: '0.00',
-      availableAmount: '0.00',
       summary: null,
       stats: {},
       funnelData: {},
       funnelSteps: [],
-      // 家庭收益
+      // 家庭 CF 总览
       familySummary: null,
       members: [],
       membersExpanded: false,
       showAllRanks: false,
-      // 弹窗
-      showWithdrawSheet: false,
-      showDistributeSheet: false,
-      withdrawAmount: '',
-      distributeAmount: '',
-      distributeMemberIdx: -1,
-      memberOptions: [],
       // 分享推广码(用于右上角菜单分享)
       shareReferralCode: ''
     }
@@ -281,74 +245,34 @@ export default {
     },
     async loadData() {
       try {
-        var summaryRes = await getReferralSummary()
-        if (summaryRes.data) {
-          this.totalEarnings = summaryRes.data.totalEarnings || '0.00'
-        }
-      } catch (e) {
-        console.error('获取邀请统计失败', e)
-      }
-      try {
-        var comRes = await getCfSummary()
-        if (comRes.data) {
-          this.summary = comRes.data
-          this.availableAmount = comRes.data.available || '0.00'
+        var res = await getCfBalance()
+        if (res && res.data) {
+          this.summary = res.data
         }
       } catch (e) {
         console.error('获取 CF 总览失败', e)
       }
     },
     async loadFamilyData() {
-      if (this.isChild) {
-        // 成员只读:仅加载概要,不加载管理员功能
-        try {
-          var sRes = await getFamilyEarningsSummary()
-          if (sRes.data) {
-            this.familySummary = sRes.data
-            this.members = sRes.data.members || []
-          }
-        } catch (e) {
-          console.error('获取家庭收益概览失败', e)
-        }
-        return
-      }
       try {
-        var sRes = await getFamilyEarningsSummary()
-        if (sRes.data) {
+        var sRes = await getCfFamilySummary()
+        if (sRes && sRes.data) {
           this.familySummary = sRes.data
           this.members = sRes.data.members || []
-          // 构建picker选项
-          var opts = []
-          var arr = this.members
-          for (var i = 0; i < arr.length; i++) {
-            opts.push((arr[i].nickname || '用户' + arr[i].userId) + ' (余额:' + this.cfVal(arr[i].availableAmount) + ' CF)')
-          }
-          this.memberOptions = opts
         }
       } catch (e) {
-        console.error('获取家庭收益概览失败', e)
+        console.error('获取家庭 CF 总览失败', e)
       }
     },
-    loadStats() {
-      var self = this
-      var token = uni.getStorageSync('token')
-      var baseUrl = ''
+    async loadStats() {
       try {
-        var config = require('../../config.js')
-        baseUrl = config.default.baseUrl || config.baseUrl || ''
+        var res = await getCfStats()
+        if (res && res.data) {
+          this.stats = res.data
+        }
       } catch (e) {
-        baseUrl = ''
+        console.error('获取 CF 统计失败', e)
       }
-      uni.request({
-        url: baseUrl + '/api/commission/stats',
-        method: 'POST',
-        header: { 'Authorization': 'Bearer ' + token },
-        success: function(res) {
-          if (res.data && res.data.code === 200) {
-            self.stats = res.data.data || {}
-          }
-        }
-      })
     },
     loadFunnelData() {
       var self = this
@@ -390,79 +314,6 @@ export default {
       if (isNaN(num)) return '0'
       return String(num)
     },
-    // 管理员操作
-    toggleMemberAccess(m) {
-      var self = this
-      var enabled = !m.canUseFamilyBalance
-      uni.showLoading({ title: '操作中...' })
-      toggleMemberBalance({ userId: m.userId, enabled: enabled }).then(function(res) {
-        uni.hideLoading()
-        if (res.code === 200) {
-          m.canUseFamilyBalance = enabled
-          uni.showToast({ title: '操作成功', icon: 'success' })
-        } else {
-          uni.showToast({ title: res.message || '操作失败', icon: 'none' })
-        }
-      }).catch(function(e) {
-        uni.hideLoading()
-        uni.showToast({ title: '操作失败', icon: 'none' })
-      })
-    },
-    onDistributeMemberChange(e) {
-      this.distributeMemberIdx = e.detail.value
-    },
-    doDistribute() {
-      var idx = this.distributeMemberIdx
-      if (idx < 0 || !this.members[idx]) {
-        uni.showToast({ title: '请选择成员', icon: 'none' })
-        return
-      }
-      var amount = Number(this.distributeAmount)
-      if (!amount || amount <= 0) {
-        uni.showToast({ title: '请输入有效金额', icon: 'none' })
-        return
-      }
-      var self = this
-      uni.showLoading({ title: '分配中...' })
-      distributeToMember({ userId: this.members[idx].userId, amount: amount }).then(function(res) {
-        uni.hideLoading()
-        if (res.code === 200) {
-          uni.showToast({ title: '分配成功', icon: 'success' })
-          self.showDistributeSheet = false
-          self.distributeAmount = ''
-          self.distributeMemberIdx = -1
-          self.loadFamilyData()
-        } else {
-          uni.showToast({ title: res.message || '分配失败', icon: 'none' })
-        }
-      }).catch(function(e) {
-        uni.hideLoading()
-        uni.showToast({ title: '分配失败', icon: 'none' })
-      })
-    },
-    doWithdraw() {
-      var amount = Number(this.withdrawAmount)
-      if (!amount || amount <= 0) {
-        uni.showToast({ title: '请输入有效金额', icon: 'none' })
-        return
-      }
-      var self = this
-      uni.showLoading({ title: '提现中...' })
-      withdrawFamilyEarnings({ amount: amount }).then(function(res) {
-        uni.hideLoading()
-        if (res.code === 200) {
-          uni.showToast({ title: '提现申请已提交', icon: 'success' })
-          self.showWithdrawSheet = false
-          self.withdrawAmount = ''
-          self.loadFamilyData()
-        } else {
-          uni.showToast({ title: res.message || '提现失败', icon: 'none' })
-        }
-      }).catch(function(e) {
-        uni.hideLoading()
-        uni.showToast({ title: '提现失败', icon: 'none' })
-      })
-    },
     goRecords() {
       uni.navigateTo({ url: '/pages/promotion/records' })
     },

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

@@ -3168,6 +3168,10 @@ export const exchangeCouponByCf = (data) => request('/api/family-platform/exchan
 export const getCfBalance = () => request('/api/cf/balance', 'GET', {})
 export const getCfLogs = (params) => request('/api/cf/logs', 'GET', params || { page: 1, size: 20 })
 export const getFamilyCoupons = () => request('/api/cf/family-coupons', 'GET', {})
+// CF 周期统计(今日/本月/累计获得)与家庭 CF 总览 / 推广类 CF 收益
+export const getCfStats = () => request('/api/cf/stats', 'GET', {})
+export const getCfFamilySummary = () => request('/api/cf/family-summary', 'GET', {})
+export const getCfPromotionEarnings = () => request('/api/cf/promotion-earnings', 'GET', {})
 
 // ===== 站内通知 =====
 export const getNotificationList = () => request('/api/notification/list', 'POST', {})