isSuperAdmin(); } public function isGridMember(AdminUser $user): bool { if ($this->isSuperAdmin($user)) { return false; } return $user->roles()->where('code', 'grid_member')->exists(); } public function hasScope(AdminUser $user): bool { if ($this->isSuperAdmin($user)) { return false; } if (! $this->isGridMember($user)) { return false; } return $this->universityIds($user) !== [] || $this->researchDirectionNames($user) !== []; } /** * @return array */ public function universityIds(AdminUser $user): array { return $user->universities()->pluck('universities.id')->map(fn ($id) => (int) $id)->all(); } /** * @return array */ public function researchDirectionIds(AdminUser $user): array { return $user->researchDirections() ->where('research_directions.status', 1) ->pluck('research_directions.id') ->map(fn ($id) => (int) $id) ->all(); } /** * @return array */ public function researchDirectionNames(AdminUser $user): array { return $user->researchDirections() ->where('research_directions.status', 1) ->orderBy('research_directions.sort') ->pluck('research_directions.name') ->all(); } /** * @return array{university_ids: int[], research_direction_ids: int[], research_direction_names: string[]} */ public function scopePayload(AdminUser $user): array { return [ 'university_ids' => $this->universityIds($user), 'research_direction_ids' => $this->researchDirectionIds($user), 'research_direction_names' => $this->researchDirectionNames($user), ]; } public function applyTeacherScope(Builder $query, AdminUser $user): void { if (! $this->isGridMember($user)) { return; } $uniIds = $this->universityIds($user); $dirIds = $this->researchDirectionIds($user); if ($uniIds === [] || $dirIds === []) { $query->whereRaw('1 = 0'); return; } $query->whereIn('university_id', $uniIds) ->whereHas('researchDirections', fn ($q) => $q->whereIn('research_directions.id', $dirIds)); } public function assertTeacherAccessible(AdminUser $user, Teacher $teacher): void { if (! $this->isGridMember($user)) { return; } $uniIds = $this->universityIds($user); $dirIds = $this->researchDirectionIds($user); if ($uniIds === [] || $dirIds === []) { $this->deny(); } if (! in_array((int) $teacher->university_id, $uniIds, true)) { $this->deny(); } $teacher->loadMissing('researchDirections'); $overlap = $teacher->researchDirections->pluck('id')->intersect($dirIds); if ($overlap->isEmpty()) { $this->deny(); } } public function assertCanMutateTeachers(AdminUser $user): void { if ($this->isGridMember($user)) { $this->deny('网格员仅可编辑与跟进已配置范围内的老师'); } } /** * @param array $data */ public function assertTeacherDataInScope(AdminUser $user, array $data, ?Teacher $existing = null): void { if (! $this->isGridMember($user)) { return; } $uniIds = $this->universityIds($user); $dirIds = $this->researchDirectionIds($user); if (isset($data['university_id']) && ! in_array((int) $data['university_id'], $uniIds, true)) { $this->deny('所选高校不在您的负责范围内'); } if (isset($data['research_direction_ids'])) { foreach ($data['research_direction_ids'] as $dirId) { if (! in_array((int) $dirId, $dirIds, true)) { $this->deny('所选研究方向不在您的负责范围内'); } } } if ($existing) { $this->assertTeacherAccessible($user, $existing); } } public function userFromRequest(Request $request): AdminUser { /** @var AdminUser $user */ $user = $request->user(); return $user; } protected function deny(string $message = '无权访问该老师'): void { throw new HttpResponseException( response()->json([ 'message' => $message, 'data' => null, ], 403) ); } }