fix(planting-service): 签名后查看合同返回已签名的PDF
- 修改 /tasks/:orderNo/pdf 接口,检查任务状态 - 如果已签名且有 signedPdfUrl,从 MinIO 下载已签名的 PDF - 添加 downloadSignedPdf 方法到 MinioStorageService - 在 ContractSigningTaskDto 中添加 signedPdfUrl 字段 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
86103e4c4d
commit
666be6ea60
|
|
@ -428,18 +428,23 @@ export class ContractSigningController {
|
|||
throw new Error('签署任务不存在');
|
||||
}
|
||||
|
||||
// 格式化签署日期
|
||||
const signingDate = new Date().toISOString().split('T')[0];
|
||||
let pdfBuffer: Buffer;
|
||||
|
||||
// 生成 PDF(使用 pdf-lib 直接操作 PDF 模板)
|
||||
const pdfBuffer = await this.pdfGeneratorService.generateContractPdf({
|
||||
contractNo: task.contractNo,
|
||||
userRealName: task.userRealName || '未认证',
|
||||
userIdCard: task.userIdCardNumber || '',
|
||||
userPhone: task.userPhoneNumber || '',
|
||||
treeCount: task.treeCount,
|
||||
signingDate,
|
||||
});
|
||||
// 如果已签名且有签名PDF URL,从MinIO下载已签名的PDF
|
||||
if (task.status === 'SIGNED' && task.signedPdfUrl) {
|
||||
this.logger.log(`Downloading signed PDF from MinIO for order ${orderNo}`);
|
||||
try {
|
||||
pdfBuffer = await this.minioStorageService.downloadSignedPdf(task.signedPdfUrl);
|
||||
this.logger.log(`Signed PDF downloaded: ${pdfBuffer.length} bytes`);
|
||||
} catch (downloadError) {
|
||||
this.logger.warn(`Failed to download signed PDF, regenerating: ${downloadError.message}`);
|
||||
// 下载失败时回退到重新生成
|
||||
pdfBuffer = await this.regeneratePreviewPdf(task);
|
||||
}
|
||||
} else {
|
||||
// 未签名,生成预览PDF
|
||||
pdfBuffer = await this.regeneratePreviewPdf(task);
|
||||
}
|
||||
|
||||
// 设置响应头
|
||||
res.set({
|
||||
|
|
@ -450,8 +455,29 @@ export class ContractSigningController {
|
|||
|
||||
return new StreamableFile(pdfBuffer);
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to generate PDF for order ${orderNo}:`, error);
|
||||
this.logger.error(`Failed to get PDF for order ${orderNo}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成预览PDF(不含签名)
|
||||
*/
|
||||
private async regeneratePreviewPdf(task: {
|
||||
contractNo: string;
|
||||
userRealName?: string;
|
||||
userIdCardNumber?: string;
|
||||
userPhoneNumber?: string;
|
||||
treeCount: number;
|
||||
}): Promise<Buffer> {
|
||||
const signingDate = new Date().toISOString().split('T')[0];
|
||||
return this.pdfGeneratorService.generateContractPdf({
|
||||
contractNo: task.contractNo,
|
||||
userRealName: task.userRealName || '未认证',
|
||||
userIdCard: task.userIdCardNumber || '',
|
||||
userPhone: task.userPhoneNumber || '',
|
||||
treeCount: task.treeCount,
|
||||
signingDate,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ export interface ContractSigningTaskDto {
|
|||
scrolledToBottomAt?: Date;
|
||||
acknowledgedAt?: Date;
|
||||
signedAt?: Date;
|
||||
signedPdfUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -466,6 +467,7 @@ export class ContractSigningService {
|
|||
scrolledToBottomAt: task.scrolledToBottomAt,
|
||||
acknowledgedAt: task.acknowledgedAt,
|
||||
signedAt: task.signedAt,
|
||||
signedPdfUrl: task.signedPdfUrl,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,45 @@ export class MinioStorageService implements OnModuleInit {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载已签署的合同 PDF
|
||||
* @param signedPdfUrl PDF 文件的公开 URL
|
||||
* @returns PDF 文件 Buffer
|
||||
*/
|
||||
async downloadSignedPdf(signedPdfUrl: string): Promise<Buffer> {
|
||||
try {
|
||||
// 从 URL 中提取对象名称
|
||||
const objectName = this.extractObjectName(signedPdfUrl);
|
||||
|
||||
const dataStream = await this.minioClient.getObject(this.bucketName, objectName);
|
||||
|
||||
// 将流转换为 Buffer
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of dataStream) {
|
||||
chunks.push(Buffer.from(chunk));
|
||||
}
|
||||
|
||||
const buffer = Buffer.concat(chunks);
|
||||
this.logger.log(`Downloaded signed PDF: ${objectName}, size: ${buffer.length} bytes`);
|
||||
return buffer;
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to download signed PDF from ${signedPdfUrl}: ${error.message}`);
|
||||
throw new Error(`已签署合同下载失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 URL 中提取对象名称
|
||||
*/
|
||||
private extractObjectName(objectUrl: string): string {
|
||||
// URL 格式: https://minio.xxx.com/contracts/contracts/orderNo/signed-contract-xxx.pdf
|
||||
// 需要提取: contracts/orderNo/signed-contract-xxx.pdf
|
||||
const url = new URL(objectUrl);
|
||||
const pathParts = url.pathname.split('/').filter(Boolean);
|
||||
// 第一个是桶名,后面的是对象路径
|
||||
return pathParts.slice(1).join('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
* @param objectUrl 文件的公开 URL
|
||||
|
|
|
|||
Loading…
Reference in New Issue