253 lines
8.1 KiB
TypeScript
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);
|
|
}
|
|
}
|