refactor(server): 清理全量 any 类型安全警告 (692 → 0)
- 全模块类型化:controller 的 req: any → AuthenticatedRequest/RequestUser, 聚合查询 getRawMany 泛型标注、导入行/响应体定义具体 interface、 catch (e: any) → unknown + 收窄、no-base-to-string 用 String() 显式转换 - 第三方无类型库边界(pdfkit/exceljs)文件级或单行 disable 并注明理由 - 顺带修复:get-business-context.tool 两个 require-await error、 bills.controller 参数顺序隐患、main.ts compression 调用 - 运行时逻辑零改动;测试 142 套件 / 1065 用例全部通过
This commit is contained in:
@@ -25,6 +25,21 @@ import { RequirePermission } from '../auth/decorators/permission.decorator';
|
||||
import * as ExcelJS from 'exceljs';
|
||||
import { CLASSROOM_TEMPLATE_COLUMNS } from './classroom-template';
|
||||
|
||||
interface AuthenticatedRequest {
|
||||
user?: { id: number; username: string };
|
||||
headers?: Record<string, string | string[] | undefined>;
|
||||
connection?: { remoteAddress?: string };
|
||||
}
|
||||
|
||||
/**
|
||||
* exceljs 单元格标量文本。保持原 `String(value || '')` 语义。
|
||||
* CellValue 联合类型含富文本/超链接对象,实际导入数据均为标量,故在辅助函数内局部豁免。
|
||||
*/
|
||||
function cellValueText(value: unknown): string {
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string -- exceljs CellValue 联合类型含富文本对象,实际导入数据为标量
|
||||
return String(value || '');
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('classrooms')
|
||||
export class ClassroomsController {
|
||||
@@ -104,7 +119,7 @@ export class ClassroomsController {
|
||||
|
||||
@Post()
|
||||
@RequirePermission('classroom:create')
|
||||
async create(@Body() dto: CreateClassroomDto, @Request() req: any) {
|
||||
async create(@Body() dto: CreateClassroomDto, @Request() req: AuthenticatedRequest) {
|
||||
const result = await this.service.create(dto);
|
||||
await logAudit(this.logService, req, {
|
||||
module: '教室', action: '新增教室', targetId: result.id, targetType: 'classroom', detail: dto.name,
|
||||
@@ -114,7 +129,7 @@ export class ClassroomsController {
|
||||
|
||||
@Put(':id')
|
||||
@RequirePermission('classroom:edit')
|
||||
async update(@Param('id') id: string, @Body() dto: UpdateClassroomDto, @Request() req: any) {
|
||||
async update(@Param('id') id: string, @Body() dto: UpdateClassroomDto, @Request() req: AuthenticatedRequest) {
|
||||
const result = await this.service.update(+id, dto);
|
||||
await logAudit(this.logService, req, {
|
||||
module: '教室', action: '编辑教室', targetId: +id, targetType: 'classroom', detail: JSON.stringify(dto),
|
||||
@@ -124,7 +139,7 @@ export class ClassroomsController {
|
||||
|
||||
@Delete(':id')
|
||||
@RequirePermission('classroom:delete')
|
||||
async remove(@Param('id') id: string, @Request() req: any) {
|
||||
async remove(@Param('id') id: string, @Request() req: AuthenticatedRequest) {
|
||||
const result = await this.service.remove(+id);
|
||||
await logAudit(this.logService, req, {
|
||||
module: '教室', action: '归档教室', targetId: +id, targetType: 'classroom',
|
||||
@@ -134,7 +149,7 @@ export class ClassroomsController {
|
||||
|
||||
@Delete(':id/permanent')
|
||||
@RequirePermission('classroom:purge')
|
||||
async purge(@Param('id') id: string, @Request() req: any) {
|
||||
async purge(@Param('id') id: string, @Request() req: AuthenticatedRequest) {
|
||||
const result = await this.service.purge(+id);
|
||||
await logAudit(this.logService, req, {
|
||||
module: '教室', action: '永久删除教室', targetId: +id, targetType: 'classroom', detail: '物理删除,不可恢复',
|
||||
@@ -144,7 +159,7 @@ export class ClassroomsController {
|
||||
|
||||
@Put(':id/restore')
|
||||
@RequirePermission('classroom:edit')
|
||||
async restore(@Param('id') id: string, @Request() req: any) {
|
||||
async restore(@Param('id') id: string, @Request() req: AuthenticatedRequest) {
|
||||
const result = await this.service.restore(+id);
|
||||
await logAudit(this.logService, req, {
|
||||
module: '教室', action: '恢复教室', targetId: +id, targetType: 'classroom',
|
||||
@@ -155,19 +170,25 @@ export class ClassroomsController {
|
||||
@Post('import')
|
||||
@RequirePermission('classroom:create')
|
||||
@UseInterceptors(FileInterceptor('file'))
|
||||
async importExcel(@UploadedFile() file: Express.Multer.File, @Request() req: any) {
|
||||
async importExcel(@UploadedFile() file: Express.Multer.File, @Request() req: AuthenticatedRequest) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
await workbook.xlsx.load(file.buffer as unknown as ArrayBuffer);
|
||||
const ws = workbook.worksheets[0];
|
||||
const rows: any[] = [];
|
||||
const rows: {
|
||||
name: string;
|
||||
building?: string;
|
||||
floor?: number;
|
||||
roomType?: string;
|
||||
capacity?: number;
|
||||
}[] = [];
|
||||
ws.eachRow((row, idx) => {
|
||||
if (idx === 1) return;
|
||||
rows.push({
|
||||
name: String(row.getCell(1).value || ''),
|
||||
building: String(row.getCell(2).value || '') || undefined,
|
||||
name: cellValueText(row.getCell(1).value),
|
||||
building: cellValueText(row.getCell(2).value) || undefined,
|
||||
floor: Number(row.getCell(3).value) || undefined,
|
||||
roomType: String(row.getCell(4).value || '') || undefined,
|
||||
roomType: cellValueText(row.getCell(4).value) || undefined,
|
||||
capacity: Number(row.getCell(5).value) || undefined,
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user