feat: improve attendance scheduling and API validation

This commit is contained in:
2026-07-14 23:12:14 +08:00
parent c75a08affe
commit e45da7f998
33 changed files with 869 additions and 297 deletions

View File

@@ -11,6 +11,7 @@ import {
Request,
Res,
Req,
ParseIntPipe,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, In } from 'typeorm';
@@ -75,38 +76,38 @@ export class BillsController {
findAll(
@Query('periodStart') periodStart?: string,
@Query('periodEnd') periodEnd?: string,
@Query('studentId') studentId?: string,
@Query('studentId', new ParseIntPipe({ optional: true })) studentId?: number,
@Query('status') status?: string,
@Query('expenseType') expenseType?: string,
) {
return this.service.findAll({
periodStart, periodEnd,
studentId: studentId ? +studentId : undefined,
studentId,
status, expenseType,
});
}
@Get(':id')
@RequirePermission('bill:view')
findOne(@Param('id') id: string) {
return this.service.findOne(+id);
findOne(@Param('id', ParseIntPipe) id: number) {
return this.service.findOne(id);
}
@Put(':id/status')
@RequirePermission('bill:confirm')
async updateStatus(
@Param('id') id: string,
@Param('id', ParseIntPipe) id: number,
@Body() dto: UpdateBillStatusDto,
@Request() req: any,
) {
const { ipAddress, userAgent } = extractRequestInfo(req);
const result = await this.service.updateStatus(+id, dto);
const result = await this.service.updateStatus(id, dto);
await this.logService.log({
userId: req.user?.id,
username: req.user?.username,
module: '账单管理',
action: '确认账单',
targetId: +id,
targetId: id,
targetType: 'bill',
ipAddress,
userAgent,
@@ -160,15 +161,15 @@ export class BillsController {
@Post(':id/cancel')
@RequirePermission('bill:delete')
async cancel(@Param('id') id: string, @Body() dto: CancelBillDto, @Request() req: any) {
const result = await this.service.cancel(+id, dto, req.user?.id);
async cancel(@Param('id', ParseIntPipe) id: number, @Body() dto: CancelBillDto, @Request() req: any) {
const result = await this.service.cancel(id, dto, req.user?.id);
const { ipAddress, userAgent } = extractRequestInfo(req);
await this.logService.log({
userId: req.user?.id,
username: req.user?.username,
module: '账单管理',
action: '取消账单并冲正',
targetId: +id,
targetId: id,
targetType: 'bill',
detail: dto.reason,
ipAddress,
@@ -179,15 +180,15 @@ export class BillsController {
@Delete(':id')
@RequirePermission('bill:delete')
async remove(@Param('id') id: string, @Request() req: any) {
async remove(@Param('id', ParseIntPipe) id: number, @Request() req: any) {
const { ipAddress, userAgent } = extractRequestInfo(req);
const result = await this.service.remove(+id);
const result = await this.service.remove(id);
await this.logService.log({
userId: req.user?.id,
username: req.user?.username,
module: '账单管理',
action: '删除账单',
targetId: +id,
targetId: id,
targetType: 'bill',
ipAddress,
userAgent,
@@ -217,7 +218,7 @@ export class BillsController {
async exportExcel(
@Query('periodStart') periodStart?: string,
@Query('periodEnd') periodEnd?: string,
@Query('studentId') studentId?: string,
@Query('studentId', new ParseIntPipe({ optional: true })) studentId?: number,
@Query('status') status?: string,
@Res() res?: Response,
@Req() req?: any,
@@ -236,7 +237,7 @@ export class BillsController {
{
periodStart,
periodEnd,
studentId: studentId ? +studentId : undefined,
studentId,
status,
},
res!,
@@ -245,18 +246,18 @@ export class BillsController {
@Get('export/pdf/:id')
@RequirePermission('bill:export-pdf')
async exportPdf(@Param('id') id: string, @Res() res: Response, @Req() req: any) {
async exportPdf(@Param('id', ParseIntPipe) id: number, @Res() res: Response, @Req() req: any) {
const { ipAddress, userAgent } = extractRequestInfo(req);
await this.logService.log({
userId: req?.user?.id,
username: req?.user?.username,
module: '账单管理',
action: '导出账单',
targetId: +id,
targetId: id,
targetType: 'bill',
ipAddress,
userAgent,
});
return this.exportService.exportStudentPdf(+id, res);
return this.exportService.exportStudentPdf(id, res);
}
}

View File

@@ -9,6 +9,7 @@ import { PersonalExpense } from '../entities/personal-expense.entity';
import { Occupancy } from '../entities/occupancy.entity';
import { Room } from '../entities/room.entity';
import { Student } from '../entities/student.entity';
import { Deposit } from '../entities/deposit.entity';
import { BillsService } from './bills.service';
import { BillsExportService } from './bills-export.service';
import { BillsController } from './bills.controller';
@@ -23,6 +24,7 @@ import { BillsController } from './bills.controller';
Occupancy,
Room,
Student,
Deposit,
]),
NotificationsModule,
WalletsModule,