From 9ee5e06e896c5c81d95895913dbadf0a753cd0ad Mon Sep 17 00:00:00 2001 From: chen Date: Thu, 17 Sep 2026 08:38:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(dashboard):=20=E5=A2=9E=E5=8A=A0CFO?= =?UTF-8?q?=E8=B4=A2=E5=8A=A1=E8=B5=84=E9=87=91=E6=B5=AE=E5=AD=98=E4=B8=8E?= =?UTF-8?q?=E8=B5=84=E4=BA=A7=E8=B4=9F=E5=80=BA=E4=B8=AD=E6=9E=A2=E3=80=81?= =?UTF-8?q?COO=E8=BF=90=E8=90=A5=E8=BD=AC=E5=8C=96=E5=A4=8D=E8=B4=AD?= =?UTF-8?q?=E4=B8=8E=E5=90=88=E4=BC=99=E4=BA=BA=E6=96=AD=E6=A1=A3=E9=9B=B7?= =?UTF-8?q?=E8=BE=BE=E5=85=A8=E8=B2=8C=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/controller/shopro/Dashboard.php | 260 ++++++++++++ .../admin/view/shopro/dashboard/index.html | 370 ++++++++++++++++++ public/assets/js/backend/shopro/dashboard.js | 79 ++++ tests/partner/DashboardWealthTest.php | 53 +++ 4 files changed, 762 insertions(+) diff --git a/application/admin/controller/shopro/Dashboard.php b/application/admin/controller/shopro/Dashboard.php index 839e327..8158e09 100644 --- a/application/admin/controller/shopro/Dashboard.php +++ b/application/admin/controller/shopro/Dashboard.php @@ -16,6 +16,9 @@ use addons\shopro\service\SearchHistory; use addons\shopro\service\partner\RateService; use addons\shopro\service\partner\IdentityService; use addons\shopro\service\partner\PartnerConfig; +use app\admin\model\shopro\Withdraw; +use app\admin\model\shopro\Refund; +use app\admin\model\shopro\goods\SkuPrice as SkuPriceModel; class Dashboard extends Common { @@ -283,6 +286,261 @@ class Dashboard extends Common 'role_stats' => $roleStats, ]; + // 8. CFO 视角:资金浮存、提现出款风控与资产负债中枢 + $userCommissionFloat = (float) User::sum('commission'); + $userMoneyFloat = (float) User::sum('money'); + $totalFloatFunds = round($userCommissionFloat + $userMoneyFloat, 2); + + $totalWithdrawApplied = (float) Withdraw::sum('amount'); + $totalWithdrawPaid = (float) Withdraw::where('status', 2)->sum('paid_fee'); + $pendingWithdrawAmount = (float) Withdraw::where('status', 0)->sum('amount'); + $pendingWithdrawCount = (int) Withdraw::where('status', 0)->count(); + $withdrawCashRate = $totalPayout > 0 ? round(($totalWithdrawPaid / $totalPayout) * 100, 2) : 0.0; + + $totalRefundAmount = (float) Refund::where('status', 'completed')->sum('refund_fee'); + $totalRefundCount = (int) Refund::where('status', 'completed')->count(); + $refundRate = $totalGmv > 0 ? round(($totalRefundAmount / $totalGmv) * 100, 2) : 0.0; + $realNetCashFlow = round($totalGmv - $totalRefundAmount - $totalWithdrawPaid, 2); + + // 未来总承兑责任 (待释放消费券 + 马豆折算市值 + 用户未提现佣金) + $pendingVoucherLiability = $pendingVoucher; + $madowMarketLiability = $totalMadowCny; + $commissionLiability = $userCommissionFloat; + $totalFutureLiability = round($pendingVoucherLiability + $madowMarketLiability + $commissionLiability, 2); + + $financeOverview = [ + 'commission_float' => number_format($userCommissionFloat, 2, '.', ''), + 'user_balance_float' => number_format($userMoneyFloat, 2, '.', ''), + 'total_float_funds' => number_format($totalFloatFunds, 2, '.', ''), + 'total_withdraw_applied' => number_format($totalWithdrawApplied, 2, '.', ''), + 'total_withdraw_paid' => number_format($totalWithdrawPaid, 2, '.', ''), + 'pending_withdraw_amount' => number_format($pendingWithdrawAmount, 2, '.', ''), + 'pending_withdraw_count' => $pendingWithdrawCount, + 'withdraw_cash_rate' => $withdrawCashRate, + 'total_refund_amount' => number_format($totalRefundAmount, 2, '.', ''), + 'total_refund_count' => $totalRefundCount, + 'refund_rate' => $refundRate, + 'real_net_cash_flow' => number_format($realNetCashFlow, 2, '.', ''), + 'pending_voucher_liability' => number_format($pendingVoucherLiability, 2, '.', ''), + 'madow_market_liability' => number_format($madowMarketLiability, 2, '.', ''), + 'commission_liability' => number_format($commissionLiability, 2, '.', ''), + 'total_future_liability' => number_format($totalFutureLiability, 2, '.', ''), + ]; + + // 9. COO 视角:转化复购漏斗、合伙人30天掉队雷达与供应链库存安全 + // 9.1 用户购买频次聚合与转化漏斗 + $paidOrderUsers = Order::whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED]) + ->group('user_id') + ->field('user_id, count(*) as buy_count') + ->select(); + + $paidUsersCount = count($paidOrderUsers); + $singleBuyCount = 0; + $repeatBuyCount = 0; + foreach ($paidOrderUsers as $buyer) { + if ((int)$buyer->buy_count > 1) { + $repeatBuyCount++; + } else { + $singleBuyCount++; + } + } + $payConversionRate = $totalRegisteredUsers > 0 ? round(($paidUsersCount / $totalRegisteredUsers) * 100, 1) : 0.0; + $repeatPurchaseRate = $paidUsersCount > 0 ? round(($repeatBuyCount / $paidUsersCount) * 100, 1) : 0.0; + $arpu = $paidUsersCount > 0 ? round($totalGmv / $paidUsersCount, 2) : 0.0; + + // 9.2 合伙人 30 天自购断档掉队雷达(安全活跃、7天即将断档预警、已断档失效) + $now = time(); + $activeDays = (int) PartnerConfig::get('partner_active_days', 30); + $warningThresholdDays = 7; + $activeWindow = $now - ($activeDays * 86400); + $warningWindow = $now - (($activeDays - $warningThresholdDays) * 86400); + + $activePartnersCount = 0; + $warningPartnersCount = 0; + $frozenPartnersCount = 0; + $warningList = []; + $frozenList = []; + + // 批量拉取合伙人用户信息,避免循环内查询 + $agentUserIds = array_column(collection($allAgents)->toArray(), 'user_id'); + $agentUserMap = []; + if (!empty($agentUserIds)) { + $agentUserRows = User::whereIn('id', $agentUserIds)->field('id, nickname, mobile, avatar')->select(); + foreach ($agentUserRows as $uRow) { + $agentUserMap[$uRow->id] = $uRow; + } + } + + foreach ($allAgents as $ag) { + $lastTime = (int) $ag->getData('last_self_order_time'); + $uid = $ag->user_id; + $u = $agentUserMap[$uid] ?? null; + $nickname = $u ? ($u->nickname ?: '用户#' . $uid) : ('用户#' . $uid); + $mobile = ($u && $u->mobile) ? substr_replace($u->mobile, '****', 3, 4) : '-'; + $avatar = $u ? ($u->avatar ?: '') : ''; + $identityData = IdentityService::build($ag); + $identityText = $identityData['identity_text'] ?: ('Lv.' . $ag->level); + + if ($lastTime > 0 && $lastTime >= $warningWindow) { + // 安全活跃期 (距今 < 23天) + $activePartnersCount++; + } elseif ($lastTime > 0 && $lastTime >= $activeWindow) { + // 7 天内即将断档预警 (距今 23~30天) + $warningPartnersCount++; + $daysLeft = max(1, (int) ceil(($lastTime + $activeDays * 86400 - $now) / 86400)); + $warningList[] = [ + 'user_id' => $uid, + 'nickname' => $nickname, + 'avatar' => $avatar, + 'mobile' => $mobile, + 'level_text' => $identityText, + 'last_order_date' => date('Y-m-d H:i', $lastTime), + 'days_left' => $daysLeft, + ]; + } else { + // 已断档冻结 (> 30天 或 从未自购) + $frozenPartnersCount++; + if (count($frozenList) < 10) { + $overdueDays = $lastTime > 0 ? max(1, (int) floor(($now - $lastTime) / 86400) - $activeDays) : 999; + $frozenList[] = [ + 'user_id' => $uid, + 'nickname' => $nickname, + 'avatar' => $avatar, + 'mobile' => $mobile, + 'level_text' => $identityText, + 'last_order_date' => $lastTime > 0 ? date('Y-m-d H:i', $lastTime) : '从未自购', + 'overdue_days' => $overdueDays == 999 ? '从未自购' : "逾期 {$overdueDays} 天", + ]; + } + } + } + + // 9.3 供应链库存安全与动销商品 + $onSaleGoodsCount = (int) Goods::where('status', 'up')->count(); + $totalStock = (int) SkuPriceModel::where('status', 'up')->sum('stock'); + $lowStockCount = (int) SkuPriceModel::alias('sp') + ->join('shopro_goods g', 'sp.goods_id = g.id') + ->where('g.status', 'up') + ->where('sp.status', 'up') + ->where('sp.stock', '<=', 10) + ->count(); + + $lowStockSkuList = SkuPriceModel::alias('sp') + ->join('shopro_goods g', 'sp.goods_id = g.id') + ->where('g.status', 'up') + ->where('sp.status', 'up') + ->where('sp.stock', '<=', 10) + ->field('sp.id as sku_id, sp.goods_id, g.title as goods_title, g.image as goods_image, sp.goods_sku_text, sp.stock, sp.price') + ->order('sp.stock', 'asc') + ->limit(10) + ->select(); + + $lowStockFormatted = []; + foreach ($lowStockSkuList as $lsku) { + $skuText = is_array($lsku->goods_sku_text) ? implode(' ', $lsku->goods_sku_text) : ($lsku->goods_sku_text ?: '默认单规格'); + $lowStockFormatted[] = [ + 'sku_id' => $lsku->sku_id, + 'goods_id' => $lsku->goods_id, + 'goods_title' => $lsku->goods_title, + 'goods_image' => $lsku->goods_image, + 'sku_text' => $skuText, + 'stock' => (int) $lsku->stock, + 'price' => $lsku->price, + ]; + } + + // 9.4 平台经营健康度评分模型 (满分 100) + // ① 拨比健康度 (30分) + $payoutScore = 30.0; + if ($totalGmv > 0) { + if ($payoutRate > 60) { + $payoutScore = 10.0; + } elseif ($payoutRate > 40) { + $payoutScore = 20.0; + } elseif ($payoutRate < 15) { + $payoutScore = 25.0; + } else { + $payoutScore = 30.0; + } + } + // ② 合伙人活跃健康度 (25分) + $partnerActiveRate = $totalAgents > 0 ? ($activePartnersCount / $totalAgents) : 0; + $activeScore = round($partnerActiveRate * 25, 1); + // ③ 用户复购粘性 (25分, 基准30%得满分) + $repeatScore = $paidUsersCount > 0 ? min(25.0, round(($repeatPurchaseRate / 30) * 25, 1)) : 15.0; + // ④ 资金履约安全度 (20分) + $safetyScore = 20.0; + if ($refundRate > 5.0) { + $safetyScore = 10.0; + } elseif ($refundRate > 2.0) { + $safetyScore = 15.0; + } else { + $safetyScore = 20.0; + } + + $healthTotalScore = round($payoutScore + $activeScore + $repeatScore + $safetyScore, 1); + $healthGrade = 'S·卓越'; + $healthGradeColor = '#52c41a'; + if ($healthTotalScore < 70) { + $healthGrade = 'C·预警'; + $healthGradeColor = '#f5222d'; + } elseif ($healthTotalScore < 80) { + $healthGrade = 'B·稳健'; + $healthGradeColor = '#fa8c16'; + } elseif ($healthTotalScore < 90) { + $healthGrade = 'A·良好'; + $healthGradeColor = '#1890ff'; + } + + $healthSuggestions = []; + if ($payoutRate <= 35) { + $healthSuggestions[] = "当前综合拨比为 {$payoutRate}%,处于精算设定的安全区间,净现金流沉淀稳固。"; + } else { + $healthSuggestions[] = "当前综合拨比为 {$payoutRate}%,略高于基准安全线,建议关注毛利率较高的商品排期。"; + } + if ($warningPartnersCount > 0) { + $healthSuggestions[] = "监测到有 {$warningPartnersCount} 位合伙人进入 7 天内即将断档预警期,建议及时定向唤醒催单。"; + } else { + $healthSuggestions[] = "合伙股东团队自购状态良好,暂无 7 天内即将断档的合伙人。"; + } + if ($lowStockCount > 0) { + $healthSuggestions[] = "仓储有 {$lowStockCount} 款商品 SKU 库存告急(≤10件),请及时补充库存避免断货缺货。"; + } else { + $healthSuggestions[] = "在售商品库存充沛,供应链运转健康。"; + } + if ($pendingWithdrawCount > 0) { + $healthSuggestions[] = "当前有 {$pendingWithdrawCount} 笔提现申请等待审核(¥{$financeOverview['pending_withdraw_amount']}),请及时审核保障出款体验。"; + } + + $operationOverview = [ + 'total_registered' => $totalRegisteredUsers, + 'paid_users_count' => $paidUsersCount, + 'pay_conversion_rate' => $payConversionRate, + 'single_buy_users_count' => $singleBuyCount, + 'repeat_buy_users_count' => $repeatBuyCount, + 'repeat_purchase_rate' => $repeatPurchaseRate, + 'arpu' => number_format($arpu, 2, '.', ''), + 'active_partners' => $activePartnersCount, + 'warning_partners' => $warningPartnersCount, + 'frozen_partners' => $frozenPartnersCount, + 'warning_list' => $warningList, + 'frozen_list' => $frozenList, + 'on_sale_goods_count' => $onSaleGoodsCount, + 'total_stock' => $totalStock, + 'low_stock_count' => $lowStockCount, + 'low_stock_list' => $lowStockFormatted, + 'health' => [ + 'score' => $healthTotalScore, + 'grade' => $healthGrade, + 'grade_color' => $healthGradeColor, + 'payout_score' => $payoutScore, + 'active_score' => $activeScore, + 'repeat_score' => $repeatScore, + 'safety_score' => $safetyScore, + 'suggestions' => $healthSuggestions, + ] + ]; + $this->success('获取成功', null, [ 'user_data' => $userData, 'agent_data' => $agentData ?? null, @@ -291,6 +549,8 @@ class Dashboard extends Common 'madow_data' => $madowData, 'voucher_data' => $voucherData, 'partner_network' => $partnerNetwork, + 'finance_overview' => $financeOverview, + 'operation_overview' => $operationOverview, ]); } diff --git a/application/admin/view/shopro/dashboard/index.html b/application/admin/view/shopro/dashboard/index.html index 3f1e84e..dd64973 100644 --- a/application/admin/view/shopro/dashboard/index.html +++ b/application/admin/view/shopro/dashboard/index.html @@ -245,6 +245,87 @@ width: 18px; height: 20px; } + + /* CFO 财务中枢与资产负债卡片 */ + .dashboard-index .finance-hub-card { + padding: 16px 18px; + min-height: 200px; + } + + .dashboard-index .finance-sub-metric { + padding: 8px 12px; + background: #fbfbfc; + border: 1px solid #f0f2f5; + border-radius: 6px; + margin-bottom: 8px; + font-size: 12px; + } + + /* COO 运营全貌与雷达卡片 */ + .dashboard-index .coo-panel-card { + padding: 16px 18px; + min-height: 280px; + } + + .dashboard-index .funnel-stage { + flex: 1; + padding: 10px 8px; + background: #fafafa; + border-radius: 6px; + text-align: center; + margin-right: 6px; + position: relative; + } + + .dashboard-index .funnel-stage:last-child { + margin-right: 0; + } + + .dashboard-index .radar-stat-pill { + padding: 8px 10px; + border-radius: 6px; + cursor: pointer; + transition: all .2s; + } + + .dashboard-index .radar-stat-pill:hover { + opacity: 0.9; + transform: translateY(-1px); + } + + .dashboard-index .health-score-dial { + text-align: center; + padding: 14px 10px; + background: linear-gradient(135deg, #f8faff 0%, #f0f5ff 100%); + border: 1px solid #d6e4ff; + border-radius: 8px; + } + + .dashboard-index .health-score-val { + font-size: 34px; + font-weight: 800; + line-height: 1.1; + color: #1890ff; + } + + .dashboard-index .warning-alert-row { + background: #fffbe6; + border: 1px solid #ffe58f; + padding: 8px 12px; + border-radius: 6px; + font-size: 12px; + color: #d46b08; + } + + .dashboard-index .low-stock-tag { + display: inline-block; + padding: 2px 6px; + border-radius: 3px; + background: #fff1f0; + color: #cf1322; + border: 1px solid #ffa39e; + font-weight: bold; + }
@@ -343,6 +424,98 @@ + + + + +
+
+
+ 浮 + 资金浮存池 (Cash Float) +
+ 平台流动免息资金 +
+
+ ¥{{ state.finance.total_float_funds }} +
+
+ 未提现佣金沉淀 (用户收益留存): + ¥{{ state.finance.commission_float }} +
+
+ 用户账户余额沉淀 (已充未销): + ¥{{ state.finance.user_balance_float }} +
+
+ 真实净现金流 (GMV-出款-退款): + ¥{{ state.finance.real_net_cash_flow }} +
+
+
+ + + +
+
+
+ 提 + 提现出款与风控敞口 +
+ 提现流水 → +
+
+ ¥{{ state.finance.total_withdraw_paid }} + 已打款出款 +
+
+ 待审核出款风控资金: +
+ ¥{{ state.finance.pending_withdraw_amount }} + + 审核 +
+
+
+ 累计申请总额:¥{{ state.finance.total_withdraw_applied }} + 出款兑现率:{{ state.finance.withdraw_cash_rate }}% +
+
+ 累计退款:¥{{ state.finance.total_refund_amount }} ({{ state.finance.total_refund_count }}笔) + 退款率:{{ state.finance.refund_rate }}% +
+
+
+ + + +
+
+
+ 债 + 未来承兑责任准备金 (负债中枢) +
+ 履约与承兑储备 +
+
+ ¥{{ state.finance.total_future_liability }} +
+
+ ① 消费兑换券补贴待释放负债 (1.5倍补贴): + ¥{{ state.finance.pending_voucher_liability }} +
+
+ ② 马豆流通折算市值负债 (生态回购承兑): + ¥{{ state.finance.madow_market_liability }} +
+
+ ③ 用户未提佣金流动负债: + ¥{{ state.finance.commission_liability }} +
+
+
+
+ @@ -515,6 +688,203 @@
+ + + + + +
+
+
+ 用户转化漏斗与复购粘性 +
+ 会员中心 → +
+ + +
+
+
全网注册
+
{{ state.operation.total_registered }} 人
+ 基数 100% +
+
→
+
+
付费买家
+
{{ state.operation.paid_users_count }} 人
+ 转化 {{ state.operation.pay_conversion_rate }}% +
+
→
+
+
复购会员
+
{{ state.operation.repeat_buy_users_count }} 人
+ 复购 {{ state.operation.repeat_purchase_rate }}% +
+
+ +
+ 单次购买买家:{{ state.operation.single_buy_users_count }} 人 + 复购买家:{{ state.operation.repeat_buy_users_count }} 人 +
+
+ 付费用户人均客单 (ARPU): + ¥{{ state.operation.arpu }} +
+
+ 在架商品:{{ state.operation.on_sale_goods_count }} 款 + 全仓总库存:{{ state.operation.total_stock }} 件 +
+
+
+ + + +
+
+
+ 合伙人 30天自购断档掉队雷达 +
+ 合伙团队 → +
+ + + + +
+
活跃达标
+
{{ state.operation.active_partners }}
+
>7天余量
+
+
+ +
+
即将断档
+
{{ state.operation.warning_partners }}
+
≤7天临界
+
+
+ +
+
已断档冻结
+
{{ state.operation.frozen_partners }}
+
无分佣资格
+
+
+
+ + +
+
+ ⚠️ 紧急唤醒:以下合伙人自购即将到期 + {{ state.operation.warning_partners }} 人临界 +
+
+
+
+ +
+ {{ wUser.nickname }} + {{ wUser.level_text }} +
+
+
+ 剩余 {{ wUser.days_left }} 天 + 催单 +
+
+
+
+ +
+
+ 🛡️ 合伙股东自购健康度良好,暂无临近断档人员 + 全部在保 +
+
已断档冻结人员采样 (失去分佣资格):
+
+
+
+ #{{ fUser.user_id }} + {{ fUser.nickname }} + ({{ fUser.mobile }}) +
+ {{ fUser.overdue_days }} +
+
+
+
+
+ + + +
+
+
+ 经营健康评分与供应链安全 +
+ + {{ state.operation.health.grade }} + +
+ + + + +
+
综合健康度
+
{{ state.operation.health.score }}
+
满分 100分
+
+
+ +
+
+ 拨比健康 (30分): + {{ state.operation.health.payout_score }}分 +
+
+ 合伙人活力 (25分): + {{ state.operation.health.active_score }}分 +
+
+ 复购粘性 (25分): + {{ state.operation.health.repeat_score }}分 +
+
+ 履约安全 (20分): + {{ state.operation.health.safety_score }}分 +
+
+
+
+ + +
+
+ 库存告急预警 (≤10件) + +
+ 预警中心 → +
+ +
+
+
+ + {{ sku.goods_title }} +
+
+ {{ sku.stock }}件 + 补货 +
+
+
+
+ ✅ 所有在售商品库存充足 +
+
+
+
{/if} {if $auth->check('shopro/dashboard/chart')} diff --git a/public/assets/js/backend/shopro/dashboard.js b/public/assets/js/backend/shopro/dashboard.js index c20e5b0..d328833 100644 --- a/public/assets/js/backend/shopro/dashboard.js +++ b/public/assets/js/backend/shopro/dashboard.js @@ -47,6 +47,52 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ( role_list: [], role_stats: {} }, + finance: { + commission_float: '0.00', + user_balance_float: '0.00', + total_float_funds: '0.00', + total_withdraw_applied: '0.00', + total_withdraw_paid: '0.00', + pending_withdraw_amount: '0.00', + pending_withdraw_count: 0, + withdraw_cash_rate: 0, + total_refund_amount: '0.00', + total_refund_count: 0, + refund_rate: 0, + real_net_cash_flow: '0.00', + pending_voucher_liability: '0.00', + madow_market_liability: '0.00', + commission_liability: '0.00', + total_future_liability: '0.00', + }, + operation: { + total_registered: 0, + paid_users_count: 0, + pay_conversion_rate: 0, + single_buy_users_count: 0, + repeat_buy_users_count: 0, + repeat_purchase_rate: 0, + arpu: '0.00', + active_partners: 0, + warning_partners: 0, + frozen_partners: 0, + warning_list: [], + frozen_list: [], + on_sale_goods_count: 0, + total_stock: 0, + low_stock_count: 0, + low_stock_list: [], + health: { + score: 100, + grade: 'S·卓越', + grade_color: '#52c41a', + payout_score: 30, + active_score: 25, + repeat_score: 25, + safety_score: 20, + suggestions: [] + } + }, total: { user: { data: {}, @@ -99,6 +145,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ( if (res.data.partner_network) { state.partner = res.data.partner_network; } + if (res.data.finance_overview) { + state.finance = res.data.finance_overview; + } + if (res.data.operation_overview) { + state.operation = res.data.operation_overview; + } for (var key in state.total) { if (state.total[key].data && document.getElementById(`${key}Total`)) { @@ -762,6 +814,28 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ( onOpenTab(url, '收益明细'); } + function onOpenWithdraw(status) { + let url = 'shopro/withdraw/index' + (status !== undefined && status !== 'all' ? `?status=${status}` : ''); + onOpenTab(url, '提现管理'); + } + + function onOpenGoods(goodsId) { + let url = goodsId ? `shopro/goods/goods/edit?ids=${goodsId}` : 'shopro/goods/goods/index'; + onOpenTab(url, goodsId ? '编辑商品' : '商品管理'); + } + + function onOpenStockWarning() { + onOpenTab('shopro/goods/stock_warning/index', '库存预警'); + } + + function onOpenUser() { + onOpenTab('shopro/user/user/index', '会员管理'); + } + + function onOpenAftersale() { + onOpenTab('shopro/order/aftersale/index', '售后维权'); + } + onMounted(() => { Config.cardList.forEach(item => { if (item.name == 'total' && item.status) { @@ -796,6 +870,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ( onOpenDaily, onOpenVoucher, onOpenTab, + onOpenWithdraw, + onOpenGoods, + onOpenStockWarning, + onOpenUser, + onOpenAftersale, } } } diff --git a/tests/partner/DashboardWealthTest.php b/tests/partner/DashboardWealthTest.php index ae9bc0e..0c15d36 100644 --- a/tests/partner/DashboardWealthTest.php +++ b/tests/partner/DashboardWealthTest.php @@ -66,6 +66,7 @@ class DashboardWealthTest $this->testChartEmptyDateFallback(); $this->testRankingPartnerAndDailyData(); $this->testWealthFinancialFormulaIntegrity(); + $this->testCfoAndCooOverview(); echo "\n--------------------------------------------------------\n"; echo "测试执行结果: 通过 {$this->passed} 项, 失败 {$this->failed} 项\n"; @@ -237,6 +238,58 @@ class DashboardWealthTest $this->assert($payoutRate == 0, "GMV 为 0 时分成拨比率恒为 0%"); } } + + /** + * 测试 7:CFO 财务中枢与 COO 运营全貌数据结构与勾稽 + */ + public function testCfoAndCooOverview() + { + $controller = new TestableDashboard(); + $controller->total(); + + $data = $controller->lastOutput['data'] ?? []; + $finance = $data['finance_overview'] ?? null; + $operation = $data['operation_overview'] ?? null; + + $this->assert($finance !== null, "total() 返回完整的 finance_overview 财务全貌中枢数据"); + $this->assert($operation !== null, "total() 返回完整的 operation_overview 运营全貌中枢数据"); + + if ($finance) { + $this->assert(isset($finance['commission_float']), "财务包含 commission_float 未提现佣金沉淀"); + $this->assert(isset($finance['total_float_funds']), "财务包含 total_float_funds 免息流动沉淀池"); + $this->assert(isset($finance['total_withdraw_paid']), "财务包含 total_withdraw_paid 累计已打款出款"); + $this->assert(isset($finance['pending_withdraw_amount']), "财务包含 pending_withdraw_amount 待审核出款风控资金"); + $this->assert(isset($finance['real_net_cash_flow']), "财务包含 real_net_cash_flow 真实净现金流"); + $this->assert(isset($finance['total_future_liability']), "财务包含 total_future_liability 未来承兑准备金"); + + $floatDiff = abs((float)$finance['total_float_funds'] - ((float)$finance['commission_float'] + (float)$finance['user_balance_float'])); + $this->assert($floatDiff < 0.01, "资金浮存勾稽: total_float_funds == commission_float + user_balance_float"); + + $liabilityDiff = abs((float)$finance['total_future_liability'] - ((float)$finance['pending_voucher_liability'] + (float)$finance['madow_market_liability'] + (float)$finance['commission_liability'])); + $this->assert($liabilityDiff < 0.01, "承兑负债勾稽: total_future_liability == pending_voucher + madow_market + commission"); + } + + if ($operation) { + $this->assert(isset($operation['total_registered']), "运营包含 total_registered 注册用户数"); + $this->assert(isset($operation['paid_users_count']), "运营包含 paid_users_count 付费买家数"); + $this->assert(isset($operation['pay_conversion_rate']), "运营包含 pay_conversion_rate 付费转化率"); + $this->assert(isset($operation['repeat_purchase_rate']), "运营包含 repeat_purchase_rate 复购率"); + $this->assert(isset($operation['arpu']), "运营包含 arpu 付费买家客单贡献"); + $this->assert(isset($operation['active_partners']), "运营包含 active_partners 活跃合伙人"); + $this->assert(isset($operation['warning_partners']), "运营包含 warning_partners 7天内即将断档合伙人"); + $this->assert(isset($operation['frozen_partners']), "运营包含 frozen_partners 已断档冻结合伙人"); + $this->assert(is_array($operation['warning_list']), "运营包含 warning_list 即将断档人员名单"); + $this->assert(isset($operation['low_stock_count']), "运营包含 low_stock_count 低库存告急SKU数量"); + $this->assert(is_array($operation['low_stock_list']), "运营包含 low_stock_list 低库存SKU商品列表"); + $this->assert(isset($operation['health']['score']), "运营包含经营健康度评分 score"); + $this->assert(isset($operation['health']['grade']), "运营包含经营健康度评级 grade"); + + $this->assert( + $operation['paid_users_count'] == ($operation['single_buy_users_count'] + $operation['repeat_buy_users_count']), + "用户转化勾稽: paid_users_count({$operation['paid_users_count']}) == single({$operation['single_buy_users_count']}) + repeat({$operation['repeat_buy_users_count']})" + ); + } + } } if (php_sapi_name() === 'cli' && basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME'])) {