131 lines
4.8 KiB
PHP
131 lines
4.8 KiB
PHP
<?php
|
|
namespace App\Controllers\CRM;
|
|
|
|
use App\Controllers\Controller;
|
|
use App\Models\CRM\Customer;
|
|
use App\Models\CRM\Lead;
|
|
use App\Models\CRM\FollowUp;
|
|
|
|
/**
|
|
* CRM 入口与子路由
|
|
* 权限:super_admin 或 crm_role ∈ {admin,user}(路由层已拦截)。
|
|
*/
|
|
class DashboardController extends Controller
|
|
{
|
|
public function nav(string $seg): array
|
|
{
|
|
return [
|
|
['k' => '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');
|
|
}
|
|
}
|