chore(config): 添加项目配置文件和隐私协议

- 新增 .editorconfig 文件统一代码风格配置
- 新增 .env 环境变量配置文件
- 添加开发和生产环境的环境变量配置
- 配置 ESLint 忽略规则文件
- 设置代码检查配置文件 .eslintrc.js
- 添加 Git 忽略文件规则
- 创建 Prettier 格式化忽略规则
- 添加隐私政策和服务协议HTML文件
- 实现访问密钥编辑组件基础结构
This commit is contained in:
2026-02-07 16:33:13 +08:00
commit 92a6a32868
1384 changed files with 224513 additions and 0 deletions

View File

@@ -0,0 +1,636 @@
<template>
<!-- 审计核查弹窗 -->
<a-drawer
:width="`90%`"
:visible="visible"
:confirm-loading="loading"
:maxable="true"
:title="`审计核查 - ${form.name || ''}`"
:body-style="{ paddingBottom: '8px', background: '#f5f5f5' }"
@update:visible="updateVisible"
:maskClosable="false"
:footer="null"
>
<div class="audit-container">
<!-- 顶部操作区 -->
<div class="action-bar">
<div class="title">审计发现问题情况表</div>
<div class="buttons">
<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">
<template #icon><PlusOutlined /></template>
新增问题
</a-button>
<a-button @click="generateProblems" :loading="generating" class="action-button">
<template #icon><RobotOutlined /></template>
AI生成问题
</a-button>
<a-button @click="exportExcel" class="action-button">
<template #icon><ExportOutlined /></template>
导出Excel
</a-button>
<a-button type="danger" @click="saveData" class="action-button">
<template #icon><SaveOutlined /></template>
保存数据
</a-button>
</a-space>
</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-table
:dataSource="problemList"
:columns="columns"
:scroll="{ x: 1800 }"
:pagination="false"
rowKey="id"
size="middle"
bordered
>
<template #bodyCell="{ column, record, index }">
<!-- 序号列 -->
<template v-if="column.dataIndex === 'index'">
{{ index + 1 }}
</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'">
<a-input-number
v-model:value="record.amount"
:min="0"
:precision="2"
style="width: 100%"
:bordered="false"
/>
</template>
<!-- 整改类型列 -->
<template v-if="column.dataIndex === 'rectificationType'">
<a-select
v-model:value="record.rectificationType"
style="width: 100%"
:bordered="false"
>
<a-select-option value="立行立改">立行立改</a-select-option>
<a-select-option value="限期整改">限期整改</a-select-option>
<a-select-option value="长期整改">长期整改</a-select-option>
</a-select>
</template>
<!-- 整改时限列 -->
<template v-if="column.dataIndex === 'deadline'">
<a-input
v-model:value="record.deadline"
style="width: 100%"
:bordered="false"
placeholder="如1个月"
/>
</template>
<!-- 操作列 -->
<template v-if="column.dataIndex === 'action'">
<a-space>
<a-button type="link" @click="editProblem(record)">
编辑
</a-button>
<a-button type="link" danger @click="deleteProblem(index)">
删除
</a-button>
</a-space>
</template>
</template>
</a-table>
</a-card>
<!-- 其他问题区域 -->
<a-card :bordered="false" class="other-problems-card">
<template #title>审计发现的其他问题未在报告正文反映</template>
<a-textarea
v-model:value="otherProblems"
:rows="4"
placeholder="请输入其他审计发现问题..."
/>
</a-card>
<!-- 问题编辑弹窗 -->
<a-modal
v-model:visible="showEditModal"
:title="editingProblem.id ? '编辑问题' : '新增问题'"
width="800px"
@ok="saveProblem"
@cancel="cancelEdit"
>
<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-textarea
v-model:value="editingProblem.problemDescription"
:rows="3"
placeholder="请输入问题表述"
/>
</a-form-item>
<a-form-item label="问题明细">
<a-textarea
v-model:value="editingProblem.problemDetails"
:rows="3"
placeholder="请输入问题明细"
/>
</a-form-item>
<a-form-item label="法规依据">
<a-textarea
v-model:value="editingProblem.legalBasis"
:rows="3"
placeholder="请输入法规依据"
/>
</a-form-item>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="涉及金额(万元)">
<a-input-number
v-model:value="editingProblem.amount"
:min="0"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="整改类型">
<a-select v-model:value="editingProblem.rectificationType">
<a-select-option value="立行立改">立行立改</a-select-option>
<a-select-option value="限期整改">限期整改</a-select-option>
<a-select-option value="长期整改">长期整改</a-select-option>
</a-select>
</a-form-item>
</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-form-item label="具体责任界定">
<a-textarea
v-model:value="editingProblem.responsibility"
:rows="2"
placeholder="请输入具体责任界定"
/>
</a-form-item>
<a-form-item label="整改要求">
<a-textarea
v-model:value="editingProblem.rectificationRequirement"
:rows="2"
placeholder="请输入整改要求"
/>
</a-form-item>
<a-form-item label="审计建议">
<a-textarea
v-model:value="editingProblem.auditSuggestion"
:rows="3"
placeholder="请输入审计建议"
/>
</a-form-item>
</a-form>
</a-modal>
</div>
</a-drawer>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { message } from 'ant-design-vue';
import type { UploadProps } from 'ant-design-vue';
import {
PlusOutlined,
RobotOutlined,
ExportOutlined,
SaveOutlined,
UploadOutlined,
PaperClipOutlined
} from '@ant-design/icons-vue';
import type { PwlProject } from '@/api/pwl/pwlProject/model';
import { generateAuditReport2 } from "@/api/ai/auditReport";
// Props 定义
const props = defineProps<{
visible: boolean;
data?: PwlProject | null;
}>();
// Emits 定义
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 表单数据
const form = reactive<PwlProject>({
id: undefined,
name: undefined,
code: undefined,
});
// 状态变量
const problemList = ref<any[]>([]);
const otherProblems = ref('');
const loading = ref(false);
const generating = ref(false);
const showEditModal = ref(false);
const fileList = ref<any[]>([]);
const editingProblem = ref<any>({
hasProblem: 'true',
problemDescription: '',
problemDetails: '',
legalBasis: '',
amount: 0,
responsibility: '',
rectificationType: '',
rectificationRequirement: '',
deadline: '',
auditSuggestion: ''
});
// 表格列定义 - 优化后
const columns = [
{
title: '序号',
dataIndex: 'index',
width: 60,
fixed: 'left'
},
{
title: '是否存在问题',
dataIndex: 'hasProblem',
width: 100,
fixed: 'left'
},
{
title: '问题表述',
dataIndex: 'problemDescription',
width: 200,
ellipsis: true
},
{
title: '问题明细',
dataIndex: 'problemDetails',
width: 200,
ellipsis: true
},
{
title: '法规依据',
dataIndex: 'legalBasis',
width: 200,
ellipsis: true
},
{
title: '涉及金额(万元)',
dataIndex: 'amount',
width: 120
},
{
title: '具体责任界定',
dataIndex: 'responsibility',
width: 150,
ellipsis: true
},
{
title: '整改类型',
dataIndex: 'rectificationType',
width: 120
},
{
title: '整改要求',
dataIndex: 'rectificationRequirement',
width: 150,
ellipsis: true
},
{
title: '整改时限',
dataIndex: 'deadline',
width: 120
},
{
title: '审计建议',
dataIndex: 'auditSuggestion',
width: 150,
ellipsis: true
},
{
title: '操作',
dataIndex: 'action',
width: 120,
fixed: 'right'
}
];
// 上传前处理
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
// 添加到文件列表
fileList.value = [file];
return false; // 阻止自动上传
};
// 删除文件
const removeFile = (uid: string) => {
fileList.value = fileList.value.filter(file => file.uid !== uid);
};
// 更新visible
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 新增问题
const addProblem = () => {
editingProblem.value = {
hasProblem: 'true',
problemDescription: '',
problemDetails: '',
legalBasis: '',
amount: 0,
responsibility: '',
rectificationType: '',
rectificationRequirement: '',
deadline: '',
auditSuggestion: ''
};
showEditModal.value = true;
};
// 编辑问题
const editProblem = (problem: any) => {
editingProblem.value = { ...problem };
showEditModal.value = true;
};
// 保存问题
const saveProblem = () => {
if (!editingProblem.value.problemDescription) {
message.warning('请输入问题表述');
return;
}
if (!editingProblem.value.id) {
editingProblem.value.id = Date.now();
problemList.value.push({ ...editingProblem.value });
} else {
const index = problemList.value.findIndex(p => p.id === editingProblem.value.id);
if (index !== -1) {
problemList.value[index] = { ...editingProblem.value };
}
}
message.success('保存成功');
showEditModal.value = false;
};
// 取消编辑
const cancelEdit = () => {
showEditModal.value = false;
};
// 删除问题
const deleteProblem = (index: number) => {
problemList.value.splice(index, 1);
message.success('删除成功');
};
// AI生成问题 - 优化版
const generateProblems = async () => {
// 检查是否有上传文件
if (fileList.value.length === 0) {
message.warning('请先上传附件文件');
return;
}
generating.value = true;
try {
console.log('当前行数据:', props.data);
console.log('项目名称:', props.data?.name);
console.log('项目编号:', props.data?.code);
console.log('分析文库:', props.data?.analysisLibrary);
console.log('项目文库1:', props.data?.projectLibrary);
console.log('项目文库2:', props.data?.kbId);
console.log('项目文库3:', props.data?.libraryIds);
// 获取上传的文件
const fileItem = fileList.value[0];
const file = fileItem.originFileObj || fileItem;
// 调用后端接口
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;
}
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 {
generating.value = false;
}
};
// 导出Excel
const exportExcel = () => {
message.info('导出功能开发中...');
};
// 保存数据
const saveData = () => {
const dataToSave = {
problems: problemList.value,
otherProblems: otherProblems.value
};
console.log('保存的数据:', dataToSave);
message.success('数据保存成功');
};
// 加载审计核查数据
const loadAuditCheckData = () => {
problemList.value = [];
otherProblems.value = '';
fileList.value = [];
};
// 监听数据变化
watch(
() => props.data,
(data) => {
if (data) {
Object.assign(form, data);
loadAuditCheckData();
}
}
);
</script>
<style lang="less" scoped>
.audit-container {
.action-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
background: white;
padding: 16px;
border-radius: 4px;
.title {
font-size: 16px;
font-weight: bold;
color: #1890ff;
}
.action-button {
border-radius: 20px;
transition: all 0.3s ease;
&:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
}
}
}
.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 {
margin-bottom: 16px;
:deep(.ant-table) {
.ant-table-thead > tr > th {
background: #1890ff;
color: white;
text-align: center;
}
.ant-table-tbody > tr > td {
.ant-input,
.ant-input-number-input,
.ant-select-selector,
.ant-picker {
&:hover {
background: #f5f5f5;
}
}
}
.ant-table-row:hover {
.ant-input,
.ant-input-number-input,
.ant-select-selector,
.ant-picker {
background: #f5f5f5;
}
}
}
}
.other-problems-card {
:deep(.ant-card-head) {
background: #fff2e8;
border-bottom: 1px solid #ffd8bf;
}
:deep(.ant-card-head-title) {
color: #873800;
font-weight: bold;
}
}
}
</style>