feat(pwl):添加审计核查功能初版

This commit is contained in:
2025-10-16 15:55:34 +08:00
parent 39e79f2844
commit ae5d429630
2 changed files with 198 additions and 34 deletions

View File

@@ -34,3 +34,37 @@ export async function downloadAuditReport(req: AuditReport) {
} }
return Promise.reject(new Error('文件下载失败')); return Promise.reject(new Error('文件下载失败'));
} }
/**
* 生成审计核查报告 - 重构版
*/
export async function generateAuditReport2(
file: File,
kbId?: string,
libraryIds?: string,
analysisLibrary?: string,
projectLibrary?: string
) {
const formData = new FormData();
formData.append('file', file);
if (kbId) formData.append('kbId', kbId);
if (libraryIds) formData.append('libraryIds', libraryIds);
if (analysisLibrary) formData.append('analysisLibrary', analysisLibrary);
if (projectLibrary) formData.append('projectLibrary', projectLibrary);
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/ai/auditReport2/generate',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -17,6 +17,20 @@
<div class="title">审计发现问题情况表</div> <div class="title">审计发现问题情况表</div>
<div class="buttons"> <div class="buttons">
<a-space> <a-space>
<!-- 附件上传 -->
<a-upload
v-model:file-list="fileList"
:before-upload="beforeUpload"
:max-count="1"
:show-upload-list="true"
accept=".pdf,.doc,.docx,.xls,.xlsx,.txt"
>
<a-button class="action-button">
<template #icon><UploadOutlined /></template>
上传附件
</a-button>
</a-upload>
<a-button type="primary" @click="addProblem" class="action-button"> <a-button type="primary" @click="addProblem" class="action-button">
<template #icon><PlusOutlined /></template> <template #icon><PlusOutlined /></template>
新增问题 新增问题
@@ -37,12 +51,27 @@
</div> </div>
</div> </div>
<!-- 附件信息显示 -->
<a-card v-if="fileList.length > 0" :bordered="false" class="file-info-card">
<template #title>
<PaperClipOutlined /> 已上传附件
</template>
<div class="file-info">
<div class="file-item" v-for="file in fileList" :key="file.uid">
<div class="file-name">{{ file.name }}</div>
<a-button type="link" size="small" @click="removeFile(file.uid)" danger>
删除
</a-button>
</div>
</div>
</a-card>
<!-- 问题列表表格 --> <!-- 问题列表表格 -->
<a-card :bordered="false" class="table-card"> <a-card :bordered="false" class="table-card">
<a-table <a-table
:dataSource="problemList" :dataSource="problemList"
:columns="columns" :columns="columns"
:scroll="{ x: 1500 }" :scroll="{ x: 1800 }"
:pagination="false" :pagination="false"
rowKey="id" rowKey="id"
size="middle" size="middle"
@@ -54,6 +83,13 @@
{{ index + 1 }} {{ index + 1 }}
</template> </template>
<!-- 是否存在问题列 -->
<template v-if="column.dataIndex === 'hasProblem'">
<a-tag :color="record.hasProblem === 'true' ? 'red' : 'green'">
{{ record.hasProblem === 'true' ? '是' : '否' }}
</a-tag>
</template>
<!-- 金额列 --> <!-- 金额列 -->
<template v-if="column.dataIndex === 'amount'"> <template v-if="column.dataIndex === 'amount'">
<a-input-number <a-input-number
@@ -80,10 +116,11 @@
<!-- 整改时限列 --> <!-- 整改时限列 -->
<template v-if="column.dataIndex === 'deadline'"> <template v-if="column.dataIndex === 'deadline'">
<a-date-picker <a-input
v-model:value="record.deadline" v-model:value="record.deadline"
style="width: 100%" style="width: 100%"
:bordered="false" :bordered="false"
placeholder="如1个月"
/> />
</template> </template>
@@ -121,6 +158,12 @@
@cancel="cancelEdit" @cancel="cancelEdit"
> >
<a-form layout="vertical"> <a-form layout="vertical">
<a-form-item label="是否存在相关问题" required>
<a-radio-group v-model:value="editingProblem.hasProblem">
<a-radio value="true"></a-radio>
<a-radio value="false"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="问题表述" required> <a-form-item label="问题表述" required>
<a-textarea <a-textarea
v-model:value="editingProblem.problemDescription" v-model:value="editingProblem.problemDescription"
@@ -143,7 +186,7 @@
/> />
</a-form-item> </a-form-item>
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="12"> <a-col :span="8">
<a-form-item label="涉及金额(万元)"> <a-form-item label="涉及金额(万元)">
<a-input-number <a-input-number
v-model:value="editingProblem.amount" v-model:value="editingProblem.amount"
@@ -153,7 +196,7 @@
/> />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="12"> <a-col :span="8">
<a-form-item label="整改类型"> <a-form-item label="整改类型">
<a-select v-model:value="editingProblem.rectificationType"> <a-select v-model:value="editingProblem.rectificationType">
<a-select-option value="立行立改">立行立改</a-select-option> <a-select-option value="立行立改">立行立改</a-select-option>
@@ -162,6 +205,14 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="8">
<a-form-item label="整改时限">
<a-input
v-model:value="editingProblem.deadline"
placeholder="如1个月"
/>
</a-form-item>
</a-col>
</a-row> </a-row>
<a-form-item label="具体责任界定"> <a-form-item label="具体责任界定">
<a-textarea <a-textarea
@@ -177,12 +228,6 @@
placeholder="请输入整改要求" placeholder="请输入整改要求"
/> />
</a-form-item> </a-form-item>
<a-form-item label="整改时限">
<a-date-picker
v-model:value="editingProblem.deadline"
style="width: 100%"
/>
</a-form-item>
<a-form-item label="审计建议"> <a-form-item label="审计建议">
<a-textarea <a-textarea
v-model:value="editingProblem.auditSuggestion" v-model:value="editingProblem.auditSuggestion"
@@ -199,13 +244,17 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, watch } from 'vue'; import { ref, reactive, watch } from 'vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import type { UploadProps } from 'ant-design-vue';
import { import {
PlusOutlined, PlusOutlined,
RobotOutlined, RobotOutlined,
ExportOutlined, ExportOutlined,
SaveOutlined SaveOutlined,
UploadOutlined,
PaperClipOutlined
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import type { PwlProject } from '@/api/pwl/pwlProject/model'; import type { PwlProject } from '@/api/pwl/pwlProject/model';
import { generateAuditReport2 } from "@/api/ai/auditReport";
// Props 定义 // Props 定义
const props = defineProps<{ const props = defineProps<{
@@ -232,7 +281,9 @@ const otherProblems = ref('');
const loading = ref(false); const loading = ref(false);
const generating = ref(false); const generating = ref(false);
const showEditModal = ref(false); const showEditModal = ref(false);
const fileList = ref<any[]>([]);
const editingProblem = ref<any>({ const editingProblem = ref<any>({
hasProblem: 'true',
problemDescription: '', problemDescription: '',
problemDetails: '', problemDetails: '',
legalBasis: '', legalBasis: '',
@@ -240,11 +291,11 @@ const editingProblem = ref<any>({
responsibility: '', responsibility: '',
rectificationType: '', rectificationType: '',
rectificationRequirement: '', rectificationRequirement: '',
deadline: null, deadline: '',
auditSuggestion: '' auditSuggestion: ''
}); });
// 表格列定义 // 表格列定义 - 优化后
const columns = [ const columns = [
{ {
title: '序号', title: '序号',
@@ -252,6 +303,12 @@ const columns = [
width: 60, width: 60,
fixed: 'left' fixed: 'left'
}, },
{
title: '是否存在问题',
dataIndex: 'hasProblem',
width: 100,
fixed: 'left'
},
{ {
title: '问题表述', title: '问题表述',
dataIndex: 'problemDescription', dataIndex: 'problemDescription',
@@ -311,6 +368,18 @@ const columns = [
} }
]; ];
// 上传前处理
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
// 添加到文件列表
fileList.value = [file];
return false; // 阻止自动上传
};
// 删除文件
const removeFile = (uid: string) => {
fileList.value = fileList.value.filter(file => file.uid !== uid);
};
// 更新visible // 更新visible
const updateVisible = (value: boolean) => { const updateVisible = (value: boolean) => {
emit('update:visible', value); emit('update:visible', value);
@@ -319,6 +388,7 @@ const updateVisible = (value: boolean) => {
// 新增问题 // 新增问题
const addProblem = () => { const addProblem = () => {
editingProblem.value = { editingProblem.value = {
hasProblem: 'true',
problemDescription: '', problemDescription: '',
problemDetails: '', problemDetails: '',
legalBasis: '', legalBasis: '',
@@ -326,7 +396,7 @@ const addProblem = () => {
responsibility: '', responsibility: '',
rectificationType: '', rectificationType: '',
rectificationRequirement: '', rectificationRequirement: '',
deadline: null, deadline: '',
auditSuggestion: '' auditSuggestion: ''
}; };
showEditModal.value = true; showEditModal.value = true;
@@ -370,29 +440,71 @@ const deleteProblem = (index: number) => {
message.success('删除成功'); message.success('删除成功');
}; };
// AI生成问题 // AI生成问题 - 优化版
const generateProblems = async () => { const generateProblems = async () => {
// 检查是否有上传文件
if (fileList.value.length === 0) {
message.warning('请先上传附件文件');
return;
}
generating.value = true; generating.value = true;
try { try {
await new Promise(resolve => setTimeout(resolve, 2000)); console.log('当前行数据:', props.data);
const sampleProblems = [ console.log('项目名称:', props.data?.name);
{ console.log('项目编号:', props.data?.code);
id: Date.now(), console.log('分析文库:', props.data?.analysisLibrary);
problemDescription: '内部控制制度的制定和执行情况,未建立代管业务相关的管理办法', console.log('项目文库1:', props.data?.projectLibrary);
problemDetails: '审计发现,企业管理公司未建立代管业务的管理办法及代管业务流程机制。', console.log('项目文库2:', props.data?.kbId);
legalBasis: '上述情况不符合《企业内部控制基本规范》第四条"企业建立与实施内部控制,应当贯穿决策、执行和监督全过程,覆盖企业及其所属单位的各种业务和事项。"的规定。', console.log('项目文库3:', props.data?.libraryIds);
amount: 0,
responsibility: '罗世东同志、莫咏麟同志对任期内问题负有领导责任', // 获取上传的文件
rectificationType: '限期整改', const fileItem = fileList.value[0];
rectificationRequirement: '建立健全代管业务管理制度', const file = fileItem.originFileObj || fileItem;
deadline: null,
auditSuggestion: '建议尽快制定代管业务相关管理办法,明确业务流程和职责分工' // 调用后端接口
const result = await generateAuditReport2(
file,
props.data?.kbId,
props.data?.libraryIds,
props.data?.analysisLibrary,
props.data?.projectLibrary
);
// 处理返回结果 - 优化后的数据映射
if (result && result.findings) {
const generatedProblems = result.findings.map((finding: any, index: number) => {
// 统一处理字段映射
const problem = {
id: Date.now() + index,
hasProblem: finding['是否存在相关问题'] || 'true',
problemDescription: finding['问题表述'] || finding.problemDescription || '',
problemDetails: finding['问题明细'] || finding.problemDetails || '',
legalBasis: finding['法规依据'] || finding.legalBasis || '',
amount: parseFloat(finding['涉及金额(万元)']) || finding.amount || 0,
responsibility: finding['具体责任界定'] || finding.responsibility || '',
rectificationType: finding['整改类型'] || finding.rectificationType || '',
rectificationRequirement: finding['整改要求'] || finding.rectificationRequirement || '',
deadline: finding['整改时限'] || finding.deadline || '',
auditSuggestion: finding['审计建议'] || finding.auditSuggestion || ''
};
// 处理金额字段的特殊情况
if (finding['涉及金额(万元)'] === '/') {
problem.amount = 0;
} }
];
problemList.value = [...problemList.value, ...sampleProblems]; return problem;
message.success('问题生成成功'); });
} catch (error) {
message.error('问题生成失败'); problemList.value = generatedProblems;
message.success(`成功生成 ${generatedProblems.length} 个审计问题`);
} else {
throw new Error('生成结果格式错误');
}
} catch (error: any) {
console.error('AI生成问题失败:', error);
message.error('生成失败: ' + (error.message || '未知错误'));
} finally { } finally {
generating.value = false; generating.value = false;
} }
@@ -417,6 +529,7 @@ const saveData = () => {
const loadAuditCheckData = () => { const loadAuditCheckData = () => {
problemList.value = []; problemList.value = [];
otherProblems.value = ''; otherProblems.value = '';
fileList.value = [];
}; };
// 监听数据变化 // 监听数据变化
@@ -459,6 +572,23 @@ watch(
} }
} }
.file-info-card {
margin-bottom: 16px;
.file-info {
.file-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
.file-name {
font-weight: 500;
}
}
}
}
.table-card { .table-card {
margin-bottom: 16px; margin-bottom: 16px;