'total', 'card' => 'shopro/dashboard/total', 'status' => $this->auth->check('shopro/dashboard/total') ], [ 'name' => 'chart', 'card' => 'shopro/dashboard/chart', 'status' => $this->auth->check('shopro/dashboard/chart') ], [ 'name' => 'ranking', 'card' => 'shopro/dashboard/ranking', 'status' => $this->auth->check('shopro/dashboard/ranking') ], ]; $this->assignconfig('cardList', $cardList); return $this->view->fetch(); } public function total() { // 1. 基础用户数据 (保持向下兼容) $userData = [ 'total' => User::count(), 'today' => User::whereTime('createtime', 'today')->count(), 'week' => User::whereTime('createtime', 'week')->count(), 'array' => collection(User::field('id,createtime')->whereTime('createtime', 'today')->select())->each(function ($user) { $user->counter = 1; $user->createtime_unix = $user->getData('createtime') * 1000; }) ]; // 2. 分销商/合伙人基础数据 (保持向下兼容) $agentData = [ 'total' => Agent::count(), 'today' => Agent::whereTime('createtime', 'today')->count(), 'week' => Agent::whereTime('createtime', 'week')->count(), 'array' => collection(Agent::field('user_id,createtime')->whereTime('createtime', 'today')->select())->each(function ($agent) { $agent->counter = 1; $agent->createtime_unix = $agent->getData('createtime') * 1000; }) ]; // 3. 分享数据 (保持向下兼容) $shareData = [ 'total' => Share::count(), 'today' => Share::whereTime('createtime', 'today')->count(), 'week' => Share::whereTime('createtime', 'week')->count(), 'array' => collection(Share::field('id,createtime')->whereTime('createtime', 'today')->select())->each(function ($share) { $share->counter = 1; $share->createtime_unix = $share->getData('createtime') * 1000; }) ]; // 4. 全局财富大盘与资金流 (专业财富指标) $paidStatuses = [Order::STATUS_PAID, Order::STATUS_COMPLETED]; $totalGmv = (float) Order::whereIn('status', $paidStatuses)->sum('pay_fee'); $todayGmv = (float) Order::whereIn('status', $paidStatuses)->whereTime('createtime', 'today')->sum('pay_fee'); $paidOrderCount = (int) Order::whereIn('status', $paidStatuses)->count(); $todayPaidOrderCount = (int) Order::whereIn('status', $paidStatuses)->whereTime('createtime', 'today')->count(); $avgOrderAmount = $paidOrderCount > 0 ? round($totalGmv / $paidOrderCount, 2) : 0.00; // 现金分成总支出 (status = 1 真实入账) $totalPayout = (float) Reward::where('status', 1)->sum('amount'); $todayPayout = (float) Reward::where('status', 1)->whereTime('createtime', 'today')->sum('amount'); $netRetention = round($totalGmv - $totalPayout, 2); $payoutRate = $totalGmv > 0 ? round(($totalPayout / $totalGmv) * 100, 2) : 0.00; $wealthData = [ 'total_gmv' => number_format($totalGmv, 2, '.', ''), 'today_gmv' => number_format($todayGmv, 2, '.', ''), 'total_payout' => number_format($totalPayout, 2, '.', ''), 'today_payout' => number_format($todayPayout, 2, '.', ''), 'net_retention' => number_format($netRetention, 2, '.', ''), 'payout_rate' => number_format($payoutRate, 2, '.', ''), 'paid_order_count' => $paidOrderCount, 'today_paid_order_count' => $todayPaidOrderCount, 'avg_order_amount' => number_format($avgOrderAmount, 2, '.', ''), ]; // 5. 马豆生态资产蓄水池 $totalMadow = (float) Agent::sum('madow'); $rateService = new RateService(); $currentRate = $rateService->currentRate(); $totalMadowCny = round($totalMadow * $currentRate, 2); $historyOrderN = $rateService->countN(); $latestReport = DailyReport::order('settle_date', 'desc')->find(); $yesterdayMadowPool = $latestReport ? (float) $latestReport->madow_pool : 0.00; $madowData = [ 'total_madow' => IdentityService::formatMadow($totalMadow), 'current_rate' => number_format($currentRate, 10, '.', ''), 'rate_per_wan' => number_format($currentRate * 10000, 4, '.', ''), // 每万豆价值折算 'total_madow_cny' => number_format($totalMadowCny, 2, '.', ''), 'history_order_n' => $historyOrderN, 'yesterday_madow_pool' => IdentityService::formatMadow($yesterdayMadowPool), ]; // 6. 消费兑换券杠杆池 $totalVoucher = (float) VoucherPlan::sum('total_amount'); $releasedVoucher = (float) VoucherPlan::sum('released_amount'); $usedVoucher = (float) Agent::sum('voucher_used'); $pendingVoucher = max(0, round($totalVoucher - $releasedVoucher, 2)); $availableVoucher = max(0, round($releasedVoucher - $usedVoucher, 2)); $voucherData = [ 'total_voucher' => number_format($totalVoucher, 2, '.', ''), 'released_voucher' => number_format($releasedVoucher, 2, '.', ''), 'used_voucher' => number_format($usedVoucher, 2, '.', ''), 'pending_voucher' => number_format($pendingVoucher, 2, '.', ''), 'available_voucher' => number_format($availableVoucher, 2, '.', ''), ]; // 7. 合伙股东网络与资本活力 $totalAgents = (int) Agent::count(); $tasterCount = (int) Agent::where('level', 1)->count(); $makerCount = (int) Agent::where('level', '>=', 2)->count(); $makerLevels = []; for ($lv = 2; $lv <= 7; $lv++) { $makerLevels['V' . ($lv - 1)] = (int) Agent::where('level', $lv)->count(); } $venueCount = (int) Agent::where('is_venue', 1)->count(); $countyCount = (int) Agent::where('is_county', 1)->count(); $activeWindow = time() - (int) PartnerConfig::get('partner_active_days', 30) * 86400; $activeCount = (int) Agent::where('last_self_order_time', '>=', $activeWindow)->count(); $inactiveCount = max(0, $totalAgents - $activeCount); $activeRate = $totalAgents > 0 ? round(($activeCount / $totalAgents) * 100, 1) : 0.0; $partnerNetwork = [ 'total_agents' => $totalAgents, 'taster_count' => $tasterCount, 'maker_count' => $makerCount, 'maker_levels' => $makerLevels, 'venue_count' => $venueCount, 'county_count' => $countyCount, 'active_count' => $activeCount, 'inactive_count' => $inactiveCount, 'active_rate' => $activeRate, ]; $this->success('获取成功', null, [ 'user_data' => $userData, 'agent_data' => $agentData ?? null, 'share_data' => $shareData, 'wealth_data' => $wealthData, 'madow_data' => $madowData, 'voucher_data' => $voucherData, 'partner_network' => $partnerNetwork, ]); } public function chart() { $date = $this->request->param('date', ''); $date = array_values(array_filter(explode(' - ', $date))); if (empty($date) || count($date) < 2) { $date = [date('Y-m-d 00:00:00'), date('Y-m-d 23:59:59')]; } $orders = Order::with(['items'])->whereTime('createtime', 'between', $date) ->order('id', 'asc')->select(); // 订单数 $data['orderNum'] = count($orders); $data['orderArr'] = []; // 支付订单(包含退款的订单, 不包含货到付款还未收货(未支付)订单) $data['payOrderNum'] = 0; $data['payOrderArr'] = []; // 支付金额(包含退款的订单, 不包含货到付款还未收货(未支付)订单) $data['payAmountNum'] = 0; $data['payAmountArr'] = []; // 支付用户 $userIds = []; $data['payUserNum'] = 0; $data['payUserArr'] = []; // 待发货(包含货到付款) $data['noSendNum'] = 0; $data['noSendArr'] = []; // 售后维权 $data['aftersaleNum'] = 0; $data['aftersaleArr'] = []; // 退款订单 $data['refundNum'] = 0; $data['refundArr'] = []; foreach ($orders as $key => $order) { $data['orderArr'][] = [ 'counter' => 1, 'createtime' => $order->getData('createtime') * 1000, 'user_id' => $order->user_id ]; // 已支付的,不包含货到付款未支付的 if (in_array($order->status, [Order::STATUS_PAID, Order::STATUS_COMPLETED])) { $data['payOrderNum']++; $data['payOrderArr'][] = [ 'counter' => 1, 'createtime' => $order->getData('createtime') * 1000, 'user_id' => $order->user_id ]; // 支付金额 $data['payAmountNum'] = bcadd((string)$data['payAmountNum'], $order->pay_fee, 2); $data['payAmountArr'][] = [ 'counter' => (float) $order->pay_fee, 'createtime' => $order->getData('createtime') * 1000, ]; // 下单用户 if (!in_array($order->user_id, $userIds)) { $data['payUserNum']++; $data['payUserArr'][] = [ 'counter' => 1, 'createtime' => $order->getData('createtime') * 1000, 'user_id' => $order->user_id ]; } } // 已支付的和货到付款未支付的 if (in_array($order->status, [Order::STATUS_PAID, Order::STATUS_COMPLETED]) || $order->isOffline($order)) { $flagnoSend = false; $flagaftersale = false; $flagrefund = false; $aftersaleIng = false; foreach ($order->items as $k => $item) { if ( !$flagnoSend && $item->dispatch_status == OrderItem::DISPATCH_STATUS_NOSEND && $item->refund_status == OrderItem::REFUND_STATUS_NOREFUND && in_array($order->apply_refund_status, [ Order::APPLY_REFUND_STATUS_NOAPPLY, Order::APPLY_REFUND_STATUS_REFUSE ]) ) { $flagnoSend = true; } if ( $item->aftersale_status == OrderItem::AFTERSALE_STATUS_ING && $item->dispatch_status == OrderItem::DISPATCH_STATUS_NOSEND && $item->refund_status == OrderItem::REFUND_STATUS_NOREFUND ) { $aftersaleIng = true; } if (!$flagaftersale && $item->aftersale_status != OrderItem::AFTERSALE_STATUS_NOAFTER) { $data['aftersaleNum']++; $flagaftersale = true; } if (!$flagrefund && $item->refund_status > OrderItem::REFUND_STATUS_NOREFUND) { $data['refundNum']++; $flagrefund = true; } } if (!$aftersaleIng && $flagnoSend) { $data['noSendNum']++; } } } // ================= 财富与收益分成时段穿透 (新增) ================= $rewards = Reward::where('status', 1) ->whereTime('createtime', 'between', $date) ->order('id', 'asc') ->select(); $payoutTotal = 0.00; $payoutArr = []; $periodMadow = 0.00000000; // 四大分成板块结构 $structureMap = [ 'push3' => [ 'key' => 'push3', 'name' => '直推裂变(推三返一)', 'types' => ['push3'], 'amount' => 0.00, 'count' => 0, 'color' => '#806AF6', ], 'maker' => [ 'key' => 'maker', 'name' => '创客团队(极差/平级/超越)', 'types' => ['maker_diff', 'maker_peer', 'maker_overtaken'], 'amount' => 0.00, 'count' => 0, 'color' => '#13c2c2', ], 'channel' => [ 'key' => 'channel', 'name' => '实体渠道(馆县拆分/平级)', 'types' => ['team_venue', 'team_county', 'venue_peer', 'county_peer'], 'amount' => 0.00, 'count' => 0, 'color' => '#fa8c16', ], 'share' => [ 'key' => 'share', 'name' => '全网共享(平台日结均分)', 'types' => ['venue_share', 'county_share'], 'amount' => 0.00, 'count' => 0, 'color' => '#eb2f96', ], ]; // 详细奖项映射 $detailList = []; foreach (PartnerConfig::rewardTypeMap() as $typeKey => $typeName) { if (in_array($typeKey, ['madow_share', 'voucher_grant', 'voucher_release'])) { continue; } $detailList[$typeKey] = [ 'type' => $typeKey, 'name' => $typeName, 'amount' => 0.00, 'count' => 0, ]; } foreach ($rewards as $reward) { $amt = (float) $reward->amount; $rwType = $reward->reward_type; if ($rwType === 'madow_share') { $periodMadow = function_exists('bcadd') ? (float) bcadd((string)$periodMadow, (string)($reward->madow ?? 0), 8) : ($periodMadow + (float)($reward->madow ?? 0)); continue; } if ($amt > 0) { $payoutTotal = round($payoutTotal + $amt, 2); $payoutArr[] = [ 'counter' => $amt, 'createtime' => $reward->getData('createtime') * 1000, 'type' => $rwType, ]; // 归类到板块 foreach ($structureMap as $catKey => &$cat) { if (in_array($rwType, $cat['types'])) { $cat['amount'] = round($cat['amount'] + $amt, 2); $cat['count']++; break; } } unset($cat); if (isset($detailList[$rwType])) { $detailList[$rwType]['amount'] = round($detailList[$rwType]['amount'] + $amt, 2); $detailList[$rwType]['count']++; } } } // 格式化分成板块占比 $splitStructure = []; foreach ($structureMap as $catKey => $cat) { $catAmount = (float) $cat['amount']; $ratio = $payoutTotal > 0 ? round(($catAmount / $payoutTotal) * 100, 1) : 0.0; $splitStructure[] = [ 'key' => $catKey, 'name' => $cat['name'], 'amount' => number_format($catAmount, 2, '.', ''), 'count' => $cat['count'], 'ratio' => $ratio, 'color' => $cat['color'], ]; } $payAmountNum = (float) $data['payAmountNum']; $data['payoutNum'] = number_format($payoutTotal, 2, '.', ''); $data['payoutArr'] = $payoutArr; $data['retentionNum'] = number_format(max(0, round($payAmountNum - $payoutTotal, 2)), 2, '.', ''); $data['payoutRate'] = $payAmountNum > 0 ? round(($payoutTotal / $payAmountNum) * 100, 2) : 0.00; $data['splitStructure'] = $splitStructure; $data['rewardDetails'] = array_values($detailList); $data['periodMadow'] = IdentityService::formatMadow($periodMadow); $this->success('获取成功', null, $data); } public function ranking() { // 1. 商品销量排行 (原有) $goods = Goods::limit(5)->order('sales', 'desc')->select(); foreach ($goods as $key => $gd) { $gd->append(['real_sales']); $result = OrderItem::field('sum(goods_num * goods_price) as sale_total_money')->where('goods_id', $gd['id']) ->whereExists(function ($query) use ($gd) { $order_table_name = (new Order())->getQuery()->getTable(); $table_name = (new OrderItem())->getQuery()->getTable(); $query->table($order_table_name)->where($table_name . '.order_id=' . $order_table_name . '.id') ->whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED]); // 已支付的订单 })->find(); $gd['sale_total_money'] = $result['sale_total_money'] ?: 0; } // 2. 热搜排行 (原有) $searchHistory = new SearchHistory(); $hotSearch = $searchHistory->hotSearch(); // 3. 合伙股东收益排行 TOP 5 (新增) $partnerRanking = []; $rankingRows = Reward::field('user_id, sum(amount) as total_income, count(*) as reward_count') ->where('status', 1) ->where('user_id', '>', 0) ->group('user_id') ->order('total_income', 'desc') ->limit(5) ->select(); foreach ($rankingRows as $row) { $user = User::field('id, nickname, avatar, mobile')->where('id', $row->user_id)->find(); $agent = Agent::where('user_id', $row->user_id)->find(); $identity = IdentityService::build($agent); $partnerRanking[] = [ 'user_id' => $row->user_id, 'nickname' => $user ? ($user->nickname ?: '用户#' . $row->user_id) : '用户#' . $row->user_id, 'avatar' => $user ? $user->avatar : '', 'mobile' => $user ? $user->mobile : '', 'total_income' => number_format((float)$row->total_income, 2, '.', ''), 'reward_count' => (int) $row->reward_count, 'identity_text' => $identity['identity_text'] ?: '普通会员', 'is_partner' => $identity['is_partner'], 'direct_order_seq' => $agent ? (int) $agent->direct_order_seq : 0, ]; } // 4. 最新日结概览 (新增) $dailyReport = DailyReport::order('settle_date', 'desc')->find(); $recentReport = null; if ($dailyReport) { $recentReport = [ 'settle_date' => $dailyReport->settle_date, 'gmv' => number_format((float)$dailyReport->gmv, 2, '.', ''), 'order_count' => (int)$dailyReport->order_count, 'order_count_n' => (int)$dailyReport->order_count_n, 'rate' => number_format((float)$dailyReport->rate, 10, '.', ''), 'madow_pool' => IdentityService::formatMadow($dailyReport->madow_pool), 'share_user_count' => (int)$dailyReport->share_user_count, 'venue_pool' => number_format((float)$dailyReport->venue_pool, 2, '.', ''), 'venue_user_count' => (int)$dailyReport->venue_user_count, 'county_pool' => number_format((float)$dailyReport->county_pool, 2, '.', ''), 'county_user_count' => (int)$dailyReport->county_user_count, 'voucher_release_total' => number_format((float)$dailyReport->voucher_release_total, 2, '.', ''), 'status' => (int)$dailyReport->status, 'status_text' => $dailyReport->status_text, ]; } $this->success('获取成功', null, [ 'goods' => $goods, 'hot_search' => $hotSearch, 'partner_ranking' => $partnerRanking, 'daily_report_recent' => $recentReport, ]); } }