now=$now??new \DateTimeImmutable('now',new \DateTimeZone('Asia/Shanghai')); } private function rows(): array { $end=$this->now->format('Y-m-d H:i:s'); $start=$this->now->format('Y-m-01 00:00:00'); $enterprises=WaterEnterprise::query()->selectRaw('agent_id, COUNT(*) AS enterprise_count')->groupBy('agent_id'); $sales=WaterOrder::query()->alias('o')->join('sa_water_enterprise as e','e.id','=','o.enterprise_id') ->where('o.created_at','<=',$end) ->selectRaw('e.agent_id, SUM(o.amount_cents) AS sales_cents, SUM(CASE WHEN o.created_at >= ? THEN o.amount_cents ELSE 0 END) AS month_cents',[$start])->groupBy('e.agent_id'); $rows=WaterAgent::query()->alias('a') ->leftJoin('sa_system_user as u',function ($join) { $join->on('u.id','=','a.user_id')->whereNull('u.delete_time'); }) ->leftJoinSub($enterprises,'customers','customers.agent_id','=','a.id') ->leftJoinSub($sales,'sales','sales.agent_id','=','a.id') ->selectRaw('a.id,a.name,a.contact,a.phone,a.region,a.address,a.user_id,a.parent_id,a.status,a.created_at,a.updated_at, u.username,u.status AS operator_status,COALESCE(customers.enterprise_count,0) AS enterprise_count, COALESCE(sales.sales_cents,0) AS sales_cents,COALESCE(sales.month_cents,0) AS month_cents') ->orderByDesc('a.id')->get()->toArray(); $levels=(new AgentHierarchyPolicy())->levels($rows); $access=new AgentAccessPolicy(); $granted=$access->grantedUserIds(); $names=array_column($rows,'name','id'); $pendingCommission=WaterCommission::query()->where('status','pending') ->selectRaw('agent_id,SUM(amount_cents) AS amount_cents')->groupBy('agent_id') ->get()->pluck('amount_cents','agent_id')->all(); foreach ($rows as &$row) { foreach (['id','status','enterprise_count','sales_cents','month_cents'] as $key) $row[$key]=(int)$row[$key]; $row['user_id']=$row['user_id']===null?null:(int)$row['user_id']; $row['parent_id']=$row['parent_id']===null?null:(int)$row['parent_id']; $row['level']=$levels[$row['id']]; $row['parent_name']=$names[$row['parent_id']]??null; $row['authorization']=$access->state($row,$granted); $row['commission_cents']=(int)($pendingCommission[$row['id']]??0); } unset($row); return $rows; } public function dashboard(array $input): array { $filters=new AgentFilters($input); return WaterModel::transaction(function () use ($filters) { $all=$this->rows(); $rows=array_values(array_filter($all,function ($row) use ($filters) { return ($filters->keyword==='' || mb_stripos($row['name'].' '.$row['phone'].' '.$row['contact'],$filters->keyword)!==false) && ($filters->level==='' || ($filters->level==='unset'?$row['level']===null:$row['level']===(int)$filters->level)) && ($filters->authorization==='' || $row['authorization']===$filters->authorization); })); $sales=array_sum(array_column($all,'sales_cents')); $platform=(int)WaterOrder::query()->where('created_at','<=',$this->now->format('Y-m-d H:i:s'))->sum('amount_cents'); $members=array_filter($all,fn($row)=>$row['parent_id']!==null && $row['parent_id']>0); $rank=array_values(array_filter($all,fn($row)=>$row['month_cents']>0)); usort($rank,fn($a,$b)=>($b['month_cents']<=>$a['month_cents'])?:($a['id']<=>$b['id'])); $start=$this->now->format('Y-m-01 00:00:00'); $end=$this->now->format('Y-m-d H:i:s'); return ['list'=>['data'=>array_slice($rows,($filters->page-1)*$filters->limit,$filters->limit),'total'=>count($rows), 'current_page'=>$filters->page,'per_page'=>$filters->limit], 'summary'=>['total'=>count($all),'new_month'=>count(array_filter($all,fn($r)=>$r['created_at']>=$start && $r['created_at']<=$end)), 'sales_cents'=>$sales,'platform_share'=>$platform?round(100*$sales/$platform,1):null,'commission_cents'=>array_sum(array_column($all,'commission_cents')), 'members'=>count($members),'active_members'=>count(array_filter($members,fn($r)=>$r['status']===1 && $r['month_cents']>0))], 'ranking'=>array_slice($rank,0,4), 'options'=>array_map(fn($r)=>array_intersect_key($r,array_flip(['id','name','status','level'])),$all), 'commission'=>['configured'=>true,'message'=>WaterCommissionPolicy::message()], 'updated_at'=>$end]; }); } public function detail(int $id): array { return WaterModel::transaction(function () use ($id) { $all=$this->rows(); $map=array_column($all,null,'id'); if (!isset($map[$id])) throw new ApiException('代理不存在'); return ['agent'=>$map[$id], 'children'=>array_values(array_filter($all,fn($r)=>$r['parent_id']===$id)), 'enterprises'=>WaterEnterprise::query()->where('agent_id',$id)->orderByDesc('id')->limit(20)->get(['id','name','region','status'])->toArray()]; }); } }