chore(config): 添加项目配置文件和隐私协议
- 新增 .editorconfig 文件统一代码风格配置 - 新增 .env 环境变量配置文件 - 添加开发和生产环境的环境变量配置 - 配置 ESLint 忽略规则文件 - 设置代码检查配置文件 .eslintrc.js - 添加 Git 忽略文件规则 - 创建 Prettier 格式化忽略规则 - 添加隐私政策和服务协议HTML文件 - 实现访问密钥编辑组件基础结构
This commit is contained in:
296
src/views/pwl/pwlProject/components/EditModal.vue
Normal file
296
src/views/pwl/pwlProject/components/EditModal.vue
Normal file
@@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
title="编辑行数据"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
:confirm-loading="loading"
|
||||
width="600px"
|
||||
>
|
||||
<template #title>
|
||||
<div class="modal-title">
|
||||
<span>编辑行数据</span>
|
||||
<a-tag v-if="displayRecords.length > 1" color="blue" class="ml-2">
|
||||
同步编辑 {{ displayRecords.length }} 条
|
||||
</a-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<a-alert
|
||||
v-if="displayRecords.length > 1"
|
||||
type="info"
|
||||
show-icon
|
||||
style="margin-bottom: 12px"
|
||||
:message="`已选择 ${displayRecords.length} 条记录,将把当前修改同步到这些记录`"
|
||||
/>
|
||||
<a-list
|
||||
v-if="displayRecords.length > 1"
|
||||
size="small"
|
||||
bordered
|
||||
:data-source="displayRecords"
|
||||
style="margin-bottom: 12px; max-height: 160px; overflow-y: auto"
|
||||
>
|
||||
<template #renderItem="{ item, index }">
|
||||
<a-list-item
|
||||
:class="['record-item', { active: index === selectedRecordIndex }]"
|
||||
@click="selectRecord(index)"
|
||||
>
|
||||
<span class="record-label">#{{ index + 1 }}</span>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
|
||||
<a-form layout="vertical">
|
||||
<template v-for="field in processedFields" :key="field.key">
|
||||
<a-form-item :label="field.title" v-if="!field.children">
|
||||
<template v-if="field.type === 'textarea'">
|
||||
<a-textarea
|
||||
v-model:value="activeFormData[field.dataIndex]"
|
||||
:rows="4"
|
||||
:placeholder="`请输入${field.title}`"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="field.dataIndex === 'workPaperIndex'">
|
||||
<a-textarea
|
||||
v-model:value="activeFormData[field.dataIndex]"
|
||||
:rows="4"
|
||||
:placeholder="'每行一个文件,格式为:file_id||文件名||url'"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-input
|
||||
v-model:value="activeFormData[field.dataIndex]"
|
||||
:placeholder="`请输入${field.title}`"
|
||||
/>
|
||||
</template>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 处理嵌套字段(如职务下的党内、行政) -->
|
||||
<template v-else-if="field.children">
|
||||
<div class="nested-fields">
|
||||
<div class="field-group-title">{{ field.title }}</div>
|
||||
<div class="field-group-content">
|
||||
<a-form-item
|
||||
v-for="childField in field.children"
|
||||
:key="childField.key"
|
||||
:label="childField.title"
|
||||
class="nested-field-item"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="activeFormData[childField.dataIndex]"
|
||||
:placeholder="`请输入${childField.title}`"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
record: any;
|
||||
fields: any[];
|
||||
records?: any[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:visible', 'save']);
|
||||
|
||||
const loading = ref(false);
|
||||
const formDataList = ref<any[]>([]);
|
||||
const selectedRecordIndex = ref(0);
|
||||
|
||||
const displayRecords = computed(() => {
|
||||
if (props.records && Array.isArray(props.records) && props.records.length) {
|
||||
return props.records;
|
||||
}
|
||||
if (props.record) return [props.record];
|
||||
return [];
|
||||
});
|
||||
|
||||
const transformRecordToFormData = (record: any) => {
|
||||
if (!record) return {};
|
||||
const recordCopy = JSON.parse(JSON.stringify(record));
|
||||
|
||||
if (
|
||||
hasWorkPaperIndexField.value &&
|
||||
recordCopy.workPaperIndex &&
|
||||
Array.isArray(recordCopy.workPaperIndex)
|
||||
) {
|
||||
recordCopy.workPaperIndex = recordCopy.workPaperIndex
|
||||
.map((item: any) => {
|
||||
if (typeof item === 'object') {
|
||||
return `${item.fileId || ''}||${item.fileName || ''}||${item.fileUrl || ''}`;
|
||||
}
|
||||
return item;
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
return recordCopy;
|
||||
};
|
||||
|
||||
const hasWorkPaperIndexField = computed(() => {
|
||||
return (props.fields || []).some((field) => {
|
||||
return field?.dataIndex === 'workPaperIndex' || field?.key === 'workPaperIndex';
|
||||
});
|
||||
});
|
||||
|
||||
// 处理字段,将嵌套结构展平
|
||||
const processedFields = computed(() => {
|
||||
const processed: any[] = [];
|
||||
|
||||
(props.fields || []).forEach(field => {
|
||||
if (field.children && Array.isArray(field.children)) {
|
||||
// 处理有子字段的情况(如职务)
|
||||
processed.push({
|
||||
...field,
|
||||
children: field.children.flatMap(child =>
|
||||
child.children && Array.isArray(child.children)
|
||||
? child.children // 如果是多层嵌套,直接取孙子字段
|
||||
: child // 否则就是子字段
|
||||
)
|
||||
});
|
||||
} else {
|
||||
processed.push(field);
|
||||
}
|
||||
});
|
||||
|
||||
return processed;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
selectedRecordIndex.value = 0;
|
||||
formDataList.value = displayRecords.value.map((rec) =>
|
||||
transformRecordToFormData(rec)
|
||||
);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const handleOk = () => {
|
||||
if (!formDataList.value || formDataList.value.length === 0) {
|
||||
message.warning('没有数据可保存');
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理workPaperIndex:将字符串转换回对象数组
|
||||
const dataToSave = formDataList.value.map((item) => {
|
||||
const cloned = JSON.parse(JSON.stringify(item || {}));
|
||||
if (hasWorkPaperIndexField.value && cloned.workPaperIndex && typeof cloned.workPaperIndex === 'string') {
|
||||
const lines = cloned.workPaperIndex.split('\n').filter((line: string) => line.trim() !== '');
|
||||
cloned.workPaperIndex = lines.map((line: string) => {
|
||||
const parts = line.split('||');
|
||||
if (parts.length >= 3) {
|
||||
return {
|
||||
fileId: parts[0] || '',
|
||||
fileName: parts[1] || '',
|
||||
fileUrl: parts[2] || ''
|
||||
};
|
||||
}
|
||||
return line;
|
||||
});
|
||||
}
|
||||
return cloned;
|
||||
});
|
||||
|
||||
loading.value = true;
|
||||
emit('save', dataToSave);
|
||||
loading.value = false;
|
||||
emit('update:visible', false);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false);
|
||||
};
|
||||
|
||||
const selectRecord = (index: number) => {
|
||||
if (index < 0 || index >= displayRecords.value.length) return;
|
||||
selectedRecordIndex.value = index;
|
||||
if (!formDataList.value[index]) {
|
||||
formDataList.value[index] = transformRecordToFormData(
|
||||
displayRecords.value[index]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const activeFormData = computed({
|
||||
get() {
|
||||
if (!displayRecords.value.length) return {};
|
||||
if (!formDataList.value[selectedRecordIndex.value]) {
|
||||
formDataList.value[selectedRecordIndex.value] = transformRecordToFormData(
|
||||
displayRecords.value[selectedRecordIndex.value]
|
||||
);
|
||||
}
|
||||
return formDataList.value[selectedRecordIndex.value] || {};
|
||||
},
|
||||
set(val) {
|
||||
if (!displayRecords.value.length) return;
|
||||
formDataList.value[selectedRecordIndex.value] = val || {};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.nested-fields {
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.field-group-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.field-group-content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.nested-field-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.record-label {
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.record-text {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.record-item {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.record-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.record-item.active {
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
</style>
|
||||
82
src/views/pwl/pwlProject/components/Import.vue
Normal file
82
src/views/pwl/pwlProject/components/Import.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<!-- 用户导入弹窗 -->
|
||||
<template>
|
||||
<ele-modal
|
||||
:width="520"
|
||||
:footer="null"
|
||||
title="批量导入"
|
||||
:visible="visible"
|
||||
@update:visible="updateVisible"
|
||||
>
|
||||
<a-spin :spinning="loading">
|
||||
<a-upload-dragger
|
||||
accept=".xls,.xlsx"
|
||||
:show-upload-list="false"
|
||||
:customRequest="doUpload"
|
||||
style="padding: 24px 0; margin-bottom: 16px"
|
||||
>
|
||||
<p class="ant-upload-drag-icon">
|
||||
<cloud-upload-outlined />
|
||||
</p>
|
||||
<p class="ant-upload-hint">将文件拖到此处,或点击上传</p>
|
||||
</a-upload-dragger>
|
||||
</a-spin>
|
||||
<div class="ele-text-center">
|
||||
<span>只能上传xls、xlsx文件,导入模板和导出模板格式一致</span>
|
||||
</div>
|
||||
</ele-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { CloudUploadOutlined } from '@ant-design/icons-vue';
|
||||
import {importPwlProject} from "@/api/pwl/pwlProject";
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'done'): void;
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
defineProps<{
|
||||
// 是否打开弹窗
|
||||
visible: boolean;
|
||||
}>();
|
||||
|
||||
// 导入请求状态
|
||||
const loading = ref(false);
|
||||
|
||||
/* 上传 */
|
||||
const doUpload = ({ file }) => {
|
||||
if (
|
||||
![
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
].includes(file.type)
|
||||
) {
|
||||
message.error('只能选择 excel 文件');
|
||||
return false;
|
||||
}
|
||||
if (file.size / 1024 / 1024 > 10) {
|
||||
message.error('大小不能超过 10MB');
|
||||
return false;
|
||||
}
|
||||
loading.value = true;
|
||||
importPwlProject(file)
|
||||
.then((msg) => {
|
||||
loading.value = false;
|
||||
message.success(msg);
|
||||
updateVisible(false);
|
||||
emit('done');
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
/* 更新 visible */
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
</script>
|
||||
636
src/views/pwl/pwlProject/components/auditCheck.vue
Normal file
636
src/views/pwl/pwlProject/components/auditCheck.vue
Normal 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>
|
||||
847
src/views/pwl/pwlProject/components/components/EvidenceModal.vue
Normal file
847
src/views/pwl/pwlProject/components/components/EvidenceModal.vue
Normal file
@@ -0,0 +1,847 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
title="审计取证单预览"
|
||||
:width="1100"
|
||||
:footer="null"
|
||||
@cancel="handleCancel"
|
||||
destroy-on-close
|
||||
>
|
||||
<div class="evidence-actions">
|
||||
<a-space>
|
||||
<a-button @click="resetFields">重置内容</a-button>
|
||||
<a-button type="primary" @click="handleExport" :loading="exporting">
|
||||
导出Word文档
|
||||
</a-button>
|
||||
<a-button v-if="false" @click="printEvidence">打印预览</a-button>
|
||||
</a-space>
|
||||
<div class="action-tip"
|
||||
>可直接在表格中编辑,导出即可生成与效果图一致的取证单</div
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="evidence-container">
|
||||
<div class="evidence-sheet" ref="printArea">
|
||||
<div class="sheet-title">审计取证单</div>
|
||||
<div class="sheet-meta">
|
||||
<div class="meta-left">
|
||||
<span>索引号:</span>
|
||||
<input
|
||||
v-model="form.caseIndex"
|
||||
class="inline-input long"
|
||||
placeholder="填写索引号"
|
||||
/>
|
||||
</div>
|
||||
<div class="meta-right">
|
||||
<span>第</span>
|
||||
<input v-model="form.pageIndex" class="inline-input small" />
|
||||
<span>页(共</span>
|
||||
<input v-model="form.pageTotal" class="inline-input small" />
|
||||
<span>页)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="sheet-table">
|
||||
<colgroup>
|
||||
<col style="width: 16%" />
|
||||
<col style="width: 84%" />
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>项目名称</th>
|
||||
<td>
|
||||
<textarea
|
||||
v-model="form.projectName"
|
||||
class="cell-input single"
|
||||
placeholder="填写项目名称"
|
||||
></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>被审计(调查)单位或个人</th>
|
||||
<td>
|
||||
<textarea
|
||||
v-model="form.auditedTarget"
|
||||
class="cell-input single"
|
||||
placeholder="填写被审计(调查)单位或个人"
|
||||
></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>审计(调查)事项</th>
|
||||
<td>
|
||||
<textarea
|
||||
v-model="form.auditMatter"
|
||||
class="cell-input single"
|
||||
placeholder="填写审计(调查)事项"
|
||||
></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th class="vertical-header">
|
||||
<div class="vertical-text">
|
||||
<span>审计</span>
|
||||
<span>(调查)</span>
|
||||
<span>事项</span>
|
||||
<span>摘要</span>
|
||||
</div>
|
||||
</th>
|
||||
<td class="summary-cell">
|
||||
<div class="summary-title">
|
||||
审计(调查)事项摘要包括:标题、审计记录、审计发现、定性依据。
|
||||
</div>
|
||||
<!-- <div class="summary-content">-->
|
||||
<!-- <div class="summary-item">-->
|
||||
<!-- <strong>1.标题:</strong-->
|
||||
<!-- >突出核心问题,采用观点性语句,一般为审计内容、审计目标的结论性描述。例如:-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="summary-example">-->
|
||||
<!-- 在审计期间,XX单位存在"服务费,其流通"行为。-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="summary-item">-->
|
||||
<!-- <strong>2.审计记录:</strong-->
|
||||
<!-- >仅客观记录审计核查的具体事实(时间、地点、主体、行为、数据等);不使用主观评价性语言(如"违规""不合理")或问题定性(引证合同条款、凭证等等原始凭证形式:"经核查[凭证描述]……"例如:-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="summary-example">-->
|
||||
<!-- ①-->
|
||||
<!-- 经查2019年1月1日签订的《XX服务合同》(编号:XYZ-2019-001)第3条约定:"乙方(服务商)员工薪酬中甲方考勤费,甲方有权对乙方员工薪酬进行审核并支付"。-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="summary-example">-->
|
||||
<!-- ②-->
|
||||
<!-- 调取2019年6月外包人员考勤表显示:实际出勤人数为8人,缺勤2人由甲方部门主管确认,缺勤2人由甲方资源部核实无。-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="summary-example">-->
|
||||
<!-- ③-->
|
||||
<!-- 查证2020年3月服务费结算凭证(凭证号:FV20200315):所附明细清单显示人员名单为8人且月计薪资×□工资标准结算费用。-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div class="summary-editor">
|
||||
<div class="summary-field">
|
||||
<div class="summary-field-label">标题:</div>
|
||||
<textarea
|
||||
v-model="form.summaryTitle"
|
||||
class="cell-input summary-textarea medium"
|
||||
placeholder="填写核心标题或要点"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="summary-field">
|
||||
<div class="summary-field-label">审计记录:</div>
|
||||
<textarea
|
||||
v-model="form.auditRecord"
|
||||
class="cell-input summary-textarea tall"
|
||||
placeholder="客观记录审计核查的过程与事实"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="summary-field">
|
||||
<div class="summary-field-label">审计发现:</div>
|
||||
<textarea
|
||||
v-model="form.auditFinding"
|
||||
class="cell-input summary-textarea tall"
|
||||
placeholder="写明审计发现的事实、性质及影响"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="summary-field">
|
||||
<div class="summary-field-label">定性依据:</div>
|
||||
<textarea
|
||||
v-model="form.evidenceBasis"
|
||||
class="cell-input summary-textarea medium"
|
||||
placeholder="引用法规、制度或合同条款作为依据"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>处理建议</th>
|
||||
<td>
|
||||
<textarea
|
||||
v-model="form.handling"
|
||||
class="cell-input medium"
|
||||
placeholder="拟采取的处理措施"
|
||||
></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>附件</th>
|
||||
<td>
|
||||
<textarea
|
||||
v-model="form.attachment"
|
||||
class="cell-input single"
|
||||
placeholder="列示随附的证明材料"
|
||||
></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>审计人员</th>
|
||||
<td>
|
||||
<div class="split-row">
|
||||
<div class="split-left">
|
||||
<input
|
||||
v-model="form.auditors"
|
||||
class="cell-input input-line"
|
||||
placeholder="填写审计人员"
|
||||
/>
|
||||
</div>
|
||||
<div class="split-right">
|
||||
<span class="label">编制日期:</span>
|
||||
<input
|
||||
v-model="form.compileDate"
|
||||
class="cell-input input-line"
|
||||
placeholder="YYYY-MM-DD"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>证据提供单位或个人意见</th>
|
||||
<td>
|
||||
<div class="provider-row">
|
||||
<div class="provider-opinion">
|
||||
<textarea
|
||||
v-model="form.providerOpinion"
|
||||
class="cell-input tall"
|
||||
placeholder="证据提供单位盖章,负责人或其他定的人员签名"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="provider-date">
|
||||
<div class="date-label">日期</div>
|
||||
<input
|
||||
v-model="form.providerDate"
|
||||
class="cell-input input-line"
|
||||
placeholder="YYYY-MM-DD"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="footer-note">
|
||||
<div class="note-row">
|
||||
附件:
|
||||
<input
|
||||
v-model="form.attachmentPages"
|
||||
class="inline-input small"
|
||||
placeholder="页数"
|
||||
/>
|
||||
页
|
||||
</div>
|
||||
<div class="note">
|
||||
说明:1. 请你单位在
|
||||
<input
|
||||
v-model="form.feedbackDeadline"
|
||||
class="inline-input long"
|
||||
placeholder="填写反馈期限"
|
||||
/>
|
||||
前反馈意见,以生成的编制日期为基础,往后推10天填充日期;
|
||||
</div>
|
||||
<!-- <div class="note">-->
|
||||
<!-- 2. 证据提供单位意见栏如填写不下,可另附说明。-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { PropType, reactive, ref, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { PwlProject } from '@/api/pwl/pwlProject/model';
|
||||
import { downloadAuditEvidence } from '@/api/ai/auditContent';
|
||||
|
||||
type BaseInfo = {
|
||||
caseIndex?: string;
|
||||
projectName?: string;
|
||||
auditedTarget?: string;
|
||||
auditMatter?: string;
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
baseInfo: {
|
||||
type: Object as PropType<BaseInfo>,
|
||||
default: () => ({})
|
||||
},
|
||||
project: {
|
||||
type: Object as PropType<PwlProject>,
|
||||
default: () => ({})
|
||||
},
|
||||
selectedRows: {
|
||||
type: Array as PropType<any[]>,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', value: boolean): void;
|
||||
}>();
|
||||
|
||||
const printArea = ref<HTMLElement | null>(null);
|
||||
const exporting = ref(false);
|
||||
|
||||
const defaultForm = () => ({
|
||||
caseIndex: '',
|
||||
pageIndex: '1',
|
||||
pageTotal: '1',
|
||||
projectName: '',
|
||||
auditedTarget: '',
|
||||
auditMatter: '',
|
||||
summaryTitle: '',
|
||||
auditRecord: '',
|
||||
auditFinding: '',
|
||||
evidenceBasis: '',
|
||||
handling: '',
|
||||
suggestion: '',
|
||||
attachment: '',
|
||||
auditors: '',
|
||||
compileDate: '',
|
||||
providerOpinion: '',
|
||||
providerDate: '',
|
||||
attachmentPages: '',
|
||||
feedbackDeadline: ''
|
||||
});
|
||||
|
||||
const form = reactive(defaultForm());
|
||||
|
||||
const formatAttachmentText = (caseIndex: string, raw: string) => {
|
||||
const safeCaseIndex = (caseIndex || '').trim();
|
||||
const items = (raw || '')
|
||||
.split(/[\n\r,,、;;\s]+/)
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
if (!safeCaseIndex || items.length === 0) return raw || '';
|
||||
|
||||
const escaped = safeCaseIndex.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const prefixRe = new RegExp(`^${escaped}-\\d{3}-`);
|
||||
return items
|
||||
.map((name, idx) => {
|
||||
const no = String(idx + 1).padStart(3, '0');
|
||||
const baseName = name.replace(prefixRe, '');
|
||||
return `${safeCaseIndex}-${no}-${baseName}`;
|
||||
})
|
||||
.join('\n');
|
||||
};
|
||||
|
||||
const applyBaseInfo = () => {
|
||||
console.log('applyBaseInfo called, selectedRows:', props.selectedRows);
|
||||
console.log('baseInfo:', props.baseInfo);
|
||||
|
||||
// 重置表单为默认值
|
||||
Object.assign(form, defaultForm(), props.baseInfo || {});
|
||||
|
||||
// 如果有传入的selectedRows,直接使用第一个对象的数据(生成取证单时通常只有一个)
|
||||
if (props.selectedRows && props.selectedRows.length > 0) {
|
||||
const evidenceData = props.selectedRows[0] || {};
|
||||
console.log('Evidence data from selectedRows:', evidenceData);
|
||||
|
||||
// 直接将后端返回的数据映射到表单字段
|
||||
form.caseIndex =
|
||||
props.baseInfo?.caseIndex || props.project?.caseIndex || form.caseIndex || '';
|
||||
form.projectName = props.project?.code || evidenceData.projectName || form.projectName || '';
|
||||
form.auditedTarget =
|
||||
evidenceData.auditedTarget || form.auditedTarget || '';
|
||||
form.auditMatter = evidenceData.auditMatter || form.auditMatter || '';
|
||||
form.summaryTitle = evidenceData.summaryTitle || form.summaryTitle || '';
|
||||
form.auditRecord = evidenceData.auditRecord || form.auditRecord || '';
|
||||
form.auditFinding = evidenceData.auditFinding || form.auditFinding || '';
|
||||
form.evidenceBasis =
|
||||
evidenceData.evidenceBasis || form.evidenceBasis || '';
|
||||
form.handling = evidenceData.handling || form.handling || '';
|
||||
form.suggestion = evidenceData.suggestion || form.suggestion || '';
|
||||
// form.auditors = evidenceData.auditors || form.auditors || '';
|
||||
form.auditors = '';
|
||||
if (props.project && props.project.saleUser) {
|
||||
const saleUser = JSON.parse(props.project.saleUser);
|
||||
form.auditors = saleUser.join();
|
||||
}
|
||||
form.compileDate = evidenceData.compileDate || form.compileDate || '';
|
||||
// form.providerOpinion =
|
||||
// evidenceData.providerOpinion || form.providerOpinion || '';
|
||||
// form.providerDate = evidenceData.providerDate || form.providerDate || '';
|
||||
form.providerOpinion = '';
|
||||
form.providerDate = '';
|
||||
form.attachmentPages =
|
||||
evidenceData.attachmentPages || form.attachmentPages || '';
|
||||
// form.feedbackDeadline =
|
||||
// evidenceData.feedbackDeadline || form.feedbackDeadline || '';
|
||||
form.feedbackDeadline = 'XX年XX月XX日';
|
||||
// 处理attachment字段(数组转字符串)
|
||||
if (evidenceData.attachment) {
|
||||
const rawAttachment = Array.isArray(evidenceData.attachment)
|
||||
? evidenceData.attachment.join('\n')
|
||||
: evidenceData.attachment;
|
||||
form.attachment = formatAttachmentText(form.caseIndex, rawAttachment);
|
||||
}
|
||||
|
||||
// 特殊处理:如果evidenceData中有title字段,也填充到summaryTitle
|
||||
if (evidenceData.title && !form.summaryTitle) {
|
||||
form.summaryTitle = evidenceData.title;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认编制日期(如果没有的话)
|
||||
if (!form.compileDate) {
|
||||
const now = new Date();
|
||||
form.compileDate = `${now.getFullYear()}-${String(
|
||||
now.getMonth() + 1
|
||||
).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
// 确保页码字段有值
|
||||
if (!form.pageIndex) form.pageIndex = '1';
|
||||
if (!form.pageTotal) form.pageTotal = '1';
|
||||
|
||||
console.log(
|
||||
'Form data after applyBaseInfo:',
|
||||
JSON.stringify(form, null, 2)
|
||||
);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
applyBaseInfo();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.baseInfo,
|
||||
() => {
|
||||
if (props.visible) {
|
||||
applyBaseInfo();
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.project,
|
||||
() => {
|
||||
if (props.visible) {
|
||||
applyBaseInfo();
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.selectedRows,
|
||||
() => {
|
||||
if (props.visible) {
|
||||
applyBaseInfo();
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false);
|
||||
};
|
||||
|
||||
const resetFields = () => {
|
||||
applyBaseInfo();
|
||||
message.success('内容已重置');
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出Word文档
|
||||
*/
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
exporting.value = true;
|
||||
|
||||
// 准备导出数据
|
||||
const exportData = {
|
||||
caseIndex: form.caseIndex,
|
||||
pageIndex: form.pageIndex,
|
||||
pageTotal: form.pageTotal,
|
||||
projectName: form.projectName,
|
||||
auditedTarget: form.auditedTarget,
|
||||
auditMatter: form.auditMatter,
|
||||
summaryTitle: form.summaryTitle,
|
||||
auditRecord: form.auditRecord,
|
||||
auditFinding: form.auditFinding,
|
||||
evidenceBasis: form.evidenceBasis,
|
||||
handling: form.handling,
|
||||
attachment: form.attachment,
|
||||
auditors: form.auditors,
|
||||
compileDate: form.compileDate,
|
||||
providerOpinion: form.providerOpinion,
|
||||
providerDate: form.providerDate,
|
||||
attachmentPages: form.attachmentPages,
|
||||
feedbackDeadline: form.feedbackDeadline
|
||||
};
|
||||
|
||||
// 调用后端下载接口
|
||||
const blob = await downloadAuditEvidence(exportData);
|
||||
|
||||
// 创建下载链接
|
||||
const url = window.URL.createObjectURL(new Blob([blob]));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
|
||||
// 设置文件名
|
||||
const fileName = `审计取证单_${form.projectName || '取证单'}_${form.caseIndex || ''}.docx`;
|
||||
link.setAttribute('download', fileName);
|
||||
|
||||
// 触发下载
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
// 释放URL对象
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
message.success('取证单导出成功');
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error);
|
||||
message.error('取证单导出失败');
|
||||
} finally {
|
||||
exporting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 打印预览
|
||||
*/
|
||||
const printEvidence = () => {
|
||||
const area = printArea.value;
|
||||
if (!area) {
|
||||
message.warning('暂无可打印的内容');
|
||||
return;
|
||||
}
|
||||
|
||||
const newWindow = window.open('', '_blank');
|
||||
if (!newWindow) {
|
||||
message.error('浏览器阻止了弹窗,请允许弹窗后重试');
|
||||
return;
|
||||
}
|
||||
|
||||
const style = `
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; padding: 12px; font-family: 'SimSun', 'Songti SC', serif; color: #000; }
|
||||
.evidence-sheet { padding: 14px 16px; border: 1px solid #000; }
|
||||
.sheet-title { text-align: center; font-size: 24px; letter-spacing: 8px; margin-bottom: 6px; font-weight: 700; }
|
||||
.sheet-meta { display: flex; justify-content: space-between; align-items: flex-end; font-size: 14px; margin-bottom: 8px; }
|
||||
.meta-left, .meta-right { display: flex; align-items: flex-end; gap: 4px; }
|
||||
.inline-input { border: none; border-bottom: 1px solid #000; min-width: 70px; padding: 2px 4px; font-size: 14px; background: transparent; outline: none; height: 20px; line-height: 20px; }
|
||||
.inline-input.small { width: 44px; text-align: center; }
|
||||
.inline-input.long { min-width: 180px; }
|
||||
.sheet-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
||||
.sheet-table th, .sheet-table td { border: 1px solid #000; padding: 6px 8px; vertical-align: top; font-size: 14px; line-height: 1.6; }
|
||||
.sheet-table th { background: #fff; font-weight: 600; text-align: center; vertical-align: middle; }
|
||||
.vertical-header { padding: 4px 2px; font-weight: 600; }
|
||||
.vertical-text { display: flex; flex-direction: column; align-items: center; gap: 2px; }
|
||||
.vertical-text span { display: block; line-height: 1.1; }
|
||||
.cell-input { width: 100%; border: none; resize: none; min-height: 32px; font-size: 14px; line-height: 1.6; font-family: inherit; background: transparent; overflow: hidden; field-sizing: content; }
|
||||
.cell-input:focus { outline: none; }
|
||||
.cell-input.single { min-height: 30px; }
|
||||
.cell-input.medium { min-height: 90px; }
|
||||
.cell-input.tall { min-height: 170px; }
|
||||
.input-line { height: 30px; }
|
||||
.summary-cell { padding: 8px 12px; }
|
||||
.summary-title { font-weight: 600; margin-bottom: 6px; text-align: left; }
|
||||
.summary-content { text-align: left; line-height: 1.7; font-size: 12px; }
|
||||
.summary-item { margin-bottom: 6px; }
|
||||
.summary-example { margin-left: 16px; margin-bottom: 6px; color: #000; }
|
||||
.summary-editor { margin-top: 8px; }
|
||||
.summary-field { margin-bottom: 6px; }
|
||||
.summary-field-label { font-weight: 600; margin-bottom: 4px; }
|
||||
.summary-textarea { margin: 0; padding: 0; }
|
||||
.split-row { display: flex; align-items: stretch; gap: 0; min-height: 36px; }
|
||||
.split-left { flex: 1; padding-right: 8px; }
|
||||
.split-right { display: flex; align-items: center; gap: 4px; white-space: nowrap; border-left: 1px solid #000; padding-left: 8px; }
|
||||
.provider-row { display: flex; gap: 0; min-height: 140px; align-items: stretch; }
|
||||
.provider-opinion { flex: 1; padding-right: 8px; }
|
||||
.provider-date { width: 110px; display: flex; flex-direction: column; gap: 8px; justify-content: center; align-items: center; border-left: 1px solid #000; padding-left: 6px; }
|
||||
.date-label { font-weight: 600; }
|
||||
.footer-note { margin-top: 10px; font-size: 12px; line-height: 1.6; }
|
||||
.note-row { margin-bottom: 6px; text-align: right; }
|
||||
.note { margin-bottom: 4px; }
|
||||
.note input { vertical-align: middle; }
|
||||
`;
|
||||
|
||||
newWindow.document.write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>审计取证单</title>
|
||||
<style>${style}</style>
|
||||
</head>
|
||||
<body>${area.innerHTML}</body>
|
||||
</html>
|
||||
`);
|
||||
newWindow.document.close();
|
||||
newWindow.focus();
|
||||
newWindow.print();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.evidence-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.action-tip {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.evidence-container {
|
||||
max-height: 70vh;
|
||||
overflow: auto;
|
||||
background: #f2f2f2;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.evidence-sheet {
|
||||
background: #fff;
|
||||
padding: 14px 16px;
|
||||
border: 1px solid #000;
|
||||
box-shadow: none;
|
||||
width: 794px;
|
||||
max-width: 100%;
|
||||
min-height: 1123px;
|
||||
margin: 0 auto;
|
||||
font-family: 'SimSun', 'Songti SC', serif;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.sheet-title {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
letter-spacing: 8px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sheet-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.meta-left,
|
||||
.meta-right {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.inline-input {
|
||||
border: none;
|
||||
border-bottom: 1px solid #000;
|
||||
min-width: 70px;
|
||||
padding: 2px 4px;
|
||||
font-size: 14px;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.inline-input.small {
|
||||
width: 44px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.inline-input.long {
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.sheet-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.sheet-table th,
|
||||
.sheet-table td {
|
||||
border: 1px solid #000;
|
||||
padding: 6px 8px;
|
||||
vertical-align: top;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.sheet-table th {
|
||||
background: #fff;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.vertical-header {
|
||||
padding: 4px 2px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.vertical-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.vertical-text span {
|
||||
display: block;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.cell-input {
|
||||
width: 100%;
|
||||
border: none;
|
||||
resize: none;
|
||||
min-height: 32px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
font-family: inherit;
|
||||
background: transparent;
|
||||
overflow: hidden;
|
||||
field-sizing: content;
|
||||
}
|
||||
|
||||
.cell-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cell-input.single {
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.cell-input.medium {
|
||||
min-height: 90px;
|
||||
}
|
||||
|
||||
.cell-input.tall {
|
||||
min-height: 170px;
|
||||
}
|
||||
|
||||
.input-line {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.summary-cell {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.summary-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.summary-content {
|
||||
text-align: left;
|
||||
line-height: 1.7;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.summary-example {
|
||||
margin-left: 16px;
|
||||
margin-bottom: 6px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.summary-editor {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.summary-field {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.summary-field-label {
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.summary-textarea {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.split-row {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 0;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.split-left {
|
||||
flex: 1;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.split-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
border-left: 1px solid #000;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.provider-row {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
min-height: 140px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.provider-opinion {
|
||||
flex: 1;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.provider-date {
|
||||
width: 110px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-left: 1px solid #000;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.date-label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.footer-note {
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.note-row {
|
||||
margin-bottom: 6px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.note {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
</style>
|
||||
332
src/views/pwl/pwlProject/components/components/FileModal.vue
Normal file
332
src/views/pwl/pwlProject/components/components/FileModal.vue
Normal file
@@ -0,0 +1,332 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="showDocSelect"
|
||||
title="选择文档"
|
||||
width="1200px"
|
||||
:footer="null"
|
||||
wrap-class-name="doc-select-modal"
|
||||
@cancel="handleDocSelectCancel"
|
||||
>
|
||||
<div class="doc-select-container">
|
||||
<div class="doc-layout">
|
||||
<!-- 左侧目录树 -->
|
||||
<div class="dir-tree-panel">
|
||||
<div class="dir-header">
|
||||
<span>文档目录</span>
|
||||
</div>
|
||||
<div class="tree-container">
|
||||
<a-tree
|
||||
v-if="treeData.length > 0"
|
||||
:tree-data="treeData"
|
||||
:expanded-keys="expandedKeys"
|
||||
:selected-keys="selectedKeys"
|
||||
:load-data="onLoadData"
|
||||
@expand="onExpand"
|
||||
@select="onSelect"
|
||||
:field-names="{ title: 'name', key: 'id', children: 'children' }"
|
||||
checkable
|
||||
:checked-keys="checkedDirKeys"
|
||||
@check="onDirCheck"
|
||||
>
|
||||
<template #title="{ name, id }">
|
||||
<span :class="{ 'active-dir': selectedKeys[0] === id }">{{
|
||||
name
|
||||
}}</span>
|
||||
</template>
|
||||
</a-tree>
|
||||
<a-empty v-else :image="simpleImage" description="暂无目录" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧文档列表 -->
|
||||
<div class="doc-list-panel">
|
||||
<div class="doc-header">
|
||||
<div class="doc-actions">
|
||||
<span class="doc-tips"
|
||||
>已选择 {{ checkedDirKeys.length }} 个目录,
|
||||
{{ selectedFileKeys.length }} 个文件</span
|
||||
>
|
||||
<a-space>
|
||||
<a-button @click="clearSelection">清空选择</a-button>
|
||||
<a-button type="primary" @click="confirmSelection"
|
||||
>确认选择</a-button
|
||||
>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
<div class="doc-content">
|
||||
<a-table
|
||||
:dataSource="docList"
|
||||
:columns="docColumns"
|
||||
:loading="docLoading"
|
||||
rowKey="id"
|
||||
:scroll="{ y: 400 }"
|
||||
:pagination="pagination"
|
||||
@change="handleTableChange"
|
||||
size="middle"
|
||||
:row-selection="{
|
||||
selectedRowKeys: selectedFileKeys,
|
||||
onChange: onFileSelectionChange,
|
||||
type: 'checkbox'
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'fileName'">
|
||||
<div style="display: flex; align-items: center; gap: 8px">
|
||||
<FileOutlined />
|
||||
<span>{{ record.fileName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="column.key === 'fileSize'">
|
||||
{{ formatFileSize(record.fileSize) }}
|
||||
</template>
|
||||
<template v-if="column.key === 'fileType'">
|
||||
<a-tag color="blue">{{ record.fileType }}</a-tag>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { FileOutlined } from '@ant-design/icons-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { Empty } from 'ant-design-vue';
|
||||
import { listAiCloudDoc } from '@/api/ai/aiCloudDoc';
|
||||
import { listAiCloudFile } from '@/api/ai/aiCloudFile';
|
||||
import type { AiCloudDoc } from '@/api/ai/aiCloudDoc/model';
|
||||
import type { AiCloudFile } from '@/api/ai/aiCloudFile/model';
|
||||
|
||||
const showDocSelect = defineModel();
|
||||
|
||||
const props = defineProps<{
|
||||
currentCompanyId: number;
|
||||
}>();
|
||||
|
||||
// 树形结构相关
|
||||
const expandedKeys = ref<(string | number)[]>([]);
|
||||
const selectedKeys = ref<(string | number)[]>([]);
|
||||
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
||||
|
||||
// const currentKbId = ref('');
|
||||
// const currentKbName = ref('');
|
||||
|
||||
const docColumns = ref([
|
||||
{
|
||||
title: '文件名',
|
||||
dataIndex: 'fileName',
|
||||
key: 'fileName',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '文件大小',
|
||||
dataIndex: 'fileSize',
|
||||
key: 'fileSize',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '文件类型',
|
||||
dataIndex: 'fileType',
|
||||
key: 'fileType',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
dataIndex: 'uploadTime',
|
||||
key: 'uploadTime',
|
||||
width: 180
|
||||
}
|
||||
]);
|
||||
|
||||
// 计算树形数据
|
||||
const docList = ref<AiCloudFile[]>([]);
|
||||
const docLoading = ref(false);
|
||||
const allDirs = ref<AiCloudDoc[]>([]);
|
||||
const treeData = computed(() => {
|
||||
const buildTree = (parentId: number = 0): any[] => {
|
||||
return allDirs.value
|
||||
.filter((item) => item.parentId === parentId)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
key: item.id,
|
||||
title: item.name,
|
||||
children: buildTree(item.id),
|
||||
isLeaf:
|
||||
allDirs.value.filter((child) => child.parentId === item.id)
|
||||
.length === 0
|
||||
}));
|
||||
};
|
||||
return buildTree(0);
|
||||
});
|
||||
|
||||
const lastSelectedDirKeys = ref<(string | number)[]>([]);
|
||||
const lastSelectedFileKeys = ref<(string | number)[]>([]);
|
||||
// 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 handleDocSelectCancel = () => {
|
||||
// 保存当前选择状态
|
||||
lastSelectedDirKeys.value = [...checkedDirKeys.value];
|
||||
lastSelectedFileKeys.value = [...selectedFileKeys.value];
|
||||
showDocSelect.value = false;
|
||||
};
|
||||
|
||||
const confirmSelection = () => {
|
||||
// 保存当前选择状态
|
||||
lastSelectedDirKeys.value = [...checkedDirKeys.value];
|
||||
lastSelectedFileKeys.value = [...selectedFileKeys.value];
|
||||
|
||||
message.success(
|
||||
`已选择 ${checkedDirKeys.value.length} 个目录和 ${selectedFileKeys.value.length} 个文件`
|
||||
);
|
||||
showDocSelect.value = false;
|
||||
};
|
||||
|
||||
const loadAllCloudDocs = async () => {
|
||||
try {
|
||||
const params = {
|
||||
companyId: props.currentCompanyId
|
||||
};
|
||||
const result = await listAiCloudDoc(params);
|
||||
allDirs.value = result || [];
|
||||
|
||||
// 默认展开根节点并选中第一个目录
|
||||
if (allDirs.value.length > 0) {
|
||||
const rootDirs = allDirs.value.filter((item) => item.parentId === 0);
|
||||
if (rootDirs.length > 0) {
|
||||
expandedKeys.value = [0];
|
||||
|
||||
// 如果已经有选中的目录,保持选中状态,否则选中第一个目录
|
||||
if (selectedKeys.value.length === 0) {
|
||||
selectedKeys.value = [rootDirs[0].id!];
|
||||
}
|
||||
|
||||
loadCloudFiles();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('加载目录列表失败');
|
||||
console.error('加载目录错误:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 树节点展开
|
||||
const onExpand = (keys: (string | number)[]) => {
|
||||
expandedKeys.value = keys;
|
||||
};
|
||||
|
||||
// 树节点选择
|
||||
const onSelect = (keys: (string | number)[]) => {
|
||||
selectedKeys.value = keys;
|
||||
pagination.value.current = 1;
|
||||
loadCloudFiles();
|
||||
};
|
||||
|
||||
// 新增:目录勾选处理
|
||||
const onDirCheck = (checkedKeys: (string | number)[]) => {
|
||||
checkedDirKeys.value = checkedKeys;
|
||||
selectedDocList.value = checkedKeys.map((key) => key.toString());
|
||||
};
|
||||
|
||||
// 异步加载子节点
|
||||
const onLoadData = () => {
|
||||
return new Promise<void>((resolve) => {
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
// 表格分页变化处理
|
||||
const pagination = ref({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: false,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条`,
|
||||
pageSizeOptions: ['10', '20', '50', '100']
|
||||
});
|
||||
|
||||
const handleTableChange = (pag: any) => {
|
||||
pagination.value.current = pag.current;
|
||||
pagination.value.pageSize = pag.pageSize;
|
||||
loadCloudFiles();
|
||||
};
|
||||
|
||||
// 文件选择变化
|
||||
const onFileSelectionChange = (
|
||||
selectedRowKeys: (string | number)[],
|
||||
selectedRows: AiCloudFile[]
|
||||
) => {
|
||||
selectedFileKeys.value = selectedRowKeys;
|
||||
selectedFileList.value = selectedRows.map((row) => row.id!.toString());
|
||||
};
|
||||
|
||||
// 清空选择
|
||||
const clearSelection = () => {
|
||||
selectedDocList.value = [];
|
||||
selectedFileList.value = [];
|
||||
selectedFileKeys.value = [];
|
||||
checkedDirKeys.value = []; // 新增:清空勾选的目录
|
||||
|
||||
// 重新选择当前目录
|
||||
if (selectedKeys.value.length > 0) {
|
||||
selectedDocList.value = [selectedKeys.value[0].toString()];
|
||||
checkedDirKeys.value = [selectedKeys.value[0]]; // 新增:重新勾选当前目录
|
||||
}
|
||||
};
|
||||
|
||||
const loadCloudFiles = async () => {
|
||||
docLoading.value = true;
|
||||
try {
|
||||
if (!selectedKeys.value.length) {
|
||||
docList.value = [];
|
||||
pagination.value.total = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const params = {
|
||||
docId: parseInt(selectedKeys.value[0].toString()),
|
||||
page: pagination.value.current,
|
||||
pageSize: pagination.value.pageSize
|
||||
};
|
||||
const result: any = await listAiCloudFile(params);
|
||||
|
||||
if (result && result.records) {
|
||||
docList.value = result.records;
|
||||
pagination.value.total = result.total;
|
||||
} else {
|
||||
docList.value = result || [];
|
||||
pagination.value.total = docList.value.length;
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('加载文件列表失败');
|
||||
console.error('加载文件错误:', error);
|
||||
} finally {
|
||||
docLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化文件大小
|
||||
const formatFileSize = (size: number) => {
|
||||
if (!size) return '-';
|
||||
if (size < 1024) return size + ' B';
|
||||
if (size < 1024 * 1024) return (size / 1024).toFixed(1) + ' KB';
|
||||
return (size / (1024 * 1024)).toFixed(1) + ' MB';
|
||||
};
|
||||
|
||||
const open = () => {
|
||||
showDocSelect.value = true;
|
||||
loadAllCloudDocs();
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
|
||||
</script>
|
||||
290
src/views/pwl/pwlProject/components/components/HistoryModal.vue
Normal file
290
src/views/pwl/pwlProject/components/components/HistoryModal.vue
Normal file
@@ -0,0 +1,290 @@
|
||||
<!-- 编辑弹窗 -->
|
||||
<template>
|
||||
<ele-modal
|
||||
width="85%"
|
||||
:visible="visible"
|
||||
:maskClosable="false"
|
||||
title="历史记录"
|
||||
:body-style="{ paddingBottom: '20px' }"
|
||||
@update:visible="updateVisible"
|
||||
:footer="null"
|
||||
>
|
||||
<ele-pro-table
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:columns="columns"
|
||||
:datasource="datasource"
|
||||
:scroll="{ x: 1000 }"
|
||||
size="small"
|
||||
tool-class="ele-toolbar-form"
|
||||
class="compact-history-table"
|
||||
bordered
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'createTime'">
|
||||
<span>{{ toDateString(record.createTime, 'MM-DD HH:mm') }}</span>
|
||||
</template>
|
||||
<template v-if="column.key === 'username'">
|
||||
<span>{{ record.username || '-' }}</span>
|
||||
</template>
|
||||
<template v-if="column.key === 'interfaceName'">
|
||||
<a-tag :color="getInterfaceColor(record.interfaceName)" size="small">
|
||||
{{ getInterfaceName(record.interfaceName) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'dataCount'">
|
||||
<a-tag v-if="record.dataCount > 0" color="blue" size="small">
|
||||
{{ record.dataCount }}条
|
||||
</a-tag>
|
||||
<span v-else class="text-gray">无</span>
|
||||
</template>
|
||||
<template v-if="column.key === 'processingTime'">
|
||||
<a-tag v-if="record.processingTime" color="green" size="small">
|
||||
{{ formatProcessingTime(record.processingTime) }}
|
||||
</a-tag>
|
||||
<span v-else class="text-gray">-</span>
|
||||
</template>
|
||||
<template v-if="column.key === 'requestData'">
|
||||
<a-tooltip :title="getRequestDataPreview(record)">
|
||||
<a-button type="link" size="small" class="p-0 h-auto">
|
||||
查看
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<a-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleSelect(record)"
|
||||
:disabled="!hasValidData(record)"
|
||||
>
|
||||
选择
|
||||
</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</ele-pro-table>
|
||||
</ele-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { type EleProTable, toDateString } from 'ele-admin-pro';
|
||||
import type {
|
||||
ColumnItem,
|
||||
DatasourceFunction
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import { pageAiHistory } from '@/api/ai/aiHistory';
|
||||
import type { AiHistoryParam } from '@/api/ai/aiHistory/model';
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
interfaceName?: string;
|
||||
projectId?: number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
(e: 'select', record: any): void;
|
||||
}>();
|
||||
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
|
||||
const datasource: DatasourceFunction = async ({ page, limit, orders }) => {
|
||||
const params: AiHistoryParam = { page, limit };
|
||||
|
||||
if (orders) {
|
||||
Object.assign(params, orders);
|
||||
}
|
||||
console.log(props,'props');
|
||||
// 使用传入的接口名称进行过滤
|
||||
if (props.interfaceName) {
|
||||
params.interfaceName = props.interfaceName;
|
||||
}
|
||||
if (props.projectId) {
|
||||
params.projectId = props.projectId;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await pageAiHistory(params);
|
||||
|
||||
const processedList = result.list.map(record => {
|
||||
let dataCount = 0;
|
||||
let processingTime = '';
|
||||
|
||||
try {
|
||||
if (record.responseData) {
|
||||
const responseData = JSON.parse(record.responseData);
|
||||
if (responseData.data && Array.isArray(responseData.data)) {
|
||||
dataCount = responseData.data.length;
|
||||
} else if (responseData.data?.data && Array.isArray(responseData.data.data)) {
|
||||
dataCount = responseData.data.data.length;
|
||||
}
|
||||
processingTime = responseData.processing_time || responseData.generated_time || '';
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('解析响应数据失败:', error);
|
||||
}
|
||||
|
||||
return { ...record, dataCount, processingTime };
|
||||
});
|
||||
|
||||
return { total: result.total, list: processedList };
|
||||
} catch (error) {
|
||||
console.error('获取历史记录失败:', error);
|
||||
return { total: 0, list: [] };
|
||||
}
|
||||
};
|
||||
|
||||
// 监听 visible 变化,当弹窗显示时刷新表格
|
||||
watch(() => props.visible, (newVal) => {
|
||||
if (newVal && tableRef.value) {
|
||||
// 延迟一下确保表格已经渲染
|
||||
setTimeout(() => {
|
||||
tableRef.value?.reload();
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
|
||||
const columns = ref<ColumnItem[]>([
|
||||
{
|
||||
title: '序号',
|
||||
key: 'index',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
|
||||
},
|
||||
{
|
||||
title: '接口',
|
||||
key: 'interfaceName',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '数据量',
|
||||
key: 'dataCount',
|
||||
width: 70,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '耗时',
|
||||
key: 'processingTime',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '用户',
|
||||
dataIndex: 'username',
|
||||
key: 'username',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '参数',
|
||||
key: 'requestData',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
width: 110,
|
||||
align: 'center',
|
||||
sorter: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
fixed: 'right'
|
||||
}
|
||||
]);
|
||||
|
||||
const getInterfaceName = (interfaceName: string) => {
|
||||
const nameMap: Record<string, string> = {
|
||||
'/api/ai/auditContent3/generateTripleOneTable': '三重一大',
|
||||
'/api/ai/auditContent3/generateDecisionTable': '重大经济决策调查表'
|
||||
};
|
||||
return nameMap[interfaceName] || interfaceName.split('/').pop() || interfaceName;
|
||||
};
|
||||
|
||||
const getInterfaceColor = (interfaceName: string) => {
|
||||
const colorMap: Record<string, string> = {
|
||||
'/api/ai/auditContent3/generateTripleOneTable': 'blue',
|
||||
'/api/ai/auditContent3/generateDecisionTable': 'green'
|
||||
};
|
||||
return colorMap[interfaceName] || 'default';
|
||||
};
|
||||
|
||||
const formatProcessingTime = (time: string) => {
|
||||
if (time.includes('ms')) {
|
||||
const ms = parseInt(time);
|
||||
if (!isNaN(ms)) return `${(ms / 1000).toFixed(1)}s`;
|
||||
}
|
||||
if (time.includes('CST')) {
|
||||
return new Date(time).toLocaleTimeString('zh-CN', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
}
|
||||
return time.length > 8 ? time.substring(0, 7) + '...' : time;
|
||||
};
|
||||
|
||||
const getRequestDataPreview = (record: any) => {
|
||||
try {
|
||||
if (record.requestData) {
|
||||
const requestData = JSON.parse(record.requestData);
|
||||
const preview: string[] = [];
|
||||
|
||||
if (requestData.kbIds) preview.push(`知识库: ${requestData.kbIds}`);
|
||||
if (requestData.libraryIds) preview.push(`项目库: ${requestData.libraryIds}`);
|
||||
if (requestData.suggestion) preview.push(`要求: ${requestData.suggestion.substring(0, 20)}...`);
|
||||
if (requestData.docList?.length > 0) preview.push(`文档: ${requestData.docList.length}个`);
|
||||
if (requestData.fileList?.length > 0) preview.push(`文件: ${requestData.fileList.length}个`);
|
||||
|
||||
return preview.join('\n') || '无参数';
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('解析请求数据失败:', error);
|
||||
}
|
||||
return '解析失败';
|
||||
};
|
||||
|
||||
const hasValidData = (record: any) => {
|
||||
try {
|
||||
if (record.responseData) {
|
||||
const responseData = JSON.parse(record.responseData);
|
||||
const hasData = (responseData.data && Array.isArray(responseData.data) && responseData.data.length > 0) ||
|
||||
(responseData.data?.data && Array.isArray(responseData.data.data) && responseData.data.data.length > 0);
|
||||
return hasData && responseData.success !== false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('检查数据有效性失败:', error);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleSelect = (record: any) => {
|
||||
if (!hasValidData(record)) return;
|
||||
emit('select', record);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.text-gray {
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.compact-history-table :deep(.ant-table-thead > tr > th) {
|
||||
padding: 8px 4px;
|
||||
}
|
||||
|
||||
.compact-history-table :deep(.ant-table-tbody > tr > td) {
|
||||
padding: 8px 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<a-space>
|
||||
<div
|
||||
v-for="(item, index) in btns"
|
||||
:key="index"
|
||||
class="btn"
|
||||
:class="[title === item ? 'btn-green' : 'btn-gray']"
|
||||
@click="onChange(item)"
|
||||
>{{ item }}</div
|
||||
>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
btns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(['change']);
|
||||
|
||||
const onChange = (title: string) => {
|
||||
emits('change', title);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import '../style/style.scss';
|
||||
</style>
|
||||
54
src/views/pwl/pwlProject/components/data/columns.ts
Normal file
54
src/views/pwl/pwlProject/components/data/columns.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
export default [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '重大经济决策事项',
|
||||
dataIndex: 'name',
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: '会议时间',
|
||||
dataIndex: 'content',
|
||||
key: 'content',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '决策事项金额',
|
||||
dataIndex: 'amount',
|
||||
key: 'amount',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '程序程序',
|
||||
dataIndex: 'progress',
|
||||
key: 'progress',
|
||||
width: 300
|
||||
},
|
||||
{
|
||||
title: '执行情况(是/否)',
|
||||
dataIndex: 'done',
|
||||
key: 'done'
|
||||
},
|
||||
{
|
||||
title: '执行效果(是否实现决策目标)',
|
||||
children: [
|
||||
{
|
||||
title: '好',
|
||||
dataIndex: 'goods'
|
||||
},
|
||||
{
|
||||
title: '一般',
|
||||
dataIndex: 'normal'
|
||||
},
|
||||
{
|
||||
title: '差',
|
||||
dataIndex: 'bad'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
85
src/views/pwl/pwlProject/components/data/funcs.ts
Normal file
85
src/views/pwl/pwlProject/components/data/funcs.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
// 导入Vue相关依赖
|
||||
import { ref } from 'vue';
|
||||
|
||||
// 当前章节的ref
|
||||
const currentSection = ref(0);
|
||||
|
||||
// 滚动到指定章节
|
||||
export const scrollToSection = (index: number) => {
|
||||
const element = document.getElementById(`section-${index}`);
|
||||
if (element) {
|
||||
element.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取滚动容器
|
||||
export const getScrollContainer = () => {
|
||||
const drawer = document.querySelector('.ant-drawer-body');
|
||||
return drawer || document.querySelector('.ant-modal-body') || document.documentElement;
|
||||
};
|
||||
|
||||
// 监听滚动位置更新当前章节
|
||||
export const handleScroll = () => {
|
||||
const scrollContainer = getScrollContainer();
|
||||
if (!scrollContainer) return;
|
||||
|
||||
const containerScrollTop = scrollContainer.scrollTop || document.documentElement.scrollTop;
|
||||
|
||||
// 获取所有章节元素
|
||||
const sections = Array.from(document.querySelectorAll('.audit-section'));
|
||||
|
||||
for (let i = sections.length - 1; i >= 0; i--) {
|
||||
const section = sections[i];
|
||||
const sectionTop = section.offsetTop;
|
||||
|
||||
if (sectionTop - 100 <= containerScrollTop) {
|
||||
currentSection.value = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 检查章节是否有内容
|
||||
export const hasContent = (section: any) => {
|
||||
if (!section) return false;
|
||||
|
||||
if (section.mode === 'table') {
|
||||
return section.data && section.data.length > 0;
|
||||
} else if (section.textareaList) {
|
||||
return section.textareaList.some(textarea => textarea.content && textarea.content.trim());
|
||||
} else {
|
||||
return !!section.content?.trim();
|
||||
}
|
||||
};
|
||||
|
||||
// 构建导出数据
|
||||
export const buildExportData = () => {
|
||||
// 这里根据实际情况构建数据
|
||||
// 由于navigationItems现在是函数返回的ref,需要先获取值
|
||||
const items = navigationItems ? navigationItems.value : [];
|
||||
|
||||
const exportData: any = {
|
||||
companyName: form?.name || '',
|
||||
auditTime: form?.expirationTime || ''
|
||||
};
|
||||
|
||||
// 收集所有表格数据
|
||||
items.forEach((item, index) => {
|
||||
if (item.mode === 'table' && item.data && item.data.length > 0) {
|
||||
const currentTable = item.tableOptions[item.currentTableIndex];
|
||||
if (currentTable) {
|
||||
exportData[`table${index + 1}_${currentTable.value}`] = item.data;
|
||||
}
|
||||
} else if (item.content) {
|
||||
exportData[`content${index + 1}`] = item.content;
|
||||
}
|
||||
});
|
||||
|
||||
return exportData;
|
||||
};
|
||||
|
||||
// 导出currentSection以便其他文件使用
|
||||
export { currentSection };
|
||||
48
src/views/pwl/pwlProject/components/data/navigationItems.ts
Normal file
48
src/views/pwl/pwlProject/components/data/navigationItems.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { ref } from 'vue';
|
||||
import { getTableConfig } from './tableCommon';
|
||||
|
||||
const navigationItems = ref([]);
|
||||
|
||||
// 初始化导航项
|
||||
export function initNavigationItems() {
|
||||
navigationItems.value = Array.from({ length: 11 }, (_, index) => {
|
||||
const config = getTableConfig(index);
|
||||
return {
|
||||
number: getChineseNumber(index + 1),
|
||||
name: `审计内容${index + 1}`,
|
||||
title: config?.title || `审计内容${index + 1}`,
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
generating: false,
|
||||
suggestion: '',
|
||||
mode: 'table',
|
||||
showFileSelect: true, // 所有项都显示文件选择
|
||||
data: [],
|
||||
extraData: [],
|
||||
currentTableIndex: 0, // 当前选中的表格索引
|
||||
columns: null,
|
||||
extraTableTitle: config?.extraTableTitle || null,
|
||||
extraColumns: config?.extraColumns || [],
|
||||
tableOptions: config?.options || [],
|
||||
count: index + 1,
|
||||
tableType: config?.type || `auditContent${index + 1}`,
|
||||
content: '',
|
||||
rows: 8
|
||||
};
|
||||
});
|
||||
|
||||
return navigationItems;
|
||||
}
|
||||
|
||||
// 获取中文数字
|
||||
function getChineseNumber(num) {
|
||||
const chineseNumbers = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一'];
|
||||
return chineseNumbers[num - 1] || num;
|
||||
}
|
||||
|
||||
// 导出初始化的导航项
|
||||
export default function useNavigationItems() {
|
||||
if (navigationItems.value.length === 0) {
|
||||
initNavigationItems();
|
||||
}
|
||||
return navigationItems;
|
||||
}
|
||||
81
src/views/pwl/pwlProject/components/data/table10Columns.ts
Normal file
81
src/views/pwl/pwlProject/components/data/table10Columns.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
// 党风廉政建设责任制表格列
|
||||
export const partyConductColumns = [
|
||||
{
|
||||
title: '大类',
|
||||
dataIndex: 'category',
|
||||
key: 'category',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
customCell: (_, index) => {
|
||||
if (index === 0) return { rowSpan: 37 };
|
||||
else if (index === 37) return { rowSpan: 3 };
|
||||
else if (index === 40) return { rowSpan: 3 };
|
||||
return { rowSpan: 0 };
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '子类',
|
||||
dataIndex: 'subCategory',
|
||||
key: 'subCategory',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
customCell: (_, index) => {
|
||||
if (index === 0) return { rowSpan: 17 };
|
||||
else if (index === 17) return { rowSpan: 8 };
|
||||
else if (index === 25) return { rowSpan: 8 };
|
||||
else if (index === 33) return { rowSpan: 4 };
|
||||
else if (index === 37) return { rowSpan: 3 };
|
||||
else if (index === 40) return { rowSpan: 3 };
|
||||
return { rowSpan: 0 };
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '小类',
|
||||
dataIndex: 'detailCategory',
|
||||
key: 'detailCategory',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
customCell: (_, index) => {
|
||||
if ([4, 17, 22, 25, 26, 27, 28, 29, 32, 33, 34, 37, 38, 39, 42].includes(index))
|
||||
return { rowSpan: 1 };
|
||||
else if ([18, 20, 23, 30, 35, 40].includes(index)) return { rowSpan: 2 };
|
||||
if (index === 0) return { rowSpan: 4 };
|
||||
else if (index === 5) return { rowSpan: 4 };
|
||||
else if (index === 9) return { rowSpan: 5 };
|
||||
else if (index === 14) return { rowSpan: 3 };
|
||||
return { rowSpan: 0 };
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
dataIndex: 'content',
|
||||
key: 'content',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '执行情况',
|
||||
dataIndex: 'executionStatus',
|
||||
key: 'executionStatus',
|
||||
align: 'center',
|
||||
width: 300
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
// ellipsis: true
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 100
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
partyConductColumns
|
||||
};
|
||||
94
src/views/pwl/pwlProject/components/data/table11Columns.ts
Normal file
94
src/views/pwl/pwlProject/components/data/table11Columns.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
// 历史审计问题整改表格列
|
||||
export const auditHistoryColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '审计年度',
|
||||
dataIndex: 'auditYear',
|
||||
key: 'auditYear',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '审计类型',
|
||||
dataIndex: 'auditType',
|
||||
key: 'auditType',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '审计发现的问题',
|
||||
dataIndex: 'problemFound',
|
||||
key: 'problemFound',
|
||||
align: 'center',
|
||||
width: 250,
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '整改要求',
|
||||
dataIndex: 'rectificationRequirement',
|
||||
key: 'rectificationRequirement',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '整改措施',
|
||||
dataIndex: 'rectificationMeasures',
|
||||
key: 'rectificationMeasures',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '整改完成情况',
|
||||
dataIndex: 'rectificationStatus',
|
||||
key: 'rectificationStatus',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '整改完成时间',
|
||||
dataIndex: 'completionDate',
|
||||
key: 'completionDate',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '整改责任人',
|
||||
dataIndex: 'responsiblePerson',
|
||||
key: 'responsiblePerson',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
// ellipsis: true
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 100
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
auditHistoryColumns
|
||||
};
|
||||
446
src/views/pwl/pwlProject/components/data/table1Columns.ts
Normal file
446
src/views/pwl/pwlProject/components/data/table1Columns.ts
Normal file
@@ -0,0 +1,446 @@
|
||||
// 创建测试结果渲染函数
|
||||
export function createTestResultRender() {
|
||||
return ({ text }) => {
|
||||
if (text === '通过') return '<span style="color: #52c41a">通过</span>';
|
||||
if (text === '不通过') return '<span style="color: #ff4d4f">不通过</span>';
|
||||
return text || '待检查';
|
||||
};
|
||||
}
|
||||
|
||||
// 贯彻决策部署表格列
|
||||
export const default1Columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '单位名称',
|
||||
dataIndex: 'unitName',
|
||||
key: 'unitName',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '规格',
|
||||
dataIndex: 'specification',
|
||||
key: 'specification',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '经费来源',
|
||||
dataIndex: 'fundSource',
|
||||
key: 'fundSource',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '编制数额',
|
||||
dataIndex: 'establishmentNum',
|
||||
key: 'establishmentNum',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '编制数额',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '其他编制',
|
||||
dataIndex: 'otherEstablishment',
|
||||
key: 'otherEstablishment',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '事业编制',
|
||||
dataIndex: 'institutionEstablishment',
|
||||
key: 'institutionEstablishment',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '实用人员',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '参公人数',
|
||||
dataIndex: 'publicServantNum',
|
||||
key: 'publicServantNum',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '聘用人数',
|
||||
dataIndex: 'employedNum',
|
||||
key: 'employedNum',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '领导职数',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '处级',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '核定数',
|
||||
dataIndex: 'departmentApproved',
|
||||
key: 'departmentApproved',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '实有数',
|
||||
dataIndex: 'departmentActual',
|
||||
key: 'departmentActual',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '科级',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '核定数',
|
||||
dataIndex: 'sectionApproved',
|
||||
key: 'sectionApproved',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '实有数',
|
||||
dataIndex: 'sectionActual',
|
||||
key: 'sectionActual',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '股级',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '核定数',
|
||||
dataIndex: 'teamApproved',
|
||||
key: 'teamApproved',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '实有数',
|
||||
dataIndex: 'teamActual',
|
||||
key: 'teamActual',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '参公单位非领导职数',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '处级',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '核定数',
|
||||
dataIndex: 'nonLeaderDeptApproved',
|
||||
key: 'nonLeaderDeptApproved',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '实有数',
|
||||
dataIndex: 'nonLeaderDeptActual',
|
||||
key: 'nonLeaderDeptActual',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '科级',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '核定数',
|
||||
dataIndex: 'nonLeaderSectionApproved',
|
||||
key: 'nonLeaderSectionApproved',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '实有数',
|
||||
dataIndex: 'nonLeaderSectionActual',
|
||||
key: 'nonLeaderSectionActual',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '股级',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '核定数',
|
||||
dataIndex: 'nonLeaderTeamApproved',
|
||||
key: 'nonLeaderTeamApproved',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '实有数',
|
||||
dataIndex: 'nonLeaderTeamActual',
|
||||
key: 'nonLeaderTeamActual',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '岗位设置',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '管理岗位',
|
||||
dataIndex: 'managementPosition',
|
||||
key: 'managementPosition',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '专业技术岗位',
|
||||
dataIndex: 'technicalPosition',
|
||||
key: 'technicalPosition',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '工勤技能岗位',
|
||||
dataIndex: 'workerPosition',
|
||||
key: 'workerPosition',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 100
|
||||
}
|
||||
];
|
||||
|
||||
// 领导班子名单列
|
||||
export const leaderListColumns = [
|
||||
{
|
||||
title: '单位',
|
||||
dataIndex: 'unit',
|
||||
key: 'unit',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '部门',
|
||||
dataIndex: 'department',
|
||||
key: 'department',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '职务',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '党内',
|
||||
dataIndex: 'partyPosition',
|
||||
key: 'partyPosition',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '行政',
|
||||
dataIndex: 'adminPosition',
|
||||
key: 'adminPosition',
|
||||
align: 'center',
|
||||
width: 120
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '任职期间',
|
||||
dataIndex: 'tenurePeriod',
|
||||
key: 'tenurePeriod',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '主要工作责任',
|
||||
dataIndex: 'mainResponsibilities',
|
||||
key: 'mainResponsibilities',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 100
|
||||
}
|
||||
];
|
||||
|
||||
// 决策支出表列
|
||||
export const expenseColumns = [
|
||||
{
|
||||
title: '支出类型',
|
||||
dataIndex: 'expenseType',
|
||||
key: 'expenseType',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '年份',
|
||||
dataIndex: 'year',
|
||||
key: 'year',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '决算报表数(元)',
|
||||
dataIndex: 'finalStatementAmount',
|
||||
key: 'finalStatementAmount',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '年初预算数(元)',
|
||||
dataIndex: 'initialBudgetAmount',
|
||||
key: 'initialBudgetAmount',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '增减情况(%)',
|
||||
dataIndex: 'changePercentage',
|
||||
key: 'changePercentage',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '占年初预算比例(%)',
|
||||
dataIndex: 'budgetRatio',
|
||||
key: 'budgetRatio',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '数据来源',
|
||||
dataIndex: 'dataSource',
|
||||
key: 'dataSource',
|
||||
align: 'center',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 100
|
||||
}
|
||||
];
|
||||
|
||||
// 八项规定表格列
|
||||
export const eightRegColumns = [
|
||||
{
|
||||
title: '审计内容',
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '审计内容',
|
||||
dataIndex: 'content',
|
||||
key: 'content',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '检查的证据及测试内容',
|
||||
dataIndex: 'testContent',
|
||||
key: 'testContent',
|
||||
align: 'center',
|
||||
width: 300
|
||||
},
|
||||
{
|
||||
title: '测试结果',
|
||||
dataIndex: 'result',
|
||||
key: 'result',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
customRender: createTestResultRender()
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 140
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
default1Columns,
|
||||
leaderListColumns,
|
||||
expenseColumns,
|
||||
eightRegColumns,
|
||||
createTestResultRender
|
||||
};
|
||||
62
src/views/pwl/pwlProject/components/data/table2Columns.ts
Normal file
62
src/views/pwl/pwlProject/components/data/table2Columns.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
// 创建测试结果渲染函数
|
||||
export function createTestResultRender() {
|
||||
return ({ text }) => {
|
||||
if (text === '通过') return '<span style="color: #52c41a">通过</span>';
|
||||
if (text === '不通过') return '<span style="color: #ff4d4f">不通过</span>';
|
||||
return text || '待检查';
|
||||
};
|
||||
}
|
||||
|
||||
// 审计内容2表格列
|
||||
export const strategyAuditColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '审计内容',
|
||||
dataIndex: 'auditContent',
|
||||
key: 'auditContent',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '检查的证据及测试内容',
|
||||
dataIndex: 'checkEvidence',
|
||||
key: 'checkEvidence',
|
||||
width: 350,
|
||||
align: 'center',
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '测试结果',
|
||||
dataIndex: 'testResult',
|
||||
key: 'testResult',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
customRender: createTestResultRender()
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
width: 200,
|
||||
align: 'center',
|
||||
// ellipsis: true
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// width: 100,
|
||||
// align: 'center'
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
strategyAuditColumns,
|
||||
createTestResultRender
|
||||
};
|
||||
140
src/views/pwl/pwlProject/components/data/table3Columns.ts
Normal file
140
src/views/pwl/pwlProject/components/data/table3Columns.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { createTestResultRender } from './table2Columns';
|
||||
|
||||
// 三重一大表格列
|
||||
export const tripleOneColumns = [
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'category',
|
||||
key: 'category',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '政策内容',
|
||||
dataIndex: 'policyContent',
|
||||
key: 'policyContent',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '集团制度',
|
||||
dataIndex: 'groupSystem',
|
||||
key: 'groupSystem',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '公司制度',
|
||||
dataIndex: 'companyFormulation',
|
||||
key: 'companyFormulation',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '公司执行情况',
|
||||
dataIndex: 'checkEvidence',
|
||||
key: 'checkEvidence',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '执行结果',
|
||||
dataIndex: 'testResult',
|
||||
key: 'testResult',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
customRender: createTestResultRender()
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 100
|
||||
}
|
||||
];
|
||||
|
||||
// 重大经济决策表格列
|
||||
export const decisionTableColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '重大经济决策事项',
|
||||
dataIndex: 'decisionItem',
|
||||
key: 'decisionItem',
|
||||
width: 200,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '会议时间',
|
||||
dataIndex: 'meetingTime',
|
||||
key: 'meetingTime',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '决策事项金额',
|
||||
dataIndex: 'decisionAmount',
|
||||
key: 'decisionAmount',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '程序',
|
||||
dataIndex: 'procedure',
|
||||
key: 'procedure',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '执行情况(是/否)',
|
||||
dataIndex: 'executionStatus',
|
||||
key: 'executionStatus',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '执行效果(是否实现决策目标)',
|
||||
children: [
|
||||
{
|
||||
title: '好',
|
||||
dataIndex: 'goods',
|
||||
key: 'goods',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '一般',
|
||||
dataIndex: 'normal',
|
||||
key: 'normal',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '差',
|
||||
dataIndex: 'bad',
|
||||
key: 'bad',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 140
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
tripleOneColumns,
|
||||
decisionTableColumns
|
||||
};
|
||||
87
src/views/pwl/pwlProject/components/data/table4Columns.ts
Normal file
87
src/views/pwl/pwlProject/components/data/table4Columns.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
export const columns0 = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '年度',
|
||||
dataIndex: 'year',
|
||||
key: 'year',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '上级主管部门下达目标责任制',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '下达文件',
|
||||
dataIndex: 'superiorFile',
|
||||
key: 'superiorFile',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '完成情况',
|
||||
dataIndex: 'superiorCompletion',
|
||||
key: 'superiorCompletion',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '未完成原因',
|
||||
dataIndex: 'superiorReason',
|
||||
key: 'superiorReason',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '单位自定下达目标责任制',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '计划文件',
|
||||
dataIndex: 'selfPlan',
|
||||
key: 'selfPlan',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '完成情况',
|
||||
dataIndex: 'selfCompletion',
|
||||
key: 'selfCompletion',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '未完成原因',
|
||||
dataIndex: 'selfReason',
|
||||
key: 'selfReason',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
}
|
||||
];
|
||||
|
||||
export default { columns0 };
|
||||
178
src/views/pwl/pwlProject/components/data/table5Columns.ts
Normal file
178
src/views/pwl/pwlProject/components/data/table5Columns.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
export const budgetManageColumns = [
|
||||
{
|
||||
title: '预算科目名称',
|
||||
dataIndex: 'budgetSubject',
|
||||
key: 'budgetSubject',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '指标来源',
|
||||
dataIndex: 'indicatorSource',
|
||||
key: 'indicatorSource',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '合计',
|
||||
dataIndex: 'total',
|
||||
key: 'total',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '上年结余',
|
||||
dataIndex: 'lastYearBalance',
|
||||
key: 'lastYearBalance',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '年初部门预算',
|
||||
dataIndex: 'initialBudget',
|
||||
key: 'initialBudget',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '追加(减)预算',
|
||||
dataIndex: 'additionalBudget',
|
||||
key: 'additionalBudget',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '指标运用',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '合计',
|
||||
dataIndex: 'indicatorUseTotal',
|
||||
key: 'indicatorUseTotal',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '拨款小计',
|
||||
dataIndex: 'appropriationSubtotal',
|
||||
key: 'appropriationSubtotal',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '拨款',
|
||||
dataIndex: 'appropriation',
|
||||
key: 'appropriation',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '工资统发',
|
||||
dataIndex: 'salaryPayment',
|
||||
key: 'salaryPayment',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '政府采购',
|
||||
dataIndex: 'govProcurement',
|
||||
key: 'govProcurement',
|
||||
align: 'center',
|
||||
width: 100
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '指标结余',
|
||||
dataIndex: 'indicatorBalance',
|
||||
key: 'indicatorBalance',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 100
|
||||
}
|
||||
];
|
||||
|
||||
// 预算执行情况列
|
||||
export const budgetExecutionColumns = [
|
||||
{
|
||||
title: '项目',
|
||||
dataIndex: 'project',
|
||||
key: 'project',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '上年结转',
|
||||
dataIndex: 'lastYearCarryOver',
|
||||
key: 'lastYearCarryOver',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '本年预算小计',
|
||||
dataIndex: 'currentYearBudgetTotal',
|
||||
key: 'currentYearBudgetTotal',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '年初批复预算数',
|
||||
dataIndex: 'initialApprovedBudget',
|
||||
key: 'initialApprovedBudget',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '追加预算数',
|
||||
dataIndex: 'additionalBudgetAmount',
|
||||
key: 'additionalBudgetAmount',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '实际拨款数',
|
||||
dataIndex: 'actualAppropriation',
|
||||
key: 'actualAppropriation',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '指标结余',
|
||||
dataIndex: 'indicatorBalance',
|
||||
key: 'indicatorBalance',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 100
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
budgetManageColumns,
|
||||
budgetExecutionColumns
|
||||
};
|
||||
118
src/views/pwl/pwlProject/components/data/table6Columns.ts
Normal file
118
src/views/pwl/pwlProject/components/data/table6Columns.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
export const stateAssetsManageColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '国有资产名称',
|
||||
dataIndex: 'assetName',
|
||||
key: 'assetName',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '取得方式',
|
||||
dataIndex: 'acquisitionMethod',
|
||||
key: 'acquisitionMethod',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '资产价值',
|
||||
dataIndex: 'assetValue',
|
||||
key: 'assetValue',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '资产地址',
|
||||
dataIndex: 'assetAddress',
|
||||
key: 'assetAddress',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '面积',
|
||||
dataIndex: 'area',
|
||||
key: 'area',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '承租方',
|
||||
dataIndex: 'tenant',
|
||||
key: 'tenant',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '合同金额',
|
||||
dataIndex: 'contractAmount',
|
||||
key: 'contractAmount',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '租赁起止时间',
|
||||
dataIndex: 'leasePeriod',
|
||||
key: 'leasePeriod',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '租金缴纳时间',
|
||||
dataIndex: 'rentPaymentTime',
|
||||
key: 'rentPaymentTime',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '是否上平台',
|
||||
dataIndex: 'platformLease',
|
||||
key: 'platformLease',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '审批文件',
|
||||
dataIndex: 'approvalDoc',
|
||||
key: 'approvalDoc',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '纳入预算',
|
||||
dataIndex: 'inBudget',
|
||||
key: 'inBudget',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 100
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
stateAssetsManageColumns
|
||||
};
|
||||
55
src/views/pwl/pwlProject/components/data/table7Columns.ts
Normal file
55
src/views/pwl/pwlProject/components/data/table7Columns.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { createTestResultRender } from './table2Columns';
|
||||
|
||||
// 重大投资情况审计表格列
|
||||
export const investmentSituationColumns = [
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'category',
|
||||
key: 'category',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '审计内容',
|
||||
dataIndex: 'auditContent',
|
||||
key: 'auditContent',
|
||||
align: 'center',
|
||||
width: 300,
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '检查的证据及测试内容',
|
||||
dataIndex: 'checkEvidence',
|
||||
key: 'checkEvidence',
|
||||
align: 'center',
|
||||
width: 400,
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '测试结果',
|
||||
dataIndex: 'testResult',
|
||||
key: 'testResult',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
customRender: createTestResultRender()
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
// ellipsis: true
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 100
|
||||
// }
|
||||
];
|
||||
|
||||
// 删除不再需要的单独列配置
|
||||
export default {
|
||||
investmentSituationColumns
|
||||
};
|
||||
83
src/views/pwl/pwlProject/components/data/table8Columns.ts
Normal file
83
src/views/pwl/pwlProject/components/data/table8Columns.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { createTestResultRender } from './table2Columns';
|
||||
|
||||
// 内部控制测试表格列
|
||||
export const internalControlTestColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '控制环节',
|
||||
dataIndex: 'controlLink',
|
||||
key: 'controlLink',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '控制要求',
|
||||
dataIndex: 'controlRequirement',
|
||||
key: 'controlRequirement',
|
||||
align: 'center',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '控制活动描述',
|
||||
dataIndex: 'controlActivity',
|
||||
key: 'controlActivity',
|
||||
align: 'center',
|
||||
width: 300,
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '控制职责岗位',
|
||||
dataIndex: 'controlPosition',
|
||||
key: 'controlPosition',
|
||||
align: 'center',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '测试步骤',
|
||||
dataIndex: 'testSteps',
|
||||
key: 'testSteps',
|
||||
align: 'center',
|
||||
width: 250,
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '测试结果',
|
||||
dataIndex: 'testResult',
|
||||
key: 'testResult',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
customRender: createTestResultRender()
|
||||
},
|
||||
{
|
||||
title: '检查证据',
|
||||
dataIndex: 'checkEvidence',
|
||||
key: 'checkEvidence',
|
||||
align: 'center',
|
||||
width: 250,
|
||||
// ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
// ellipsis: true
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 100
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
internalControlTestColumns
|
||||
};
|
||||
55
src/views/pwl/pwlProject/components/data/table9Columns.ts
Normal file
55
src/views/pwl/pwlProject/components/data/table9Columns.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
export const personnelEstablishmentColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '审计内容',
|
||||
dataIndex: 'auditContent',
|
||||
key: 'auditContent',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '审计目标',
|
||||
dataIndex: 'auditTarget',
|
||||
key: 'auditTarget',
|
||||
align: 'center',
|
||||
width: 250,
|
||||
},
|
||||
{
|
||||
title: '审计证据',
|
||||
dataIndex: 'auditEvidence',
|
||||
key: 'auditEvidence',
|
||||
align: 'center',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: '生成结果',
|
||||
dataIndex: 'generationResult',
|
||||
key: 'generationResult',
|
||||
align: 'center',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: '工作底稿索引',
|
||||
dataIndex: 'workPaperIndex',
|
||||
key: 'workPaperIndex',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// align: 'center',
|
||||
// width: 100
|
||||
// }
|
||||
];
|
||||
|
||||
export default {
|
||||
personnelEstablishmentColumns
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
export const benefitEstablishmentColumns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '凭证号',
|
||||
dataIndex: 'voucher',
|
||||
key: 'voucher',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '支出日期',
|
||||
dataIndex: 'expenditureDate',
|
||||
key: 'expenditureDate',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '用途',
|
||||
dataIndex: 'usage',
|
||||
key: 'usage',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '收款方',
|
||||
dataIndex: 'payee',
|
||||
key: 'payee',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '金额(元)',
|
||||
dataIndex: 'amount',
|
||||
key: 'amount',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '归属部门/人员',
|
||||
dataIndex: 'belongTo',
|
||||
key: 'belongTo',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '款项性质说明',
|
||||
dataIndex: 'natureDesc',
|
||||
key: 'natureDesc',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '违规说明',
|
||||
dataIndex: 'violationDesc',
|
||||
key: 'violationDesc',
|
||||
align: 'center'
|
||||
}
|
||||
];
|
||||
|
||||
export default benefitEstablishmentColumns;
|
||||
482
src/views/pwl/pwlProject/components/data/tableCommon.ts
Normal file
482
src/views/pwl/pwlProject/components/data/tableCommon.ts
Normal file
@@ -0,0 +1,482 @@
|
||||
import table9ExtraColumns from './table9ExtraColumns';
|
||||
|
||||
export const tableConfigs = {
|
||||
// 审计内容1表格配置
|
||||
auditContent1: {
|
||||
type: 'auditContent1',
|
||||
title: '贯彻决策部署情况',
|
||||
options: [
|
||||
// { title: '贯彻决策部署', value: 'default1', columns: () => import('./table1Columns').then(m => m.default1Columns) },
|
||||
{
|
||||
title: '领导班子名单',
|
||||
value: 'leaderList',
|
||||
columns: () =>
|
||||
import('./table1Columns').then((m) => m.leaderListColumns)
|
||||
},
|
||||
{
|
||||
title: '决策支出表',
|
||||
value: 'expense',
|
||||
columns: () => import('./table1Columns').then((m) => m.expenseColumns)
|
||||
},
|
||||
{
|
||||
title: '八项规定',
|
||||
value: 'eightReg',
|
||||
columns: () => import('./table1Columns').then((m) => m.eightRegColumns)
|
||||
}
|
||||
],
|
||||
// 接口映射
|
||||
interfaceMap: {
|
||||
default1: '/api/ai/auditContent1/generateDefault1Table',
|
||||
leaderList: '/api/ai/auditContent1/generateLeaderListTable',
|
||||
expense: '/api/ai/auditContent1/generateExpenseTable',
|
||||
eightReg: '/api/ai/auditContent1/generateEightRegTable'
|
||||
}
|
||||
},
|
||||
// 审计内容2表格配置
|
||||
auditContent2: {
|
||||
type: 'auditContent2',
|
||||
title: '单位发展战略执行',
|
||||
options: [
|
||||
{
|
||||
title: '单位发展战略执行',
|
||||
value: 'strategyAudit',
|
||||
columns: () =>
|
||||
import('./table2Columns').then((m) => m.strategyAuditColumns)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
strategyAudit: '/api/ai/auditContent2/generateStrategyAuditTable'
|
||||
}
|
||||
},
|
||||
// 审计内容3表格配置
|
||||
auditContent3: {
|
||||
type: 'auditContent3',
|
||||
title: '重大经济决策调查',
|
||||
options: [
|
||||
{
|
||||
title: '重大经济决策调查表',
|
||||
value: 'decisionTable',
|
||||
columns: () =>
|
||||
import('./table3Columns').then((m) => m.decisionTableColumns)
|
||||
},
|
||||
{
|
||||
title: '三重一大',
|
||||
value: 'tripleOne',
|
||||
columns: () => import('./table3Columns').then((m) => m.tripleOneColumns)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
tripleOne: '/api/ai/auditContent3/generateTripleOneTable',
|
||||
decisionTable: '/api/ai/auditContent3/generateDecisionTable'
|
||||
}
|
||||
},
|
||||
// 审计内容4表格配置
|
||||
auditContent4: {
|
||||
type: 'auditContent4',
|
||||
title: '目标完成情况',
|
||||
options: [
|
||||
{
|
||||
title: '目标责任完成情况表',
|
||||
value: 'target',
|
||||
columns: () => import('./table4Columns').then((m) => m.columns0)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
target: '/api/ai/auditContent4/generateTargetTable'
|
||||
}
|
||||
},
|
||||
// 审计内容5表格配置
|
||||
auditContent5: {
|
||||
type: 'auditContent5',
|
||||
title: '财务管理情况',
|
||||
options: [
|
||||
{
|
||||
title: '预算管理审计',
|
||||
value: 'budgetManage',
|
||||
columns: () =>
|
||||
import('./table5Columns').then((m) => m.budgetManageColumns)
|
||||
},
|
||||
{
|
||||
title: '预算执行情况审计',
|
||||
value: 'budgetExecution',
|
||||
columns: () =>
|
||||
import('./table5Columns').then((m) => m.budgetExecutionColumns)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
budgetManage: '/api/ai/auditContent5/generateBudgetManageTable',
|
||||
budgetExecution: '/api/ai/auditContent5/generateBudgetExecutionTable'
|
||||
}
|
||||
},
|
||||
// 审计内容6表格配置
|
||||
auditContent6: {
|
||||
type: 'auditContent6',
|
||||
title: '国资管理情况',
|
||||
options: [
|
||||
{
|
||||
title: '国有资产管理审计',
|
||||
value: 'assets',
|
||||
columns: () =>
|
||||
import('./table6Columns').then((m) => m.stateAssetsManageColumns)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
assets: '/api/ai/auditContent6/generateAssetsTable'
|
||||
}
|
||||
},
|
||||
auditContent7: {
|
||||
type: 'auditContent7',
|
||||
title: '重大投资情况',
|
||||
options: [
|
||||
{
|
||||
title: '重大投资情况审计',
|
||||
value: 'investmentSituation',
|
||||
columns: () =>
|
||||
import('./table7Columns').then((m) => m.investmentSituationColumns)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
investmentSituation:
|
||||
'/api/ai/auditContent7/generateInvestmentSituationTable'
|
||||
}
|
||||
},
|
||||
auditContent8: {
|
||||
type: 'auditContent8',
|
||||
title: '治理结构与内部控制',
|
||||
options: [
|
||||
{
|
||||
title: '内部控制测试',
|
||||
value: 'internalControl',
|
||||
columns: () =>
|
||||
import('./table8Columns').then((m) => m.internalControlTestColumns)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
internalControl: '/api/ai/auditContent8/generateInternalControlTable'
|
||||
}
|
||||
},
|
||||
auditContent9: {
|
||||
type: 'auditContent9',
|
||||
title: '人员编制管理',
|
||||
options: [
|
||||
{
|
||||
title: '人员编制管理审计',
|
||||
value: 'personnel',
|
||||
columns: () =>
|
||||
import('./table9Columns').then((m) => m.personnelEstablishmentColumns)
|
||||
}
|
||||
],
|
||||
extraTableTitle: '福利费超范围支出明细清单',
|
||||
extraColumns: table9ExtraColumns,
|
||||
interfaceMap: {
|
||||
personnel: '/api/ai/auditContent9/generatePersonnelTable'
|
||||
}
|
||||
},
|
||||
auditContent10: {
|
||||
type: 'auditContent10',
|
||||
title: '廉政情况',
|
||||
options: [
|
||||
{
|
||||
title: '党风廉政建设责任制审计',
|
||||
value: 'partyConduct',
|
||||
columns: () =>
|
||||
import('./table10Columns').then((m) => m.partyConductColumns)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
partyConduct: '/api/ai/auditContent10/generatePartyConductTable'
|
||||
}
|
||||
},
|
||||
auditContent11: {
|
||||
type: 'auditContent11',
|
||||
title: '历史审计问题整改',
|
||||
options: [
|
||||
{
|
||||
title: '历史审计问题整改',
|
||||
value: 'history',
|
||||
columns: () =>
|
||||
import('./table11Columns').then((m) => m.auditHistoryColumns)
|
||||
}
|
||||
],
|
||||
interfaceMap: {
|
||||
history: '/api/ai/auditContent11/generateHistoryTable'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 获取表格配置
|
||||
export function getTableConfig(sectionIndex: number) {
|
||||
const configKeys = Object.keys(tableConfigs);
|
||||
if (sectionIndex >= 0 && sectionIndex < configKeys.length) {
|
||||
return tableConfigs[configKeys[sectionIndex]];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取所有表格配置
|
||||
export function getAllTableConfigs() {
|
||||
return tableConfigs;
|
||||
}
|
||||
|
||||
// 通过接口名称查找表格配置
|
||||
export function findTableConfigByInterface(interfaceName: string) {
|
||||
for (const [key, config] of Object.entries(tableConfigs)) {
|
||||
for (const [tableValue, tableInterface] of Object.entries(
|
||||
config.interfaceMap || {}
|
||||
)) {
|
||||
if (tableInterface === interfaceName) {
|
||||
return {
|
||||
sectionType: key,
|
||||
tableValue,
|
||||
config
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 解析workPaperIndex字符串为对象数组
|
||||
function parseWorkPaperIndex(workPaperIndex) {
|
||||
if (!workPaperIndex || !Array.isArray(workPaperIndex)) return [];
|
||||
|
||||
return workPaperIndex.map((item) => {
|
||||
if (item && typeof item === 'object') {
|
||||
return {
|
||||
fileId: item.fileId || item.file_id || '',
|
||||
fileName: item.fileName || item.file_name || '',
|
||||
fileUrl: item.fileUrl || item.url || ''
|
||||
};
|
||||
}
|
||||
if (typeof item === 'string') {
|
||||
const parts = item.split('||');
|
||||
if (parts.length >= 3) {
|
||||
return {
|
||||
fileId: parts[0] || '',
|
||||
fileName: parts[1] || '',
|
||||
fileUrl: parts[2] || ''
|
||||
};
|
||||
}
|
||||
}
|
||||
// 兼容旧格式
|
||||
return {
|
||||
fileId: '',
|
||||
fileName: typeof item === 'string' ? item : '',
|
||||
fileUrl: ''
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 通用数据映射函数
|
||||
export function createDataMapper(type: string) {
|
||||
const mappers = {
|
||||
default1: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
index: index + 1,
|
||||
...item,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
leaderList: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
...item,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
expense: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
...item,
|
||||
finalStatementAmount: formatAmount(item.finalStatementAmount),
|
||||
initialBudgetAmount: formatAmount(item.initialBudgetAmount),
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
eightReg: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
...item,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
strategyAudit: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
index: index + 1,
|
||||
...item,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
tripleOne: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
...item,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
decisionTable: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
index: index + 1,
|
||||
goods: item.executionEffect?.good || item.goods || '否',
|
||||
normal: item.executionEffect?.normal || item.normal || '否',
|
||||
bad: item.executionEffect?.bad || item.bad || '否',
|
||||
...item,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
budgetManage: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
index: index + 1,
|
||||
...item,
|
||||
budgetSubject: item.budgetSubject || '-',
|
||||
indicatorSource: item.indicatorSource,
|
||||
total: formatAmount(item.indicatorSourceTotal),
|
||||
lastYearBalance: formatAmount(item.indicatorSourceLastYearBalance),
|
||||
initialBudget: formatAmount(item.indicatorSourceInitialBudget),
|
||||
additionalBudget: formatAmount(item.indicatorSourceAdditionalBudget),
|
||||
indicatorUseTotal: formatAmount(item.indicatorUseTotal),
|
||||
appropriationSubtotal: formatAmount(
|
||||
item.indicatorUseAppropriationSubtotal
|
||||
),
|
||||
appropriation: formatAmount(item.indicatorUseAppropriation),
|
||||
salaryPayment: formatAmount(item.indicatorUseSalaryPayment),
|
||||
govProcurement: formatAmount(item.indicatorUseGovProcurement),
|
||||
indicatorBalance: formatAmount(item.indicatorBalance),
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
investmentSituation: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
index: index + 1,
|
||||
category: item.category || '未分类',
|
||||
auditContent: item.auditContent || item.content || '',
|
||||
checkEvidence: item.checkEvidence || item.evidence || '',
|
||||
testResult: item.testResult || '待检查',
|
||||
...item,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
})),
|
||||
personnel: (data) => {
|
||||
const mainData = data.map((item, index) => {
|
||||
const { ext, ...rest } = item;
|
||||
return {
|
||||
key: index,
|
||||
index: item.index || index + 1,
|
||||
...rest,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
};
|
||||
});
|
||||
const extraData = data.reduce((acc, item) => {
|
||||
if (item.ext && Array.isArray(item.ext)) {
|
||||
return [...acc, ...item.ext];
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
return {
|
||||
mainData: mainData,
|
||||
extraData: extraData.map((item, idx) => ({
|
||||
key: idx,
|
||||
...item,
|
||||
index: item.index || idx + 1
|
||||
}))
|
||||
};
|
||||
},
|
||||
// 其他类型的映射...
|
||||
default: (data) =>
|
||||
data.map((item, index) => ({
|
||||
key: index,
|
||||
index: index + 1,
|
||||
...item,
|
||||
workPaperIndex: parseWorkPaperIndex(item.workPaperIndex)
|
||||
}))
|
||||
};
|
||||
|
||||
return mappers[type] || mappers.default;
|
||||
}
|
||||
|
||||
// 格式化金额
|
||||
function formatAmount(amount) {
|
||||
if (!amount) return '0.00';
|
||||
if (typeof amount === 'string' && amount.includes(',')) return amount;
|
||||
const num = parseFloat(amount);
|
||||
return isNaN(num)
|
||||
? '0.00'
|
||||
: num.toLocaleString('zh-CN', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
});
|
||||
}
|
||||
|
||||
// 生成接口映射
|
||||
export const apiMethodMap = {
|
||||
// 审计内容1
|
||||
default1: {
|
||||
generate: 'generateDefault1Table',
|
||||
export: 'exportDefault1Table'
|
||||
},
|
||||
leaderList: {
|
||||
generate: 'generateLeaderListTable',
|
||||
export: 'exportLeaderListTable'
|
||||
},
|
||||
expense: { generate: 'generateExpenseTable', export: 'exportExpenseTable' },
|
||||
eightReg: {
|
||||
generate: 'generateEightRegTable',
|
||||
export: 'exportEightRegTable'
|
||||
},
|
||||
// 审计内容2
|
||||
strategyAudit: {
|
||||
generate: 'generateStrategyAuditTable',
|
||||
export: 'exportStrategyAuditTable'
|
||||
},
|
||||
// 审计内容3
|
||||
tripleOne: {
|
||||
generate: 'generateTripleOneTable',
|
||||
export: 'exportTripleOneTable'
|
||||
},
|
||||
decisionTable: {
|
||||
generate: 'generateDecisionTable',
|
||||
export: 'exportDecisionTable'
|
||||
},
|
||||
// 审计内容4
|
||||
target: { generate: 'generateTargetTable', export: 'exportTargetTable' },
|
||||
// 审计内容5
|
||||
budgetManage: {
|
||||
generate: 'generateBudgetManageTable',
|
||||
export: 'exportBudgetManageTable'
|
||||
},
|
||||
budgetExecution: {
|
||||
generate: 'generateBudgetExecutionTable',
|
||||
export: 'exportBudgetExecutionTable'
|
||||
},
|
||||
// 审计内容6
|
||||
assets: { generate: 'generateAssetsTable', export: 'exportAssetsTable' },
|
||||
// 审计内容7
|
||||
investmentSituation: {
|
||||
generate: 'generateInvestmentSituationTable',
|
||||
export: 'exportInvestmentSituationTable'
|
||||
},
|
||||
// 审计内容8
|
||||
internalControl: {
|
||||
generate: 'generateInternalControlTable',
|
||||
export: 'exportInternalControlTable'
|
||||
},
|
||||
// 审计内容9
|
||||
personnel: {
|
||||
generate: 'generatePersonnelTable',
|
||||
export: 'exportPersonnelTable'
|
||||
},
|
||||
// 审计内容10
|
||||
partyConduct: {
|
||||
generate: 'generatePartyConductTable',
|
||||
export: 'exportPartyConductTable'
|
||||
},
|
||||
// 审计内容11
|
||||
history: { generate: 'generateHistoryTable', export: 'exportHistoryTable' },
|
||||
// 默认
|
||||
default: { generate: 'generateDefaultTable', export: 'exportDefaultTable' }
|
||||
};
|
||||
|
||||
export default {
|
||||
tableConfigs,
|
||||
getTableConfig,
|
||||
getAllTableConfigs,
|
||||
findTableConfigByInterface,
|
||||
createDataMapper,
|
||||
apiMethodMap
|
||||
};
|
||||
60
src/views/pwl/pwlProject/components/extra.vue
Normal file
60
src/views/pwl/pwlProject/components/extra.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<!-- 搜索表单 -->
|
||||
<template>
|
||||
<a-space style="flex-wrap: wrap">
|
||||
<a-button
|
||||
v-if="hasRole('superAdmin')"
|
||||
@click="openUrl('/count')"
|
||||
>统计
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {watch,nextTick} from 'vue';
|
||||
import {CmsWebsite} from '@/api/cms/cmsWebsite/model';
|
||||
import {openUrl} from "@/utils/common";
|
||||
import {message} from 'ant-design-vue';
|
||||
import {removeSiteInfoCache} from "@/api/cms/cmsWebsite";
|
||||
import {hasRole} from "@/utils/permission";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
// 选中的角色
|
||||
selection?: [];
|
||||
website?: CmsWebsite;
|
||||
count?: 0;
|
||||
}>(),
|
||||
{}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'add'): void;
|
||||
}>();
|
||||
|
||||
const add = () => {
|
||||
emit('add');
|
||||
};
|
||||
|
||||
// 清除缓存
|
||||
const clearSiteInfoCache = () => {
|
||||
removeSiteInfoCache('SiteInfo:' + localStorage.getItem('TenantId') + "*").then(
|
||||
(msg) => {
|
||||
if (msg) {
|
||||
message.success(msg);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
nextTick(() => {
|
||||
if(localStorage.getItem('NotActive')){
|
||||
// IsActive.value = false
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.selection,
|
||||
() => {
|
||||
}
|
||||
);
|
||||
</script>
|
||||
812
src/views/pwl/pwlProject/components/pwlProjectEdit.vue
Normal file
812
src/views/pwl/pwlProject/components/pwlProjectEdit.vue
Normal file
@@ -0,0 +1,812 @@
|
||||
<!-- 编辑弹窗 -->
|
||||
<template>
|
||||
<ele-modal
|
||||
:width="1000"
|
||||
:visible="visible"
|
||||
:maskClosable="false"
|
||||
:maxable="maxable"
|
||||
:title="isUpdate ? '编辑项目' : '添加项目'"
|
||||
:body-style="{ paddingBottom: '28px' }"
|
||||
:confirm-loading="loading"
|
||||
@update:visible="updateVisible"
|
||||
@ok="save"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
|
||||
:wrapper-col="
|
||||
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
|
||||
"
|
||||
>
|
||||
<a-form-item label="被审计单位" name="name">
|
||||
<SelectCompany v-model:value="form.name" @done="onCompany" />
|
||||
</a-form-item>
|
||||
<a-form-item label="项目类型" name="type">
|
||||
<DictSelect
|
||||
dict-code="Type"
|
||||
:width="200"
|
||||
:show-search="true"
|
||||
placeholder="项目类型"
|
||||
v-model:value="form.type"
|
||||
@done="chooseType"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="报告时间" name="expirationTime">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入报告时间"
|
||||
v-model:value="form.expirationTime"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="项目名称" name="code">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 400px"
|
||||
placeholder="请输入项目名称"
|
||||
v-model:value="form.code"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="案引号" name="caseIndex">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 400px"
|
||||
placeholder="请输入项目名称"
|
||||
v-model:value="form.caseIndex"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 行业库 -->
|
||||
<a-form-item label="行业库" name="bizLibIds">
|
||||
<a-select
|
||||
show-search
|
||||
:allow-clear="true"
|
||||
optionFilterProp="label"
|
||||
v-model:value="form.bizLibIds"
|
||||
mode="multiple"
|
||||
style="width: 100%"
|
||||
placeholder="选择行业库"
|
||||
:options="bizLibList"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 公共库 -->
|
||||
<a-form-item label="公共库" name="pubLibIds">
|
||||
<a-select
|
||||
show-search
|
||||
:allow-clear="true"
|
||||
optionFilterProp="label"
|
||||
v-model:value="form.pubLibIds"
|
||||
mode="multiple"
|
||||
style="width: 100%"
|
||||
placeholder="选择公共库"
|
||||
:options="pubLibList"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-divider orientation="left" style="margin-top: 50px">项目信息</a-divider>
|
||||
<a-form-item label="开票单位/汇款人" name="itemName">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 400px"
|
||||
placeholder="请输入项目信息-开票单位/汇款人"
|
||||
v-model:value="form.itemName"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="所属年度" name="itemYear">
|
||||
<a-input-number
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入项目信息-年度"
|
||||
v-model:value="form.itemYear"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="类型" name="itemType">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入类型"
|
||||
v-model:value="form.itemType"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="审计意见" name="itemOpinion">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入审计意见"
|
||||
v-model:value="form.itemOpinion"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="年末资产总额(万元)" name="totalAssets">
|
||||
<a-input-number
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入年末资产总额(万元)"
|
||||
v-model:value="form.totalAssets"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="合同金额" name="contractPrice">
|
||||
<a-input-number
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入合同金额"
|
||||
v-model:value="form.contractPrice"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="实收金额" name="payPrice">
|
||||
<a-input-number
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入实收金额"
|
||||
v-model:value="form.payPrice"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-divider orientation="left" style="margin-top: 50px">到账信息</a-divider>
|
||||
<a-form-item label="银行" name="bankName">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入银行名称"
|
||||
v-model:value="form.bankName"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="日期" name="bankPayTime">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入到账日期"
|
||||
v-model:value="form.bankPayTime"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="金额" name="bankPrice">
|
||||
<a-input-number
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入到账金额"
|
||||
v-model:value="form.bankPrice"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-divider orientation="left" style="margin-top: 50px">开票信息</a-divider>
|
||||
<a-form-item label="日期" name="invoiceTime">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入开票日期"
|
||||
v-model:value="form.invoiceTime"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="金额" name="invoicePrice">
|
||||
<a-input-number
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入开票金额"
|
||||
v-model:value="form.invoicePrice"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="类型" name="invoiceType">
|
||||
<DictSelect
|
||||
dict-code="InvoiceType"
|
||||
:width="200"
|
||||
:show-search="true"
|
||||
placeholder="项目类型"
|
||||
v-model:value="form.invoiceType"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-divider orientation="left" style="margin-top: 50px">其他设置</a-divider>
|
||||
<a-form-item label="报告份数" name="reportNum">
|
||||
<a-input
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
placeholder="请输入报告份数"
|
||||
v-model:value="form.reportNum"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="底稿人员" name="draftUserId">
|
||||
<a-select
|
||||
show-search
|
||||
:allow-clear="true"
|
||||
optionFilterProp="label"
|
||||
v-model:value="form.draftUserId"
|
||||
mode="tags"
|
||||
style="width: 100%"
|
||||
placeholder="选择底稿人员"
|
||||
:options="userList"
|
||||
@search="handleSearch"
|
||||
@change="handleDraftUserId"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="参与成员" name="userIds" extra="配置项目权限->参与成员可见">
|
||||
<a-select
|
||||
show-search
|
||||
:allow-clear="true"
|
||||
optionFilterProp="label"
|
||||
v-model:value="form.userIds"
|
||||
mode="tags"
|
||||
style="width: 100%"
|
||||
placeholder="选择参与成员"
|
||||
:options="userList"
|
||||
@change="handleUsers"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="签字注会" name="signUserId">
|
||||
<a-select
|
||||
show-search
|
||||
:allow-clear="true"
|
||||
optionFilterProp="label"
|
||||
v-model:value="form.signUserId"
|
||||
mode="tags"
|
||||
style="width: 100%"
|
||||
placeholder="选择参与成员"
|
||||
:options="userList"
|
||||
@change="handleSignUser"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="展业人员" name="saleUserId">
|
||||
<a-select
|
||||
show-search
|
||||
:allow-clear="true"
|
||||
optionFilterProp="label"
|
||||
v-model:value="form.saleUserId"
|
||||
mode="tags"
|
||||
style="width: 100%"
|
||||
placeholder="选择参与成员"
|
||||
:options="userList"
|
||||
@change="handleSaleUser"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="电子底稿完成情况" name="electron">
|
||||
<a-space direction="vertical">
|
||||
<a-radio-group v-model:value="form.electron">
|
||||
<a-radio :value="1">未完成</a-radio>
|
||||
<a-radio :value="0">已完成</a-radio>
|
||||
</a-radio-group>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
<a-form-item label="纸质底稿完成情况" name="paper">
|
||||
<a-space direction="vertical">
|
||||
<a-radio-group v-model:value="form.paper">
|
||||
<a-radio :value="1">未完成</a-radio>
|
||||
<a-radio :value="0">已完成</a-radio>
|
||||
</a-radio-group>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
<a-form-item label="报告完成状态" name="status">
|
||||
<a-radio-group v-model:value="form.status">
|
||||
<a-radio :value="1">未完成</a-radio>
|
||||
<a-radio :value="0">已完成</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" name="sortNumber">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
:max="9999"
|
||||
placeholder="请输入排序号"
|
||||
v-model:value="form.sortNumber"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="备注" name="comments">
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
:maxlength="200"
|
||||
placeholder="请输入描述"
|
||||
v-model:value="form.comments"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</ele-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, reactive, watch} from 'vue';
|
||||
import {Form, message} from 'ant-design-vue';
|
||||
import {assignObject, uuid} from 'ele-admin-pro';
|
||||
import {addPwlProject, updatePwlProject} from '@/api/pwl/pwlProject';
|
||||
import {PwlProject} from '@/api/pwl/pwlProject/model';
|
||||
import {useThemeStore} from '@/store/modules/theme';
|
||||
import {storeToRefs} from 'pinia';
|
||||
import {ItemType} from 'ele-admin-pro/es/ele-image-upload/types';
|
||||
import {FormInstance} from 'ant-design-vue/es/form';
|
||||
import DictSelect from "@/components/DictSelect/index.vue";
|
||||
import {DictData} from "@/api/system/dict-data/model";
|
||||
import {pageUsers} from "@/api/system/user";
|
||||
import {User} from "@/api/system/user/model";
|
||||
import {hasRole} from "@/utils/permission";
|
||||
import SelectCompany from "@/components/SelectCompany/index.vue";
|
||||
import {Company} from "@/api/system/company/model";
|
||||
import {OaCompany} from "@/api/oa/oaCompany/model";
|
||||
import {listPwlProjectLibrary} from '@/api/pwl/pwlProjectLibrary';
|
||||
|
||||
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
const useForm = Form.useForm;
|
||||
// 是否开启响应式布局
|
||||
const themeStore = useThemeStore();
|
||||
const {styleResponsive} = storeToRefs(themeStore);
|
||||
|
||||
// 资料库响应式数据
|
||||
const bizLibList = ref<any[]>([]);
|
||||
const pubLibList = ref<any[]>([]);
|
||||
// 存储完整的资料库数据,用于查找名称
|
||||
const allLibraries = ref<any[]>([]);
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
visible: boolean;
|
||||
// 修改回显的数据
|
||||
data?: PwlProject | null;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'done'): void;
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
// 提交状态
|
||||
const loading = ref(false);
|
||||
// 是否显示最大化切换按钮
|
||||
const maxable = ref(true);
|
||||
// 表格选中数据
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
const images = ref<ItemType[]>([]);
|
||||
const userList = ref<User[]>([]);
|
||||
const draftUser = ref<any[]>([]);
|
||||
const users = ref<any[]>([]);
|
||||
const signUser = ref<any[]>([]);
|
||||
const saleUser = ref<any[]>([]);
|
||||
const keywords = ref<string>();
|
||||
|
||||
// 用户信息
|
||||
const form = reactive<PwlProject>({
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
code: undefined,
|
||||
caseIndex: undefined,
|
||||
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: [],
|
||||
draftUser: [],
|
||||
userIds: [],
|
||||
users: [],
|
||||
signUserId: [],
|
||||
signUser: [],
|
||||
saleUserId: [],
|
||||
saleUser: [],
|
||||
bizLibIds: [], // 修改为bizLibIds
|
||||
bizLibName: [],
|
||||
pubLibIds: [], // 修改为pubLibIds
|
||||
pubLibName: [],
|
||||
libraryIds: undefined,
|
||||
analysisLibrary: undefined,
|
||||
projectLibrary: undefined,
|
||||
comments: undefined,
|
||||
electron: undefined,
|
||||
paper: undefined,
|
||||
status: undefined,
|
||||
deleted: undefined,
|
||||
userId: undefined,
|
||||
tenantId: undefined,
|
||||
createTime: undefined,
|
||||
updateTime: undefined,
|
||||
sortNumber: 100,
|
||||
});
|
||||
|
||||
/* 更新visible */
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
type: [
|
||||
{
|
||||
required: true,
|
||||
type: 'string',
|
||||
message: '请选择项目类型',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
type: 'string',
|
||||
message: '请填写项目名称',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
draftUserId: [
|
||||
{
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请选择底稿人员',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
userIds: [
|
||||
{
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请选择参与成员',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
saleUserId:[
|
||||
{
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请选择展业人员',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
electron: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '电子底稿是否已完成',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
paper: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '纸质底稿是否已完成',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
status: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请选择项目状态',
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const chooseType = (data: DictData) => {
|
||||
console.log(data);
|
||||
form.type = data.dictDataName;
|
||||
}
|
||||
// const chooseImage = (data: FileRecord) => {
|
||||
// images.value.push({
|
||||
// uid: data.id,
|
||||
// url: data.path,
|
||||
// status: 'done'
|
||||
// });
|
||||
// form.image = data.path;
|
||||
// };
|
||||
//
|
||||
// const onDeleteItem = (index: number) => {
|
||||
// images.value.splice(index, 1);
|
||||
// form.image = '';
|
||||
// };
|
||||
|
||||
|
||||
const onCompany = (item: OaCompany) => {
|
||||
console.log('选择的公司:', item);
|
||||
form.name = item.companyName;
|
||||
form.companyId = item.companyId;
|
||||
form.kbId = item.kbId;
|
||||
form.libraryIds = item.libraryIds;
|
||||
// 需要等待资料库列表加载完成后再设置回显
|
||||
fetchLibraries().then(() => {
|
||||
setLibraryEcho();
|
||||
});
|
||||
console.log('设置后的form.name:', form.name);
|
||||
};
|
||||
|
||||
const handleSearch = (item) => {
|
||||
keywords.value = item
|
||||
fetchUsers();
|
||||
}
|
||||
|
||||
const handleDraftUserId = (userId: number, item: User[]) => {
|
||||
draftUser.value = [];
|
||||
item.map(d => {
|
||||
draftUser.value.push(d.realName);
|
||||
});
|
||||
console.log(userId)
|
||||
}
|
||||
|
||||
const handleUsers = (userId: number, item: User[]) => {
|
||||
users.value = [];
|
||||
item.map(d => {
|
||||
users.value.push(d.realName);
|
||||
});
|
||||
console.log(userId)
|
||||
}
|
||||
const handleSignUser = (userId: number, item: User[]) => {
|
||||
signUser.value = [];
|
||||
item.map(d => {
|
||||
signUser.value.push(d.realName);
|
||||
});
|
||||
console.log(userId)
|
||||
}
|
||||
const handleSaleUser = (userId: number, item: User[]) => {
|
||||
saleUser.value = [];
|
||||
item.map(d => {
|
||||
saleUser.value.push(d.realName);
|
||||
});
|
||||
console.log(userId)
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
const fetchUsers = () => {
|
||||
pageUsers({keywords: keywords.value,limit: 100}).then(res => {
|
||||
userList.value = res?.list.map(d => {
|
||||
d.label = d.realName;
|
||||
d.value = d.userId;
|
||||
return d;
|
||||
}) || [];
|
||||
})
|
||||
};
|
||||
|
||||
// 获取资料库列表
|
||||
const fetchLibraries = () => {
|
||||
return listPwlProjectLibrary().then(res => {
|
||||
allLibraries.value = res;
|
||||
|
||||
// 过滤行业库 (type='biz')
|
||||
bizLibList.value = res
|
||||
.filter(item => item.type === 'biz')
|
||||
.map(item => ({
|
||||
label: item.name,
|
||||
value: String(item.id) // 将 ID 转换为字符串
|
||||
}));
|
||||
|
||||
// 过滤公共库 (type='pub')
|
||||
pubLibList.value = res
|
||||
.filter(item => item.type === 'pub')
|
||||
.map(item => ({
|
||||
label: item.name,
|
||||
value: String(item.id) // 将 ID 转换为字符串
|
||||
}));
|
||||
|
||||
return res;
|
||||
});
|
||||
};
|
||||
|
||||
// 根据ID获取资料库名称
|
||||
const getLibraryNamesByIds = (ids: string[]) => {
|
||||
return ids.map(id => {
|
||||
const library = allLibraries.value.find(lib => lib.id == id);
|
||||
return library ? library.name : '';
|
||||
}).filter(name => name !== '');
|
||||
};
|
||||
|
||||
const {resetFields} = useForm(form, rules);
|
||||
|
||||
/* 保存编辑 */
|
||||
const save = () => {
|
||||
if (!formRef.value) {
|
||||
return;
|
||||
}
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(() => {
|
||||
loading.value = true;
|
||||
|
||||
// 合并行业库和公共库的ID到libraryIds
|
||||
const allLibraryIds = [
|
||||
...(form.bizLibIds || []),
|
||||
...(form.pubLibIds || [])
|
||||
]
|
||||
|
||||
const formData = {
|
||||
...form,
|
||||
draftUserId: JSON.stringify(form.draftUserId),
|
||||
draftUser: JSON.stringify(Array.from(new Set(draftUser.value))),
|
||||
userIds: JSON.stringify(form.userIds),
|
||||
users: JSON.stringify(Array.from(new Set(users.value))),
|
||||
signUserId: JSON.stringify(form.signUserId),
|
||||
signUser: JSON.stringify(Array.from(new Set(signUser.value))),
|
||||
saleUserId: JSON.stringify(form.saleUserId),
|
||||
saleUser: JSON.stringify(Array.from(new Set(saleUser.value))),
|
||||
libraryIds: allLibraryIds.join(','), // 保存为逗号分隔的字符串
|
||||
};
|
||||
|
||||
if (!hasRole('superAdmin')) {
|
||||
form.payPrice = undefined;
|
||||
}
|
||||
if (!hasRole('admin')) {
|
||||
form.contractPrice = undefined;
|
||||
form.bankName = undefined;
|
||||
form.bankPayTime = undefined;
|
||||
form.bankPrice = undefined;
|
||||
form.invoiceType = undefined;
|
||||
form.invoiceTime = undefined;
|
||||
form.invoicePrice = undefined;
|
||||
}
|
||||
console.log(formData);
|
||||
const saveOrUpdate = isUpdate.value ? updatePwlProject : addPwlProject;
|
||||
saveOrUpdate(formData)
|
||||
.then((msg) => {
|
||||
loading.value = false;
|
||||
message.success(msg);
|
||||
updateVisible(false);
|
||||
emit('done');
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 设置资料库回显
|
||||
const setLibraryEcho = () => {
|
||||
// 优先使用form中的libraryIds,回退到props.data.libraryIds
|
||||
const libraryIdsSource = form.libraryIds || props.data?.libraryIds;
|
||||
|
||||
if (libraryIdsSource) {
|
||||
// 如果是字符串,按逗号分割成数组
|
||||
if (typeof libraryIdsSource === 'string') {
|
||||
const libraryIdsArray = libraryIdsSource.split(',').filter(id => id.trim() !== '');
|
||||
|
||||
// 清空当前的选择
|
||||
form.bizLibIds = [];
|
||||
form.pubLibIds = [];
|
||||
|
||||
// 根据资料库类型分别设置回显
|
||||
libraryIdsArray.forEach(id => {
|
||||
// 检查是否在行业库列表中
|
||||
const isBizLib = bizLibList.value.some(lib => lib.value === String(id)); // 转换为字符串比较
|
||||
// 检查是否在公共库列表中
|
||||
const isPubLib = pubLibList.value.some(lib => lib.value === String(id)); // 转换为字符串比较
|
||||
|
||||
if (isBizLib) {
|
||||
form.bizLibIds.push(String(id)); // 确保存储为字符串
|
||||
}
|
||||
if (isPubLib) {
|
||||
form.pubLibIds.push(String(id)); // 确保存储为字符串
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 如果是数组,直接使用相同的逻辑
|
||||
form.bizLibIds = [];
|
||||
form.pubLibIds = [];
|
||||
|
||||
libraryIdsSource.forEach(id => {
|
||||
const isBizLib = bizLibList.value.some(lib => lib.value === String(id));
|
||||
const isPubLib = pubLibList.value.some(lib => lib.value === String(id));
|
||||
|
||||
if (isBizLib) {
|
||||
form.bizLibIds.push(String(id));
|
||||
}
|
||||
if (isPubLib) {
|
||||
form.pubLibIds.push(String(id));
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
form.bizLibIds = [];
|
||||
form.pubLibIds = [];
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
async (visible) => {
|
||||
if (visible) {
|
||||
fetchUsers();
|
||||
|
||||
// 等待资料库列表加载完成后再设置回显
|
||||
await fetchLibraries();
|
||||
|
||||
images.value = [];
|
||||
if (props.data) {
|
||||
assignObject(form, props.data);
|
||||
if (props.data.image) {
|
||||
images.value.push({
|
||||
uid: uuid(),
|
||||
url: props.data.image,
|
||||
status: 'done'
|
||||
})
|
||||
}
|
||||
|
||||
// 处理底稿人员
|
||||
if (props.data.draftUserId) {
|
||||
form.draftUserId = JSON.parse(props.data.draftUserId);
|
||||
} else {
|
||||
form.draftUserId = [];
|
||||
}
|
||||
if (props.data.draftUser) {
|
||||
const arr = JSON.parse(props.data.draftUser) || [];
|
||||
arr.map(d => {
|
||||
draftUser.value.push(d);
|
||||
})
|
||||
} else {
|
||||
draftUser.value = [];
|
||||
}
|
||||
|
||||
// 处理参与成员
|
||||
if (props.data.userIds) {
|
||||
form.userIds = JSON.parse(props.data.userIds) || [];
|
||||
} else {
|
||||
form.userIds = [];
|
||||
}
|
||||
if (props.data.users) {
|
||||
const arr = JSON.parse(props.data.users) || [];
|
||||
arr.map(d => {
|
||||
users.value.push(d);
|
||||
})
|
||||
} else {
|
||||
users.value = [];
|
||||
}
|
||||
|
||||
// 处理签字注会
|
||||
if (props.data.signUserId) {
|
||||
form.signUserId = JSON.parse(props.data.signUserId) || [];
|
||||
} else {
|
||||
form.signUserId = [];
|
||||
}
|
||||
if (props.data.signUser) {
|
||||
const arr = JSON.parse(props.data.signUser) || [];
|
||||
arr.map(d => {
|
||||
signUser.value.push(d);
|
||||
})
|
||||
} else {
|
||||
signUser.value = [];
|
||||
}
|
||||
|
||||
// 处理展业人员
|
||||
if (props.data.saleUserId) {
|
||||
form.saleUserId = JSON.parse(props.data.saleUserId) || [];
|
||||
} else {
|
||||
form.saleUserId = [];
|
||||
}
|
||||
if (props.data.saleUser) {
|
||||
const arr = JSON.parse(props.data.saleUser) || [];
|
||||
arr.map(d => {
|
||||
saleUser.value.push(d);
|
||||
})
|
||||
} else {
|
||||
saleUser.value = [];
|
||||
}
|
||||
|
||||
// 设置资料库回显
|
||||
setLibraryEcho();
|
||||
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
isUpdate.value = false;
|
||||
// 新增时清空资料库选择
|
||||
form.bizLibIds = [];
|
||||
form.pubLibIds = [];
|
||||
}
|
||||
} else {
|
||||
resetFields();
|
||||
}
|
||||
},
|
||||
{immediate: true}
|
||||
);
|
||||
</script>
|
||||
1197
src/views/pwl/pwlProject/components/report.vue
Normal file
1197
src/views/pwl/pwlProject/components/report.vue
Normal file
File diff suppressed because it is too large
Load Diff
2045
src/views/pwl/pwlProject/components/reportContent.vue
Normal file
2045
src/views/pwl/pwlProject/components/reportContent.vue
Normal file
File diff suppressed because it is too large
Load Diff
243
src/views/pwl/pwlProject/components/search.vue
Normal file
243
src/views/pwl/pwlProject/components/search.vue
Normal file
@@ -0,0 +1,243 @@
|
||||
<!-- 搜索表单 -->
|
||||
<template>
|
||||
<a-space :size="10" style="flex-wrap: wrap">
|
||||
<a-button type="primary" class="ele-btn-icon" @click="add">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
<span>添加</span>
|
||||
</a-button>
|
||||
<a-button
|
||||
danger
|
||||
v-if="hasRole('superAdmin')"
|
||||
type="primary"
|
||||
class="ele-btn-icon"
|
||||
:disabled="selection?.length === 0"
|
||||
@click="removeBatch"
|
||||
>
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
<span>批量删除</span>
|
||||
</a-button>
|
||||
<DictSelect
|
||||
dict-code="Type"
|
||||
:width="200"
|
||||
:show-search="true"
|
||||
placeholder="项目类型"
|
||||
v-model:value="where.type"
|
||||
@done="chooseType"
|
||||
/>
|
||||
<a-date-picker
|
||||
v-model:value="where.itemYear"
|
||||
value-format="YYYY"
|
||||
picker="year"
|
||||
@change="onYear"
|
||||
/>
|
||||
<a-input-search
|
||||
allow-clear
|
||||
placeholder="请输入关键词"
|
||||
v-model:value="where.keywords"
|
||||
@pressEnter="search"
|
||||
@search="search"
|
||||
/>
|
||||
<a-button @click="reset">重置</a-button>
|
||||
<div
|
||||
class="border-blue-400 text-blue-400 rounded border border-solid py-1 px-2 text-sm cursor-pointer"
|
||||
type="text"
|
||||
v-if="hasRole('superAdmin')"
|
||||
@click="handleExport"
|
||||
>导出xls</div
|
||||
>
|
||||
<div
|
||||
class="border-green-600 text-green-600 rounded border border-solid py-1 px-2 text-sm cursor-pointer"
|
||||
type="text"
|
||||
v-if="hasRole('superAdmin')"
|
||||
@click="openImport"
|
||||
>导入xls</div
|
||||
>
|
||||
</a-space>
|
||||
|
||||
<!-- 导入弹窗 -->
|
||||
<Import v-model:visible="showImport" @done="search" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||
import type { GradeParam } from '@/api/user/grade/model';
|
||||
import { watch, ref } from 'vue';
|
||||
import { hasRole } from '@/utils/permission';
|
||||
import dayjs from 'dayjs';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
import { PwlProject, PwlProjectParam } from '@/api/pwl/pwlProject/model';
|
||||
import useSearch from '@/utils/use-search';
|
||||
import { listPwlProject } from '@/api/pwl/pwlProject';
|
||||
import Import from './Import.vue';
|
||||
import DictSelect from '@/components/DictSelect/index.vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
// 选中的角色
|
||||
selection?: [];
|
||||
}>(),
|
||||
{}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'search', where?: GradeParam): void;
|
||||
(e: 'add'): void;
|
||||
(e: 'remove'): void;
|
||||
(e: 'batchMove'): void;
|
||||
}>();
|
||||
|
||||
// 新增
|
||||
const add = () => {
|
||||
emit('add');
|
||||
};
|
||||
// 日期范围选择
|
||||
const dateRange = ref<[string, string]>(['', '']);
|
||||
const loading = ref(false);
|
||||
const projectList = ref<PwlProject[]>([]);
|
||||
const xlsFileName = ref<string>();
|
||||
// 是否显示用户导入弹窗
|
||||
const showImport = ref(false);
|
||||
// 表单数据
|
||||
const { where, resetFields } = useSearch<PwlProjectParam>({
|
||||
id: undefined,
|
||||
type: undefined,
|
||||
itemYear: undefined,
|
||||
keywords: undefined
|
||||
});
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openImport = () => {
|
||||
showImport.value = true;
|
||||
};
|
||||
|
||||
const chooseType = (e) => {
|
||||
console.log(e, 'yyyy');
|
||||
where.type = e.label;
|
||||
search();
|
||||
};
|
||||
|
||||
// 批量删除
|
||||
const removeBatch = () => {
|
||||
emit('remove');
|
||||
};
|
||||
|
||||
const onYear = (date: any, dateString: string) => {
|
||||
where.itemYear = dateString;
|
||||
search();
|
||||
};
|
||||
|
||||
/* 搜索 */
|
||||
const search = () => {
|
||||
const [d1, d2] = dateRange.value ?? [];
|
||||
emit('search', {
|
||||
...where,
|
||||
createTimeStart: d1 ? d1 + ' 00:00:00' : '',
|
||||
createTimeEnd: d2 ? d2 + ' 23:59:59' : ''
|
||||
});
|
||||
};
|
||||
|
||||
/* 重置 */
|
||||
const reset = () => {
|
||||
resetFields();
|
||||
search();
|
||||
};
|
||||
|
||||
// 导出
|
||||
const handleExport = async () => {
|
||||
loading.value = true;
|
||||
const array: (string | number)[][] = [
|
||||
[
|
||||
'报告时间',
|
||||
'审计单位',
|
||||
'项目名称',
|
||||
'项目信息-开票单位/汇款人',
|
||||
'项目信息-所属年度',
|
||||
'项目信息-类型',
|
||||
'项目信息-审计意见',
|
||||
'年末资产总额(万元)',
|
||||
'合同金额',
|
||||
'实收金额',
|
||||
'到账信息-银行',
|
||||
'到账信息-日期',
|
||||
'到账信息-金额',
|
||||
'开票信息-日期',
|
||||
'开票信息-金额',
|
||||
'开票信息-发票类型',
|
||||
'报告份数',
|
||||
'底稿人员',
|
||||
'参与人员',
|
||||
'签字注会',
|
||||
'展业人员',
|
||||
'底稿情况'
|
||||
]
|
||||
];
|
||||
|
||||
// 按搜索结果导出
|
||||
where.sceneType = 'Content';
|
||||
await listPwlProject(where)
|
||||
.then((list) => {
|
||||
projectList.value = list;
|
||||
list?.forEach((d: PwlProject) => {
|
||||
array.push([
|
||||
`${d.expirationTime || ''}`,
|
||||
`${d.name || ''}`,
|
||||
`${d.code || ''}`,
|
||||
`${d.itemName || ''}`,
|
||||
`${d.itemYear || ''}`,
|
||||
`${d.itemType || ''}`,
|
||||
`${d.itemOpinion || ''}`,
|
||||
`${d.totalAssets || ''}`,
|
||||
// `${d.comments || ''}`,
|
||||
`${d.contractPrice || ''}`,
|
||||
`${d.payPrice || ''}`,
|
||||
`${d.bankName || ''}`,
|
||||
`${d.bankPayTime || ''}`,
|
||||
`${d.bankPrice || ''}`,
|
||||
`${d.invoiceTime || ''}`,
|
||||
`${d.invoicePrice || ''}`,
|
||||
`${d.invoiceType || ''}`,
|
||||
`${d.reportNum || ''}`,
|
||||
`${d.draftUser ? JSON.parse(d.draftUser).join(',') : ''}`,
|
||||
`${d.users ? JSON.parse(d.users).join(',') : ''}`,
|
||||
`${d.signUser ? JSON.parse(d.signUser).join(',') : ''}`,
|
||||
`${d.saleUser ? JSON.parse(d.saleUser).join(',') : ''}`,
|
||||
`${d.files || ''}`
|
||||
]);
|
||||
});
|
||||
const sheetName = `导出项目列表${dayjs(new Date()).format('YYYYMMDD')}`;
|
||||
const workbook = {
|
||||
SheetNames: [sheetName],
|
||||
Sheets: {}
|
||||
};
|
||||
const sheet = utils.aoa_to_sheet(array);
|
||||
workbook.Sheets[sheetName] = sheet;
|
||||
// 设置列宽
|
||||
sheet['!cols'] = [];
|
||||
message.loading('正在导出...');
|
||||
setTimeout(() => {
|
||||
writeFile(
|
||||
workbook,
|
||||
`${
|
||||
where.createTimeEnd ? xlsFileName.value + '_' : ''
|
||||
}${sheetName}.xlsx`
|
||||
);
|
||||
loading.value = false;
|
||||
}, 1000);
|
||||
})
|
||||
.catch((msg) => {
|
||||
message.error(msg);
|
||||
loading.value = false;
|
||||
})
|
||||
.finally(() => {});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.selection,
|
||||
() => {}
|
||||
);
|
||||
</script>
|
||||
456
src/views/pwl/pwlProject/components/style/style.scss
Normal file
456
src/views/pwl/pwlProject/components/style/style.scss
Normal file
@@ -0,0 +1,456 @@
|
||||
.audit-content {
|
||||
.audit-section {
|
||||
.child-title {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #1890ff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.ant-btn {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.question-prompt {
|
||||
color: #1677ff;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
content: '✍️';
|
||||
margin-right: 6px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #0958d9;
|
||||
}
|
||||
}
|
||||
|
||||
.suggestion-textarea {
|
||||
&:focus {
|
||||
border-color: #1677ff !important;
|
||||
box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: #4096ff !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* textarea内嵌按钮样式 */
|
||||
.textarea-with-button {
|
||||
position: relative;
|
||||
|
||||
.suggestion-textarea-inner {
|
||||
padding-right: 70px !important;
|
||||
border-radius: 6px;
|
||||
|
||||
&:focus {
|
||||
border-color: #1677ff !important;
|
||||
box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: #4096ff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.send-button-inner {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
z-index: 10;
|
||||
padding: 4px 12px;
|
||||
height: 28px;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
transform: none;
|
||||
box-shadow: 0 2px 8px rgba(24, 144, 255, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.export-button) {
|
||||
border: 2px solid #ff4d4f !important;
|
||||
border-radius: 20px !important;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-color: #ff7875 !important;
|
||||
box-shadow: 0 0 8px rgba(255, 77, 79, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
/* 统一设置所有按钮为圆角 */
|
||||
:deep(.ant-btn) {
|
||||
border-radius: 20px !important;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
/* 发送按钮特殊样式 */
|
||||
:deep(.ant-btn-primary) {
|
||||
border-radius: 20px !important;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
/* 生成全部方案按钮橙色样式 */
|
||||
:deep(.generate-all-button) {
|
||||
background-color: #ff7b00 !important;
|
||||
border-color: #ff7b00 !important;
|
||||
|
||||
&:hover {
|
||||
background-color: #e56500 !important;
|
||||
border-color: #e56500 !important;
|
||||
box-shadow: 0 4px 12px rgba(255, 123, 0, 0.4) !important;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background-color: #e56500 !important;
|
||||
border-color: #e56500 !important;
|
||||
box-shadow: 0 4px 12px rgba(255, 123, 0, 0.4) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-container {
|
||||
.nav-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.nav-button {
|
||||
height: 48px;
|
||||
border-radius: 20px !important;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0 16px;
|
||||
text-align: left;
|
||||
|
||||
.nav-number {
|
||||
font-weight: bold;
|
||||
margin-right: 8px;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.nav-text {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
&.active {
|
||||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.progress-bar {
|
||||
flex: 1;
|
||||
height: 6px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #1890ff, #52c41a);
|
||||
border-radius: 3px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
min-width: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.audit-content {
|
||||
.audit-section {
|
||||
scroll-margin-top: 20px;
|
||||
|
||||
.section-description {
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
padding: 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.child-section {
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px dashed #e8e8e8;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.child-title {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #1890ff;
|
||||
}
|
||||
|
||||
.content-textarea {
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:focus {
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-card-head) {
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
:deep(.ant-card-body) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
:deep(.ant-back-top) {
|
||||
right: 30px;
|
||||
bottom: 30px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 5px 10px;
|
||||
color: white;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn-gray {
|
||||
background-color: #bbbbbb;
|
||||
}
|
||||
.btn-green {
|
||||
background-color: #479b33;
|
||||
}
|
||||
|
||||
/* 选择文件按钮样式 */
|
||||
.select-file-btn {
|
||||
color: #1890ff;
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 文档选择弹窗样式 */
|
||||
.doc-select-container {
|
||||
height: 550px;
|
||||
}
|
||||
|
||||
.doc-layout {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.dir-tree-panel {
|
||||
width: 280px;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dir-header {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
background: #fafafa;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tree-container {
|
||||
flex: 1;
|
||||
padding: 8px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.doc-list-panel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 6px;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.doc-header {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.doc-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.doc-tips {
|
||||
color: #1890ff;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.doc-content {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 树节点激活样式 */
|
||||
:deep(.active-dir) {
|
||||
color: #1890ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.ant-tree-node-content-wrapper) {
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
:deep(.ant-tree-node-content-wrapper:hover) {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
:deep(.ant-tree .ant-tree-treenode-selected .ant-tree-node-content-wrapper) {
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
|
||||
/* 优化表格样式 */
|
||||
:deep(.doc-select-modal .ant-modal-body) {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-table-wrapper) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-spin-nested-loading) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-spin-container) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-table) {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-table-container) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-table-body) {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-table-thead > tr > th) {
|
||||
background: #fafafa;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-table-tbody > tr > td) {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* 文件名列特殊处理,允许换行 */
|
||||
:deep(.doc-content .ant-table-tbody > tr > td:first-child) {
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
line-height: 1.4;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
/* 分页样式调整 */
|
||||
:deep(.doc-content .ant-pagination) {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
:deep(.doc-content .ant-table-pagination) {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
723
src/views/pwl/pwlProject/index.vue
Normal file
723
src/views/pwl/pwlProject/index.vue
Normal file
@@ -0,0 +1,723 @@
|
||||
<template>
|
||||
<a-page-header :title="getPageTitle()" @back="() => $router.go(-1)">
|
||||
<template #subTitle>
|
||||
<div style="width: 300px;margin-left: 100px">
|
||||
<a-steps :current="1" size="small">
|
||||
<a-step title="单位信息" status="wait" />
|
||||
<a-step title="项目管理" />
|
||||
</a-steps>
|
||||
</div>
|
||||
</template>
|
||||
<template #extra>
|
||||
<Extra />
|
||||
</template>
|
||||
<a-card :bordered="false" :body-style="{ padding: '16px' }">
|
||||
<ele-pro-table
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:columns="columns"
|
||||
:datasource="datasource"
|
||||
:customRow="customRow"
|
||||
:scroll="{ x: 4000 }"
|
||||
tool-class="ele-toolbar-form"
|
||||
class="sys-org-table"
|
||||
bordered
|
||||
>
|
||||
<template #toolbar>
|
||||
<search
|
||||
@search="reload"
|
||||
:selection="selection"
|
||||
@add="openEdit"
|
||||
@remove="removeBatch"
|
||||
@batchMove="openMove"
|
||||
/>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'image'">
|
||||
<a-image v-if="record.image" :src="record.image" :width="50" />
|
||||
</template>
|
||||
<template v-if="column.key === 'status'">
|
||||
<a-tag v-if="record.status === 0" color="green">已完成</a-tag>
|
||||
<a-tag v-if="record.status === 1" color="red">未完成</a-tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'draftUser'">
|
||||
<a-space direction="vertical" v-if="record.draftUser">
|
||||
<a-tag
|
||||
v-for="(item, index) in JSON.parse(record.draftUser)"
|
||||
:key="index"
|
||||
>{{ item }}</a-tag
|
||||
>
|
||||
</a-space>
|
||||
</template>
|
||||
<template v-if="column.key === 'users'">
|
||||
<a-space direction="vertical" v-if="record.users">
|
||||
<a-tag
|
||||
v-for="(item, index) in JSON.parse(record.users)"
|
||||
:key="index"
|
||||
>{{ item }}</a-tag
|
||||
>
|
||||
</a-space>
|
||||
</template>
|
||||
<template v-if="column.key === 'signUser'">
|
||||
<a-space direction="vertical" v-if="record.signUser">
|
||||
<a-tag
|
||||
v-for="(item, index) in JSON.parse(record.signUser)"
|
||||
:key="index"
|
||||
>{{ item }}</a-tag
|
||||
>
|
||||
</a-space>
|
||||
</template>
|
||||
<template v-if="column.key === 'saleUser'">
|
||||
<a-space direction="vertical" v-if="record.saleUser">
|
||||
<a-tag
|
||||
v-for="(item, index) in JSON.parse(record.saleUser)"
|
||||
:key="index"
|
||||
>{{ item }}</a-tag
|
||||
>
|
||||
</a-space>
|
||||
</template>
|
||||
<template v-if="column.key === 'electron'">
|
||||
<span>电子:</span>
|
||||
<a-tag v-if="record.electron === 0" color="green">已完成</a-tag>
|
||||
<a-tag v-else color="red">未完成</a-tag>
|
||||
<span>纸质:</span>
|
||||
<a-tag v-if="record.paper === 0" color="green">已完成</a-tag>
|
||||
<a-tag v-else color="red">未完成</a-tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'createTime'">
|
||||
<a-tooltip
|
||||
:title="`创建于:${record.createTime}`"
|
||||
class="flex flex-col"
|
||||
>
|
||||
<a-space>
|
||||
<span>{{ toDateString(record.createTime, 'YYYY-MM-dd') }}</span>
|
||||
<a-avatar :src="record.avatar" size="small" />
|
||||
</a-space>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<div>
|
||||
<a-space>
|
||||
<a class="action-btn bg-blue-500" @click="openReport(record)"
|
||||
>1生成审计方案</a
|
||||
>
|
||||
<a class="action-btn bg-green-600" @click="openReportContent(record)">2审计内容</a>
|
||||
<a class="action-btn bg-red-600" @click="openAuditCheck(record)"
|
||||
>3审计核查</a
|
||||
>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<a-space>
|
||||
<a class="edit-btn" @click="openEdit(record)">修改</a>
|
||||
<a-popconfirm
|
||||
title="确定要删除此记录吗?"
|
||||
@confirm="remove(record)"
|
||||
>
|
||||
<a class="remove-btn">删除</a>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</ele-pro-table>
|
||||
</a-card>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<Edit v-model:visible="showEdit" :data="current" @done="reload" />
|
||||
<!-- 生成报告 -->
|
||||
<Report v-model:visible="showReport" :data="current" @done="reload" />
|
||||
<ReportContent v-model:visible="showReportContent" :data="current" @done="reload" />
|
||||
<!-- 审计核查弹窗 -->
|
||||
<AuditCheck
|
||||
v-model:visible="showAuditCheck"
|
||||
:data="current"
|
||||
@done="reload"
|
||||
/>
|
||||
|
||||
<!-- 添加文档管理弹窗 -->
|
||||
<a-modal
|
||||
v-model:visible="showDocManage"
|
||||
:title="`文档管理 - ${currentDocType} - ${current?.name || ''}`"
|
||||
width="800px"
|
||||
:footer="null"
|
||||
>
|
||||
<div style="margin-bottom: 16px">
|
||||
<a-button type="primary" @click="openImport">新增文档</a-button>
|
||||
</div>
|
||||
<a-table
|
||||
:dataSource="docList"
|
||||
:columns="docColumns"
|
||||
:loading="docLoading"
|
||||
rowKey="id"
|
||||
:pagination="{
|
||||
current: currentPage,
|
||||
pageSize: 10,
|
||||
total: total,
|
||||
showSizeChanger: false,
|
||||
showTotal: (total) => `共 ${total} 条`
|
||||
}"
|
||||
@change="
|
||||
(pag) => {
|
||||
currentPage = pag.current;
|
||||
loadDocuments();
|
||||
}
|
||||
"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a-popconfirm
|
||||
title="确定要删除此文档吗?"
|
||||
@confirm="deleteDoc(record)"
|
||||
>
|
||||
<a class="ele-text-danger">删除</a>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-modal>
|
||||
|
||||
<!-- 导入弹窗 -->
|
||||
<Import
|
||||
v-model:visible="showImport"
|
||||
@done="loadDocuments"
|
||||
:kbId="currentKbId"
|
||||
/>
|
||||
</a-page-header>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createVNode, ref } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import type { EleProTable } from 'ele-admin-pro';
|
||||
import { toDateString } from 'ele-admin-pro';
|
||||
import type {
|
||||
DatasourceFunction,
|
||||
ColumnItem
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import Search from './components/search.vue';
|
||||
import Edit from './components/pwlProjectEdit.vue';
|
||||
import Report from './components/report.vue';
|
||||
import ReportContent from './components/reportContent.vue';
|
||||
import {
|
||||
pagePwlProject,
|
||||
removePwlProject,
|
||||
removeBatchPwlProject
|
||||
} from '@/api/pwl/pwlProject';
|
||||
import type { PwlProject, PwlProjectParam } from '@/api/pwl/pwlProject/model';
|
||||
import { getPageTitle } from '@/utils/common';
|
||||
import Extra from './components/extra.vue';
|
||||
import Import from '@/views/oa/oaCompany/components/Import.vue';
|
||||
import {
|
||||
getKnowledgeBaseDocuments,
|
||||
deleteKnowledgeBaseDocument
|
||||
} from '@/api/ai/knowledgeBase';
|
||||
import AuditCheck from './components/auditCheck.vue';
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
|
||||
// 表格选中数据
|
||||
const selection = ref<PwlProject[]>([]);
|
||||
// 当前编辑数据
|
||||
const current = ref<PwlProject | null>(null);
|
||||
// 是否显示编辑弹窗
|
||||
const showEdit = ref(false);
|
||||
// 是否显示报告弹窗
|
||||
const showReport = ref(false);
|
||||
// 是否显示审计核查弹窗
|
||||
const showAuditCheck = ref(false);
|
||||
// 是否显示批量移动弹窗
|
||||
const showMove = ref(false);
|
||||
// const draftUser = ref<string[]>([]);
|
||||
// const users = ref<string[]>([]);
|
||||
// const signUser = ref<string[]>([]);
|
||||
// const saleUser = ref<string[]>([]);
|
||||
// 加载状态
|
||||
const loading = ref(true);
|
||||
// 文档管理相关响应式变量
|
||||
const showDocManage = ref(false); // 是否显示文档管理弹窗
|
||||
const showImport = ref(false); // 是否显示导入弹窗
|
||||
const currentKbId = ref(''); // 当前知识库ID
|
||||
const currentDocType = ref(''); // 当前文档类型(材料分析/项目文档)
|
||||
const docList = ref<any[]>([]); // 文档列表数据
|
||||
const docLoading = ref(false); // 文档加载状态
|
||||
const currentPage = ref(1);
|
||||
const total = ref(0);
|
||||
|
||||
// 文档表格列配置
|
||||
const docColumns = ref([
|
||||
{
|
||||
title: '文件名',
|
||||
dataIndex: 'name',
|
||||
key: 'fileName'
|
||||
},
|
||||
{
|
||||
title: '文件大小',
|
||||
dataIndex: 'size',
|
||||
key: 'fileSize'
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
dataIndex: 'gmtModified',
|
||||
key: 'createTime',
|
||||
customRender: ({ text }) => toDateString(text)
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 100
|
||||
}
|
||||
]);
|
||||
|
||||
// 打开审计核查弹窗
|
||||
const openAuditCheck = (record: PwlProject) => {
|
||||
current.value = record;
|
||||
showAuditCheck.value = true;
|
||||
};
|
||||
|
||||
// 打开材料分析
|
||||
const openCaseManagement = (record: PwlProject) => {
|
||||
if (!record.analysisLibrary) {
|
||||
message.warning('当前记录没有关联材料分析知识库');
|
||||
return;
|
||||
}
|
||||
currentKbId.value = record.analysisLibrary;
|
||||
currentDocType.value = '材料分析';
|
||||
currentPage.value = 1;
|
||||
showDocManage.value = true;
|
||||
loadDocuments();
|
||||
};
|
||||
|
||||
// 打开项目文档
|
||||
const openDocumentManagement = (record: PwlProject) => {
|
||||
if (!record.projectLibrary) {
|
||||
message.warning('当前记录没有关联项目文档知识库');
|
||||
return;
|
||||
}
|
||||
currentKbId.value = record.projectLibrary;
|
||||
currentDocType.value = '项目文档';
|
||||
currentPage.value = 1;
|
||||
showDocManage.value = true;
|
||||
loadDocuments();
|
||||
};
|
||||
|
||||
// 加载文档列表
|
||||
const loadDocuments = async () => {
|
||||
docLoading.value = true;
|
||||
try {
|
||||
const response = await getKnowledgeBaseDocuments(
|
||||
currentKbId.value,
|
||||
10,
|
||||
currentPage.value
|
||||
);
|
||||
docList.value = Array.isArray(response?.list) ? response.list : [];
|
||||
total.value = response?.count || 0;
|
||||
} catch (error) {
|
||||
message.error('加载文档列表失败');
|
||||
console.error('加载文档错误:', error);
|
||||
} finally {
|
||||
docLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 删除文档
|
||||
const deleteDoc = async (record: any) => {
|
||||
try {
|
||||
await deleteKnowledgeBaseDocument(currentKbId.value, record.id);
|
||||
|
||||
// 立即本地删除
|
||||
const index = docList.value.findIndex((item) => item.id === record.id);
|
||||
if (index > -1) {
|
||||
docList.value.splice(index, 1);
|
||||
total.value -= 1;
|
||||
}
|
||||
message.success('删除成功');
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 打开导入弹窗
|
||||
const openImport = () => {
|
||||
showImport.value = true;
|
||||
};
|
||||
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
|
||||
return pagePwlProject({
|
||||
...where,
|
||||
...orders,
|
||||
page,
|
||||
limit
|
||||
});
|
||||
};
|
||||
|
||||
// 表格列配置
|
||||
const columns = ref<ColumnItem[]>([
|
||||
{
|
||||
title: '序号',
|
||||
key: 'index',
|
||||
width: 48,
|
||||
fixed: 'left',
|
||||
align: 'center',
|
||||
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
|
||||
},
|
||||
{
|
||||
title: '被审计单位',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 240,
|
||||
fixed: 'left',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '项目名称',
|
||||
dataIndex: 'code',
|
||||
key: 'code',
|
||||
width: 240,
|
||||
sorter: true,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '案引号',
|
||||
dataIndex: 'caseIndex',
|
||||
key: 'caseIndex',
|
||||
width: 240,
|
||||
sorter: true,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '项目完成进度',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 120,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '报告时间',
|
||||
dataIndex: 'expirationTime',
|
||||
key: 'expirationTime',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
// {
|
||||
// title: '类型',
|
||||
// dataIndex: 'type',
|
||||
// key: 'type',
|
||||
// align: 'center',
|
||||
// customRender: ({text}) => ['审字', '专审', '验证', '咨询'][text]
|
||||
// },
|
||||
{
|
||||
title: '项目信息',
|
||||
dataIndex: 'itemName',
|
||||
key: 'itemName',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '开票单位/汇款人',
|
||||
dataIndex: 'itemName',
|
||||
key: 'itemName',
|
||||
align: 'center',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '所属年度',
|
||||
dataIndex: 'itemYear',
|
||||
key: 'itemYear',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'itemType',
|
||||
key: 'itemType',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '审计意见',
|
||||
dataIndex: 'itemOpinion',
|
||||
key: 'itemOpinion',
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '年末资产总额(万元)',
|
||||
dataIndex: 'totalAssets',
|
||||
key: 'totalAssets',
|
||||
align: 'center',
|
||||
width: 170
|
||||
},
|
||||
{
|
||||
title: '合同金额',
|
||||
dataIndex: 'contractPrice',
|
||||
key: 'contractPrice',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '实收金额',
|
||||
dataIndex: 'payPrice',
|
||||
key: 'payPrice',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '到账信息',
|
||||
dataIndex: 'itemName',
|
||||
key: 'itemName',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '银行',
|
||||
dataIndex: 'bankName',
|
||||
key: 'bankName',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '日期',
|
||||
dataIndex: 'bankPayTime',
|
||||
key: 'bankPayTime',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
dataIndex: 'bankPrice',
|
||||
key: 'bankPrice',
|
||||
align: 'center',
|
||||
width: 120
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '开票信息',
|
||||
dataIndex: 'invoice',
|
||||
key: 'invoice',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '日期',
|
||||
dataIndex: 'invoiceTime',
|
||||
key: 'invoiceTime',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
dataIndex: 'invoicePrice',
|
||||
key: 'invoicePrice',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '发票类型',
|
||||
dataIndex: 'invoiceType',
|
||||
key: 'invoiceType',
|
||||
align: 'center',
|
||||
width: 120
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: '报告份数',
|
||||
dataIndex: 'reportNum',
|
||||
key: 'reportNum',
|
||||
align: 'center',
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
title: '底稿人员',
|
||||
dataIndex: 'draftUser',
|
||||
key: 'draftUser',
|
||||
align: 'center',
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
title: '参与成员',
|
||||
dataIndex: 'users',
|
||||
key: 'users',
|
||||
align: 'center',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '签字注会',
|
||||
dataIndex: 'signUser',
|
||||
key: 'signUser',
|
||||
align: 'center',
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
title: '展业人员',
|
||||
dataIndex: 'saleUser',
|
||||
key: 'saleUser',
|
||||
align: 'center',
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
title: '底稿完成情况',
|
||||
dataIndex: 'electron',
|
||||
key: 'electron',
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'comments',
|
||||
key: 'comments',
|
||||
align: 'center',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd HH:mm')
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 260,
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
hideInSetting: true
|
||||
}
|
||||
]);
|
||||
|
||||
/* 搜索 */
|
||||
const reload = (where?: PwlProjectParam) => {
|
||||
selection.value = [];
|
||||
tableRef?.value?.reload({ where: where });
|
||||
};
|
||||
|
||||
/* 打开编辑弹窗 */
|
||||
const openEdit = (row?: PwlProject) => {
|
||||
current.value = row ?? null;
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
const openReport = (row?: PwlProject) => {
|
||||
current.value = row ?? null;
|
||||
showReport.value = true;
|
||||
};
|
||||
|
||||
const showReportContent = ref(false)
|
||||
const openReportContent = (row?: PwlProject) => {
|
||||
current.value = row ?? null;
|
||||
showReportContent.value = true;
|
||||
};
|
||||
|
||||
/* 打开批量移动弹窗 */
|
||||
const openMove = () => {
|
||||
showMove.value = true;
|
||||
};
|
||||
|
||||
/* 删除单个 */
|
||||
const remove = (row: PwlProject) => {
|
||||
const hide = message.loading('请求中..', 0);
|
||||
removePwlProject(row.id)
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
reload();
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
/* 批量删除 */
|
||||
const removeBatch = () => {
|
||||
if (!selection.value.length) {
|
||||
message.error('请至少选择一条数据');
|
||||
return;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除选中的记录吗?',
|
||||
icon: createVNode(ExclamationCircleOutlined),
|
||||
maskClosable: true,
|
||||
onOk: () => {
|
||||
const hide = message.loading('请求中..', 0);
|
||||
removeBatchPwlProject(selection.value.map((d) => d.id))
|
||||
.then((msg) => {
|
||||
hide();
|
||||
message.success(msg);
|
||||
reload();
|
||||
})
|
||||
.catch((e) => {
|
||||
hide();
|
||||
message.error(e.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/* 查询 */
|
||||
const query = () => {
|
||||
loading.value = true;
|
||||
};
|
||||
|
||||
/* 自定义行属性 */
|
||||
const customRow = (record: PwlProject) => {
|
||||
return {
|
||||
// 行点击事件
|
||||
onClick: () => {
|
||||
// console.log(record);
|
||||
},
|
||||
// 行双击事件
|
||||
onDblclick: () => {
|
||||
openEdit(record);
|
||||
}
|
||||
};
|
||||
};
|
||||
query();
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'PwlProject'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.action-btn {
|
||||
border-radius: 3px;
|
||||
padding: 3px;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
border-radius: 3px;
|
||||
padding: 3px 10px;
|
||||
color: #3B82F6;
|
||||
border: 1px solid #3B82F6;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
border-radius: 3px;
|
||||
padding: 3px 10px;
|
||||
color: red;
|
||||
border: 1px solid red;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
/* 修改已完成步骤的连接线颜色 */
|
||||
.ant-steps-item-wait > .ant-steps-item-container > .ant-steps-item-tail::after {
|
||||
background-color: red !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user