feat: 恭学教育基地管理系统初始提交

- 后端: NestJS 11 + TypeORM + JWT认证 + SQLite/MySQL
- 前端: React 19 + Ant Design 6 + Vite 8 + ECharts
- 功能模块: 数据面板、学生管理、宿舍管理、入住管理、费用录入、账单管理、教室管理、押金管理、操作日志、账号管理
- 支持Docker一键部署
This commit is contained in:
陈浩
2026-06-06 17:26:10 +08:00
commit 78676a124a
123 changed files with 26403 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
import { Controller, Get, Query, UseGuards } from '@nestjs/common';
import { OperationLogsService } from './operation-logs.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
@UseGuards(JwtAuthGuard)
@Controller('operation-logs')
export class OperationLogsController {
constructor(private service: OperationLogsService) {}
@Get()
findAll(
@Query('module') module?: string,
@Query('userId') userId?: string,
@Query('startDate') startDate?: string,
@Query('endDate') endDate?: string,
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
) {
return this.service.findAll({
module,
userId: userId ? +userId : undefined,
startDate,
endDate,
page: page ? +page : 1,
pageSize: pageSize ? +pageSize : 50,
});
}
}

View File

@@ -0,0 +1,14 @@
import { Module, Global } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { OperationLog } from '../entities/operation-log.entity';
import { OperationLogsService } from './operation-logs.service';
import { OperationLogsController } from './operation-logs.controller';
@Global()
@Module({
imports: [TypeOrmModule.forFeature([OperationLog])],
controllers: [OperationLogsController],
providers: [OperationLogsService],
exports: [OperationLogsService],
})
export class OperationLogsModule {}

View File

@@ -0,0 +1,48 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { OperationLog } from '../entities/operation-log.entity';
@Injectable()
export class OperationLogsService {
constructor(
@InjectRepository(OperationLog) private repo: Repository<OperationLog>,
) {}
async log(params: {
userId?: number;
username?: string;
module: string;
action: string;
targetId?: number;
targetType?: string;
detail?: string;
ipAddress?: string;
userAgent?: string;
status?: string;
}) {
const entry = this.repo.create(params);
return this.repo.save(entry);
}
async findAll(query?: {
module?: string;
userId?: number;
startDate?: string;
endDate?: string;
page?: number;
pageSize?: number;
}) {
const qb = this.repo.createQueryBuilder('log')
.orderBy('log.createdAt', 'DESC');
if (query?.module) qb.andWhere('log.module = :module', { module: query.module });
if (query?.userId) qb.andWhere('log.userId = :userId', { userId: query.userId });
if (query?.startDate) qb.andWhere('log.createdAt >= :startDate', { startDate: query.startDate });
if (query?.endDate) qb.andWhere('log.createdAt <= :endDate', { endDate: query.endDate + ' 23:59:59' });
const page = query?.page || 1;
const pageSize = query?.pageSize || 50;
const [data, total] = await qb.skip((page - 1) * pageSize).take(pageSize).getManyAndCount();
return { data, total, page, pageSize };
}
}