chore: commit oxfmt formatting changes and verify artifacts
This commit is contained in:
@@ -1,8 +1,26 @@
|
||||
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, Request, Res, UseInterceptors, UploadedFile } from '@nestjs/common';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Request,
|
||||
Res,
|
||||
UseInterceptors,
|
||||
UploadedFile,
|
||||
} from '@nestjs/common';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import type { Response } from 'express';
|
||||
import { ExpensesService } from './expenses.service';
|
||||
import { CreateRoomExpenseDto, CreatePersonalExpenseDto, BatchRoomExpenseDto } from './dto/expense.dto';
|
||||
import {
|
||||
CreateRoomExpenseDto,
|
||||
CreatePersonalExpenseDto,
|
||||
BatchRoomExpenseDto,
|
||||
} from './dto/expense.dto';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { OperationLogsService } from '../operation-logs/operation-logs.service';
|
||||
import { extractRequestInfo } from '../common/request-utils';
|
||||
@@ -15,13 +33,13 @@ function readCell(cell: ExcelJS.Cell): any {
|
||||
if (v == null) return '';
|
||||
if (typeof v === 'object') {
|
||||
// 公式单元格:{ formula, result }
|
||||
if ('result' in v) v = (v as any).result;
|
||||
if ('result' in v) v = v.result;
|
||||
// 富文本:{ richText: [...] }
|
||||
else if ('richText' in v && Array.isArray((v as any).richText)) {
|
||||
return (v as any).richText.map((r: any) => r.text || '').join('');
|
||||
else if ('richText' in v && Array.isArray(v.richText)) {
|
||||
return v.richText.map((r: any) => r.text || '').join('');
|
||||
}
|
||||
// 超链接:{ text, hyperlink }
|
||||
else if ('text' in v) v = (v as any).text;
|
||||
else if ('text' in v) v = v.text;
|
||||
// 错误值:{ error: '#DIV/0!' }
|
||||
else if ('error' in v) return '';
|
||||
}
|
||||
@@ -49,14 +67,27 @@ function readCellStr(cell: ExcelJS.Cell): string {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('expenses')
|
||||
export class ExpensesController {
|
||||
constructor(private service: ExpensesService, private logService: OperationLogsService) {}
|
||||
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);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '录入宿舍费用', targetId: result.id, targetType: 'room_expense', detail: `房间${dto.roomId} ¥${dto.amount} ${dto.expenseType}`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '录入宿舍费用',
|
||||
targetId: result.id,
|
||||
targetType: 'room_expense',
|
||||
detail: `房间${dto.roomId} ¥${dto.amount} ${dto.expenseType}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -65,7 +96,15 @@ export class ExpensesController {
|
||||
async batchCreateRoomExpenses(@Body() dto: BatchRoomExpenseDto, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.batchCreateRoomExpenses(dto, req.user?.id);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '批量录入费用', detail: JSON.stringify(dto), ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '批量录入费用',
|
||||
detail: JSON.stringify(dto),
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -78,7 +117,8 @@ export class ExpensesController {
|
||||
) {
|
||||
return this.service.findRoomExpenses({
|
||||
roomId: roomId ? +roomId : undefined,
|
||||
periodStart, periodEnd,
|
||||
periodStart,
|
||||
periodEnd,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,7 +127,16 @@ export class ExpensesController {
|
||||
async deleteRoomExpense(@Param('id') id: string, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.deleteRoomExpense(+id);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '删除宿舍费用', targetId: +id, targetType: 'room_expense', ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '删除宿舍费用',
|
||||
targetId: +id,
|
||||
targetType: 'room_expense',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -96,16 +145,38 @@ export class ExpensesController {
|
||||
async batchDeleteRoomExpenses(@Body() body: { ids: number[] }, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.batchDeleteRoomExpenses(body.ids || []);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '批量删除宿舍费用', detail: `IDs: ${(body.ids || []).join(',')}`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '批量删除宿舍费用',
|
||||
detail: `IDs: ${(body.ids || []).join(',')}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@Put('room/:id')
|
||||
@RequirePermission('expense:edit')
|
||||
async updateRoomExpense(@Param('id') id: string, @Body() dto: CreateRoomExpenseDto, @Request() req: any) {
|
||||
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);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '编辑宿舍费用', targetId: +id, targetType: 'room_expense', detail: `¥${dto.amount} ${dto.expenseType}`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '编辑宿舍费用',
|
||||
targetId: +id,
|
||||
targetType: 'room_expense',
|
||||
detail: `¥${dto.amount} ${dto.expenseType}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -114,7 +185,15 @@ export class ExpensesController {
|
||||
async createPersonalExpense(@Body() dto: CreatePersonalExpenseDto, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.createPersonalExpense(dto, req.user?.id);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '录入个人费用', detail: `学生${dto.studentId} ¥${dto.amount} ${dto.expenseType}`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '录入个人费用',
|
||||
detail: `学生${dto.studentId} ¥${dto.amount} ${dto.expenseType}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -129,7 +208,15 @@ export class ExpensesController {
|
||||
async deletePersonalExpense(@Param('id') id: string, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.deletePersonalExpense(+id);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '删除个人费用', targetId: +id, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '删除个人费用',
|
||||
targetId: +id,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -138,16 +225,37 @@ export class ExpensesController {
|
||||
async batchDeletePersonalExpenses(@Body() body: { ids: number[] }, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.batchDeletePersonalExpenses(body.ids || []);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '批量删除个人费用', detail: `IDs: ${(body.ids || []).join(',')}`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '批量删除个人费用',
|
||||
detail: `IDs: ${(body.ids || []).join(',')}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@Put('personal/:id')
|
||||
@RequirePermission('expense:edit')
|
||||
async updatePersonalExpense(@Param('id') id: string, @Body() dto: CreatePersonalExpenseDto, @Request() req: any) {
|
||||
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);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '编辑个人费用', targetId: +id, detail: `¥${dto.amount} ${dto.expenseType}`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '编辑个人费用',
|
||||
targetId: +id,
|
||||
detail: `¥${dto.amount} ${dto.expenseType}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -168,8 +276,20 @@ export class ExpensesController {
|
||||
];
|
||||
ws.getRow(1).font = { bold: true };
|
||||
ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } };
|
||||
ws.addRow({ seq: 1, period: '2026-01-21 - 2026-02-08', roomNumber: '4-102', electricity: 50, electricityFee: 25.5, water: 3, waterFee: 14.7, total: 40.2 });
|
||||
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
ws.addRow({
|
||||
seq: 1,
|
||||
period: '2026-01-21 - 2026-02-08',
|
||||
roomNumber: '4-102',
|
||||
electricity: 50,
|
||||
electricityFee: 25.5,
|
||||
water: 3,
|
||||
waterFee: 14.7,
|
||||
total: 40.2,
|
||||
});
|
||||
res.setHeader(
|
||||
'Content-Type',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
);
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=utility_template.xlsx');
|
||||
await workbook.xlsx.write(res);
|
||||
res.end();
|
||||
@@ -199,7 +319,15 @@ export class ExpensesController {
|
||||
});
|
||||
});
|
||||
const result = await this.service.batchImportUtilityExpenses(rows, req.user?.id);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '导入水电费', detail: result.message, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '导入水电费',
|
||||
detail: result.message,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -217,12 +345,23 @@ export class ExpensesController {
|
||||
];
|
||||
ws.getRow(1).font = { bold: true };
|
||||
ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } };
|
||||
ws.addRow({ studentName: '张三', expenseType: '钥匙费', amount: 30, expenseDate: '2026-01-15', description: '丢失宿舍钥匙' });
|
||||
ws.addRow({
|
||||
studentName: '张三',
|
||||
expenseType: '钥匙费',
|
||||
amount: 30,
|
||||
expenseDate: '2026-01-15',
|
||||
description: '丢失宿舍钥匙',
|
||||
});
|
||||
// 添加费用类型说明
|
||||
const noteSheet = workbook.addWorksheet('费用类型说明');
|
||||
noteSheet.columns = [{ header: '费用类型可用值', key: 'type', width: 25 }];
|
||||
['物品损坏', '保洁费', '罚款', '钥匙费', '空调遥控器', '押金扣除', '其他'].forEach(t => noteSheet.addRow({ type: t }));
|
||||
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
['物品损坏', '保洁费', '罚款', '钥匙费', '空调遥控器', '押金扣除', '其他'].forEach((t) =>
|
||||
noteSheet.addRow({ type: t }),
|
||||
);
|
||||
res.setHeader(
|
||||
'Content-Type',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
);
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=personal_expense_template.xlsx');
|
||||
await workbook.xlsx.write(res);
|
||||
res.end();
|
||||
@@ -250,7 +389,15 @@ export class ExpensesController {
|
||||
});
|
||||
});
|
||||
const result = await this.service.batchImportPersonalExpenses(rows, req.user?.id);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '费用', action: '导入个人附加费', detail: result.message, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '费用',
|
||||
action: '导入个人附加费',
|
||||
detail: result.message,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -258,7 +405,15 @@ export class ExpensesController {
|
||||
@RequirePermission('expense:view')
|
||||
async exportPersonalExpenses(@Res() res: Response) {
|
||||
const data = await this.service.findPersonalExpenses();
|
||||
const typeMap: Record<string, string> = { damage: '物品损坏', cleaning: '保洁费', penalty: '罚款', key: '钥匙费', remote: '空调遥控器', deposit_deduction: '押金扣除', other: '其他' };
|
||||
const typeMap: Record<string, string> = {
|
||||
damage: '物品损坏',
|
||||
cleaning: '保洁费',
|
||||
penalty: '罚款',
|
||||
key: '钥匙费',
|
||||
remote: '空调遥控器',
|
||||
deposit_deduction: '押金扣除',
|
||||
other: '其他',
|
||||
};
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const ws = workbook.addWorksheet('个人附加费');
|
||||
ws.columns = [
|
||||
@@ -278,7 +433,10 @@ export class ExpensesController {
|
||||
description: d.description || '',
|
||||
});
|
||||
});
|
||||
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
res.setHeader(
|
||||
'Content-Type',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
);
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=personal_expenses_export.xlsx');
|
||||
await workbook.xlsx.write(res);
|
||||
res.end();
|
||||
|
||||
Reference in New Issue
Block a user