model = new AdminModel(); return null; } 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(); $res = $this->model ->withoutField('login_failure,password,salt') ->withJoin($this->withJoinTable ?? [], $this->withJoinType ?? 'LEFT') ->alias($alias) ->where($where) ->order($order) ->paginate($limit); return $this->success('', [ 'list' => $res->items(), 'total' => $res->total(), 'remark' => get_route_remark(), ]); } 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 ($result !== false) { $agentId = strtolower(md5($this->model->username . $this->model->id)); $agentSecret = strtoupper(md5($this->model->username . $this->model->id)); // 使用原生 SQL,避免 ThinkORM 按当前表结构校验字段时因未迁移缺少 agent_api_secret 列而报错 Db::execute( 'UPDATE `admin` SET `agent_id` = ?, `agent_api_secret` = ? WHERE `id` = ?', [$agentId, $agentSecret, $this->model->id] ); } 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')); } /** * 远程下拉(返回管理员列表供 remoteSelect 使用) */ public function select(Request $request): Response { $response = $this->initializeBackend($request); if ($response !== null) { return $response; } list($where, $alias, $limit, $order) = $this->queryBuilder(); $res = $this->model ->withoutField('login_failure,password,salt') ->withJoin($this->withJoinTable ?? [], $this->withJoinType ?? 'LEFT') ->alias($alias) ->where($where) ->order($order) ->paginate($limit); return $this->success('', [ 'list' => $res->items(), 'total' => $res->total(), ]); } /** * 去掉已废弃的渠道字段,避免组合搜索生成对不存在列的条件 */ protected function filterSearchArray(array $search): array { return array_values(array_filter($search, static function ($item) { if (!is_array($item) || !isset($item['field'])) { return true; } $f = (string) $item['field']; if ($f === 'channel_id' || str_ends_with($f, '.channel_id')) { return false; } if ($f === 'channel.name' || str_starts_with($f, 'channel.')) { return false; } return true; })); } public function queryOrderBuilder(): array { $order = parent::queryOrderBuilder(); foreach (array_keys($order) as $key) { if ($key === 'channel_id' || (is_string($key) && str_contains($key, 'channel.'))) { unset($order[$key]); } } return $order; } private function checkGroupAuth(array $groups): ?Response { if ($this->auth->isSuperAdmin()) { return null; } $authGroups = $this->auth->getAllAuthGroups('allAuthAndOthers'); foreach ($groups as $group) { if (!in_array($group, $authGroups)) { return $this->error(__('You have no permission to add an administrator to this group!')); } } return null; } }