Files
lislgosms/api/src/report-materials/report-materials.controller.ts
T

253 lines
8.1 KiB
TypeScript

import {
BadRequestException,
Body,
Controller,
Get,
Param,
Post,
Put,
Query,
Res,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiTags } from '@nestjs/swagger';
import { RequireRecentAuthentication } from '../auth/require-recent-authentication.decorator';
import { CurrentSessionUserId } from '../auth/current-session-user.decorator';
import { ReportMaterialsService } from './report-materials.service';
import { ReportBatchDownloadService } from './batch-download.service';
import {
CreateImportProfileDto,
CreateReportBatchDto,
ImportCommitDto,
ReviewImportItemsDto,
SingleReportMaterialDto,
} from './report-materials.contracts';
type UploadedWorkbook = { originalname: string; mimetype: string; size: number; buffer: Buffer };
type DownloadResponse = { setHeader(name: string, value: string): void; send(content: Buffer): void };
@ApiTags('report-materials')
@Controller('admin/report-materials')
export class ReportMaterialsController {
constructor(
private readonly service: ReportMaterialsService,
private readonly batchDownloads: ReportBatchDownloadService,
) {}
@Get('pending')
listPending(
@Query('reportType') reportType?: 'signature' | 'drainage',
@Query('tenantId') tenantId?: string,
@Query('applicationId') applicationId?: string,
@Query('keyword') keyword?: string,
@Query('startAt') startAt?: string,
@Query('endAt') endAt?: string,
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
) {
return this.service.listPending({
reportType,
tenantId,
applicationId,
keyword,
startAt,
endAt,
page: Number(page),
pageSize: Number(pageSize),
});
}
@Get('templates/:reportType')
async downloadTemplate(
@Param('reportType') reportType: 'signature' | 'drainage',
@CurrentSessionUserId() operatorId: string | undefined,
@Res() response: DownloadResponse,
) {
if (!['signature', 'drainage'].includes(reportType))
throw new BadRequestException('reportType must be signature or drainage');
this.sendWorkbook(response, await this.service.buildOfficialTemplate(reportType, operatorId));
}
@Get('pending/export')
async exportPending(
@Query('reportType') reportType: 'signature' | 'drainage' | undefined,
@Query('tenantId') tenantId: string | undefined,
@Query('applicationId') applicationId: string | undefined,
@CurrentSessionUserId() operatorId: string | undefined,
@Res() response: DownloadResponse,
) {
this.sendWorkbook(response, await this.service.exportPending({ reportType, tenantId, applicationId }, operatorId));
}
@Get('import-profiles')
listImportProfiles(@Query('reportType') reportType?: 'signature' | 'drainage') {
return this.service.listImportProfiles(reportType);
}
@Post('import-profiles')
@RequireRecentAuthentication()
saveImportProfile(@Body() body: CreateImportProfileDto) {
return this.service.saveImportProfile(body);
}
@Post('imports/analyze')
@UseInterceptors(
FileInterceptor('file', { limits: { fileSize: 100 * 1024 * 1024, files: 1, fields: 12, parts: 13 } }),
)
analyzeImport(
@UploadedFile() file: UploadedWorkbook,
@Body() body: Record<string, string>,
@CurrentSessionUserId() operatorId?: string,
) {
if (!file) throw new BadRequestException('请选择 XLSX 文件');
return this.service.analyzeImport(file, {
tenantId: body.tenantId,
applicationId: body.applicationId,
reportType: body.reportType as 'signature' | 'drainage',
sheetName: body.sheetName || undefined,
headerRowCount: Number(body.headerRowCount || 1),
dataStartRow: Number(body.dataStartRow || 2),
profileId: body.profileId || undefined,
operatorId,
});
}
@Put('imports/:id/commit')
@RequireRecentAuthentication()
commitImport(@Param('id') id: string, @Body() body: ImportCommitDto, @CurrentSessionUserId() operatorId?: string) {
return this.service.commitImport(id, { ...body, operatorId });
}
@Get('imports/review-batches')
listImportReviewBatches(
@Query('reportType') reportType?: 'signature' | 'drainage',
@Query('status') status?: string,
@Query('keyword') keyword?: string,
@Query('startAt') startAt?: string,
@Query('endAt') endAt?: string,
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
) {
return this.service.listImportReviewBatches({
reportType,
status,
keyword,
startAt,
endAt,
page: Number(page),
pageSize: Number(pageSize),
});
}
@Post('imports/:id/review')
@RequireRecentAuthentication()
reviewImportItems(
@Param('id') id: string,
@Body() body: ReviewImportItemsDto,
@CurrentSessionUserId() reviewerId?: string,
) {
return this.service.reviewImportItems(id, { ...body, reviewerId });
}
@Get('batches')
listBatches(
@Query('keyword') keyword?: string,
@Query('startAt') startAt?: string,
@Query('endAt') endAt?: string,
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
) {
return this.service.listBatches({ keyword, startAt, endAt, page: Number(page), pageSize: Number(pageSize) });
}
@Get('batches/:id/download')
async downloadBatch(
@Param('id') id: string,
@Query('outputFormat') outputFormat: 'excel_drawing' | 'wps_cell_image' | undefined,
@Res() response: DownloadResponse,
) {
this.sendDownload(response, await this.batchDownloads.exportBundle(await this.service.getBatch(id), outputFormat));
}
@Get('batches/:id/files/:fileId/download')
async downloadBatchFile(
@Param('id') id: string,
@Param('fileId') fileId: string,
@Query('outputFormat') outputFormat: 'excel_drawing' | 'wps_cell_image' | undefined,
@Res() response: DownloadResponse,
) {
this.sendDownload(
response,
await this.batchDownloads.exportFile(await this.service.getBatch(id), fileId, outputFormat),
);
}
@Get('batches/:id')
getBatch(@Param('id') id: string) {
return this.service.getBatch(id);
}
@Get('batches/:id/tasks')
listBatchTasks(
@Param('id') id: string,
@Query('keyword') keyword?: string,
@Query('reportType') reportType?: string,
@Query('status') status?: string,
@Query('channelId') channelId?: string,
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
) {
return this.service.listBatchTasks(id, {
keyword,
reportType,
status,
channelId,
page: Number(page),
pageSize: Number(pageSize),
});
}
@Post('batches/preflight')
preflightBatch(@Body() body: CreateReportBatchDto) {
return this.service.preflightBatch(body);
}
@Post('batches')
@RequireRecentAuthentication()
createBatch(@Body() body: CreateReportBatchDto, @CurrentSessionUserId() operatorId?: string) {
return this.service.createBatch({ ...body, createdById: operatorId });
}
@Post('single-detail')
getSingleMaterialDetail(@Body() body: SingleReportMaterialDto) {
return this.service.getSingleMaterialDetail(body);
}
@Post('single-export')
@RequireRecentAuthentication()
async exportSingleMaterial(
@Body() body: SingleReportMaterialDto | undefined,
@CurrentSessionUserId() operatorId: string | undefined,
@Res() response: DownloadResponse,
) {
this.sendWorkbook(response, await this.service.exportSingleMaterial(body, operatorId));
}
private sendWorkbook(response: DownloadResponse, exported: { fileName: string; content: Buffer }) {
response.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
response.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodeURIComponent(exported.fileName)}`);
response.send(exported.content);
}
private sendDownload(
response: DownloadResponse,
exported: { fileName: string; contentType: string; content: Buffer },
) {
response.setHeader('Content-Type', exported.contentType);
response.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodeURIComponent(exported.fileName)}`);
response.send(exported.content);
}
}