dashboard(); } // 用户管理(仅该系统管理员):统一管理本系统用户及其页面权限 if ($res === 'users') { if (!\subsys_admin('psi')) { \Core\App::forbidden('需要 PSI 管理员权限'); return; } $uc = new \App\Controllers\PSI\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; } // 订单管理:合并原「后台订单」到 PSI,方便管理人员在同一系统内快速处理 if ($res === 'orders') { if (!\subsys_page_can('psi', 'orders')) { \Core\App::forbidden('您没有访问订单管理的权限'); return; } $oc = new \App\Controllers\PSI\OrdersController(); if ($action === '' || $action === 'index') return $oc->index(); if ($action === 'show') return $oc->show($id); if ($action === 'markPaid') return $oc->markPaid($id); if ($action === 'destroy') return $oc->destroy($id); \Core\App::notFound('未知操作: ' . $action); return; } // 销售订单:录入 / 打印 / 关联出库 if ($res === 'sales_orders') { if (!\subsys_page_can('psi', 'sales_orders')) { \Core\App::forbidden('您没有访问销售订单的权限'); return; } $c = new \App\Controllers\PSI\SalesOrdersController(); if ($action === '' || $action === 'index') return $c->index(); if ($action === 'create') return $c->create(); if ($action === 'store') return $c->store(); if ($action === 'show') return $c->show($id); if ($action === 'edit') return $c->edit($id); if ($action === 'update') return $c->update($id); if ($action === 'destroy') return $c->destroy($id); if ($action === 'print') return $c->printDoc($id); \Core\App::notFound('未知操作: ' . $action); return; } // 采购订单:录入 / 打印 / 收货入库 if ($res === 'purchase_orders') { if (!\subsys_page_can('psi', 'purchase_orders')) { \Core\App::forbidden('您没有访问采购订单的权限'); return; } $c = new \App\Controllers\PSI\PurchaseOrdersController(); if ($action === '' || $action === 'index') return $c->index(); if ($action === 'create') return $c->create(); if ($action === 'store') return $c->store(); if ($action === 'show') return $c->show($id); if ($action === 'edit') return $c->edit($id); if ($action === 'update') return $c->update($id); if ($action === 'destroy') return $c->destroy($id); if ($action === 'receive') return $c->receive($id); if ($action === 'print') return $c->printDoc($id); \Core\App::notFound('未知操作: ' . $action); return; } // 出库单:录入 / 打印(关联销售订单、扣减库存) if ($res === 'outbounds') { if (!\subsys_page_can('psi', 'outbounds')) { \Core\App::forbidden('您没有访问出库单的权限'); return; } $c = new \App\Controllers\PSI\OutboundsController(); if ($action === '' || $action === 'index') return $c->index(); if ($action === 'create') return $c->create(); if ($action === 'store') return $c->store(); if ($action === 'show') return $c->show($id); if ($action === 'edit') return $c->edit($id); if ($action === 'update') return $c->update($id); if ($action === 'destroy') return $c->destroy($id); if ($action === 'print') return $c->printDoc($id); \Core\App::notFound('未知操作: ' . $action); return; } // 报表中心:采购订单明细 / 销售·采购订单明细 / 交付明细 if ($res === 'reports') { if (!\subsys_page_can('psi', 'reports')) { \Core\App::forbidden('您没有访问报表中心的权限'); return; } $c = new \App\Controllers\PSI\ReportsController(); if ($action === '' || $action === 'index') return $c->index(); if ($action === 'poDetail') return $c->poDetail(); if ($action === 'soPo') return $c->soPo(); if ($action === 'delivery') return $c->delivery(); \Core\App::notFound('未知操作: ' . $action); return; } // 紧急提醒中心(所有 PSI 用户可见) if ($res === 'reminders') { $c = new \App\Controllers\PSI\RemindersController(); return $c->handle(array_slice($s, 1)); } // 通知设置(仅 PSI 管理员,控制器内二次鉴权) if ($res === 'notifications') { $c = new \App\Controllers\PSI\NotificationsController(); return $c->handle(array_slice($s, 1)); } // 销售出库(支持 show/print 查看与打印预览) if ($res === 'sales') { if (!\subsys_page_can('psi', 'sales')) { \Core\App::forbidden('您没有访问销售出库的权限'); return; } $c = new \App\Controllers\PSI\SalesController(); if ($action === '' || $action === 'index') return $c->index(); if ($action === 'create') return $c->create(); if ($action === 'store') return $c->store(); if ($action === 'show') return $c->show($id); if ($action === 'destroy') return $c->destroy($id); if ($action === 'print') return $c->printDoc($id); \Core\App::notFound('未知操作: ' . $action); return; } $map = [ 'materials' => 'MaterialsController', 'products' => 'ProductsController', 'suppliers' => 'SuppliersController', 'purchases' => 'PurchasesController', 'stock' => 'StockController', ]; if (!isset($map[$res])) { \Core\App::notFound('未知页面: ' . $res); return; } // 页面级权限:按分系统「页面可见权限」拦截 if (!\subsys_page_can('psi', $res)) { \Core\App::forbidden('您没有访问该页面的权限'); return; } // 资源子操作路由:/PSI/{resource}[/{action}[/{id}]] // 支持 index/create/store/edit/update/destroy/adjust $method = $this->resolveSubsysAction($action); if ($method === null) { \Core\App::notFound('未知操作: ' . $action); return; } $class = 'App\\Controllers\\PSI\\' . $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', 'adjust' => 'adjust', ]; return $verbs[$action] ?? null; } public function dashboard() { $materials = (new Material())->all(); $products = (new Product())->all(); $purchases = (new Purchase())->all(); $sales = (new Sales())->all(); $matStock = array_sum(array_map(fn($m) => (float)($m['stock'] ?? 0), $materials)); $prodStock = array_sum(array_map(fn($p) => (float)($p['stock'] ?? 0), $products)); $purchaseAmt = array_sum(array_map(fn($p) => (float)($p['amount'] ?? 0), $purchases)); $salesAmt = array_sum(array_map(fn($s) => (float)($s['amount'] ?? 0), $sales)); $lowStock = []; foreach ($materials as $m) { if ((float)($m['stock'] ?? 0) < 20) $lowStock[] = ['type' => '物料', 'item' => $m]; } foreach ($products as $p) { if ((float)($p['stock'] ?? 0) < 20) $lowStock[] = ['type' => '成品', 'item' => $p]; } $recentPurchases = array_slice(array_reverse($purchases), 0, 5); $recentSales = array_slice(array_reverse($sales), 0, 5); // 订单/出库业务指标(表未创建时静默降级) $bySalesman = []; $salesAmount = 0; $salesAmountMonth = 0; $undelivered = ['count' => 0, 'amount' => 0]; $monthDeliveries = ['count' => 0, 'amount' => 0]; try { $bySalesman = \Core\Db::query( "SELECT o.salesman AS salesman, COUNT(DISTINCT o.id) AS orders, COALESCE(SUM(i.amount),0) AS amount FROM psi_sales_orders o LEFT JOIN psi_sales_order_items i ON i.so_id=o.id WHERE o.salesman <> '' AND o.status <> 'closed' GROUP BY o.salesman ORDER BY amount DESC" )->fetchAll(); $r = \Core\Db::query( "SELECT COALESCE(SUM(i.amount),0) AS amt, COALESCE(SUM(CASE WHEN MONTH(o.created_at)=MONTH(CURDATE()) AND YEAR(o.created_at)=YEAR(CURDATE()) THEN i.amount ELSE 0 END),0) AS amt_m FROM psi_sales_orders o LEFT JOIN psi_sales_order_items i ON i.so_id=o.id WHERE o.status <> 'closed'" )->fetch(); $salesAmount = (float)($r['amt'] ?? 0); $salesAmountMonth = (float)($r['amt_m'] ?? 0); $u = \Core\Db::query( "SELECT COUNT(*) AS c, COALESCE(SUM(i.amount),0) AS amt FROM psi_sales_orders o LEFT JOIN psi_sales_order_items i ON i.so_id=o.id WHERE o.status IN ('pending','partial')" )->fetch(); $undelivered = ['count' => (int)($u['c'] ?? 0), 'amount' => (float)($u['amt'] ?? 0)]; $d = \Core\Db::query( "SELECT COUNT(*) AS c, COALESCE(SUM(i.amount),0) AS amt FROM psi_outbounds ob LEFT JOIN psi_outbound_items i ON i.ob_id=ob.id WHERE MONTH(ob.created_at)=MONTH(CURDATE()) AND YEAR(ob.created_at)=YEAR(CURDATE())" )->fetch(); $monthDeliveries = ['count' => (int)($d['c'] ?? 0), 'amount' => (float)($d['amt'] ?? 0)]; } catch (\Throwable $e) { /* 表未创建时不报错 */ } return $this->renderSubsys('psi', 'psi/dashboard', [ 'materialTotal' => count($materials), 'productTotal' => count($products), 'matStock' => $matStock, 'prodStock' => $prodStock, 'purchaseAmt' => $purchaseAmt, 'salesAmt' => $salesAmt, 'lowStock' => $lowStock, 'recentPurchases' => $recentPurchases, 'recentSales' => $recentSales, 'bySalesman' => $bySalesman, 'salesAmount' => $salesAmount, 'salesAmountMonth' => $salesAmountMonth, 'undelivered' => $undelivered, 'monthDeliveries' => $monthDeliveries, ], $this->nav('dashboard'), 'dashboard'); } }