model = new AdminModel(); return null; } /** * 非超管:仅可管理「本人 + 树形下级组内」的管理员账号;与角色组管理页的可见范围一致(列表不含仅同级的其他管理员) */ protected function getDataLimitAdminIds(): array { if (!$this->dataLimit || !$this->auth || $this->auth->isSuperAdmin()) { return []; } return $this->auth->getSelfAndSubordinateAdminIds(); } public function index(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; if ($request->get('select') ?? $request->post('select')) { $selectRes = $this->select($request); if ($selectRes !== null) return $selectRes; } list($where, $alias, $limit, $order) = $this->queryBuilder(); $query = $this->model ->withoutField('login_failure,password,salt') ->withJoin($this->withJoinTable, $this->withJoinType) ->alias($alias) ->where($where); // 仅返回“顶级角色组(pid=0)”下的管理员(用于远程下拉等场景) $topGroup = $request->get('top_group') ?? $request->post('top_group'); if ($topGroup === '1' || $topGroup === 1 || $topGroup === true) { $query = $query ->join('admin_group_access aga', $alias['admin'] . '.id = aga.uid') ->join('admin_group ag', 'aga.group_id = ag.id') ->where('ag.pid', 0) ->distinct(true); } $res = $query ->order($order) ->paginate($limit); return $this->success('', [ 'list' => $res->items(), 'total' => $res->total(), 'remark' => get_route_remark(), ]); } /** * 远程下拉(重写:支持 top_group=1 仅返回顶级组管理员) */ protected function _select(): Response { if (empty($this->model)) { return $this->success('', [ 'list' => [], 'total' => 0, ]); } $pk = $this->model->getPk(); $fields = [$pk]; $quickSearchArr = is_array($this->quickSearchField) ? $this->quickSearchField : explode(',', (string) $this->quickSearchField); foreach ($quickSearchArr as $f) { $f = trim((string) $f); if ($f === '') continue; $f = str_contains($f, '.') ? substr($f, strrpos($f, '.') + 1) : $f; if ($f !== '' && !in_array($f, $fields, true)) { $fields[] = $f; } } list($where, $alias, $limit, $order) = $this->queryBuilder(); $modelTable = strtolower($this->model->getTable()); $mainAlias = ($alias[$modelTable] ?? $modelTable) . '.'; // 联表时避免字段歧义:主表字段统一 select 为 "admin.xxx as xxx" $selectFields = []; foreach ($fields as $f) { $f = trim((string) $f); if ($f === '') continue; $selectFields[] = $mainAlias . $f . ' as ' . $f; } // 联表时避免排序字段歧义:无前缀的字段默认加主表前缀 $qualifiedOrder = []; if (is_array($order)) { foreach ($order as $k => $v) { $k = (string) $k; $qualifiedOrder[str_contains($k, '.') ? $k : ($mainAlias . $k)] = $v; } } $query = $this->model ->field($selectFields) ->alias($alias) ->where($where); $topGroup = $this->request ? ($this->request->get('top_group') ?? $this->request->post('top_group')) : null; if ($topGroup === '1' || $topGroup === 1 || $topGroup === true) { $query = $query ->join('admin_group_access aga', $mainAlias . 'id = aga.uid') ->join('admin_group ag', 'aga.group_id = ag.id') ->where('ag.pid', 0) ->distinct(true); } $res = $query ->order($qualifiedOrder ?: $order) ->paginate($limit); return $this->success('', [ 'list' => $res->items(), 'total' => $res->total(), ]); } public function add(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; if ($request->method() === 'POST') { $data = $request->post(); if (!$data) { return $this->error(__('Parameter %s can not be empty', [''])); } if ($this->modelValidate) { try { $rules = [ 'username' => 'required|string|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/|unique:admin,username', 'nickname' => 'required|string', 'password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/', 'email' => 'email|unique:admin,email', 'mobile' => 'regex:/^1[3-9]\d{9}$/|unique:admin,mobile', 'group_arr' => 'required|array', ]; $messages = [ 'username.regex' => __('Please input correct username'), 'password.regex' => __('Please input correct password'), ]; Validator::make($data, $rules, $messages)->validate(); } catch (ValidationException $e) { return $this->error($e->getMessage()); } } $passwd = $data['password'] ?? ''; $data = $this->excludeFields($data); $result = false; if (!empty($data['group_arr'])) { $authRes = $this->checkGroupAuth($data['group_arr']); if ($authRes !== null) return $authRes; } $this->model->startTrans(); try { $result = $this->model->save($data); if (!empty($data['group_arr'])) { $groupAccess = []; foreach ($data['group_arr'] as $datum) { $groupAccess[] = [ 'uid' => $this->model->id, 'group_id' => $datum, ]; } Db::name('admin_group_access')->insertAll($groupAccess); } $this->model->commit(); if (!empty($passwd)) { $this->model->resetPassword($this->model->id, $passwd); } } catch (Throwable $e) { $this->model->rollback(); return $this->error($e->getMessage()); } if ($result !== false) { return $this->success(__('Added successfully')); } return $this->error(__('No rows were added')); } return $this->error(__('Parameter error')); } public function edit(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; $pk = $this->model->getPk(); $id = $request->get($pk) ?? $request->post($pk); $row = $this->model->find($id); if (!$row) { return $this->error(__('Record not found')); } $dataLimitAdminIds = $this->getDataLimitAdminIds(); if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { return $this->error(__('You have no permission')); } if ($request->method() === 'POST') { $data = $request->post(); if (!$data) { return $this->error(__('Parameter %s can not be empty', [''])); } if ($this->modelValidate) { try { $rules = [ 'username' => 'required|string|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/|unique:admin,username,' . $id, 'nickname' => 'required|string', 'password' => 'nullable|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/', 'email' => 'email|unique:admin,email,' . $id, 'mobile' => 'regex:/^1[3-9]\d{9}$/|unique:admin,mobile,' . $id, 'group_arr' => 'required|array', ]; $messages = [ 'username.regex' => __('Please input correct username'), 'password.regex' => __('Please input correct password'), ]; Validator::make($data, $rules, $messages)->validate(); } catch (ValidationException $e) { return $this->error($e->getMessage()); } } if ($this->auth->id == $data['id'] && ($data['status'] ?? '') == 'disable') { return $this->error(__('Please use another administrator account to disable the current account!')); } if (!empty($data['password'])) { $this->model->resetPassword($row->id, $data['password']); } $groupAccess = []; if (!empty($data['group_arr'])) { $checkGroups = []; $rowGroupArr = $row->group_arr ?? []; foreach ($data['group_arr'] as $datum) { if (!in_array($datum, $rowGroupArr)) { $checkGroups[] = $datum; } $groupAccess[] = [ 'uid' => $id, 'group_id' => $datum, ]; } $authRes = $this->checkGroupAuth($checkGroups); if ($authRes !== null) return $authRes; } Db::name('admin_group_access') ->where('uid', $id) ->delete(); $data = $this->excludeFields($data); $result = false; $this->model->startTrans(); try { $result = $row->save($data); if ($groupAccess) { Db::name('admin_group_access')->insertAll($groupAccess); } $this->model->commit(); } catch (Throwable $e) { $this->model->rollback(); return $this->error($e->getMessage()); } if ($result !== false) { return $this->success(__('Update successful')); } return $this->error(__('No rows updated')); } unset($row['salt'], $row['login_failure']); $row['password'] = ''; return $this->success('', [ 'row' => $row ]); } public function del(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; $where = []; $dataLimitAdminIds = $this->getDataLimitAdminIds(); if ($dataLimitAdminIds) { $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; } $ids = $request->get('ids') ?? $request->post('ids') ?? []; $ids = is_array($ids) ? $ids : []; $where[] = [$this->model->getPk(), 'in', $ids]; $data = $this->model->where($where)->select(); $count = 0; $this->model->startTrans(); try { foreach ($data as $v) { if ($v->id != $this->auth->id) { $count += $v->delete(); Db::name('admin_group_access') ->where('uid', $v['id']) ->delete(); } } $this->model->commit(); } catch (Throwable $e) { $this->model->rollback(); return $this->error($e->getMessage()); } if ($count) { return $this->success(__('Deleted successfully')); } return $this->error(__('No rows were deleted')); } /** * 远程下拉(Admin 无自定义,走父类默认列表) */ public function select(Request $request): Response { return parent::select($request); } private function checkGroupAuth(array $groups): ?Response { if ($this->auth->isSuperAdmin()) { return null; } $allowedGroupIds = array_values(array_unique(array_merge( Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'), $this->auth->getAdminChildGroups() ))); foreach ($groups as $group) { if (!in_array($group, $allowedGroupIds, false)) { return $this->error(__('You have no permission to add an administrator to this group!')); } } return null; } }