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
+57 -2
View File
@@ -633,8 +633,10 @@
<el-tag v-else-if="r.status === 'completed'" size="mini" type="success">已完成</el-tag>
<el-tag v-else-if="r.status === 'failed'" size="mini" type="danger">失败</el-tag>
<el-button v-if="r.htmlUrl" size="mini" type="text" @click="openUrl(r.htmlUrl)">报告下载</el-button>
<el-button v-if="r.docxUrl" size="mini" type="text" @click="openUrl(r.docxUrl)">下载 Word</el-button>
<el-button v-if="r.fileUrl" size="mini" type="text" @click="previewFile(r)">查看上传文件</el-button>
<el-button v-if="r.status === 'completed' && r.result" size="mini" type="text" @click="viewReport(r)">在线查看报告</el-button>
<el-button v-if="r.status === 'uploaded'" size="mini" type="primary" plain :loading="r._submitting" @click="reReview(r)">重新审查</el-button>
</view>
</view>
@@ -1652,14 +1654,16 @@ export default {
try {
const res = await vk.callFunction({
url: 'client/ai/pub/getMyReports',
data: { pageIndex: 1, pageSize: 50 }
data: { pageIndex: 1, pageSize: 50, uid: vk.getVuex('$user.userInfo._id') || '' }
});
if (res.code === 0 && res.data && res.data.rows) {
this.reportList = res.data.rows.map(r => ({
fileName: r.file_name,
fileSize: r.file_size,
fileId: r.file_id || '',
fileUrl: r.file_url || '',
htmlUrl: r.html_url || '',
docxUrl: r.docx_url || '',
time: dayjs(r._add_time && r._add_time['$date'] ? r._add_time['$date'] : r._add_time).format('YYYY-MM-DD HH:mm:ss'),
amount: r.points_used || 0,
result: r.result,
@@ -1678,6 +1682,56 @@ export default {
this.reviewResult = r.result || '暂无审查结果';
this.reviewFile = { name: r.fileName, size: r.fileSize || 0 };
},
// 待审查记录 → 重新发起审查
async reReview(r) {
if (!r.fileId) {
this.$message.warning('该记录缺少文件信息,请重新上传合同');
return;
}
try {
await this.$confirm(
`确认对「${r.fileName}」发起审查?审查完成后将按文件大小扣除相应积分。`,
'重新审查',
{ confirmButtonText: '确认审查', cancelButtonText: '取消', type: 'warning' }
);
} catch (e) {
return;
}
// 积分校验
try {
const balanceRes = await vk.callFunction({ url: 'client/points/kh/getBalance' });
if (balanceRes.code !== 0 || !balanceRes.data || balanceRes.data.balance < 200) {
this.$message.warning('积分不足,请先充值');
return;
}
} catch (e) {
this.$message.error('积分查询失败,请稍后重试');
return;
}
this.$set(r, '_submitting', true);
try {
const res = await vk.callFunction({
url: 'client/ai/pub/review',
data: {
record_id: r.recordId,
file_id: r.fileId,
file_name: r.fileName,
file_size: r.fileSize || 0,
uid: vk.getVuex('$user.userInfo._id') || ''
}
});
if (res.code === 0) {
r.status = (res.data && res.data.status) || 'reviewing';
this.$message.success('已提交审查,AI 正在分析中,预计 3-5 分钟完成');
setTimeout(() => this.queryReports(), 1500);
} else {
this.$message.error(res.msg || '提交审查失败');
}
} catch (e) {
this.$message.error('提交审查异常');
}
this.$set(r, '_submitting', false);
},
previewFile(r) {
if (!r.fileUrl) {
this.$message.warning('文件链接不存在');
@@ -1723,6 +1777,7 @@ export default {
file_base64: fileBase64,
file_name: file.name,
file_size: file.size,
uid: vk.getVuex('$user.userInfo._id') || '',
upload_only: true
}
});
@@ -1769,7 +1824,7 @@ export default {
file_id: this.reviewFileId,
file_name: this.reviewFile.name,
file_size: this.reviewFile.size,
uid: this.userInfo.uid
uid: vk.getVuex('$user.userInfo._id') || ''
}
});