diff --git a/backend/src/bills/bills.controller.ts b/backend/src/bills/bills.controller.ts index 8782343..42920b5 100644 --- a/backend/src/bills/bills.controller.ts +++ b/backend/src/bills/bills.controller.ts @@ -5,6 +5,7 @@ import { GenerateBillsDto, UpdateBillStatusDto } from './dto/bill.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; import type { Response } from 'express'; @UseGuards(JwtAuthGuard) @@ -13,6 +14,7 @@ export class BillsController { constructor(private service: BillsService, private exportService: BillsExportService, private logService: OperationLogsService) {} @Post('generate') + @RequirePermission('bill:generate') async generateBills(@Body() dto: GenerateBillsDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.generateBills(dto); @@ -21,6 +23,7 @@ export class BillsController { } @Get() + @RequirePermission('bill:view') findAll( @Query('periodStart') periodStart?: string, @Query('periodEnd') periodEnd?: string, @@ -35,11 +38,13 @@ export class BillsController { } @Get(':id') + @RequirePermission('bill:view') findOne(@Param('id') id: string) { return this.service.findOne(+id); } @Put(':id/status') + @RequirePermission('bill:confirm') async updateStatus(@Param('id') id: string, @Body() dto: UpdateBillStatusDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.updateStatus(+id, dto); @@ -48,6 +53,7 @@ export class BillsController { } @Put('batch/status') + @RequirePermission('bill:confirm') async batchUpdateStatus(@Body() body: { ids: number[]; status: string }, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchUpdateStatus(body.ids, body.status); @@ -56,6 +62,7 @@ export class BillsController { } @Delete(':id') + @RequirePermission('bill:delete') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id); @@ -64,6 +71,7 @@ export class BillsController { } @Post('batch/delete') + @RequirePermission('bill:delete') async batchRemove(@Body() body: { ids: number[] }, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchRemove(body.ids); @@ -72,6 +80,7 @@ export class BillsController { } @Get('export/excel') + @RequirePermission('bill:export-excel') async exportExcel( @Query('periodStart') periodStart?: string, @Query('periodEnd') periodEnd?: string, @@ -90,6 +99,7 @@ export class BillsController { } @Get('export/pdf/:id') + @RequirePermission('bill:export-pdf') async exportPdf(@Param('id') id: string, @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: '导出PDF', targetId: +id, targetType: 'bill', ipAddress, userAgent }); diff --git a/backend/src/classroom-rentals/classroom-rentals.controller.ts b/backend/src/classroom-rentals/classroom-rentals.controller.ts index 6fe3a8d..5628359 100644 --- a/backend/src/classroom-rentals/classroom-rentals.controller.ts +++ b/backend/src/classroom-rentals/classroom-rentals.controller.ts @@ -7,6 +7,7 @@ import { CreateRentalDto, UpdateRentalDto } from './dto/rental.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; @UseGuards(JwtAuthGuard) @Controller('classroom-rentals') @@ -14,6 +15,7 @@ export class ClassroomRentalsController { constructor(private service: ClassroomRentalsService, private logService: OperationLogsService) {} @Get() + @RequirePermission('rental:view') findAll( @Query('classroomId') classroomId?: string, @Query('tenantId') tenantId?: string, @@ -29,6 +31,7 @@ export class ClassroomRentalsController { } @Get('schedule') + @RequirePermission('rental:view') getSchedule(@Query('year') year?: string, @Query('month') month?: string) { const now = new Date(); const y = year ? +year : now.getFullYear(); @@ -38,11 +41,13 @@ export class ClassroomRentalsController { } @Get(':id') + @RequirePermission('rental:view') findOne(@Param('id') id: string) { return this.service.findOne(+id); } @Post() + @RequirePermission('rental:create') async create(@Body() dto: CreateRentalDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.create(dto, req.user?.id); @@ -56,6 +61,7 @@ export class ClassroomRentalsController { } @Put(':id') + @RequirePermission('rental:edit') async update(@Param('id') id: string, @Body() dto: UpdateRentalDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.update(+id, dto); @@ -68,6 +74,7 @@ export class ClassroomRentalsController { } @Delete(':id') + @RequirePermission('rental:delete') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id); @@ -81,6 +88,7 @@ export class ClassroomRentalsController { // 合同上传:multer 限制 10MB + 仅 PDF @Post(':id/contract') + @RequirePermission('rental:edit') @UseInterceptors(FileInterceptor('file', { limits: { fileSize: 10 * 1024 * 1024 }, fileFilter: (_req, file, cb) => { @@ -103,6 +111,7 @@ export class ClassroomRentalsController { } @Get(':id/contract') + @RequirePermission('rental:view') async downloadContract(@Param('id') id: string, @Res() res: Response) { const { fullPath, originalName } = await this.service.getContractPath(+id); res.setHeader('Content-Type', 'application/pdf'); @@ -112,6 +121,7 @@ export class ClassroomRentalsController { } @Delete(':id/contract') + @RequirePermission('rental:edit') async deleteContract(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.removeContract(+id); diff --git a/backend/src/classrooms/classrooms.controller.ts b/backend/src/classrooms/classrooms.controller.ts index 028a161..ebd43c0 100644 --- a/backend/src/classrooms/classrooms.controller.ts +++ b/backend/src/classrooms/classrooms.controller.ts @@ -6,6 +6,7 @@ import { CreateClassroomDto, UpdateClassroomDto } from './dto/classroom.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; import * as ExcelJS from 'exceljs'; @UseGuards(JwtAuthGuard) @@ -14,6 +15,7 @@ export class ClassroomsController { constructor(private service: ClassroomsService, private logService: OperationLogsService) {} @Get() + @RequirePermission('classroom:view') findAll(@Query('building') building?: string, @Query('roomType') roomType?: string, @Query('includeArchived') includeArchived?: string) { return this.service.findAll({ building, @@ -23,6 +25,7 @@ export class ClassroomsController { } @Get('template') + @RequirePermission('classroom:view') async downloadTemplate(@Res() res: Response) { const workbook = new ExcelJS.Workbook(); const ws = workbook.addWorksheet('教室导入模板'); @@ -60,11 +63,13 @@ export class ClassroomsController { } @Get(':id') + @RequirePermission('classroom:view') findOne(@Param('id') id: string) { return this.service.findOne(+id); } @Post() + @RequirePermission('classroom:create') async create(@Body() dto: CreateClassroomDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.create(dto); @@ -73,6 +78,7 @@ export class ClassroomsController { } @Put(':id') + @RequirePermission('classroom:edit') async update(@Param('id') id: string, @Body() dto: UpdateClassroomDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.update(+id, dto); @@ -81,6 +87,7 @@ export class ClassroomsController { } @Delete(':id') + @RequirePermission('classroom:delete') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id); @@ -89,6 +96,7 @@ export class ClassroomsController { } @Put(':id/restore') + @RequirePermission('classroom:edit') async restore(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.restore(+id); @@ -97,6 +105,7 @@ export class ClassroomsController { } @Post('import') + @RequirePermission('classroom:create') @UseInterceptors(FileInterceptor('file')) async importExcel(@UploadedFile() file: Express.Multer.File, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); diff --git a/backend/src/dashboard/dashboard.controller.ts b/backend/src/dashboard/dashboard.controller.ts index 5064432..ec6fd0b 100644 --- a/backend/src/dashboard/dashboard.controller.ts +++ b/backend/src/dashboard/dashboard.controller.ts @@ -1,8 +1,10 @@ import { Controller, Get, Query, UseGuards } from '@nestjs/common'; import { DashboardService } from './dashboard.service'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; @UseGuards(JwtAuthGuard) +@RequirePermission('dashboard:view') @Controller('dashboard') export class DashboardController { constructor(private service: DashboardService) {} diff --git a/backend/src/deposits/deposits.controller.ts b/backend/src/deposits/deposits.controller.ts index 5361b57..c5ddbd0 100644 --- a/backend/src/deposits/deposits.controller.ts +++ b/backend/src/deposits/deposits.controller.ts @@ -4,6 +4,7 @@ import { CreateDepositDto, RefundDepositDto } from './dto/deposit.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; @UseGuards(JwtAuthGuard) @Controller('deposits') @@ -11,6 +12,7 @@ export class DepositsController { constructor(private service: DepositsService, private logService: OperationLogsService) {} @Get() + @RequirePermission('deposit:view') findAll(@Query('studentId') studentId?: string, @Query('status') status?: string) { return this.service.findAll({ studentId: studentId ? +studentId : undefined, @@ -19,11 +21,13 @@ export class DepositsController { } @Get('stats') + @RequirePermission('deposit:view') getStats() { return this.service.getStats(); } @Post() + @RequirePermission('deposit:create') async create(@Body() dto: CreateDepositDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.create(dto, req.user?.id); @@ -32,6 +36,7 @@ export class DepositsController { } @Put(':id/refund') + @RequirePermission('deposit:edit') async refund(@Param('id') id: string, @Body() dto: RefundDepositDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.refund(+id, dto, req.user?.id); @@ -40,6 +45,7 @@ export class DepositsController { } @Delete(':id') + @RequirePermission('deposit:delete') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id); diff --git a/backend/src/expenses/expenses.controller.ts b/backend/src/expenses/expenses.controller.ts index d354255..b8c4ae8 100644 --- a/backend/src/expenses/expenses.controller.ts +++ b/backend/src/expenses/expenses.controller.ts @@ -6,6 +6,7 @@ import { CreateRoomExpenseDto, CreatePersonalExpenseDto, BatchRoomExpenseDto } f import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; import * as ExcelJS from 'exceljs'; /** 提取 ExcelJS 单元格的真实值,兼容公式、富文本、日期、超链接等情况 */ @@ -51,6 +52,7 @@ export class ExpensesController { constructor(private service: ExpensesService, private logService: OperationLogsService) {} @Post('room') + @RequirePermission('expense:create') async createRoomExpense(@Body() dto: CreateRoomExpenseDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.createRoomExpense(dto, req.user?.id); @@ -59,6 +61,7 @@ export class ExpensesController { } @Post('room/batch') + @RequirePermission('expense:create') async batchCreateRoomExpenses(@Body() dto: BatchRoomExpenseDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchCreateRoomExpenses(dto, req.user?.id); @@ -67,6 +70,7 @@ export class ExpensesController { } @Get('room') + @RequirePermission('expense:view') findRoomExpenses( @Query('roomId') roomId?: string, @Query('periodStart') periodStart?: string, @@ -79,6 +83,7 @@ export class ExpensesController { } @Delete('room/:id') + @RequirePermission('expense:delete') async deleteRoomExpense(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.deleteRoomExpense(+id); @@ -87,6 +92,7 @@ export class ExpensesController { } @Post('room/batch-delete') + @RequirePermission('expense:delete') async batchDeleteRoomExpenses(@Body() body: { ids: number[] }, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchDeleteRoomExpenses(body.ids || []); @@ -95,6 +101,7 @@ export class ExpensesController { } @Put('room/:id') + @RequirePermission('expense:edit') async updateRoomExpense(@Param('id') id: string, @Body() dto: CreateRoomExpenseDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.updateRoomExpense(+id, dto); @@ -103,6 +110,7 @@ export class ExpensesController { } @Post('personal') + @RequirePermission('expense:create') async createPersonalExpense(@Body() dto: CreatePersonalExpenseDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.createPersonalExpense(dto, req.user?.id); @@ -111,11 +119,13 @@ export class ExpensesController { } @Get('personal') + @RequirePermission('expense:view') findPersonalExpenses(@Query('studentId') studentId?: string) { return this.service.findPersonalExpenses({ studentId: studentId ? +studentId : undefined }); } @Delete('personal/:id') + @RequirePermission('expense:delete') async deletePersonalExpense(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.deletePersonalExpense(+id); @@ -124,6 +134,7 @@ export class ExpensesController { } @Post('personal/batch-delete') + @RequirePermission('expense:delete') async batchDeletePersonalExpenses(@Body() body: { ids: number[] }, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchDeletePersonalExpenses(body.ids || []); @@ -132,6 +143,7 @@ export class ExpensesController { } @Put('personal/:id') + @RequirePermission('expense:edit') async updatePersonalExpense(@Param('id') id: string, @Body() dto: CreatePersonalExpenseDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.updatePersonalExpense(+id, dto); @@ -140,6 +152,7 @@ export class ExpensesController { } @Get('utility/template') + @RequirePermission('expense:view') async downloadUtilityTemplate(@Res() res: Response) { const workbook = new ExcelJS.Workbook(); const ws = workbook.addWorksheet('水电费导入模板'); @@ -163,6 +176,7 @@ export class ExpensesController { } @Post('utility/import') + @RequirePermission('expense:create') @UseInterceptors(FileInterceptor('file')) async importUtilityExpenses(@UploadedFile() file: Express.Multer.File, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); @@ -190,6 +204,7 @@ export class ExpensesController { } @Get('personal/template') + @RequirePermission('expense:view') async downloadPersonalTemplate(@Res() res: Response) { const workbook = new ExcelJS.Workbook(); const ws = workbook.addWorksheet('个人附加费导入模板'); @@ -214,6 +229,7 @@ export class ExpensesController { } @Post('personal/import') + @RequirePermission('expense:create') @UseInterceptors(FileInterceptor('file')) async importPersonalExpenses(@UploadedFile() file: Express.Multer.File, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); @@ -239,6 +255,7 @@ export class ExpensesController { } @Get('personal/export') + @RequirePermission('expense:view') async exportPersonalExpenses(@Res() res: Response) { const data = await this.service.findPersonalExpenses(); const typeMap: Record = { damage: '物品损坏', cleaning: '保洁费', penalty: '罚款', key: '钥匙费', remote: '空调遥控器', deposit_deduction: '押金扣除', other: '其他' }; diff --git a/backend/src/occupancies/occupancies.controller.ts b/backend/src/occupancies/occupancies.controller.ts index 08374f6..7c82500 100644 --- a/backend/src/occupancies/occupancies.controller.ts +++ b/backend/src/occupancies/occupancies.controller.ts @@ -6,6 +6,7 @@ import { CheckInDto, CheckOutDto, TransferRoomDto, BatchCheckOutDto } from './dt import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; import * as ExcelJS from 'exceljs'; @UseGuards(JwtAuthGuard) @@ -14,6 +15,7 @@ export class OccupanciesController { constructor(private service: OccupanciesService, private logService: OperationLogsService) {} @Get() + @RequirePermission('occupancy:view') findAll( @Query('roomId') roomId?: string, @Query('studentId') studentId?: string, @@ -27,6 +29,7 @@ export class OccupanciesController { } @Post('batch-check-out') + @RequirePermission('occupancy:checkout') async batchCheckOut(@Body() dto: BatchCheckOutDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchCheckOut(dto); @@ -35,6 +38,7 @@ export class OccupanciesController { } @Post('check-in') + @RequirePermission('occupancy:checkin') async checkIn(@Body() dto: CheckInDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.checkIn(dto); @@ -43,6 +47,7 @@ export class OccupanciesController { } @Put(':id/check-out') + @RequirePermission('occupancy:checkout') async checkOut(@Param('id') id: string, @Body() dto: CheckOutDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.checkOut(+id, dto); @@ -51,6 +56,7 @@ export class OccupanciesController { } @Put(':id/transfer') + @RequirePermission('occupancy:transfer') async transferRoom(@Param('id') id: string, @Body() dto: TransferRoomDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.transferRoom(+id, dto); @@ -59,6 +65,7 @@ export class OccupanciesController { } @Delete(':id') + @RequirePermission('occupancy:view') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id); @@ -67,6 +74,7 @@ export class OccupanciesController { } @Post('batch-delete') + @RequirePermission('occupancy:view') async batchRemove(@Body() body: { ids: number[] }, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchRemove(body.ids || []); @@ -75,6 +83,7 @@ export class OccupanciesController { } @Get('export') + @RequirePermission('occupancy:view') async exportExcel(@Query('active') active?: string, @Res() res?: Response) { const records = await this.service.findAll({ active: active === 'true' }); const workbook = new ExcelJS.Workbook(); @@ -120,6 +129,7 @@ export class OccupanciesController { } @Get('template') + @RequirePermission('occupancy:view') async downloadTemplate(@Res() res: Response) { const workbook = new ExcelJS.Workbook(); const ws = workbook.addWorksheet('入住名单导入模板'); @@ -163,6 +173,7 @@ export class OccupanciesController { } @Post('import') + @RequirePermission('occupancy:checkin') @UseInterceptors(FileInterceptor('file')) async importCheckIn(@UploadedFile() file: Express.Multer.File, @Request() req: any, @Query('autoDeposit') autoDeposit?: string, @Query('depositAmount') depositAmount?: string) { const { ipAddress, userAgent } = extractRequestInfo(req); diff --git a/backend/src/operation-logs/operation-logs.controller.ts b/backend/src/operation-logs/operation-logs.controller.ts index cd89d9e..770408c 100644 --- a/backend/src/operation-logs/operation-logs.controller.ts +++ b/backend/src/operation-logs/operation-logs.controller.ts @@ -1,8 +1,10 @@ import { Controller, Get, Query, UseGuards } from '@nestjs/common'; import { OperationLogsService } from './operation-logs.service'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; @UseGuards(JwtAuthGuard) +@RequirePermission('log:view') @Controller('operation-logs') export class OperationLogsController { constructor(private service: OperationLogsService) {} diff --git a/backend/src/rooms/rooms.controller.ts b/backend/src/rooms/rooms.controller.ts index f59bf00..d2e19d8 100644 --- a/backend/src/rooms/rooms.controller.ts +++ b/backend/src/rooms/rooms.controller.ts @@ -6,6 +6,7 @@ import { CreateRoomDto, UpdateRoomDto } from './dto/room.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; import * as ExcelJS from 'exceljs'; @UseGuards(JwtAuthGuard) @@ -14,21 +15,25 @@ export class RoomsController { constructor(private service: RoomsService, private logService: OperationLogsService) {} @Get() + @RequirePermission('room:view') findAll(@Query('building') building?: string, @Query('includeArchived') includeArchived?: string) { return this.service.findAll({ building, includeArchived: includeArchived === 'true' }); } @Get('overview') + @RequirePermission('room:view') getOverview(@Query('includeArchived') includeArchived?: string) { return this.service.getRoomOverview({ includeArchived: includeArchived === 'true' }); } @Get('visual') + @RequirePermission('room:view') getVisual() { return this.service.getRoomVisual(); } @Get('template') + @RequirePermission('room:view') async downloadTemplate(@Res() res: Response) { const workbook = new ExcelJS.Workbook(); const ws = workbook.addWorksheet('宿舍导入模板'); @@ -50,6 +55,7 @@ export class RoomsController { } @Get('export') + @RequirePermission('room:view') async exportExcel(@Query('includeArchived') includeArchived?: string, @Res() res?: Response) { const rooms = await this.service.getRoomOverview({ includeArchived: includeArchived === 'true' }); const workbook = new ExcelJS.Workbook(); @@ -77,11 +83,13 @@ export class RoomsController { } @Get(':id') + @RequirePermission('room:view') findOne(@Param('id') id: string) { return this.service.findOneWithOccupants(+id); } @Post() + @RequirePermission('room:create') async create(@Body() dto: CreateRoomDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.create(dto); @@ -90,6 +98,7 @@ export class RoomsController { } @Put(':id') + @RequirePermission('room:edit') async update(@Param('id') id: string, @Body() dto: UpdateRoomDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.update(+id, dto); @@ -98,6 +107,7 @@ export class RoomsController { } @Delete(':id') + @RequirePermission('room:delete') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id); @@ -106,6 +116,7 @@ export class RoomsController { } @Post('batch-delete') + @RequirePermission('room:delete') async batchRemove(@Body() body: { ids: number[] }, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchRemove(body.ids || []); @@ -114,6 +125,7 @@ export class RoomsController { } @Put(':id/restore') + @RequirePermission('room:edit') async restore(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.restore(+id); @@ -122,6 +134,7 @@ export class RoomsController { } @Post('import') + @RequirePermission('room:create') @UseInterceptors(FileInterceptor('file')) async importExcel(@UploadedFile() file: Express.Multer.File, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); diff --git a/backend/src/students/students.controller.ts b/backend/src/students/students.controller.ts index 4605d0b..93ba85c 100644 --- a/backend/src/students/students.controller.ts +++ b/backend/src/students/students.controller.ts @@ -6,6 +6,7 @@ import { CreateStudentDto, UpdateStudentDto } from './dto/student.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; import * as ExcelJS from 'exceljs'; @UseGuards(JwtAuthGuard) @@ -14,11 +15,13 @@ export class StudentsController { constructor(private service: StudentsService, private logService: OperationLogsService) {} @Get() + @RequirePermission('student:view') findAll(@Query('name') name?: string, @Query('status') status?: string, @Query('includeArchived') includeArchived?: string) { return this.service.findAll({ name, status, includeArchived: includeArchived === 'true' }); } @Get('export') + @RequirePermission('student:export') async exportExcel(@Query('includeArchived') includeArchived?: string, @Res() res?: Response) { const students = await this.service.findAll({ includeArchived: includeArchived === 'true' }); const workbook = new ExcelJS.Workbook(); @@ -48,6 +51,7 @@ export class StudentsController { } @Get('template') + @RequirePermission('student:view') async downloadTemplate(@Res() res: Response) { const workbook = new ExcelJS.Workbook(); const ws = workbook.addWorksheet('学生导入模板'); @@ -72,11 +76,13 @@ export class StudentsController { } @Get(':id') + @RequirePermission('student:view') findOne(@Param('id') id: string) { return this.service.findOne(+id); } @Post() + @RequirePermission('student:create') async create(@Body() dto: CreateStudentDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.create(dto); @@ -85,6 +91,7 @@ export class StudentsController { } @Put(':id') + @RequirePermission('student:edit') async update(@Param('id') id: string, @Body() dto: UpdateStudentDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.update(+id, dto); @@ -93,6 +100,7 @@ export class StudentsController { } @Delete(':id') + @RequirePermission('student:delete') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id); @@ -101,6 +109,7 @@ export class StudentsController { } @Post('batch-delete') + @RequirePermission('student:delete') async batchRemove(@Body() body: { ids: number[] }, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.batchRemove(body.ids || []); @@ -109,6 +118,7 @@ export class StudentsController { } @Put(':id/restore') + @RequirePermission('student:edit') async restore(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.restore(+id); @@ -117,6 +127,7 @@ export class StudentsController { } @Post('import') + @RequirePermission('student:import') @UseInterceptors(FileInterceptor('file')) async importExcel(@UploadedFile() file: Express.Multer.File, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); diff --git a/backend/src/tenants/tenants.controller.ts b/backend/src/tenants/tenants.controller.ts index 74bfbda..774b186 100644 --- a/backend/src/tenants/tenants.controller.ts +++ b/backend/src/tenants/tenants.controller.ts @@ -4,6 +4,7 @@ import { CreateTenantDto, UpdateTenantDto } from './dto/tenant.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; +import { RequirePermission } from '../auth/decorators/permission.decorator'; @UseGuards(JwtAuthGuard) @Controller('tenants') @@ -11,16 +12,19 @@ export class TenantsController { constructor(private service: TenantsService, private logService: OperationLogsService) {} @Get() + @RequirePermission('tenant:view') findAll(@Query('includeArchived') includeArchived?: string) { return this.service.findAll({ includeArchived: includeArchived === 'true' }); } @Get(':id') + @RequirePermission('tenant:view') findOne(@Param('id') id: string) { return this.service.findOne(+id); } @Post() + @RequirePermission('tenant:create') async create(@Body() dto: CreateTenantDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.create(dto); @@ -29,6 +33,7 @@ export class TenantsController { } @Put(':id') + @RequirePermission('tenant:edit') async update(@Param('id') id: string, @Body() dto: UpdateTenantDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.update(+id, dto); @@ -37,6 +42,7 @@ export class TenantsController { } @Delete(':id') + @RequirePermission('tenant:delete') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id);