You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1344 lines
32 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>