'dashboard', 'label' => '仪表盘', 'icon' => '📊', 'url' => 'CRM'], ['k' => 'customers', 'label' => '客户管理', 'icon' => '🤝', 'url' => 'CRM/customers'], ['k' => 'leads', 'label' => '商机线索', 'icon' => '💡', 'url' => 'CRM/leads'], ['k' => 'followups', 'label' => '跟进记录', 'icon' => '📞', 'url' => 'CRM/followups'], ['k' => 'contacts', 'label' => '客户联系人', 'icon' => '👥', 'url' => 'CRM/contacts'], ]; } /** 统一子路由入口 */ public function dispatch(array $s) { $res = $s[0] ?? 'dashboard'; $action = $s[1] ?? ''; $id = $s[2] ?? null; // 仪表盘始终可进 if ($res === 'dashboard') { return $this->dashboard(); } // 用户管理(仅该系统管理员):统一管理本系统用户及其页面权限 if ($res === 'users') { if (!\subsys_admin('crm')) { \Core\App::forbidden('需要 CRM 管理员权限'); return; } $uc = new \App\Controllers\CRM\UsersController(); if ($action === '' || $action === 'index') return $uc->index(); if ($action === 'create') return $uc->create(); if ($action === 'store') return $uc->store(); if ($action === 'edit') return $uc->edit($id); if ($action === 'update') return $uc->update($id); if ($action === 'destroy') return $uc->destroy($id); if ($action === 'reset') return $uc->reset($id); \Core\App::notFound('未知操作: ' . $action); return; } $map = [ 'customers' => 'CustomersController', 'leads' => 'LeadsController', 'followups' => 'FollowUpsController', 'contacts' => 'ContactsController', ]; if (!isset($map[$res])) { \Core\App::notFound('未知页面: ' . $res); return; } // 页面级权限:仪表盘始终可进,其余页面按分系统「页面可见权限」拦截 if (!\subsys_page_can('crm', $res)) { \Core\App::forbidden('您没有访问该页面的权限'); return; } // 资源子操作路由:/CRM/{resource}[/{action}[/{id}]] $method = $this->resolveSubsysAction($action); if ($method === null) { \Core\App::notFound('未知操作: ' . $action); return; } $class = 'App\\Controllers\\CRM\\' . $map[$res]; $instance = new $class(); if (!method_exists($instance, $method)) { \Core\App::notFound('操作不存在: ' . $method); return; } return $instance->$method($id); } /** 将 URL 动作段解析为控制器方法名;不支持的动作返回 null */ private function resolveSubsysAction(string $action): ?string { $verbs = [ '' => 'index', 'index' => 'index', 'create' => 'create', 'store' => 'store', 'edit' => 'edit', 'update' => 'update', 'destroy' => 'destroy', ]; return $verbs[$action] ?? null; } public function dashboard() { $customers = (new Customer())->all(); $leads = (new Lead())->all(); $follows = (new FollowUp())->all(); $stageCount = []; foreach ($leads as $l) { $stageCount[$l['stage'] ?? 'new'] = ($stageCount[$l['stage'] ?? 'new'] ?? 0) + 1; } $amountTotal = array_sum(array_map(fn($l) => (float)($l['amount'] ?? 0), $leads)); $typeCount = []; foreach ($customers as $c) { $typeCount[$c['type'] ?? 'trade'] = ($typeCount[$c['type'] ?? 'trade'] ?? 0) + 1; } $recent = array_slice(array_reverse($follows), 0, 8); $recentCustomers = array_slice(array_reverse($customers), 0, 8); return $this->renderSubsys('crm', 'crm/dashboard', [ 'customerTotal' => count($customers), 'leadTotal' => count($leads), 'followTotal' => count($follows), 'amountTotal' => $amountTotal, 'stageCount' => $stageCount, 'typeCount' => $typeCount, 'recent' => $recent, 'recentCustomers'=> $recentCustomers, ], $this->nav('dashboard'), 'dashboard'); } }