【feat】项目手册管理功能优化

xuhongjie
项洋 2 months ago
parent 8f890ee7cf
commit ae6e44fd70

@ -40,6 +40,7 @@
"@riophae/vue-treeselect": "0.4.0",
"@vue-office/docx": "^1.6.3",
"@vue/composition-api": "^1.7.2",
"autofit.js": "^3.2.2",
"axios": "0.28.1",
"clipboard": "2.0.8",
"core-js": "3.37.1",

@ -906,7 +906,9 @@ export function deleteHandbook(idList) {
return request({
url: `/gysl/handbook/delete`,
method: 'delete',
params: { idList: idList.join(',') }
params:{
idList: idList.join(',')
}
});
}

@ -3,59 +3,57 @@
<!-- 项目手册管理 -->
<!-- 表单查询项 -->
<div v-if="!previewMode" class="headerbox">
<div class="search-form">
<div class="form-item">
<span class="label">手册名称</span>
<el-input
v-model="queryParams.name"
placeholder="请输入模板标题"
clearable
class="search-input"
/>
</div>
<div class="form-item">
<span class="label">创建时间</span>
<el-date-picker
v-model="queryParams.startTime"
type="date"
placeholder="选择日期"
class="search-date"
></el-date-picker>
</div>
<div class="form-item btn-group">
<el-button type="primary" icon="el-icon-search" @click="handleQuery"
>查询</el-button
>
<el-button icon="el-icon-refresh" @click="resetQuery"></el-button>
</div>
</div>
<el-form size="small" :inline="true" label-width="200">
<el-row>
<el-col :span="5">
<el-form-item label="手册名称" style="width: 100%;">
<el-input v-model="queryParams.name" placeholder="请输入手册名称" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="创建时间">
<el-date-picker
v-model="queryParams.startTime"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 100%;">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<!-- 表格内容区 -->
<div v-if="!previewMode" class="tablebox">
<div class="tablebtntwo">
<el-button
<!-- <el-button
type="primary"
icon="el-icon-plus"
size="mini"
:loading="exportLoading"
@click="handleExport"
>项目手册导出</el-button
>
> -->
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
size="small"
@click="handleAdd"
>新增</el-button
>
</div>
<el-table
v-loading="loading"
:data="postList"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table v-loading="loading" :data="postList">
<!-- @selection-change="handleSelectionChange"
<el-table-column type="selection" width="55" align="center" /> -->
<el-table-column label="序号" align="center">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
@ -88,6 +86,13 @@
@click="handleDelete(scope.row)"
>删除</el-button
>
<el-button
size="mini"
type="text"
style="color: #409eff"
@click="handleExport(scope.row.id)"
>项目手册导出</el-button
>
</template>
</el-table-column>
</el-table>
@ -203,7 +208,7 @@
</div>
<!-- 步骤2选择项目 -->
<div v-if="activeStep === 2" class="step-content project-step">
<div v-show="activeStep === 2" class="step-content project-step">
<div class="cover-form">
<div class="project-top">
<div class="search-container">
@ -222,22 +227,17 @@
<el-button @click="resetProjectSearch" class="search-btn"
>重置</el-button
>
<el-button
type="primary"
@click="confirmSelection"
class="search-btn"
>确认勾选</el-button
>
</div>
<div class="project-table">
<el-table
ref="projectTable"
:data="projectList"
@selection-change="handleProjectSelectionChange"
@row-click="handleRowClick"
height="400"
:row-key="(row) => row.id"
v-loading="loading"
@selection-change="handleSelectAll"
>
<el-table-column
type="selection"
@ -366,7 +366,7 @@
@click="submitHandbook"
v-if="activeStep === 3"
size="small"
>{{ editingHandbook ? '更新手册' : '生成手册' }}</el-button
>{{ editingHandbook ? "更新手册" : "生成手册" }}</el-button
>
</div>
</el-dialog>
@ -376,7 +376,7 @@
<script>
import VueOfficeDocx from "@vue-office/docx";
import pdf from "vue-pdf";
import axios from "axios";
import {
getHandbookPage,
addHandbook,
@ -418,7 +418,6 @@ export default {
subtitle: "",
imageUrl: "",
},
//
projectSearch: "",
projectList: [],
@ -428,34 +427,29 @@ export default {
pageSize: 10,
},
projectTotal: 0,
//
endForm: {
imageUrl: "",
subtitle: "",
},
//
selectedRows: [],
exportLoading: false,
selectedProjectIds: [], // id
// PDF
pdfData: null,
currentPage: 1,
pageCount: 0,
loadingPdf: false,
pdfScale: 0.9, // PDF
//
editingHandbook: null, //
isRestoringSelection: false, //
};
},
created() {
mounted() {
this.getList();
},
methods: {
//
getList() {
this.loading = true;
getHandbookPage(this.queryParams)
@ -510,39 +504,26 @@ export default {
// APIPDF
async loadPdfFromApi(id) {
try {
console.log("正在获取PDF文件ID:", id);
// 使APIPDF
const res = await exportHandbook([id]);
if (!res) {
throw new Error("获取PDF文件失败返回为空");
}
// Blob
const blob = new Blob([res], { type: "application/pdf" });
// URL
this.pdfData = URL.createObjectURL(blob);
console.log("PDF文件加载成功");
this.loadingPdf = false;
} catch (error) {
console.error("加载PDF文件失败:", error);
this.$message.error("PDF加载失败: " + (error.message || "未知错误"));
this.loadingPdf = false;
}
},
// PDF
pageLoaded() {
console.log("PDF页面加载完成");
this.loadingPdf = false;
},
// PDF
pdfLoaded() {
console.log("PDF文档加载完成");
this.loadingPdf = false;
},
// PDF
pdfError(error) {
console.error("PDF渲染错误:", error);
this.$message.error("PDF渲染失败: " + (error.message || "未知错误"));
this.loadingPdf = false;
},
@ -559,20 +540,20 @@ export default {
}
},
//
async handleExport() {
if (!this.selectedRows || this.selectedRows.length === 0) {
this.$message.warning("请先选择要导出的手册");
return;
}
async handleExport(id) {
// if (!this.selectedRows || this.selectedRows.length === 0) {
// this.$message.warning("");
// return;
// }
try {
this.exportLoading = true;
const idList = this.selectedRows.map((item) => item.id);
// const idList = this.selectedRows.map((item) => item.id);
//
const res = await exportHandbook(idList);
// const res = await exportHandbook(idList);
const res = await exportHandbook([id]);
this.$download.saveAs(res, "项目手册.pdf");
this.$message.success("导出成功");
} catch (error) {
console.error("导出错误:", error);
this.$message.error("导出过程中发生错误");
} finally {
this.exportLoading = false;
@ -585,6 +566,7 @@ export default {
this.editingHandbook = null;
this.selectedProjectIds = [];
this.selectedProjects = [];
this.projectParams.pageNum = 1 ;
this.getProjectList();
},
handleAddDialogClose(done) {
@ -617,7 +599,6 @@ export default {
//
nextStep() {
if (this.activeStep === 1) {
//
if (!this.coverForm.title) {
this.$message.warning("请输入手册名称");
return;
@ -625,11 +606,9 @@ export default {
}
this.activeStep++;
},
//
prevStep() {
this.activeStep--;
},
//
getProjectList() {
this.loading = true;
const params = {
@ -642,21 +621,21 @@ export default {
.then((response) => {
this.projectList = response.data.records;
this.projectTotal = response.data.total;
if (this.selectedProjectIds.length > 0) {
this.$nextTick(() => {
this.restoreSelection();
});
}
this.loading = false;
//
this.$nextTick(() => {
this.restoreSelection();
});
})
.catch((error) => {
console.error("获取项目列表失败:", error);
this.loading = false;
this.$message.error("获取项目列表失败");
});
},
//
searchProjects() {
// ID
this.projectParams.pageNum = 1;
this.getProjectList();
},
@ -666,51 +645,55 @@ export default {
this.projectParams.pageNum = 1;
this.getProjectList();
},
//
confirmSelection() {
if (this.selectedProjects.length === 0) {
this.$message.warning("请至少选择一个项目");
return;
}
this.$message.success(`已选择 ${this.selectedProjects.length} 个项目`);
},
handleProjectSelectionChange(selection) {
const currentPageIds = this.projectList.map((item) => item.id);
const otherPagesSelectedProjects = this.selectedProjects.filter(
(project) => !currentPageIds.includes(project.id)
);
this.selectedProjects = [...selection, ...otherPagesSelectedProjects];
const uncheckedIds = currentPageIds.filter(
(id) => !selection.some((selected) => selected.id === id)
);
this.selectedProjectIds = this.selectedProjectIds.filter(
(id) => !uncheckedIds.includes(id)
);
selection.forEach((item) => {
if (!this.selectedProjectIds.includes(item.id)) {
this.selectedProjectIds.push(item.id);
}
});
handleRowClick(row) {
//
this.$refs.projectTable.toggleRowSelection(row);
},
removeSelectedProject(project) {
//
this.selectedProjects = this.selectedProjects.filter(
(item) => item.id !== project.id
);
this.selectedProjectIds = this.selectedProjectIds.filter(
(id) => id !== project.id
);
this.$refs.projectTable.toggleRowSelection(
this.projectList.find((item) => item.id === project.id),
false
);
//
if (this.$refs.projectTable) {
const projectInCurrentPage = this.projectList.find(
(item) => item.id == project.id
);
if (projectInCurrentPage) {
this.$refs.projectTable.toggleRowSelection(
projectInCurrentPage,
false
);
}
}
},
handleProjectPagination() {
this.getProjectList();
},
handleRowClick(row) {
this.$refs.projectTable.toggleRowSelection(row);
//
restoreSelection() {
if (!this.$refs.projectTable) return;
this.$refs.projectTable.clearSelection();
if (!this.selectedProjectIds.length) return;
//
this.isRestoringSelection = true;
this.projectList.forEach((row) => {
if (this.selectedProjectIds.includes(row.id)) {
this.$refs.projectTable.toggleRowSelection(row, true);
}
});
//
this.$nextTick(() => {
this.isRestoringSelection = false;
});
},
//
@ -727,14 +710,8 @@ export default {
tail: this.endForm.subtitle,
xmId: this.selectedProjects.map((project) => project.id).join(","),
};
console.log("提交的数据:", data);
if (this.editingHandbook) {
// ID
data.id = this.editingHandbook.id;
// API
updateHandbook(data)
.then((res) => {
this.$message.success("手册更新成功");
@ -759,44 +736,67 @@ export default {
});
}
},
handleSelectAll(selection) {
//
if (this.isRestoringSelection) return;
// ID
const currentPageIds = this.projectList.map((item) => item.id);
//
const projectsNotInCurrentPage = this.selectedProjects.filter(
(project) => !currentPageIds.includes(project.id)
);
//
this.selectedProjects = [...projectsNotInCurrentPage, ...selection];
// ID
this.selectedProjectIds = this.selectedProjects.map(
(project) => project.id
);
},
//
handleEdit(row) {
//
this.loading = true;
getHandbookDetail(row.id).then(res => {
const detail = res.data;
//
this.coverForm = {
title: detail.name,
subtitle: detail.subtitle,
imageUrl: detail.coverImg
};
//
this.endForm = {
imageUrl: detail.tailingImg,
subtitle: detail.tail
};
// ID
if (detail.xmId) {
const projectIds = detail.xmId.split(',');
this.selectedProjectIds = projectIds;
console.log("已选项目ID列表", this.selectedProjectIds);
getHandbookDetail(row.id)
.then((res) => {
const detail = res.data;
this.coverForm = {
title: detail.name,
subtitle: detail.subtitle,
imageUrl: detail.coverImg,
};
this.endForm = {
imageUrl: detail.tailingImg,
subtitle: detail.tail,
};
//
this.getProjectList();
}
this.loading = false;
this.addDialogVisible = true;
this.activeStep = 1;
this.editingHandbook = detail;
}).catch(() => {
this.$message.error("获取手册详情失败");
this.loading = false;
});
//
this.selectedProjectIds = [];
this.selectedProjects = [];
if (detail.xmId) {
const projectIds = detail.xmId.split(",");
this.selectedProjectIds = projectIds.map((id) => Number(id));
//
if (detail.projectName && Array.isArray(detail.projectName)) {
this.selectedProjects = detail.projectName;
}
this.projectParams.pageNum = 1 ;
this.getProjectList();
}
this.loading = false;
this.addDialogVisible = true;
this.activeStep = 1;
this.editingHandbook = detail;
})
.catch(() => {
this.$message.error("获取手册详情失败");
this.loading = false;
});
},
//
handleDelete(row) {
@ -805,39 +805,17 @@ export default {
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.$message.success("删除成功");
this.getList();
.then(async () => {
this.loading = true;
const idList = [row.id];
await deleteHandbook(idList).then(() => {
this.$message.success("删除成功");
this.getList();
});
this.loading = false;
})
.catch(() => {});
},
//
restoreSelection() {
if (this.$refs.projectTable) {
this.$refs.projectTable.clearSelection();
const selectedRows = this.projectList.filter((row) =>
this.selectedProjectIds.includes(row.id)
);
selectedRows.forEach((row) => {
this.$refs.projectTable.toggleRowSelection(row, true);
});
const currentPageIds = this.projectList.map((item) => item.id);
const otherPagesSelectedProjects = this.selectedProjects.filter(
(project) =>
!currentPageIds.includes(project.id) &&
this.selectedProjectIds.includes(project.id)
);
const currentPageSelectedProjects = this.projectList.filter((item) =>
this.selectedProjectIds.includes(item.id)
);
//
this.selectedProjects = [
...currentPageSelectedProjects,
...otherPagesSelectedProjects,
];
}
},
},
};
</script>
@ -851,7 +829,11 @@ export default {
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
border: 1px solid #eee;
margin: 0.5rem
margin: 0.5rem;
.el-input {
flex: 1;
max-width: 100%;
}
}
.headerbox {
@ -882,9 +864,17 @@ export default {
.search-input,
.search-date {
width: 240px;
width: 30%;
transition: all 0.3s;
margin-right: 30px;
::v-deep .el-input {
flex: 1!important;
max-width: 100%!important;
}
::v-deep .el-input__inner {
width: 100%!important;
}
&:hover {
box-shadow: 0 0 0 1px #409eff;
}
@ -899,7 +889,7 @@ export default {
.tablebtntwo {
width: 100%;
display: flex;
justify-content: space-between;
justify-content: right;
margin: 10px 0 20px;
}
@ -935,7 +925,7 @@ export default {
/* PDF预览区域样式 */
.previewbox {
height: calc(100vh - 50px);
height: calc(100% - 50px);
z-index: 1500;
display: flex;
flex-direction: column;
@ -1136,11 +1126,6 @@ export default {
font-size: 14px;
}
.el-input {
flex: 1;
max-width: 80%;
}
/* 上传区域样式 */
.upload-area {
flex: 1;

Loading…
Cancel
Save