forked from wangziqi/gongxue-base
feat: integrate CampusScope.filter() into all business services (12 services + 12 modules)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { IsString, IsOptional, IsEnum } from 'class-validator';
|
||||
import { IsString, IsOptional, IsEnum, IsNumber } from 'class-validator';
|
||||
|
||||
export class CreateStudentDto {
|
||||
@IsString()
|
||||
@@ -32,6 +32,10 @@ export class CreateStudentDto {
|
||||
@IsString()
|
||||
organization?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
tenantId?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
supervisor?: string;
|
||||
@@ -70,6 +74,10 @@ export class UpdateStudentDto {
|
||||
@IsString()
|
||||
organization?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
tenantId?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
supervisor?: string;
|
||||
|
||||
@@ -12,7 +12,11 @@ import {
|
||||
Res,
|
||||
UseInterceptors,
|
||||
UploadedFile,
|
||||
Inject,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Tenant } from '../entities/tenant.entity';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import type { Response } from 'express';
|
||||
import { StudentsService } from './students.service';
|
||||
@@ -26,9 +30,11 @@ import * as ExcelJS from 'exceljs';
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('students')
|
||||
export class StudentsController {
|
||||
|
||||
constructor(
|
||||
private service: StudentsService,
|
||||
private logService: OperationLogsService,
|
||||
@InjectRepository(Tenant) private tenantRepo: Repository<Tenant>,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@@ -55,7 +61,7 @@ export class StudentsController {
|
||||
{ header: '民族', key: 'ethnicity', width: 10 },
|
||||
{ header: '紧急联系人', key: 'emergencyContact', width: 15 },
|
||||
{ header: '紧急联系人电话', key: 'emergencyPhone', width: 18 },
|
||||
{ header: '所属机构', key: 'organization', width: 18 },
|
||||
{ header: '所属机构', key: 'tenant', width: 18 },
|
||||
{ header: '负责人/班主任', key: 'supervisor', width: 15 },
|
||||
{ header: '状态', key: 'status', width: 10 },
|
||||
];
|
||||
@@ -76,7 +82,7 @@ export class StudentsController {
|
||||
ethnicity: s.ethnicity || '',
|
||||
emergencyContact: s.emergencyContact || '',
|
||||
emergencyPhone: s.emergencyPhone || '',
|
||||
organization: s.organization || '',
|
||||
tenant: s.tenant?.name || '',
|
||||
supervisor: s.supervisor || '',
|
||||
status: statusMap[s.status] || s.status,
|
||||
});
|
||||
@@ -113,7 +119,7 @@ export class StudentsController {
|
||||
{ header: '民族', key: 'ethnicity', width: 10 },
|
||||
{ header: '紧急联系人', key: 'emergencyContact', width: 15 },
|
||||
{ header: '紧急联系人电话', key: 'emergencyPhone', width: 18 },
|
||||
{ header: '所属机构', key: 'organization', width: 18 },
|
||||
{ header: '所属机构(租赁方名称)', key: 'tenant', width: 18 },
|
||||
{ header: '负责人/班主任', key: 'supervisor', width: 15 },
|
||||
];
|
||||
ws.getRow(1).font = { bold: true };
|
||||
@@ -126,7 +132,7 @@ export class StudentsController {
|
||||
ethnicity: '汉族',
|
||||
emergencyContact: '张父',
|
||||
emergencyPhone: '13900000000',
|
||||
organization: '',
|
||||
tenant: 'XX教育公司',
|
||||
supervisor: '',
|
||||
});
|
||||
res.setHeader(
|
||||
@@ -251,8 +257,9 @@ export class StudentsController {
|
||||
ethnicity?: string;
|
||||
emergencyContact?: string;
|
||||
emergencyPhone?: string;
|
||||
organization?: string;
|
||||
tenant?: string;
|
||||
supervisor?: string;
|
||||
tenantId?: number;
|
||||
}[] = [];
|
||||
ws.eachRow((row, idx) => {
|
||||
if (idx === 1) return;
|
||||
@@ -264,10 +271,19 @@ export class StudentsController {
|
||||
ethnicity: String(row.getCell(5).value || '').trim() || undefined,
|
||||
emergencyContact: String(row.getCell(6).value || '').trim() || undefined,
|
||||
emergencyPhone: String(row.getCell(7).value || '').trim() || undefined,
|
||||
organization: String(row.getCell(8).value || '').trim() || undefined,
|
||||
tenant: String(row.getCell(8).value || '').trim() || undefined,
|
||||
supervisor: String(row.getCell(9).value || '').trim() || undefined,
|
||||
});
|
||||
});
|
||||
// Resolve tenant names to IDs
|
||||
for (const row of rows) {
|
||||
if (row.tenant) {
|
||||
const tenant = await this.tenantRepo.findOne({ where: { name: row.tenant } });
|
||||
if (tenant) {
|
||||
row.tenantId = tenant.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
const result = await this.service.batchImport(rows);
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Student } from '../entities/student.entity';
|
||||
import { DepartmentsModule } from '../departments/departments.module';
|
||||
import { ClassStudent } from '../entities/class-student.entity';
|
||||
import { AttendanceRecord } from '../entities/attendance-record.entity';
|
||||
import { StudentsService } from './students.service';
|
||||
import { StudentsController } from './students.controller';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Student, ClassStudent, AttendanceRecord])],
|
||||
imports: [TypeOrmModule.forFeature([Student, ClassStudent, AttendanceRecord]), DepartmentsModule],
|
||||
controllers: [StudentsController],
|
||||
providers: [StudentsService],
|
||||
exports: [StudentsService],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, Like, Not, In } from 'typeorm';
|
||||
import { CampusScope } from '../common/campus-scope';
|
||||
import { Student } from '../entities/student.entity';
|
||||
import { ClassStudent } from '../entities/class-student.entity';
|
||||
import { AttendanceRecord } from '../entities/attendance-record.entity';
|
||||
@@ -13,6 +14,7 @@ export class StudentsService {
|
||||
@InjectRepository(Student) private repo: Repository<Student>,
|
||||
@InjectRepository(ClassStudent) private classStudentRepo: Repository<ClassStudent>,
|
||||
@InjectRepository(AttendanceRecord) private attendanceRepo: Repository<AttendanceRecord>,
|
||||
private readonly scope: CampusScope,
|
||||
) {}
|
||||
|
||||
async findAll(query?: { name?: string; status?: string; includeArchived?: boolean }) {
|
||||
@@ -23,7 +25,8 @@ export class StudentsService {
|
||||
} else if (!query?.includeArchived) {
|
||||
where.status = Not('archived');
|
||||
}
|
||||
return this.repo.find({ where, order: { createdAt: 'DESC' } });
|
||||
const filteredWhere = await this.scope.filter(where);
|
||||
return this.repo.find({ where: filteredWhere, order: { createdAt: 'DESC' }, relations: ['tenant'] });
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
@@ -101,6 +104,7 @@ export class StudentsService {
|
||||
emergencyPhone?: string;
|
||||
organization?: string;
|
||||
supervisor?: string;
|
||||
tenantId?: number;
|
||||
}[],
|
||||
) {
|
||||
let imported = 0;
|
||||
@@ -126,9 +130,9 @@ export class StudentsService {
|
||||
emergencyPhone: row.emergencyPhone || undefined,
|
||||
organization: row.organization || undefined,
|
||||
supervisor: row.supervisor || undefined,
|
||||
tenantId: row.tenantId || undefined,
|
||||
}),
|
||||
);
|
||||
imported++;
|
||||
}
|
||||
return {
|
||||
message: `成功导入 ${imported} 名学生,跳过 ${skipped} 条(重复或空行)`,
|
||||
|
||||
Reference in New Issue
Block a user