feat(pwl): 新增生成报告功能
- 添加生成报告弹窗组件 - 实现报告内容的 AI 生成逻辑 - 优化用户界面,增加导航和快捷键功能
This commit is contained in:
758
src/views/pwl/pwlProject/components/report.vue
Normal file
758
src/views/pwl/pwlProject/components/report.vue
Normal file
@@ -0,0 +1,758 @@
|
||||
<!-- 用户编辑弹窗 -->
|
||||
<template>
|
||||
<a-drawer
|
||||
:width="`80%`"
|
||||
:visible="visible"
|
||||
:confirm-loading="loading"
|
||||
:maxable="maxAble"
|
||||
title="AI审计方案生成器"
|
||||
:body-style="{ paddingBottom: '8px', background: '#f3f3f3' }"
|
||||
@update:visible="updateVisible"
|
||||
:maskClosable="false"
|
||||
:footer="null"
|
||||
@ok="save"
|
||||
>
|
||||
<a-card title="基本信息" style="margin-bottom: 20px" :bordered="false">
|
||||
<a-descriptions>
|
||||
<a-descriptions-item
|
||||
label="公司名称"
|
||||
:labelStyle="{ width: '90px', color: '#808080' }"
|
||||
>
|
||||
<span @click="copyText(form.name)">{{ form.name }}</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
label="被审计人"
|
||||
:labelStyle="{ width: '90px', color: '#808080' }"
|
||||
>
|
||||
<span>{{ form.nickname || '暂无' }}</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
label="审计时间"
|
||||
:labelStyle="{ width: '90px', color: '#808080' }"
|
||||
>
|
||||
<span>{{ form.expirationTime }}</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
|
||||
<a-card style="margin-bottom: 20px; text-align: center; background: transparent" :bordered="false">
|
||||
<a-space>
|
||||
<a-button type="primary" size="large">
|
||||
<template #icon>
|
||||
<UngroupOutlined/>
|
||||
</template>
|
||||
生成全部方案
|
||||
</a-button>
|
||||
<a-button size="large">
|
||||
<template #icon>
|
||||
<DownloadOutlined/>
|
||||
</template>
|
||||
保存草稿
|
||||
</a-button>
|
||||
<a-button size="large">
|
||||
<template #icon>
|
||||
<RedoOutlined/>
|
||||
</template>
|
||||
加载草稿
|
||||
</a-button>
|
||||
<a-button size="large">
|
||||
<template #icon>
|
||||
<UploadOutlined/>
|
||||
</template>
|
||||
导出文本
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-card>
|
||||
|
||||
<!-- 快速导航 -->
|
||||
<a-card style="margin-bottom: 20px" :bordered="false">
|
||||
<template #title>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between;">
|
||||
<span>快速导航</span>
|
||||
<a-tooltip title="快捷键:Ctrl+1~9 快速跳转,Ctrl+↑↓ 上下导航">
|
||||
<QuestionCircleOutlined style="color: #999; cursor: help;"/>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="navigation-container">
|
||||
<div class="nav-grid">
|
||||
<a-button
|
||||
v-for="(item, index) in navigationItems"
|
||||
:key="index"
|
||||
:type="currentSection === index ? 'primary' : 'default'"
|
||||
size="small"
|
||||
@click="scrollToSection(index)"
|
||||
class="nav-button"
|
||||
:class="{ 'active': currentSection === index }"
|
||||
>
|
||||
<span class="nav-number">{{ item.number }}</span>
|
||||
<span class="nav-text">{{ item.name }}</span>
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<!-- 进度指示器 -->
|
||||
<div class="progress-container">
|
||||
<div class="progress-bar">
|
||||
<div
|
||||
class="progress-fill"
|
||||
:style="{ width: `${((currentSection + 1) / navigationItems.length) * 100}%` }"
|
||||
></div>
|
||||
</div>
|
||||
<div class="progress-text">
|
||||
{{ currentSection + 1 }} / {{ navigationItems.length }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
<!-- 审计方案内容 -->
|
||||
<div class="audit-content">
|
||||
<div
|
||||
v-for="(item, index) in navigationItems"
|
||||
:key="index"
|
||||
:id="`section-${index}`"
|
||||
class="audit-section"
|
||||
>
|
||||
<a-card
|
||||
:title="`${item.number}、${item.name}`"
|
||||
style="margin-bottom: 20px"
|
||||
:bordered="false"
|
||||
>
|
||||
<template #extra>
|
||||
<a-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="generateContent(index)"
|
||||
:loading="item.generating"
|
||||
>
|
||||
<template #icon>
|
||||
<RobotOutlined/>
|
||||
</template>
|
||||
AI生成
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<div class="section-description">
|
||||
{{ item.description }}
|
||||
</div>
|
||||
|
||||
<a-textarea
|
||||
v-model:value="item.content"
|
||||
:rows="item.rows || 8"
|
||||
:placeholder="item.placeholder"
|
||||
class="content-textarea"
|
||||
style="margin-top: 16px"
|
||||
/>
|
||||
</a-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 返回顶部按钮 -->
|
||||
<a-back-top :target="getScrollContainer"/>
|
||||
</a-drawer>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, reactive, watch, onMounted, onUnmounted} from 'vue';
|
||||
import {Form} from 'ant-design-vue';
|
||||
import {assignObject} from 'ele-admin-pro';
|
||||
import {copyText} from '@/utils/common';
|
||||
import {PwlProject} from "@/api/pwl/pwlProject/model";
|
||||
import {
|
||||
UngroupOutlined,
|
||||
DownloadOutlined,
|
||||
UploadOutlined,
|
||||
RedoOutlined,
|
||||
RobotOutlined,
|
||||
QuestionCircleOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
const useForm = Form.useForm;
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
visible: boolean;
|
||||
// 修改回显的数据
|
||||
data?: PwlProject | null;
|
||||
}>();
|
||||
|
||||
// 是否显示最大化切换按钮
|
||||
const maxAble = ref(true);
|
||||
// 当前选中的章节
|
||||
const currentSection = ref(0);
|
||||
|
||||
// 九大审计项目导航配置
|
||||
const navigationItems = ref([
|
||||
{
|
||||
number: '一',
|
||||
name: '审计依据',
|
||||
title: '1、审计依据',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入审计依据内容...',
|
||||
content: `(一)中共中央办公厅、国务院办公厅《党政主要领导干部和国有企业领导人员经济责任审计规定》(2019年7月7日起实施);
|
||||
|
||||
(二)XXX有限公司经济责任审计管理办法》(XX(**)**号(待补充));
|
||||
|
||||
(三)国家有关法律、法规及相关文件;
|
||||
|
||||
(四)XXX有限公司下达的年度工作目标;
|
||||
|
||||
(五)XXX有限公司各项管理制度;
|
||||
|
||||
(六)双方签订的审计业务约定书。`,
|
||||
rows: 10,
|
||||
generating: false
|
||||
},
|
||||
{
|
||||
number: '二',
|
||||
name: '审计目标',
|
||||
title: '2、审计目标',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入审计目标内容...',
|
||||
content: `通过对XXX同志、XXX同志任职期间所负责公司资产、负债情况的真实性、合法性和效益性及其相关经济活动进行审计,查清其任职期间公司财经政策指导和财务收支工作目标完成情况,重大决策执行及交接情况,遵守国家财经法规情况及公司资产保值增值情况,分清其经济责任,评价其工作业绩,对其任职期间履行经济责任情况作出客观公正的评价。`,
|
||||
rows: 6,
|
||||
generating: false
|
||||
},
|
||||
{
|
||||
number: '三',
|
||||
name: '审计对象和范围',
|
||||
title: '3、审计对象和范围',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入审计对象和范围内容...',
|
||||
content: '',
|
||||
rows: 8,
|
||||
generating: false
|
||||
},
|
||||
{
|
||||
number: '四',
|
||||
name: '被审计单位基本情况',
|
||||
title: '4、被审计单位基本情况',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入被审计单位基本情况内容...',
|
||||
content: '',
|
||||
rows: 10,
|
||||
generating: false
|
||||
},
|
||||
{
|
||||
number: '五',
|
||||
name: '审计内容和重点及审计方法',
|
||||
title: '5、审计内容和重点及审计方法',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入审计内容和重点及审计方法内容...',
|
||||
content: '',
|
||||
rows: 12,
|
||||
generating: false
|
||||
},
|
||||
{
|
||||
number: '六',
|
||||
name: '重要风险的识别及应对',
|
||||
title: '6、重要风险的识别及应对',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入重要风险的识别及应对内容...',
|
||||
content: '',
|
||||
rows: 10,
|
||||
generating: false
|
||||
},
|
||||
{
|
||||
number: '七',
|
||||
name: '审计技术方法',
|
||||
title: '7、审计技术方法',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入审计技术方法内容...',
|
||||
content: '',
|
||||
rows: 8,
|
||||
generating: false
|
||||
},
|
||||
{
|
||||
number: '八',
|
||||
name: '工作步骤与时间安排',
|
||||
title: '8、工作步骤与时间安排',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入工作步骤与时间安排内容...',
|
||||
content: '',
|
||||
rows: 10,
|
||||
generating: false
|
||||
},
|
||||
{
|
||||
number: '九',
|
||||
name: '审计工作的组织实施',
|
||||
title: '9、审计工作的组织实施',
|
||||
description: '点击"AI生成"按钮让AI为您生成该部分内容,或直接在下方编辑',
|
||||
placeholder: '请输入审计工作的组织实施内容...',
|
||||
content: '',
|
||||
rows: 8,
|
||||
generating: false
|
||||
}
|
||||
]);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'done'): void;
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
// 订单信息
|
||||
const form = reactive<PwlProject>({
|
||||
// ID
|
||||
id: undefined,
|
||||
// 项目名称
|
||||
name: undefined,
|
||||
// 项目标识
|
||||
code: undefined,
|
||||
// 上级id, 0是顶级
|
||||
parentId: undefined,
|
||||
// 项目类型
|
||||
type: undefined,
|
||||
// 项目图标
|
||||
image: undefined,
|
||||
// 二维码
|
||||
qrcode: undefined,
|
||||
// 链接地址
|
||||
url: undefined,
|
||||
// 应用截图
|
||||
images: undefined,
|
||||
// 底稿情况
|
||||
files: undefined,
|
||||
// 应用介绍
|
||||
content: undefined,
|
||||
// 年末资产总额(万元)
|
||||
totalAssets: undefined,
|
||||
// 合同金额
|
||||
contractPrice: undefined,
|
||||
// 实收金额
|
||||
payPrice: undefined,
|
||||
// 软件定价
|
||||
price: undefined,
|
||||
// 是否推荐
|
||||
recommend: undefined,
|
||||
// 到期时间
|
||||
expirationTime: undefined,
|
||||
// 项目信息-开票单位/汇款人
|
||||
itemName: undefined,
|
||||
// 项目信息-年度
|
||||
itemYear: undefined,
|
||||
// 项目信息-类型
|
||||
itemType: undefined,
|
||||
// 项目信息-审计意见
|
||||
itemOpinion: undefined,
|
||||
// 到账信息-银行名称
|
||||
bankName: undefined,
|
||||
// 到账日期
|
||||
bankPayTime: undefined,
|
||||
// 到账金额
|
||||
bankPrice: undefined,
|
||||
// 发票类型
|
||||
invoiceType: undefined,
|
||||
// 开票日期
|
||||
invoiceTime: undefined,
|
||||
// 开票金额
|
||||
invoicePrice: undefined,
|
||||
// 报告份数
|
||||
reportNum: undefined,
|
||||
// 底稿人员
|
||||
draftUserId: undefined,
|
||||
// 底稿人员
|
||||
draftUser: undefined,
|
||||
// 参与成员
|
||||
userIds: undefined,
|
||||
users: undefined,
|
||||
// 签字注会
|
||||
signUserId: undefined,
|
||||
signUser: undefined,
|
||||
// 展业人员
|
||||
saleUserId: undefined,
|
||||
saleUser: undefined,
|
||||
// 备注
|
||||
comments: undefined,
|
||||
// 排序(数字越小越靠前)
|
||||
sortNumber: undefined,
|
||||
// 状态, 0正常, 1冻结
|
||||
status: undefined,
|
||||
// 电子报告是否已完成
|
||||
electron: undefined,
|
||||
// 纸质报告是否已完成
|
||||
paper: undefined,
|
||||
// 是否删除, 0否, 1是
|
||||
deleted: undefined,
|
||||
// 创建人ID
|
||||
userId: undefined,
|
||||
// 创建人
|
||||
realName: undefined,
|
||||
// 租户id
|
||||
tenantId: undefined,
|
||||
// 创建时间
|
||||
createTime: undefined,
|
||||
// 修改时间
|
||||
updateTime: undefined,
|
||||
});
|
||||
|
||||
// 请求状态
|
||||
const loading = ref(true);
|
||||
|
||||
const {resetFields} = useForm(form);
|
||||
|
||||
/* 更新visible */
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
|
||||
/* 滚动到指定章节 */
|
||||
const scrollToSection = (index: number) => {
|
||||
currentSection.value = index;
|
||||
const element = document.getElementById(`section-${index}`);
|
||||
if (element) {
|
||||
element.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/* 获取滚动容器 */
|
||||
const getScrollContainer = () => {
|
||||
return document.querySelector('.ant-modal-body');
|
||||
};
|
||||
|
||||
/* AI生成内容 */
|
||||
const generateContent = async (index: number) => {
|
||||
const item = navigationItems.value[index];
|
||||
item.generating = true;
|
||||
|
||||
try {
|
||||
// 这里可以调用AI接口生成内容
|
||||
// 模拟AI生成过程
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
// 根据不同章节生成不同的示例内容
|
||||
const sampleContent = getSampleContent(index);
|
||||
item.content = sampleContent;
|
||||
|
||||
} catch (error) {
|
||||
console.error('AI生成失败:', error);
|
||||
} finally {
|
||||
item.generating = false;
|
||||
}
|
||||
};
|
||||
|
||||
/* 获取示例内容 */
|
||||
const getSampleContent = (index: number) => {
|
||||
const samples = [
|
||||
// 审计依据
|
||||
`(一)中共中央办公厅、国务院办公厅《党政主要领导干部和国有企业领导人员经济责任审计规定》(2019年7月7日起实施);
|
||||
|
||||
(二)${form.name}经济责任审计管理办法》(相关文件编号);
|
||||
|
||||
(三)国家有关法律、法规及相关文件;
|
||||
|
||||
(四)${form.name}下达的年度工作目标;
|
||||
|
||||
(五)${form.name}各项管理制度;
|
||||
|
||||
(六)双方签订的审计业务约定书。`,
|
||||
|
||||
// 审计目标
|
||||
`通过对${form.name}相关负责人任职期间所负责公司资产、负债情况的真实性、合法性和效益性及其相关经济活动进行审计,查清其任职期间公司财经政策指导和财务收支工作目标完成情况,重大决策执行及交接情况,遵守国家财经法规情况及公司资产保值增值情况,分清其经济责任,评价其工作业绩,对其任职期间履行经济责任情况作出客观公正的评价。`,
|
||||
|
||||
// 审计对象和范围
|
||||
`审计对象:${form.name}及其相关负责人
|
||||
审计范围:${form.itemYear || '相关年度'}年度财务收支情况、资产管理情况、重大经济决策情况等。
|
||||
具体包括:
|
||||
1. 财务收支的真实性、合法性;
|
||||
2. 资产、负债、损益的真实性;
|
||||
3. 重大经济决策的程序性和效果性;
|
||||
4. 内部控制制度的建立和执行情况。`,
|
||||
|
||||
// 被审计单位基本情况
|
||||
`${form.name}基本情况:
|
||||
成立时间:[待补充]
|
||||
注册资本:[待补充]
|
||||
经营范围:[待补充]
|
||||
组织架构:[待补充]
|
||||
主要业务:[待补充]
|
||||
年末资产总额:${form.totalAssets ? form.totalAssets + '万元' : '[待补充]'}`,
|
||||
|
||||
// 审计内容和重点及审计方法
|
||||
`审计内容:
|
||||
1. 财务收支审计
|
||||
2. 资产负债审计
|
||||
3. 经营管理审计
|
||||
4. 内部控制审计
|
||||
|
||||
审计重点:
|
||||
1. 重大经济决策的合规性
|
||||
2. 资产保值增值情况
|
||||
3. 财务管理制度执行情况
|
||||
4. 风险控制措施有效性
|
||||
|
||||
审计方法:
|
||||
1. 账项基础审计
|
||||
2. 制度基础审计
|
||||
3. 风险导向审计
|
||||
4. 计算机辅助审计`,
|
||||
|
||||
// 重要风险的识别及应对
|
||||
`重要风险识别:
|
||||
1. 财务报告风险
|
||||
2. 合规性风险
|
||||
3. 经营风险
|
||||
4. 信息系统风险
|
||||
|
||||
应对措施:
|
||||
1. 加强内部控制测试
|
||||
2. 扩大实质性程序范围
|
||||
3. 增加专业判断和职业怀疑
|
||||
4. 运用专家工作和外部确认`,
|
||||
|
||||
// 审计技术方法
|
||||
`主要采用的审计技术方法:
|
||||
1. 检查:检查记录或文件
|
||||
2. 观察:观察流程或程序的执行
|
||||
3. 询问:向相关人员询问
|
||||
4. 函证:向第三方函证
|
||||
5. 重新计算:重新计算相关数据
|
||||
6. 重新执行:重新执行相关控制
|
||||
7. 分析程序:分析财务和非财务信息`,
|
||||
|
||||
// 工作步骤与时间安排
|
||||
`工作步骤:
|
||||
第一阶段:审计准备(X天)
|
||||
- 了解被审计单位情况
|
||||
- 制定审计计划
|
||||
- 组建审计组
|
||||
|
||||
第二阶段:现场审计(X天)
|
||||
- 内部控制测试
|
||||
- 实质性程序执行
|
||||
- 获取审计证据
|
||||
|
||||
第三阶段:审计报告(X天)
|
||||
- 汇总审计发现
|
||||
- 撰写审计报告
|
||||
- 与被审计单位沟通`,
|
||||
|
||||
// 审计工作的组织实施
|
||||
`组织架构:
|
||||
审计组长:[待指定]
|
||||
审计组员:[待指定]
|
||||
技术复核:[待指定]
|
||||
|
||||
实施要求:
|
||||
1. 严格按照审计准则执行
|
||||
2. 保持职业怀疑态度
|
||||
3. 获取充分适当的审计证据
|
||||
4. 及时与被审计单位沟通
|
||||
5. 按时完成审计工作
|
||||
6. 确保审计质量`
|
||||
];
|
||||
|
||||
return samples[index] || '请输入相关内容...';
|
||||
};
|
||||
|
||||
/* 监听滚动位置更新当前章节 */
|
||||
const handleScroll = () => {
|
||||
const sections = navigationItems.value.map((_, index) =>
|
||||
document.getElementById(`section-${index}`)
|
||||
);
|
||||
|
||||
const scrollContainer = getScrollContainer();
|
||||
if (!scrollContainer) return;
|
||||
|
||||
const containerTop = scrollContainer.getBoundingClientRect().top;
|
||||
|
||||
for (let i = sections.length - 1; i >= 0; i--) {
|
||||
const section = sections[i];
|
||||
if (section) {
|
||||
const sectionTop = section.getBoundingClientRect().top - containerTop;
|
||||
if (sectionTop <= 100) { // 100px 的偏移量
|
||||
currentSection.value = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* 键盘快捷键处理 */
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
// 只在弹窗打开时处理快捷键
|
||||
if (!props.visible) return;
|
||||
|
||||
// Ctrl/Cmd + 数字键 1-9 快速跳转
|
||||
if ((event.ctrlKey || event.metaKey) && event.key >= '1' && event.key <= '9') {
|
||||
event.preventDefault();
|
||||
const index = parseInt(event.key) - 1;
|
||||
if (index < navigationItems.value.length) {
|
||||
scrollToSection(index);
|
||||
}
|
||||
}
|
||||
|
||||
// 上下箭头键导航
|
||||
if (event.key === 'ArrowUp' && event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
const prevIndex = Math.max(0, currentSection.value - 1);
|
||||
scrollToSection(prevIndex);
|
||||
} else if (event.key === 'ArrowDown' && event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
const nextIndex = Math.min(navigationItems.value.length - 1, currentSection.value + 1);
|
||||
scrollToSection(nextIndex);
|
||||
}
|
||||
};
|
||||
|
||||
/* 保存编辑 */
|
||||
const save = () => {
|
||||
};
|
||||
|
||||
// 组件挂载时添加滚动监听和键盘监听
|
||||
onMounted(() => {
|
||||
const scrollContainer = getScrollContainer();
|
||||
if (scrollContainer) {
|
||||
scrollContainer.addEventListener('scroll', handleScroll);
|
||||
}
|
||||
document.addEventListener('keydown', handleKeydown);
|
||||
});
|
||||
|
||||
// 组件卸载时移除监听
|
||||
onUnmounted(() => {
|
||||
const scrollContainer = getScrollContainer();
|
||||
if (scrollContainer) {
|
||||
scrollContainer.removeEventListener('scroll', handleScroll);
|
||||
}
|
||||
document.removeEventListener('keydown', handleKeydown);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
if (props.data) {
|
||||
loading.value = true;
|
||||
assignObject(form, props.data);
|
||||
// 重置到第一个章节
|
||||
currentSection.value = 0;
|
||||
}
|
||||
} else {
|
||||
resetFields();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import * as MenuIcons from '@/layout/menu-icons';
|
||||
|
||||
export default {
|
||||
name: 'PwlProjectInfo',
|
||||
components: MenuIcons
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.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: 8px;
|
||||
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: #666;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
padding: 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
border-left: 4px 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;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -69,7 +69,7 @@
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<a class="text-pink-500" @click="openEdit(record)">生成报告</a>
|
||||
<a class="text-pink-500" @click="openReport(record)">生成报告</a>
|
||||
<a-divider type="vertical"/>
|
||||
<a @click="openEdit(record)">修改</a>
|
||||
<a-divider type="vertical"/>
|
||||
@@ -85,7 +85,9 @@
|
||||
</a-card>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<PwlProjectEdit v-model:visible="showEdit" :data="current" @done="reload"/>
|
||||
<Edit v-model:visible="showEdit" :data="current" @done="reload"/>
|
||||
<!-- 生成报告 -->
|
||||
<Report v-model:visible="showReport" :data="current" @done="reload"/>
|
||||
</a-page-header>
|
||||
</template>
|
||||
|
||||
@@ -100,7 +102,8 @@ import type {
|
||||
ColumnItem
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import Search from './components/search.vue';
|
||||
import PwlProjectEdit from './components/pwlProjectEdit.vue';
|
||||
import Edit from './components/pwlProjectEdit.vue';
|
||||
import Report from './components/report.vue';
|
||||
import {pagePwlProject, removePwlProject, removeBatchPwlProject} from '@/api/pwl/pwlProject';
|
||||
import type {PwlProject, PwlProjectParam} from '@/api/pwl/pwlProject/model';
|
||||
import {getPageTitle} from "@/utils/common";
|
||||
@@ -115,6 +118,8 @@ const selection = ref<PwlProject[]>([]);
|
||||
const current = ref<PwlProject | null>(null);
|
||||
// 是否显示编辑弹窗
|
||||
const showEdit = ref(false);
|
||||
// 是否显示报告弹窗
|
||||
const showReport = ref(false);
|
||||
// 是否显示批量移动弹窗
|
||||
const showMove = ref(false);
|
||||
// const draftUser = ref<string[]>([]);
|
||||
@@ -380,6 +385,11 @@ const openEdit = (row?: PwlProject) => {
|
||||
showEdit.value = true;
|
||||
};
|
||||
|
||||
const openReport = (row?: PwlProject) => {
|
||||
current.value = row ?? null;
|
||||
showReport.value = true;
|
||||
}
|
||||
|
||||
/* 打开批量移动弹窗 */
|
||||
const openMove = () => {
|
||||
showMove.value = true;
|
||||
|
||||
Reference in New Issue
Block a user