feat: AI审查报告支持下载Word + 我的报告支持重新审查

- 云函数jjxReviewTimer完成审查后自动将HTML报告转换为Word文档并上传
- 新增buildDocx.js纯正则解析HTML报告生成A4公文版式docx(三级数据提取兼容结构漂移)
- 兼容智能体插件直接返回docx链接(jjx-docx-link标记协议)
- router/jjxDoReview同步支持Word生成(try降级不影响主流程)
- 前端报告列表新增下载Word/重新审查按钮
- 修复上传/查询取真实uid(vk.getVuex而非页面本地data)
- login.js清理调试日志、.gitignore忽略node_modules与lock文件
This commit is contained in:
2026-10-23 19:07:05 +08:00
parent d0fb8802e7
commit 95024bb2a6
9 changed files with 2341 additions and 4 deletions
@@ -1,4 +1,20 @@
// client/ai/pub/jjxDoReview.js
// Word 报告生成器(依赖 docx,未安装时降级跳过,不影响审查)
let buildDocx = null;
let extractReportData = null;
let extractDocxLink = null;
let isDocxConvertible = null;
try {
const docxMod = require('./buildDocx.js');
buildDocx = docxMod.buildDocx;
extractReportData = docxMod.extractReportData;
extractDocxLink = docxMod.extractDocxLink;
isDocxConvertible = docxMod.isDocxConvertible;
} catch (e) {
console.log('[Docx] docx 依赖未安装,跳过 Word 生成:', e.message);
}
module.exports = {
main: async (event) => {
let { data = {}, userInfo } = event;
@@ -171,11 +187,50 @@ module.exports = {
if (jsonMatch) contractInfo = JSON.parse(jsonMatch[1].trim());
} catch (e) {}
// 生成 Word 报告:优先用智能体插件生成的链接,否则本地结构化重建
let docxUrl = extractDocxLink ? extractDocxLink(answer) : '';
let docxFileId = '';
if (docxUrl) {
console.log('[Docx] 采用智能体插件生成的 Word 链接:', docxUrl);
} else if (isDocxConvertible && !isDocxConvertible(answer)) {
// 智能体没返回完整报告(道歉/澄清文本,或 HTML 被截断),不生成残缺 Word
console.log('[Docx] 无完整 HTML 报告,跳过 Word 生成');
} else if (buildDocx && extractReportData) {
try {
const reportData = extractReportData(answer);
if (reportData) {
const docxBuffer = await buildDocx({
data: reportData,
fileName: file_name || '合同审查报告'
});
const baseName = (file_name || 'report').replace(/\.[^.]+$/, '');
const docxPath = 'review-reports/' + Date.now() + '_' + baseName + '_审查报告.docx';
const docxRes = await uniCloud.uploadFile({
cloudPath: docxPath,
fileContent: docxBuffer
});
if (docxRes.fileID) {
docxFileId = docxRes.fileID;
const docxUrlRes = await uniCloud.getTempFileURL({ fileList: [docxRes.fileID] });
if (docxUrlRes.fileList && docxUrlRes.fileList[0]) {
docxUrl = docxUrlRes.fileList[0].tempFileURL;
}
}
} else {
console.log('[Docx] 既无插件链接也无结构化数据,跳过 Word 生成');
}
} catch (e) {
console.log('[Docx] Word 报告生成失败(不影响审查结果):', e.message);
}
}
// 更新审查记录为完成
await db.collection('jjx-review-records').doc(record_id).update({
status: 'completed',
result: answer,
html_url: htmlUrl,
docx_url: docxUrl,
docx_file_id: docxFileId,
contract_info: contractInfo,
points_used: pointsUsed,
conversation_id: conversationId || '',