feat: improve attendance scheduling and API validation
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { IsIn, IsInt, IsString, IsNumber, IsOptional, Matches, Min } from 'class-validator';
|
||||
import { IsDateString, IsIn, IsInt, IsString, IsNumber, IsOptional, Matches, Min } from 'class-validator';
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class CreateRoomExpenseDto {
|
||||
@IsInt()
|
||||
@@ -7,13 +9,14 @@ export class CreateRoomExpenseDto {
|
||||
@IsString()
|
||||
expenseType: string;
|
||||
|
||||
@IsNumber()
|
||||
@IsNumber({ maxDecimalPlaces: 2 })
|
||||
@Min(0.01)
|
||||
amount: number;
|
||||
|
||||
@IsString()
|
||||
@IsDateString()
|
||||
periodStart: string;
|
||||
|
||||
@IsString()
|
||||
@IsDateString()
|
||||
periodEnd: string;
|
||||
|
||||
@IsOptional()
|
||||
@@ -32,10 +35,11 @@ export class CreatePersonalExpenseDto {
|
||||
@IsString()
|
||||
expenseType: string;
|
||||
|
||||
@IsNumber()
|
||||
@IsNumber({ maxDecimalPlaces: 2 })
|
||||
@Min(0.01)
|
||||
amount: number;
|
||||
|
||||
@IsString()
|
||||
@IsDateString()
|
||||
expenseDate: string;
|
||||
|
||||
@IsOptional()
|
||||
@@ -43,6 +47,33 @@ export class CreatePersonalExpenseDto {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
|
||||
export class UpdateRoomExpenseDto extends PartialType(CreateRoomExpenseDto) {}
|
||||
|
||||
export class UpdatePersonalExpenseDto extends PartialType(CreatePersonalExpenseDto) {}
|
||||
|
||||
export class QueryRoomExpenseDto {
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
roomId?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
periodStart?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
periodEnd?: string;
|
||||
}
|
||||
|
||||
export class QueryPersonalExpenseDto {
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
studentId?: number;
|
||||
}
|
||||
|
||||
export class BatchRoomExpenseDto {
|
||||
@IsString()
|
||||
periodStart: string;
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
Res,
|
||||
UseInterceptors,
|
||||
UploadedFile,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import type { Response } from 'express';
|
||||
@@ -21,6 +22,10 @@ import {
|
||||
CreatePersonalExpenseDto,
|
||||
BatchRoomExpenseDto,
|
||||
CreateStudentUtilityBillDto,
|
||||
QueryPersonalExpenseDto,
|
||||
QueryRoomExpenseDto,
|
||||
UpdatePersonalExpenseDto,
|
||||
UpdateRoomExpenseDto,
|
||||
} from './dto/expense.dto';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { OperationLogsService } from '../operation-logs/operation-logs.service';
|
||||
@@ -136,29 +141,21 @@ export class ExpensesController {
|
||||
|
||||
@Get('room')
|
||||
@RequirePermission('expense:view')
|
||||
findRoomExpenses(
|
||||
@Query('roomId') roomId?: string,
|
||||
@Query('periodStart') periodStart?: string,
|
||||
@Query('periodEnd') periodEnd?: string,
|
||||
) {
|
||||
return this.service.findRoomExpenses({
|
||||
roomId: roomId ? +roomId : undefined,
|
||||
periodStart,
|
||||
periodEnd,
|
||||
});
|
||||
findRoomExpenses(@Query() query: QueryRoomExpenseDto) {
|
||||
return this.service.findRoomExpenses(query);
|
||||
}
|
||||
|
||||
@Delete('room/:id')
|
||||
@RequirePermission('expense:delete')
|
||||
async deleteRoomExpense(@Param('id') id: string, @Request() req: any) {
|
||||
async deleteRoomExpense(@Param('id', ParseIntPipe) id: number, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.deleteRoomExpense(+id);
|
||||
const result = await this.service.deleteRoomExpense(id);
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用管理',
|
||||
action: '删除费用',
|
||||
targetId: +id,
|
||||
targetId: id,
|
||||
targetType: 'room_expense',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
@@ -186,18 +183,18 @@ export class ExpensesController {
|
||||
@Put('room/:id')
|
||||
@RequirePermission('expense:edit')
|
||||
async updateRoomExpense(
|
||||
@Param('id') id: string,
|
||||
@Body() dto: CreateRoomExpenseDto,
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: UpdateRoomExpenseDto,
|
||||
@Request() req: any,
|
||||
) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.updateRoomExpense(+id, dto);
|
||||
const result = await this.service.updateRoomExpense(id, dto);
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用管理',
|
||||
action: '编辑费用',
|
||||
targetId: +id,
|
||||
targetId: id,
|
||||
targetType: 'room_expense',
|
||||
detail: `¥${dto.amount} ${dto.expenseType}`,
|
||||
ipAddress,
|
||||
@@ -225,21 +222,21 @@ export class ExpensesController {
|
||||
|
||||
@Get('personal')
|
||||
@RequirePermission('expense:view')
|
||||
findPersonalExpenses(@Query('studentId') studentId?: string) {
|
||||
return this.service.findPersonalExpenses({ studentId: studentId ? +studentId : undefined });
|
||||
findPersonalExpenses(@Query() query: QueryPersonalExpenseDto) {
|
||||
return this.service.findPersonalExpenses(query);
|
||||
}
|
||||
|
||||
@Delete('personal/:id')
|
||||
@RequirePermission('expense:delete')
|
||||
async deletePersonalExpense(@Param('id') id: string, @Request() req: any) {
|
||||
async deletePersonalExpense(@Param('id', ParseIntPipe) id: number, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.deletePersonalExpense(+id);
|
||||
const result = await this.service.deletePersonalExpense(id);
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用管理',
|
||||
action: '删除费用',
|
||||
targetId: +id,
|
||||
targetId: id,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
@@ -266,18 +263,18 @@ export class ExpensesController {
|
||||
@Put('personal/:id')
|
||||
@RequirePermission('expense:edit')
|
||||
async updatePersonalExpense(
|
||||
@Param('id') id: string,
|
||||
@Body() dto: CreatePersonalExpenseDto,
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: UpdatePersonalExpenseDto,
|
||||
@Request() req: any,
|
||||
) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.updatePersonalExpense(+id, dto);
|
||||
const result = await this.service.updatePersonalExpense(id, dto);
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用管理',
|
||||
action: '编辑费用',
|
||||
targetId: +id,
|
||||
targetId: id,
|
||||
detail: `¥${dto.amount} ${dto.expenseType}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
|
||||
Reference in New Issue
Block a user