feat(pwl):添加审计核查功能初版
This commit is contained in:
@@ -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));
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
problemList.value = [...problemList.value, ...sampleProblems];
|
props.data?.kbId,
|
||||||
message.success('问题生成成功');
|
props.data?.libraryIds,
|
||||||
} catch (error) {
|
props.data?.analysisLibrary,
|
||||||
message.error('问题生成失败');
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return problem;
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user