Files
gongxue-base/apps/server/src/organizations/organizations.service.ts

90 lines
2.9 KiB
TypeScript

import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Not, Repository } from 'typeorm';
import { uuidV7 } from '../common/uuid-v7';
import { Organization } from '../entities/organization.entity';
import { CreateOrganizationDto, UpdateOrganizationDto } from './dto/organization.dto';
const COLOR_PALETTE = [
'#ff7875',
'#ffa940',
'#ffc53d',
'#73d13d',
'#36cfc9',
'#40a9ff',
'#597ef7',
'#9254de',
'#f759ab',
'#8c8c8c',
];
@Injectable()
export class OrganizationsService {
constructor(@InjectRepository(Organization) private repo: Repository<Organization>) {}
async findAll(query?: { includeArchived?: boolean; scope?: 'all' | 'host' | 'external' }) {
const where: Record<string, unknown> = {};
if (!query?.includeArchived) where.status = Not('archived');
if (query?.scope === 'host') where.isHost = true;
if (query?.scope === 'external') where.isHost = false;
return this.repo.find({ where, order: { isHost: 'DESC', name: 'ASC' } });
}
async findOptions() {
return this.repo.find({
select: ['id', 'name', 'isHost'] as const,
where: { status: 'active' },
order: { isHost: 'DESC' as const, name: 'ASC' as const },
});
}
async findOne(id: number) {
const organization = await this.repo.findOne({ where: { id } });
if (!organization) throw new NotFoundException('机构不存在');
return organization;
}
async getHostOrganization() {
const organization = await this.repo.findOne({ where: { isHost: true, status: 'active' } });
if (!organization) throw new NotFoundException('尚未配置本机构');
return organization;
}
async create(dto: CreateOrganizationDto) {
if (dto.isHost) {
const existingHost = await this.repo.findOne({ where: { isHost: true } });
if (existingHost) throw new BadRequestException('本机构已存在,只能配置一个本机构');
}
const color = dto.color || COLOR_PALETTE[(await this.repo.count()) % COLOR_PALETTE.length];
return this.repo.save(
this.repo.create({
...dto,
code: dto.code.trim().toUpperCase(),
publicId: uuidV7(),
color,
isHost: dto.isHost ?? false,
status: 'active',
}),
);
}
async update(id: number, dto: UpdateOrganizationDto) {
const organization = await this.findOne(id);
if (organization.isHost && dto.status === 'archived') {
throw new BadRequestException('本机构不能归档');
}
await this.repo.update(id, {
...dto,
...(dto.code ? { code: dto.code.trim().toUpperCase() } : {}),
});
return this.repo.findOne({ where: { id } });
}
async remove(id: number) {
const organization = await this.findOne(id);
if (organization.isHost) throw new BadRequestException('本机构不能归档');
await this.repo.update(id, { status: 'archived' });
return { message: '已归档' };
}
}