import { Injectable, NotFoundException } from '@nestjs/common'; import { Prisma } from '../generated/prisma/client.js'; import { Role } from '../generated/prisma/enums.js'; import type { ActorContext } from '../common/actor-context.js'; import { MESSAGES } from '../common/messages.js'; import { PrismaService } from '../prisma.service.js'; import { OrganizationAccessService } from '../organization-common/organization-access.service.js'; import { CreateHospitalDto } from './dto/create-hospital.dto.js'; import { UpdateHospitalDto } from './dto/update-hospital.dto.js'; import { OrganizationQueryDto } from '../organization-common/dto/organization-query.dto.js'; /** * 医院资源服务:聚焦医院实体的 CRUD 与院级权限约束。 */ @Injectable() export class HospitalsService { constructor( private readonly prisma: PrismaService, private readonly access: OrganizationAccessService, ) {} /** * 创建医院:仅系统管理员可调用。 */ async create(actor: ActorContext, dto: CreateHospitalDto) { this.access.assertSystemAdmin( actor, MESSAGES.ORG.SYSTEM_ADMIN_ONLY_CREATE_HOSPITAL, ); return this.prisma.hospital.create({ data: { name: this.access.normalizeName( dto.name, MESSAGES.ORG.HOSPITAL_NAME_REQUIRED, ), }, }); } /** * 查询医院列表:系统管理员可查全量;院管/主任/组长仅可查看本院。 */ async findAll(actor: ActorContext, query: OrganizationQueryDto) { this.access.assertRole(actor, [ Role.SYSTEM_ADMIN, Role.HOSPITAL_ADMIN, Role.DIRECTOR, Role.LEADER, ]); const paging = this.access.resolvePaging(query); const where: Prisma.HospitalWhereInput = {}; if (query.keyword) { where.name = { contains: query.keyword.trim(), mode: 'insensitive' }; } if (actor.role !== Role.SYSTEM_ADMIN) { where.id = this.access.requireActorHospitalId(actor); } const [total, list] = await this.prisma.$transaction([ this.prisma.hospital.count({ where }), this.prisma.hospital.findMany({ where, skip: paging.skip, take: paging.take, orderBy: { id: 'desc' }, }), ]); return { total, ...paging, list }; } /** * 查询医院详情:院管/主任/组长仅能查看本院。 */ async findOne(actor: ActorContext, id: number) { this.access.assertRole(actor, [ Role.SYSTEM_ADMIN, Role.HOSPITAL_ADMIN, Role.DIRECTOR, Role.LEADER, ]); const hospitalId = this.access.toInt(id, MESSAGES.ORG.HOSPITAL_ID_REQUIRED); const hospital = await this.prisma.hospital.findUnique({ where: { id: hospitalId }, include: { _count: { select: { departments: true, users: true, patients: true, tasks: true, }, }, }, }); if (!hospital) { throw new NotFoundException(MESSAGES.ORG.HOSPITAL_NOT_FOUND); } this.access.assertHospitalScope(actor, hospital.id); return hospital; } /** * 更新医院:院管仅能更新本院。 */ async update(actor: ActorContext, id: number, dto: UpdateHospitalDto) { const current = await this.findOne(actor, id); const data: Prisma.HospitalUpdateInput = {}; if (dto.name !== undefined) { data.name = this.access.normalizeName( dto.name, MESSAGES.ORG.HOSPITAL_NAME_REQUIRED, ); } return this.prisma.hospital.update({ where: { id: current.id }, data, }); } /** * 删除医院:仅系统管理员允许。 */ async remove(actor: ActorContext, id: number) { this.access.assertSystemAdmin( actor, MESSAGES.ORG.SYSTEM_ADMIN_ONLY_DELETE_HOSPITAL, ); const hospitalId = this.access.toInt(id, MESSAGES.ORG.HOSPITAL_ID_REQUIRED); await this.access.ensureHospitalExists(hospitalId); try { return await this.prisma.hospital.delete({ where: { id: hospitalId } }); } catch (error) { this.access.handleDeleteConflict(error); throw error; } } }