Files
template-10561/src/views/pwl/pwlProject/components/reportContent.vue

1243 lines
39 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 用户编辑弹窗 -->
<template>
<a-drawer
:width="`95%`"
:visible="visible"
:confirm-loading="loading"
:maxable="maxAble"
title="AI审计内容生成器"
:body-style="{ paddingBottom: '8px', background: '#f3f3f3' }"
@update:visible="updateVisible"
:maskClosable="false"
:footer="null"
@ok="save"
>
<a-card title="基本信息" style="margin-bottom: 20px" :bordered="false">
<a-descriptions>
<a-descriptions-item
label="公司名称"
:labelStyle="{ width: '90px', color: '#808080' }"
>
<span @click="copyText(form.name)">{{ form.name }}</span>
</a-descriptions-item>
<a-descriptions-item
label="被审计人"
:labelStyle="{ width: '90px', color: '#808080' }"
>
<span>{{ form.nickname || '暂无' }}</span>
</a-descriptions-item>
<a-descriptions-item
label="审计时间"
:labelStyle="{ width: '90px', color: '#808080' }"
>
<span>{{ form.expirationTime }}</span>
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card
style="margin-bottom: 20px; text-align: center; background: transparent"
:bordered="false"
>
<a-space>
<a-button
size="large"
type="primary"
@click="handleGenerateAll"
:loading="generatingAll"
class="generate-all-button"
:disabled="!hasTripleOneData"
>
<template #icon>
<UngroupOutlined />
</template>
生成全部方案
<a-tooltip
v-if="!hasTripleOneData"
title="请先生成三重一大制度对比分析表"
>
<QuestionCircleOutlined style="margin-left: 5px" />
</a-tooltip>
</a-button>
<a-button size="large">
<template #icon>
<DownloadOutlined />
</template>
保存草稿
</a-button>
<a-button size="large">
<template #icon>
<RedoOutlined />
</template>
加载草稿
</a-button>
<a-button
size="large"
type="danger"
class="export-button"
@click="handleExport"
>
<template #icon>
<UploadOutlined />
</template>
下载文件
</a-button>
</a-space>
</a-card>
<!-- 快速导航 -->
<a-card style="margin-bottom: 20px" :bordered="false">
<template #title>
<div
style="
display: flex;
align-items: center;
justify-content: space-between;
"
>
<span>快速导航</span>
<a-tooltip title="快捷键Ctrl+1~9 快速跳转Ctrl+↑↓ 上下导航">
<QuestionCircleOutlined style="color: #999; cursor: help" />
</a-tooltip>
</div>
</template>
<div class="navigation-container">
<div class="nav-grid">
<a-button
v-for="(item, index) in navigationItems"
:key="index"
:type="currentSection === index ? 'primary' : 'default'"
size="small"
@click="scrollToSection(index)"
class="nav-button"
:class="{ active: currentSection === index }"
>
<span class="nav-number">{{ item.number }}</span>
<span class="nav-text">{{ item.name }}</span>
</a-button>
</div>
<!-- 进度指示器 -->
<div class="progress-container">
<div class="progress-bar">
<div
class="progress-fill"
:style="{
width: `${
((currentSection + 1) / navigationItems.length) * 100
}%`
}"
></div>
</div>
<div class="progress-text">
{{ currentSection + 1 }} / {{ navigationItems.length }}
</div>
</div>
</div>
</a-card>
<!-- 审计方案内容 -->
<div class="audit-content">
<div
v-for="(item, index) in navigationItems"
:key="index"
:id="`section-${index}`"
class="audit-section"
>
<a-card style="margin-bottom: 20px" :bordered="false">
<template #title>
<span class="font-bold">{{ `${item.number}${item.name}` }}</span>
<span class="ml-4 text-gray-400" v-if="item.extra1">{{
table1Title
}}</span>
<span class="ml-4 text-gray-400" v-if="item.file1">
<!-- 修改选择文件组件 -->
<a-button
type="link"
@click="openDocSelect(index)"
class="select-file-btn"
>
<FolderOpenOutlined />
选择文件
</a-button>
</span>
<span class="ml-4 text-gray-400" v-if="item.extra3">{{
table3Title
}}</span>
<span class="ml-4 text-gray-400" v-if="item.file3">
<!-- 修改选择文件组件 -->
<a-button
type="link"
@click="openDocSelect(index)"
class="select-file-btn"
>
<FolderOpenOutlined />
选择文件
</a-button>
</span>
</template>
<template #extra>
<a-space>
<!-- 添加导出重大经济决策调查表按钮 -->
<a-button
v-if="item.extra3 && table3Title === '重大经济决策调查表'"
type="primary"
@click="handleExportDecisionTable"
:loading="exportingDecisionTable"
>
<template #icon>
<DownloadOutlined />
</template>
导出调查表
</a-button>
<!-- 添加导出三重一大按钮 -->
<a-button
v-if="item.extra3 && table3Title === '三重一大'"
type="primary"
@click="handleExportTripleOne"
:loading="exportingTripleOne"
>
<template #icon>
<DownloadOutlined />
</template>
导出三重一大
</a-button>
<a-button
type="primary"
@click="generateContent(index)"
:loading="item.generating"
>
<template #icon>
<RobotOutlined />
</template>
AI生成
</a-button>
</a-space>
</template>
<div class="flex justify-between items-center">
<div class="flex justify-start items-center">
<template v-if="item.extra1">
<div class="mb-2">
<TableSwitcher
:title="table1Title"
:btns="['贯彻决策部署', '领导班子名单', '决策支出表']"
@change="changeTable1"
/>
</div>
</template>
<template v-if="item.extra3">
<div class="mb-2">
<TableSwitcher
:title="table3Title"
:btns="['重大经济决策调查表', '三重一大']"
@change="changeTable3"
/>
</div>
</template>
<span class="ml-2"
>共生成
<span class="text-red-400 mx-1 font-bold">{{ item.data ? item.data.length : 0 }}</span>
条数据</span
>
</div>
<a @click="openHistory(index)" class="cursor-pointer">历史记录</a>
</div>
<a-table
v-if="item.mode === 'table'"
:columns="item.columns"
:scroll="{ y: 500 }"
:pagination="false"
bordered
:data-source="item.data"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-button type="primary" danger>删除</a-button>
</template>
<template v-if="column.key === 'testResult'">
<span class="text-green-400" v-if="record.testResult === '通过'"
>通过</span
>
<span
class="text-red-400"
v-else-if="record.testResult === '不通过'"
>不通过</span
>
<span class="text-gray-400" v-else>{{
record.testResult || '待检查'
}}</span>
</template>
<template v-if="column.key === 'workPaperIndex'">
<div
v-for="(fileItem, fileIndex) in record.workPaperIndex"
:key="fileIndex"
>
<img
src="@/assets/word.png"
style="width: 20px; height: 20px"
alt=""
/>
<span class="cursor-pointer text-wrap">{{ fileItem }}</span>
</div>
</template>
<template v-if="column.key === 'fileIndex'">
<div
v-for="(fileItem, fileIndex) in record.fileIndex"
:key="fileIndex"
>
<img
src="@/assets/word.png"
style="width: 20px; height: 20px"
alt=""
/>
<span class="cursor-pointer text-wrap">{{ fileItem }}</span>
</div>
</template>
<template v-if="column.key === 'goods'">
<span v-if="record.goods === '是'"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'normal'">
<span v-if="record.normal === '是'"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'bad'">
<span v-if="record.bad === '是'"></span>
<span v-else></span>
</template>
</template>
</a-table>
<template v-else-if="item.mode === 'radio'">
<div
class="mb-1"
v-for="(radio, radioIndex) in item.radioList"
:key="radioIndex"
>
<p class="mb-1">{{ radio.label }}</p>
<a-radio-group v-model:value="radio.content" :name="radio.label">
<a-radio value="是"></a-radio>
<a-radio value="否"></a-radio>
</a-radio-group>
</div>
</template>
<template v-else>
<template v-if="!item.textareaList || !item.textareaList.length">
<a-textarea
v-model:value="item.content"
:rows="item.rows || 8"
:placeholder="'点击(AI生成)按钮让AI为您生成该部分内容或直接填入'"
class="content-textarea"
style="margin-top: 16px; background-color: #f0fdf4"
/>
</template>
</template>
<template v-if="item.textareaList && item.textareaList.length">
<div
class="py-2 box-border"
:key="textareaIndex"
v-for="(textarea, textareaIndex) in item.textareaList"
>
<p class="mb-1">{{ textarea.label }}</p>
<a-textarea
v-model:value="textarea.content"
:rows="item.rows || 8"
:placeholder="'点击(AI生成)按钮让AI为您生成该部分内容或直接填入'"
class="content-textarea"
style="margin-top: 16px; background-color: #f0fdf4"
/>
</div>
</template>
<div style="margin-top: 12px">
<div class="question-prompt">AI小助手</div>
<div class="textarea-with-button" style="width: 600px">
<a-textarea
v-model:value="item.suggestion"
:rows="3"
placeholder="请输入您的要求并回车..."
class="suggestion-textarea-inner"
@pressEnter="generateContent(index)"
/>
<a-button
type="danger"
size="small"
@click="generateContent(index)"
:loading="item.generating"
class="send-button-inner"
>
<template #icon>
<RobotOutlined />
</template>
发送
</a-button>
</div>
</div>
</a-card>
</div>
</div>
<!-- 返回顶部按钮 -->
<a-back-top :target="getScrollContainer" />
<FileModal ref="fileModal" :current-company-id="currentCompanyId" />
<HistoryModal
v-model:visible="showHistory"
:interface-name="currentInterfaceName"
@select="handleHistorySelect"
/>
<!-- 文档选择弹窗 -->
</a-drawer>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, onMounted, onUnmounted, computed } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import { copyText } from '@/utils/common';
import { PwlProject } from '@/api/pwl/pwlProject/model';
import { RedoOutlined, RobotOutlined } from '@ant-design/icons-vue';
import {
generateAuditReport,
downloadAuditReport
} from '@/api/ai/auditReport';
import { getPwlProjectLibraryByIds } from '@/api/pwl/pwlProjectLibrary';
import {
generateTripleOneTable,
generateDecisionTable,
exportTripleOneTable,
exportDecisionTable
} from '@/api/ai/auditContent';
import FileModal from '@/views/pwl/pwlProject/components/components/FileModal.vue';
import TableSwitcher from '@/views/pwl/pwlProject/components/components/TableSwitcher.vue';
import navigationItems from './data/navigationItems';
import table1Columns from './data/table1Columns';
import table3Columns from './data/table3Columns';
import {
scrollToSection,
getScrollContainer,
handleKeydown,
handleScroll,
buildExportData,
hasContent
} from './data/funcs';
import HistoryModal from '@/views/pwl/pwlProject/components/components/HistoryModal.vue';
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: PwlProject | null;
}>();
// 是否显示最大化切换按钮
const maxAble = ref(true);
// 添加生成状态
const generatingAll = ref(false);
// 当前选中的章节
const currentSection = ref(0);
// 存储拼接后的 kbIds
const combinedKbIds = ref('');
// 九大审计项目导航配置
const table3Title = ref('重大经济决策调查表');
const table1Title = ref('贯彻决策部署');
// 存储两种表格的数据状态
const tripleOneTableData = ref([]);
const decisionTableData = ref([]);
// 文档选择相关变量
const showDocSelect = ref(false);
const currentSectionIndex = ref(2); // 默认是审计内容3
const selectedDocList = ref<string[]>([]);
const selectedFileList = ref<string[]>([]);
const selectedFileKeys = ref<(string | number)[]>([]);
const checkedDirKeys = ref<(string | number)[]>([]); // 新增勾选的目录keys
// 新增:保存上次选择的状态
const lastSelectedDirKeys = ref<(string | number)[]>([]);
const lastSelectedFileKeys = ref<(string | number)[]>([]);
// 文档管理相关变量
const currentCompanyId = ref<number>();
// 历史记录接口相关变量
const currentInterfaceName = ref('');
// 添加计算属性检查是否已生成三重一大数据
const hasTripleOneData = computed(() => {
const section = navigationItems.value[2];
return (
section.data &&
section.data.length > 0 &&
table3Title.value === '三重一大'
);
});
// 存储三重一大数据
const tripleOneData = ref(null);
// 添加导出状态
const exportingTripleOne = ref(false);
const exportingDecisionTable = ref(false);
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 订单信息
const form = reactive<PwlProject>({
// ID
id: undefined,
// 项目名称
name: undefined,
// 项目标识
code: undefined,
// 上级id, 0是顶级
parentId: undefined,
// 项目类型
type: undefined,
// 项目图标
image: undefined,
// 二维码
qrcode: undefined,
// 链接地址
url: undefined,
// 应用截图
images: undefined,
// 底稿情况
files: undefined,
// 应用介绍
content: undefined,
// 年末资产总额(万元)
totalAssets: undefined,
// 合同金额
contractPrice: undefined,
// 实收金额
payPrice: undefined,
// 软件定价
price: undefined,
// 是否推荐
recommend: undefined,
// 到期时间
expirationTime: undefined,
// 项目信息-开票单位/汇款人
itemName: undefined,
// 项目信息-年度
itemYear: undefined,
// 项目信息-类型
itemType: undefined,
// 项目信息-审计意见
itemOpinion: undefined,
// 到账信息-银行名称
bankName: undefined,
// 到账日期
bankPayTime: undefined,
// 到账金额
bankPrice: undefined,
// 发票类型
invoiceType: undefined,
// 开票日期
invoiceTime: undefined,
// 开票金额
invoicePrice: undefined,
// 报告份数
reportNum: undefined,
// 底稿人员
draftUserId: undefined,
// 底稿人员
draftUser: undefined,
// 参与成员
userIds: undefined,
users: undefined,
// 签字注会
signUserId: undefined,
signUser: undefined,
// 展业人员
saleUserId: undefined,
saleUser: undefined,
// 备注
comments: undefined,
// 排序(数字越小越靠前)
sortNumber: undefined,
// 状态, 0正常, 1冻结
status: undefined,
// 电子报告是否已完成
electron: undefined,
// 纸质报告是否已完成
paper: undefined,
// 是否删除, 0否, 1是
deleted: undefined,
// 创建人ID
userId: undefined,
// 创建人
realName: undefined,
// 租户id
tenantId: undefined,
// 创建时间
createTime: undefined,
// 修改时间
updateTime: undefined,
// 知识库id
kbId: undefined
});
// 请求状态
const loading = ref(true);
const { resetFields } = useForm(form);
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
/* 批量生成全部内容 */
// const handleGenerateAll2 = async () => {
// generatingAll.value = true;
// try {
// // 使用Promise.all进行并行生成
// const promises: Promise<void>[] = [];
//
// navigationItems.value.forEach((item: any, index) => {
// if (item.children) {
// // 有子项的章节,为每个子项生成内容
// item.children.forEach((child, childIndex) => {
// promises.push(generateContent(index, childIndex));
// });
// } else {
// // 没有子项的章节
// promises.push(generateContent(index));
// }
// });
//
// await Promise.all(promises);
// message.success('全部内容生成完成');
// } catch (error) {
// console.error('批量生成失败:', error);
// message.error('部分内容生成失败,请检查');
// } finally {
// generatingAll.value = false;
// }
// };
/* 批量生成全部内容 */
const handleGenerateAll = async () => {
generatingAll.value = true;
try {
// 改为顺序生成
for (const [index, item] of navigationItems.value.entries()) {
// 跳过未完成的依赖项
if (index === 4 && !hasContent(navigationItems.value[3])) {
message.warning('请先生成第四项「被审计单位基本情况」');
continue;
}
if (index === 5 && !hasContent(navigationItems.value[4])) {
message.warning('请先生成第五项「审计内容和重点及审计方法」');
continue;
}
if (item.children) {
for (const [childIndex] of item.children.entries()) {
await generateContent(index, childIndex);
}
} else {
await generateContent(index);
}
}
message.success('全部内容生成完成');
} catch (error) {
console.error('批量生成失败:', error);
message.error('部分内容生成失败,请检查');
} finally {
generatingAll.value = false;
}
};
/* 修改导出方法使用公共构建方法 */
const handleExport = async () => {
try {
const exportData = buildExportData();
const blob = await downloadAuditReport(exportData);
// 创建下载链接
const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `审计报告_${form.name}.docx`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
} catch (error) {
console.error('导出失败:', error);
message.error('文档导出失败');
}
};
/* 导出三重一大表格 */
const handleExportTripleOne = async () => {
const section = navigationItems.value[2];
if (!section.data || section.data.length === 0) {
message.warning('没有可导出的三重一大数据');
return;
}
exportingTripleOne.value = true;
try {
// 构建导出数据
const exportData = {
data: section.data,
companyName: form.name || '未知公司',
auditTime: form.expirationTime || '未知时间'
};
const blob = await exportTripleOneTable(exportData);
// 创建下载链接
const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute(
'download',
`三重一大制度对比分析表_${form.name || '未知公司'}.xlsx`
);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
message.success('三重一大表格导出成功');
} catch (error: any) {
console.error('导出三重一大表格失败:', error);
message.error('导出失败: ' + (error.message || '未知错误'));
} finally {
exportingTripleOne.value = false;
}
};
// 导出重大经济决策调查表
const handleExportDecisionTable = async () => {
const section = navigationItems.value[2];
if (!section.data || section.data.length === 0) {
message.warning('没有可导出的重大经济决策调查表数据');
return;
}
exportingDecisionTable.value = true;
try {
// 构建导出数据
const exportData = {
data: section.data,
companyName: form.name || '未知公司',
auditTime: form.expirationTime || '未知时间'
};
const blob = await exportDecisionTable(exportData);
// 创建下载链接
const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute(
'download',
`重大经济决策调查表_${form.name || '未知公司'}.xlsx`
);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
message.success('重大经济决策调查表导出成功');
} catch (error: any) {
console.error('导出重大经济决策调查表失败:', error);
message.error('导出失败: ' + (error.message || '未知错误'));
} finally {
exportingDecisionTable.value = false;
}
};
/* AI生成内容 */
const generateContent = async (sectionIndex: number, childIndex?: number) => {
// 特殊处理审计内容3根据当前表格类型调用不同的生成方法
if (sectionIndex === 2) {
const section: any = navigationItems.value[sectionIndex];
if (section.generateMethod) {
await section.generateMethod();
} else {
// 默认根据表格标题调用相应方法
if (table3Title.value === '三重一大') {
await generateContent3();
} else {
await generateDecisionContent();
}
}
return;
}
const section: any = navigationItems.value[sectionIndex];
// 处理主项生成当主项没有formCommit时
if (childIndex === undefined && !section.formCommit && section.children) {
section.generating = true;
try {
await Promise.all(
section.children.map((_, i) => generateContent(sectionIndex, i))
);
} finally {
section.generating = false;
}
return;
}
// 处理单个项生成
let item: any;
let formCommit: number;
const isChild = childIndex !== undefined;
if (isChild) {
item = section.children[childIndex];
formCommit = item.formCommit;
} else {
item = section;
formCommit = item.formCommit;
}
// 新增:构建上下文数据
const contextData = await buildExportData(); // 复用导出数据的构建逻辑
item.generating = true;
try {
item.content = await generateAuditReport({
kbId: form.kbId || '',
kbIds: combinedKbIds.value,
formCommit: formCommit,
history: item.content || '',
suggestion: item.suggestion || '',
// 新增:传递完整的上下文数据
...contextData
});
} finally {
item.generating = false;
}
};
// 三重一大生成方法
const generateContent3 = async () => {
const section: any = navigationItems.value[2];
section.generating = true;
// 构建history - 将当前已有的数据作为历史记录
const history =
section.data && section.data.length > 0
? JSON.stringify(section.data, null, 2)
: '';
// 获取用户输入的建议
const suggestion = section.suggestion || '';
console.log('生成三重一大参数:', {
kbIds: props.data?.kbId,
libraryIds: props.data?.libraryIds,
projectLibrary: props.data?.projectLibrary,
history: history ? `历史数据(${section.data.length}条)` : '无',
suggestion: suggestion || '无',
docList: checkedDirKeys.value, // 修复使用勾选的目录keys
fileList: selectedFileKeys.value // 修复使用勾选的文件keys
});
try {
// 构建请求参数对象
const requestData = {
kbIds: props.data?.kbId || '',
libraryIds: props.data?.libraryIds || '',
projectLibrary: props.data?.projectLibrary || '',
history: history,
suggestion: suggestion,
docList: checkedDirKeys.value, // 修复传入目录id数组
fileList: selectedFileKeys.value // 修复传入文件id数组
};
// 调用三重一大生成接口
const result = await generateTripleOneTable(requestData);
console.log('三重一大接口返回结果:', result);
if (result.code === 0 && result.data && result.data.success) {
const tableData = mapTripleOneData(result.data.data);
// 保存到三重一大数据
tripleOneTableData.value = tableData;
section.data = tableData;
// 保存三重一大数据用于Sheet1生成
tripleOneData.value = result.data.data;
// 生成成功后清空建议输入框
section.suggestion = '';
message.success(`成功生成 ${tableData.length} 条三重一大制度对比记录`);
} else {
const errorMsg = result.data?.error || result.message || '生成失败';
throw new Error(errorMsg);
}
} catch (error: any) {
console.error('生成三重一大制度对比分析表失败:', error);
message.error('生成失败: ' + (error.message || '未知错误'));
} finally {
section.generating = false;
}
};
// 添加生成重大经济决策调查表的方法
const generateDecisionContent = async () => {
const section: any = navigationItems.value[2];
section.generating = true;
// 构建history - 将当前已有的数据作为历史记录
const history =
section.data && section.data.length > 0
? JSON.stringify(section.data, null, 2)
: '';
// 获取用户输入的建议
const suggestion: any = section.suggestion || '';
console.log('生成重大经济决策调查表参数:', {
kbIds: props.data?.kbId,
libraryIds: props.data?.libraryIds,
projectLibrary: props.data?.projectLibrary,
history: history ? `历史数据(${section.data.length}条)` : '无',
suggestion: suggestion || '无',
data: tripleOneData.value
? `三重一大数据(${tripleOneData.value.length}条)`
: '无',
docList: checkedDirKeys.value,
fileList: selectedFileKeys.value
});
try {
// 构建请求参数对象
const requestData = {
kbIds: props.data?.kbId || '',
libraryIds: props.data?.libraryIds || '',
projectLibrary: props.data?.projectLibrary || '',
history: history,
suggestion: suggestion,
data: tripleOneData.value, // 传入三重一大数据
docList: checkedDirKeys.value,
fileList: selectedFileKeys.value
};
// 调用重大经济决策调查表生成接口
const result = await generateDecisionTable(requestData);
console.log('重大经济决策调查表接口返回结果:', result);
if (result.code === 0 && result.data && result.data.success) {
const tableData = mapDecisionTableData(result.data.data);
console.log('生成的表格数据:', tableData);
// 保存到重大经济决策调查表数据
decisionTableData.value = tableData;
section.data = tableData;
// 生成成功后清空建议输入框
section.suggestion = '';
message.success(`成功生成 ${tableData.length} 条重大经济决策调查记录`);
} else {
const errorMsg = result.data?.error || result.message || '生成失败';
throw new Error(errorMsg);
}
} catch (error: any) {
console.error('生成重大经济决策调查表失败:', error);
message.error('生成失败: ' + (error.message || '未知错误'));
} finally {
section.generating = false;
}
};
/* 保存编辑 */
const save = () => {};
// 打开文档选择弹窗
const fileModal = ref();
const openDocSelect = (sectionIndex: number) => {
currentSectionIndex.value = sectionIndex;
showDocSelect.value = true;
// 恢复上次选择的状态
checkedDirKeys.value = [...lastSelectedDirKeys.value];
selectedFileKeys.value = [...lastSelectedFileKeys.value];
selectedDocList.value = lastSelectedDirKeys.value.map((key) =>
key.toString()
);
selectedFileList.value = lastSelectedFileKeys.value.map((key) =>
key.toString()
);
// 加载文档目录
// loadAllCloudDocs();
fileModal.value.open();
};
const changeTable1 = (title) => {
table1Title.value = title;
const section: any = navigationItems.value[0];
if (title === '贯彻决策部署') {
section.columns = table1Columns.columns0;
section.data = tripleOneTableData.value || [];
section.generateMethod = generateContent3;
} else if (title === '领导班子名单') {
section.columns = table1Columns.columns1;
section.data = tripleOneTableData.value || [];
section.generateMethod = generateContent3;
} else {
section.columns = table1Columns.columns2;
section.data = decisionTableData.value || [];
section.generateMethod = generateDecisionContent;
}
};
// const file3List = ref([])
const changeTable3 = (title) => {
const section: any = navigationItems.value[2];
table3Title.value = title;
if (title === '三重一大') {
// 切换到三重一大表格
section.columns = table3Columns.columns0;
// 恢复三重一大数据,如果没有生成过则为空数组
section.data = tripleOneTableData.value || [];
// 更新生成方法
section.generateMethod = generateContent3;
} else {
// 切换到重大经济决策调查表
section.columns = table3Columns.columns1;
// 恢复重大经济决策调查表数据,如果没有生成过则为空数组
section.data = decisionTableData.value || [];
// 更新生成方法
section.generateMethod = generateDecisionContent;
}
};
/* 键盘快捷键处理 */
const handleKeydown = (event: KeyboardEvent) => {
// 只在弹窗打开时处理快捷键
if (!props.visible) return;
// Ctrl/Cmd + 数字键 1-9 快速跳转
if (
(event.ctrlKey || event.metaKey) &&
event.key >= '1' &&
event.key <= '9'
) {
event.preventDefault();
const index = parseInt(event.key) - 1;
if (index < navigationItems.value.length) {
scrollToSection(index);
currentSection.value = index;
}
}
// 上下箭头键导航
if (event.key === 'ArrowUp' && event.ctrlKey) {
event.preventDefault();
const prevIndex = Math.max(0, currentSection.value - 1);
scrollToSection(prevIndex);
currentSection.value = prevIndex;
} else if (event.key === 'ArrowDown' && event.ctrlKey) {
event.preventDefault();
const nextIndex = Math.min(
navigationItems.value.length - 1,
currentSection.value + 1
);
scrollToSection(nextIndex);
currentSection.value = nextIndex;
}
};
// 组件挂载时添加滚动监听和键盘监听
onMounted(() => {
const scrollContainer = getScrollContainer();
if (scrollContainer) {
scrollContainer.addEventListener('scroll', handleScroll);
}
document.addEventListener('keydown', handleKeydown);
});
// 组件卸载时移除监听
onUnmounted(() => {
const scrollContainer = getScrollContainer();
if (scrollContainer) {
scrollContainer.removeEventListener('scroll', handleScroll);
}
document.removeEventListener('keydown', handleKeydown);
});
watch(
() => props.visible,
async (visible) => {
if (visible) {
if (props.data) {
loading.value = true;
assignObject(form, props.data);
// 获取知识库并拼接 kbIds
if (props.data && props.data.libraryIds) {
if (props.data.libraryIds?.length > 0) {
try {
const result = await getPwlProjectLibraryByIds(
props.data.libraryIds
);
const kbIds = result
.map((lib) => lib.kbId)
.filter((kbId) => kbId);
if (form.kbId) {
kbIds.unshift(form.kbId);
}
combinedKbIds.value = kbIds.join(',');
} catch (error) {
console.error('获取知识库失败:', error);
combinedKbIds.value = form.kbId || '';
}
} else {
combinedKbIds.value = form.kbId || '';
}
}
// 设置当前公司ID用于文档管理
currentCompanyId.value = props.data.companyId;
// 重置到第一个章节
currentSection.value = 0;
}
} else {
resetFields();
combinedKbIds.value = ''; // 关闭时清空
}
}
);
// 数据映射工具函数
const mapTripleOneData = (data: any[]) => {
return data.map((item, index) => ({
key: index,
category: item.category || '',
policyContent: item.policyContent || '',
groupSystem: item.groupSystem || '',
companyFormulation: item.companyFormulation || '',
checkEvidence: item.checkEvidence || '',
testResult: item.testResult || '待检查',
workPaperIndex: item.workPaperIndex || []
}));
};
const mapDecisionTableData = (data: any[]) => {
return data.map((item, index) => ({
key: index,
index: index + 1,
name: item.decisionItem || item.name || '',
meetingTime: item.meetingTime || '',
decisionAmount: item.decisionAmount || '',
procedure: item.procedure || '',
executionStatus: item.executionStatus || '否',
goods: item.executionEffect?.good || item.goods || '否',
normal: item.executionEffect?.normal || item.normal || '否',
bad: item.executionEffect?.bad || item.bad || '否'
}));
};
// 应用历史记录数据到指定章节
const applyHistoryData = (sectionIndex: number, data: any[], dataType: 'tripleOne' | 'decisionTable') => {
const section = navigationItems.value[sectionIndex];
if (dataType === 'tripleOne') {
const tableData = mapTripleOneData(data);
section.data = tableData;
tripleOneTableData.value = tableData;
// 强制刷新当前显示的表格
if (table3Title.value === '三重一大') {
section.columns = table3Columns.columns0;
section.data = [...tableData];
}
} else {
const tableData = mapDecisionTableData(data);
section.data = tableData;
decisionTableData.value = tableData;
// 强制刷新当前显示的表格
if (table3Title.value === '重大经济决策调查表') {
section.columns = table3Columns.columns1;
section.data = [...tableData];
}
}
};
const showHistory = ref(false);
const openHistory = (sectionIndex: number) => {
// 重置接口名称
currentInterfaceName.value = '';
// 根据当前章节和表格类型确定接口名称
if (sectionIndex === 2) { // 审计内容3章节
if (table3Title.value === '三重一大') {
currentInterfaceName.value = '/api/ai/auditContent3/generateTripleOneTable';
} else if (table3Title.value === '重大经济决策调查表') {
currentInterfaceName.value = '/api/ai/auditContent3/generateDecisionTable';
}
}
showHistory.value = true;
};
// 历史记录选择处理方法
const handleHistorySelect = (record: any) => {
// 关闭历史记录弹窗
showHistory.value = false;
try {
const responseData = JSON.parse(record.responseData);
if (!responseData.success || !responseData.data) {
throw new Error('历史记录数据格式错误');
}
// 根据接口名称确定数据类型
if (record.interfaceName === '/api/ai/auditContent3/generateTripleOneTable') {
applyHistoryData(2, responseData.data, 'tripleOne');
message.success('已应用选择的三重一大历史记录');
} else if (record.interfaceName === '/api/ai/auditContent3/generateDecisionTable') {
applyHistoryData(2, responseData.data, 'decisionTable');
message.success('已应用选择的重大经济决策调查表历史记录');
} else {
message.warning('不支持的历史记录类型');
}
} catch (error) {
console.error('解析历史记录数据失败:', error);
message.error('历史记录数据解析失败');
}
};
</script>
<script lang="ts">
import * as MenuIcons from '@/layout/menu-icons';
export default {
name: 'PwlProjectInfo',
components: MenuIcons
};
</script>
<style lang="less" scoped>
@import './style/style.scss';
</style>