sys() === 'psi' ? 'PSI 进销存' : 'CRM 客户管理'; } private function nav(): array { return \subsys_nav($this->sys()); } public function index() { $sys = $this->sys(); $other = $sys === 'crm' ? 'psi' : 'crm'; $col = $sys . '_role'; $rows = Db::query("SELECT * FROM admin_users WHERE `{$col}` != 'none' ORDER BY id ASC")->fetchAll(); // 子系统管理员仅管理「本系统的用户」,严格执行边界隔离: // - 不可越权操作后台超管 / 全局管理员; // - 不可跨界看到 / 管理另一系统(CRM 看不到 PSI,PSI 看不到 CRM)。 if (admin_role() !== 'super_admin') { $rows = array_filter($rows, static function ($r) use ($other) { // 排除后台超管 / 全局管理员 if (in_array($r['role'] ?? 'none', ['super_admin', 'admin'], true)) return false; // 排除另一系统的管理员(防跨界) if (($r[$other . '_role'] ?? 'none') === 'admin') return false; return true; }); } return $this->renderSubsys($sys, 'subsys/users', [ 'users' => $rows, 'sysName' => $this->sysName(), 'pages' => \subsys_pages($sys), 'sys' => $sys, ], $this->nav(), 'users'); } public function create() { $sys = $this->sys(); $user = [ 'id' => 0, 'username' => '', 'name' => '', 'status' => 1, $sys . '_role' => 'user', $sys . '_perms' => '', ]; return $this->renderSubsys($sys, 'subsys/user_form', [ 'user' => $user, 'sysName'=> $this->sysName(), 'pages' => \subsys_pages($sys), 'sys' => $sys, 'edit' => false, ], $this->nav(), 'users'); } public function store() { $sys = $this->sys(); $upper = strtoupper($sys); if (!csrf_check()) { $this->flash('表单已过期,请重试', 'err'); return $this->redirect($upper . '/users/create'); } $username = trim($this->post('username')); $name = trim($this->post('name')); $pwd = $this->post('password'); $role = $this->post($sys . '_role') === 'admin' ? 'admin' : 'user'; $perms = $this->collectPerms($sys); $status = $this->post('status') === '0' ? 0 : 1; if ($username === '' || $pwd === '') { $this->flash('用户名和密码不能为空', 'err'); return $this->redirect($upper . '/users/create'); } if (!preg_match('/^[a-zA-Z0-9_]{3,30}$/', $username)) { $this->flash('账号须为 3-30 位字母/数字/下划线', 'err'); return $this->redirect($upper . '/users/create'); } if (strlen($pwd) < 6) { $this->flash('密码至少 6 位', 'err'); return $this->redirect($upper . '/users/create'); } if ((new AdminUser())->byUsername($username)) { $this->flash('用户名已存在', 'err'); return $this->redirect($upper . '/users/create'); } (new AdminUser())->insert([ 'username' => $username, 'password' => password_hash($pwd, PASSWORD_DEFAULT), 'name' => $name, 'role' => 'none', // 子系统账号:全局后台角色为 none $sys . '_role' => $role, $sys . '_perms' => json_encode($perms, JSON_UNESCAPED_UNICODE), 'status' => $status, 'created_at' => date('Y-m-d H:i:s'), ]); $this->flash('用户已创建', 'ok'); return $this->redirect($upper . '/users'); } public function edit($id) { $sys = $this->sys(); $user = (new AdminUser())->find($id); if (!$user || !$this->manageable($user)) { return $this->redirect(strtoupper($sys) . '/users'); } return $this->renderSubsys($sys, 'subsys/user_form', [ 'user' => $user, 'sysName'=> $this->sysName(), 'pages' => \subsys_pages($sys), 'sys' => $sys, 'edit' => true, ], $this->nav(), 'users'); } public function update($id) { $sys = $this->sys(); $upper = strtoupper($sys); if (!csrf_check()) { $this->flash('表单已过期,请重试', 'err'); return $this->redirect($upper . '/users'); } $user = (new AdminUser())->find($id); if (!$user || !$this->manageable($user)) { $this->flash('无权操作该用户', 'err'); return $this->redirect($upper . '/users'); } $username = trim($this->post('username')); $name = trim($this->post('name')); $pwd = $this->post('password'); $role = $this->post($sys . '_role') === 'admin' ? 'admin' : 'user'; $perms = $this->collectPerms($sys); $status = $this->post('status') === '0' ? 0 : 1; if ($username === '' || !preg_match('/^[a-zA-Z0-9_]{3,30}$/', $username)) { $this->flash('账号不合法', 'err'); return $this->redirect($upper . '/users/edit/' . $id); } $existing = (new AdminUser())->byUsername($username); if ($existing && (int)$existing['id'] !== (int)$id) { $this->flash('用户名已存在', 'err'); return $this->redirect($upper . '/users/edit/' . $id); } if ($pwd !== '' && strlen($pwd) < 6) { $this->flash('密码至少 6 位', 'err'); return $this->redirect($upper . '/users/edit/' . $id); } $data = [ 'username' => $username, 'name' => $name, $sys . '_role' => $role, $sys . '_perms' => json_encode($perms, JSON_UNESCAPED_UNICODE), 'status' => $status, ]; if ($pwd !== '') { $data['password'] = password_hash($pwd, PASSWORD_DEFAULT); } (new AdminUser())->update($id, $data); $this->flash('用户已更新', 'ok'); return $this->redirect($upper . '/users'); } public function destroy($id) { $sys = $this->sys(); $upper = strtoupper($sys); if (!csrf_check()) { $this->flash('操作已失效,请重试', 'err'); return $this->redirect($upper . '/users'); } $user = (new AdminUser())->find($id); if (!$user || !$this->manageable($user) || (int)$user['id'] === (int)admin_uid()) { $this->flash('无法删除该用户', 'err'); return $this->redirect($upper . '/users'); } (new AdminUser())->delete($id); $this->flash('用户已删除', 'ok'); return $this->redirect($upper . '/users'); } /** 管理员为该用户重置密码 */ public function reset($id) { $sys = $this->sys(); $upper = strtoupper($sys); $user = (new AdminUser())->find($id); if (!$user || !$this->manageable($user)) { $this->flash('无权操作该用户', 'err'); return $this->redirect($upper . '/users'); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!csrf_check()) { $this->flash('表单已过期,请重试', 'err'); return $this->redirect($upper . '/users/reset/' . $id); } $pwd = $this->post('password'); if ($pwd === '' || strlen($pwd) < 6) { $this->flash('密码至少 6 位', 'err'); return $this->redirect($upper . '/users/reset/' . $id); } (new AdminUser())->update($id, ['password' => password_hash($pwd, PASSWORD_DEFAULT)]); $this->flash('密码已重置', 'ok'); return $this->redirect($upper . '/users'); } return $this->renderSubsys($sys, 'subsys/user_reset', [ 'user' => $user, 'sysName'=> $this->sysName(), 'sys' => $sys, ], $this->nav(), 'users'); } /** 收集页面权限:返回 {page: bool} 形式(与后台 UserController 一致,登录时按 JSON 解码) */ private function collectPerms(string $sys): array { $out = []; foreach (\subsys_pages($sys) as $p) { if ($p === 'dashboard') continue; $out[$p] = $this->post('perm_' . $p) ? true : false; } return $out; } /** 当前登录管理员是否可管理该目标用户(严格边界隔离:只管本系统用户,禁止跨界) */ private function manageable(array $target): bool { if (admin_role() === 'super_admin') return true; $sys = $this->sys(); $other = $sys === 'crm' ? 'psi' : 'crm'; // 不能管理后台超管 / 全局管理员 if (in_array($target['role'] ?? 'none', ['super_admin', 'admin'], true)) return false; // 只能管理本系统用户 if (($target[$sys . '_role'] ?? 'none') === 'none') return false; // 不能跨界管理另一系统的管理员(CRM 管不了 PSI,PSI 管不了 CRM) if (($target[$other . '_role'] ?? 'none') === 'admin') return false; return true; } }