<template> <div style="height: 100%"> <!-- 项目手册管理 --> <!-- 表单查询项 --> <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> </div> <!-- 表格内容区 --> <div v-if="!previewMode" class="tablebox"> <div class="tablebtntwo"> <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" @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-column label="序号" align="center"> <template slot-scope="scope"> <span>{{ scope.$index + 1 }}</span> </template> </el-table-column> <el-table-column label="手册名称" align="center" prop="name" /> <!-- <el-table-column label="发布单位" align="center" prop="unit" /> --> <!-- <el-table-column label="发布人" align="center" prop="author" /> --> <el-table-column label="创建时间" align="center" prop="createTime" /> <el-table-column label="操作" align="center"> <template slot-scope="scope"> <el-button size="mini" type="text" style="color: gray" @click="handlePreview(scope.row)" >预览</el-button > <el-button size="mini" type="text" style="color: #67c23a" @click="handleEdit(scope.row)" >编辑</el-button > <el-button size="mini" type="text" style="color: #f56c6c" @click="handleDelete(scope.row)" >删除</el-button > </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" :page.sync="queryParams.current" :limit.sync="queryParams.size" @pagination="getList" /> </div> <div v-if="previewMode" class="previewbox"> <div class="preview-header"> <div class="preview-title"> <i class="el-icon-document"></i> <span>{{ previewData.name || "项目手册预览" }}</span> </div> <div class="preview-controls"> <div class="page-counter" v-if="pageCount > 0"> <span>{{ currentPage }} / {{ pageCount }}</span> </div> <el-button-group class="navigation-buttons"> <el-button size="mini" type="primary" icon="el-icon-arrow-left" :disabled="currentPage <= 1" @click="prevPage" >上一页</el-button > <el-button size="mini" type="primary" icon="el-icon-arrow-right" :disabled="currentPage >= pageCount" @click="nextPage" >下一页</el-button > </el-button-group> <el-button size="mini" type="info" icon="el-icon-back" @click="previewMode = false" >返回</el-button > </div> </div> <div class="preview-content" v-loading="loadingPdf"> <pdf v-if="pdfData" :src="pdfData" :page="currentPage" @num-pages="pageCount = $event" @page-loaded="pageLoaded" @loaded="pdfLoaded" @error="pdfError" :scale="pdfScale" ></pdf> </div> </div> <!-- 创建新手册弹框 --> <el-dialog :title="editingHandbook ? '编辑手册' : '创建新手册'" :visible.sync="addDialogVisible" width="70%" :close-on-click-modal="false" :show-close="true" :before-close="handleAddDialogClose" class="handbook-dialog" > <div class="step-container"> <el-steps :active="activeStep" align-center finish-status="finish "> <el-step title="封面设置"></el-step> <el-step title="选择项目"></el-step> <el-step title="封尾设计"></el-step> </el-steps> </div> <!-- 步骤1:封面设置 --> <div v-if="activeStep === 1" class="step-content"> <div class="cover-form"> <div class="form-row"> <div class="form-col"> <label class="form-label">手册名称</label> <el-input v-model="coverForm.title" placeholder="请输入" ></el-input> </div> <div class="form-col"> <label class="form-label">副标题</label> <el-input v-model="coverForm.subtitle" placeholder="请输入" ></el-input> </div> </div> <div class="form-row"> <div class="form-col-full"> <label class="form-label">封面图片</label> <file-upload v-model="coverForm.imageUrl" :limit="1" :file-size="10" :file-type="['png', 'jpg', 'jpeg', 'gif']" ></file-upload> </div> </div> </div> </div> <!-- 步骤2:选择项目 --> <div v-if="activeStep === 2" class="step-content project-step"> <div class="cover-form"> <div class="project-top"> <div class="search-container"> <div class="search-label">项目名称:</div> <el-input v-model="projectSearch" placeholder="请输入" class="search-input" ></el-input> <el-button type="primary" @click="searchProjects" class="search-btn" >查询</el-button > <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" > <el-table-column type="selection" width="55" align="center" :reserve-selection="true" ></el-table-column> <el-table-column label="序号" width="60" align="center"> <template slot-scope="scope">{{ scope.$index + 1 }}</template> </el-table-column> <el-table-column prop="name" label="项目名称" align="center" ></el-table-column> <el-table-column prop="xzfl" label="现状分类" align="center" ></el-table-column> <el-table-column prop="xmfrdwxz" label="项目法人单位" align="center" > </el-table-column> <el-table-column label="项目建设起止时间" align="center"> <template slot-scope="scope"> <span >{{ scope.row.begainTime ? scope.row.begainTime.replace(/-/g, ".") : "" }}-{{ scope.row.endTime ? scope.row.endTime.replace(/-/g, ".") : "" }}</span > </template> </el-table-column> <el-table-column prop="ztze" label="总投资额(万元)" align="center" ></el-table-column> <el-table-column prop="zydmj" label="总用地面积(平方米)" align="center" ></el-table-column> </el-table> <div class="pagination-box"> <pagination v-show="projectTotal > 0" :total="projectTotal" :page.sync="projectParams.pageNum" :limit.sync="projectParams.pageSize" @pagination="handleProjectPagination" /> </div> </div> </div> <div class="selected-projects-container" v-if="selectedProjects.length > 0" > <div class="selected-header">已选中项目</div> <div class="selected-list"> <div v-for="(project, index) in selectedProjects" :key="index" class="selected-item" @click="removeSelectedProject(project)" > <div class="dot-indicator"></div> <span class="project-name">{{ project.name }}</span> </div> </div> </div> </div> </div> <div v-if="activeStep === 3" class="step-content"> <div class="cover-form"> <div class="form-row"> <div class="form-col-full"> <label class="form-label">封尾图片</label> <file-upload v-model="endForm.imageUrl" :limit="1" :file-size="10" :file-type="['png', 'jpg', 'jpeg', 'gif']" ></file-upload> </div> </div> <div class="form-row"> <div class="form-col"> <label class="form-label">副标题</label> <el-input v-model="endForm.subtitle" placeholder="请输入" style="width: 60%" ></el-input> </div> </div> </div> </div> <div slot="footer" class="dialog-footer"> <el-button @click="prevStep" v-if="activeStep > 1" size="small" >上一步</el-button > <el-button type="primary" class="btn-next" @click="nextStep" v-if="activeStep < 3" size="small" >下一步</el-button > <el-button type="primary" class="btn-next" @click="submitHandbook" v-if="activeStep === 3" size="small" >{{ editingHandbook ? '更新手册' : '生成手册' }}</el-button > </div> </el-dialog> </div> </template> <script> import VueOfficeDocx from "@vue-office/docx"; import pdf from "vue-pdf"; import axios from "axios"; import { getHandbookPage, addHandbook, updateHandbook, deleteHandbook, getHandbookDetail, exportHandbook, getBasicInformationPage, } from "@/api/ManageApi/index"; import FileUpload from "@/components/FileUpload3"; export default { components: { "vue-office-docx": VueOfficeDocx, pdf: pdf, Pagination: () => import("@/components/Pagination"), FileUpload, }, data() { return { queryParams: { current: 1, size: 10, name: "", startTime: "", }, allPostList: [], postList: [], loading: false, total: 0, previewMode: false, previewData: {}, // DOCX文件数据 docxFileData: null, addDialogVisible: false, activeStep: 1, coverForm: { title: "", subtitle: "", imageUrl: "", }, // 项目选择相关 projectSearch: "", projectList: [], selectedProjects: [], projectParams: { pageNum: 1, 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, // 当前正在编辑的手册对象 }; }, created() { this.getList(); }, methods: { // 获取表格数据 getList() { this.loading = true; getHandbookPage(this.queryParams) .then((res) => { this.postList = res.data.records; this.total = res.data.total; this.loading = false; }) .catch(() => { this.loading = false; }); }, getHandbookDetail(id) { getHandbookDetail(id) .then((res) => { this.previewData = res.data; }) .catch(() => { this.loading = false; }); }, // 查询 handleQuery() { this.queryParams.current = 1; this.getList(); }, // 重置查询 resetQuery() { this.queryParams = { current: 1, size: 10, title: undefined, startTime: undefined, }; this.handleQuery(); }, // 表格选择变化 handleSelectionChange(selection) { this.selectedRows = selection; }, // 预览文档 handlePreview(row) { this.previewMode = true; this.previewData = row; this.currentPage = 1; this.pageCount = 0; this.loadingPdf = true; // 使用exportHandbook API获取PDF流 this.loadPdfFromApi(row.id); }, // 从API获取PDF流并预览 async loadPdfFromApi(id) { try { console.log("正在获取PDF文件,ID:", id); // 使用和导出功能相同的API获取PDF文件 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文档加载完成"); }, // PDF加载错误 pdfError(error) { console.error("PDF渲染错误:", error); this.$message.error("PDF渲染失败: " + (error.message || "未知错误")); this.loadingPdf = false; }, // 上一页 prevPage() { if (this.currentPage > 1) { this.currentPage--; } }, // 下一页 nextPage() { if (this.currentPage < this.pageCount) { this.currentPage++; } }, // 项目手册导出 async handleExport() { if (!this.selectedRows || this.selectedRows.length === 0) { this.$message.warning("请先选择要导出的手册"); return; } try { this.exportLoading = true; const idList = this.selectedRows.map((item) => item.id); // 修改请求为直接获取二进制数据 const res = await exportHandbook(idList); this.$download.saveAs(res, "项目手册.pdf"); this.$message.success("导出成功"); } catch (error) { console.error("导出错误:", error); this.$message.error("导出过程中发生错误"); } finally { this.exportLoading = false; } }, handleAdd() { this.addDialogVisible = true; this.activeStep = 1; this.resetAddForm(); this.editingHandbook = null; this.selectedProjectIds = []; this.selectedProjects = []; this.getProjectList(); }, handleAddDialogClose(done) { // this.$confirm("确认关闭?未保存的数据将会丢失", "提示", { // confirmButtonText: "确定", // cancelButtonText: "取消", // type: "warning", // }) // .then(() => { this.resetAddForm(); this.editingHandbook = null; this.selectedProjectIds = []; this.selectedProjects = []; done(); // }) // .catch(() => {}); }, resetAddForm() { this.coverForm = { title: "", subtitle: "", imageUrl: "", }; this.projectSearch = ""; this.endForm = { imageUrl: "", subtitle: "", }; }, // 下一步 nextStep() { if (this.activeStep === 1) { // 可以添加表单验证 if (!this.coverForm.title) { this.$message.warning("请输入手册名称"); return; } } this.activeStep++; }, // 上一步 prevStep() { this.activeStep--; }, // 获取项目列表 getProjectList() { this.loading = true; const params = { current: this.projectParams.pageNum, size: this.projectParams.pageSize, name: this.projectSearch || undefined, }; getBasicInformationPage(params) .then((response) => { this.projectList = response.data.records; this.projectTotal = response.data.total; this.loading = false; // 恢复之前选中的行 this.$nextTick(() => { this.restoreSelection(); }); }) .catch((error) => { console.error("获取项目列表失败:", error); this.loading = false; this.$message.error("获取项目列表失败"); }); }, // 搜索项目 searchProjects() { this.projectParams.pageNum = 1; this.getProjectList(); }, // 重置项目搜索 resetProjectSearch() { this.projectSearch = ""; 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); } }); }, 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 ); }, handleProjectPagination() { this.getProjectList(); }, handleRowClick(row) { this.$refs.projectTable.toggleRowSelection(row); }, // 提交生成手册 submitHandbook() { if (this.selectedProjects.length === 0) { this.$message.warning("请至少选择一个项目"); return; } const data = { coverImg: this.coverForm.imageUrl, name: this.coverForm.title, subtitle: this.coverForm.subtitle, tailingImg: this.endForm.imageUrl, 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("手册更新成功"); this.addDialogVisible = false; this.getList(); // 重置编辑状态 this.editingHandbook = null; }) .catch(() => { this.$message.error("手册更新失败"); }); } else { // 新增模式 addHandbook(data) .then((res) => { this.$message.success("手册生成成功"); this.addDialogVisible = false; this.getList(); }) .catch(() => { this.$message.error("手册生成失败"); }); } }, // 编辑按钮操作 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); // 获取项目列表以显示已选项目 this.getProjectList(); } this.loading = false; this.addDialogVisible = true; this.activeStep = 1; this.editingHandbook = detail; }).catch(() => { this.$message.error("获取手册详情失败"); this.loading = false; }); }, // 删除按钮操作 handleDelete(row) { this.$confirm("是否确认删除该手册?", "警告", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }) .then(() => { this.$message.success("删除成功"); this.getList(); }) .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> <style scoped lang="scss"> /* 通用容器样式 */ .headerbox, .tablebox { background-color: #fff; border-radius: 8px; padding: 20px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); border: 1px solid #eee; margin: 0.5rem } .headerbox { margin-bottom: 15px; } /* 搜索表单样式 */ .search-form { display: flex; align-items: center; flex-wrap: wrap; gap: 15px; } .form-item { display: flex; align-items: center; margin-bottom: 10px; } .label { font-size: 14px; color: #606266; margin-right: 10px; white-space: nowrap; font-weight: 500; } .search-input, .search-date { width: 240px; transition: all 0.3s; &:hover { box-shadow: 0 0 0 1px #409eff; } } .btn-group { display: flex; gap: 10px; } /* 表格样式 */ .tablebtntwo { width: 100%; display: flex; justify-content: space-between; margin: 10px 0 20px; } .tablebox ::v-deep .el-table { border-radius: 4px; overflow: hidden; .el-table__header-wrapper th { background-color: #f5f7fa; color: #606266; font-weight: 600; padding: 12px 0; } .el-table__row { transition: all 0.2s; &:hover { background-color: #ecf5ff; } } .el-button--text { padding: 0 5px; font-weight: 500; transition: all 0.3s; &:hover { transform: scale(1.05); } } } /* PDF预览区域样式 */ .previewbox { height: calc(100vh - 50px); z-index: 1500; display: flex; flex-direction: column; padding: 20px; overflow: hidden; animation: fadeIn 0.3s ease; } .preview-header { display: flex; justify-content: space-between; align-items: center; // margin-bottom: 15px; padding: 15px 20px; background-color: #ffffff; border-radius: 8px 8px 0 0; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); flex-shrink: 0; } .preview-title { font-size: 18px; font-weight: 600; color: #303133; display: flex; align-items: center; i { margin-right: 10px; color: #409eff; font-size: 20px; } } .preview-controls { display: flex; align-items: center; gap: 15px; } .page-counter { background-color: #ecf5ff; padding: 6px 12px; border-radius: 4px; color: #409eff; font-size: 14px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); min-width: 60px; text-align: center; } .navigation-buttons { display: flex; gap: 10px; .el-button { padding: 7px 15px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); transition: all 0.2s ease; &:hover:not([disabled]) { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } &[disabled] { opacity: 0.6; cursor: not-allowed; } } } .preview-content { flex: 1; overflow: auto; background-color: #f5f7fa; border-radius: 0 0 8px 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); display: flex; justify-content: center; position: relative; width: 100%; scrollbar-width: none; span { width: 100%; height: 100%; } ::v-deep canvas { max-width: 100% !important; height: auto !important; box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); border-radius: 2px; background-color: white; } ::v-deep .vue-pdf-embed { width: 100%; display: flex; justify-content: center; } &.el-loading-parent--relative { .el-loading-mask { background-color: rgba(255, 255, 255, 0.9); .el-loading-spinner { .circular { width: 50px; height: 50px; } .el-loading-text { color: #409eff; font-size: 14px; margin-top: 10px; } } } } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } /* 对话框样式 */ .handbook-dialog { ::v-deep .el-dialog__header { background-color: #1890ff; .el-dialog__title { color: #fff; } } ::v-deep .el-dialog__headerbtn .el-dialog__close { color: #fff; } ::v-deep .el-step__icon { width: 15px; height: 15px; font-size: 0; border-radius: 50%; position: relative; z-index: 2; border: 2px solid rgb(255, 255, 255); box-shadow: 0 0 0 2px rgba(136, 137, 137, 0.1); } ::v-deep { .is-process { color: #c0c4cc !important; font-weight: normal !important; .el-step__icon { background: none !important; background-color: #c0c4cc !important; } } .is-finish .el-step__icon { background: none !important; background-color: #1890ff !important; } .is-wait .el-step__icon { background: none !important; background-color: #c0c4cc !important; } } .el-dialog { border-radius: 4px; overflow: hidden; } .el-button--primary { background-color: #1890ff; border-color: #1890ff; } } /* 表单样式 */ .form-label { width: 70px; text-align: right; padding-right: 10px; line-height: 32px; color: #333; font-size: 14px; } .el-input { flex: 1; max-width: 80%; } /* 上传区域样式 */ .upload-area { flex: 1; border: 1px dashed #d9d9d9; border-radius: 6px; overflow: hidden; position: relative; &:hover { border-color: #409eff; } } .upload-box { width: 100%; height: 180px; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; background-color: #fafafa; } .upload-icon { font-size: 28px; color: #8c939d; margin-bottom: 8px; } .upload-text { color: #606266; font-size: 14px; text-align: center; } .upload-tip { font-size: 12px; color: #909399; margin-top: 8px; } .preview-image { width: 100%; height: 180px; object-fit: cover; cursor: pointer; border: 1px solid #dcdfe6; border-radius: 3px; } /* 表单布局样式 */ .cover-form { width: 100%; max-width: 1200px; } .form-row { display: flex; margin-bottom: 60px; justify-content: space-around; @media (max-width: 768px) { flex-direction: column; } } .form-col { flex: 1; margin-right: 20px; &:last-child { margin-right: 0; } @media (max-width: 768px) { margin-right: 0; margin-bottom: 16px; } } .form-col-full { width: 100%; } /* 项目选择区域样式 */ .project-top { border: 1px solid #1890ff; padding: 15px 15px 0px 15px; border-radius: 4px; margin-bottom: 10px; } .search-container { display: flex; align-items: center; margin-bottom: 16px; background-color: #fff; } .search-label { font-size: 14px; color: #606266; margin-right: 8px; } .search-btn { margin-right: 8px; } .project-table { border-radius: 4px; overflow: hidden; margin-bottom: 20px; ::v-deep .el-table { max-height: 400px; overflow-y: auto; .el-table__body-wrapper { overflow-y: auto; } .el-table__row { cursor: pointer; &:hover { background-color: #f5f7fa; } } } } .pagination-box { display: flex; justify-content: right; margin: 16px 0; } /* 已选项目区域样式 */ .selected-projects-container { border: 1px solid #1890ff; padding: 15px 15px 10px 15px; border-radius: 4px; } .selected-header { font-size: 15px; font-weight: 500; color: #333; margin-bottom: 15px; } .selected-list { display: flex; flex-direction: column; gap: 12px; } .selected-item { display: flex; align-items: center; padding: 8px 15px; background-color: #f8f8f8; border-radius: 4px; } .dot-indicator { width: 8px; height: 8px; border-radius: 50%; background-color: #409eff; margin-right: 10px; } .project-name { flex: 1; color: #333; } .remove-icon { cursor: pointer; color: #c0c4cc; font-size: 16px; &:hover { color: #f56c6c; } } /* 步骤内容区域样式 */ .step-content { padding: 10px 10%; min-height: 400px; } ::v-deep .el-dialog__body { padding: 20px 15px !important; } </style>