Files
klp-oa/klp-ui/src/views/wms/post/objection/index.vue
砂糖 3d5c0a7281 feat(wms盘库): 完成多项功能升级与体验优化
1. 新增仓库选择组件多选支持,适配批量库区操作
2. 售后单新增自动生成编号与当前日期填充
3. 盘点计划新增流程审批操作按钮,支持驳回与审批通过
4. 优化库区绑定页面,支持编辑删除已绑定库区
5. 替换人员选择为可搜索下拉框,支持多选参与人
6. 新增驳回审批弹窗,提供快捷驳回理由
7. 优化表单提交逻辑,适配多库区数据格式
2026-06-27 14:38:33 +08:00

843 lines
27 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container objection-container">
<DragResizePanel :initialSize="280" :minSize="280" :maxSize="600">
<template #panelA>
<div class="left-panel">
<div class="panel-header">
<div class="header-title">
<i class="el-icon-s-claim"></i>
<span>售后单</span>
<el-button size="mini" type="text" icon="el-icon-refresh" @click="getList" style="margin-left:4px;"
title="刷新列表"></el-button>
</div>
<el-select v-model="queryParams.flowStatus" placeholder="全部阶段" clearable size="mini" @change="handleQuery"
class="header-filter">
<el-option label="待审核" :value="1" />
<el-option label="意见填写中" :value="2" />
<el-option label="待汇总方案" :value="3" />
<el-option label="执行反馈中" :value="4" />
<el-option label="执行完成" :value="5" />
<el-option label="全部办结" :value="6" />
</el-select>
</div>
<div class="search-row">
<el-input v-model="queryParams.complaintNo" placeholder="搜索售后编号..." clearable prefix-icon="el-icon-search"
size="small" @keyup.enter.native="handleQuery" @clear="handleQuery" />
<el-button type="primary" size="small" @click="handleAdd">
<i class="el-icon-plus"></i>
</el-button>
</div>
<div v-loading="loading" class="list-body">
<div v-for="item in dataList" :key="item.acceptId" class="list-item"
:class="{ active: currentRow && currentRow.acceptId === item.acceptId }" @click="handleRowClick(item)">
<div class="item-main">
<span class="item-title">{{ item.complaintNo }}</span>
<span class="item-sub">{{ parseTime(item.complaintDate, '{y}-{m}-{d}') }}</span>
</div>
<div class="item-meta">
<el-tag v-if="item.flowStatus === 1" type="info" size="mini">待审核</el-tag>
<el-tag v-else-if="item.flowStatus === 2" type="warning" size="mini">意见填写中</el-tag>
<el-tag v-else-if="item.flowStatus === 3" size="mini">待汇总方案</el-tag>
<el-tag v-else-if="item.flowStatus === 4" type="warning" size="mini">执行反馈中</el-tag>
<el-tag v-else-if="item.flowStatus === 5" type="success" size="mini">执行完成</el-tag>
<el-tag v-else-if="item.flowStatus === 6" type="success" size="mini">全部办结</el-tag>
</div>
<div class="item-actions">
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(item)"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(item)"></el-button>
</div>
</div>
<div v-if="dataList.length === 0 && !loading" class="list-empty">
<i class="el-icon-folder-opened"></i>
<span>暂无售后单数据</span>
</div>
</div>
<div class="list-footer">
<pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
</div>
</div>
</template>
<template #panelB>
<div class="right-panel">
<div v-if="!currentRow" class="empty-tip">
<i class="el-icon-info"></i>
<span>请在左侧列表中选择一条售后单查看详情</span>
</div>
<div v-else v-loading="detailLoading" class="detail-content">
<HeaderControlSection :complaintNo="currentRow.complaintNo" :flowStatus="currentRow.flowStatus"
:meta="currentRow">
<template #actions>
<!-- <el-button :loading="pdfLoading" size="mini" type="text" icon="el-icon-printer" @click="handlePrint"
:disabled="pdfLoading" title="导出PDF">导出PDF</el-button> -->
<el-button v-if="currentRow.flowStatus === 1" size="mini" type="primary" plain
icon="el-icon-s-promotion" @click="handleOpinionDispatch">意见下发</el-button>
<el-button v-if="currentRow.flowStatus === 3" size="mini" type="warning" plain
icon="el-icon-s-promotion" @click="handleFeedbackDispatch">执行下发</el-button>
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail"
title="刷新详情">刷新</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(currentRow)">编辑</el-button>
<el-button size="mini" type="text" icon="el-icon-delete"
@click="handleDelete(currentRow)">删除</el-button>
</template>
<template #basic-info>
<BasicInfoSection :data="currentRow" />
</template>
</HeaderControlSection>
<el-divider />
<FlowOverviewSection :flowStatus="currentRow.flowStatus" />
<CoilInfoSection :coilList="coilList" :loading="coilLoading" :editable="currentRow.flowStatus === 1"
@refresh="loadCoilList(currentRow.acceptId)"
@remove="handleRemoveCoil">
<template v-if="currentRow.flowStatus === 1" #selector>
<CoilSelector :multiple="true" :filters="{ status: 1 }" @confirm="handleSelectorConfirm"
style="margin-left: 4px; display: inline-block;">
<el-button size="mini" type="primary" plain icon="el-icon-plus">添加</el-button>
</CoilSelector>
</template>
</CoilInfoSection>
<div class="section-gap" />
<ContractInfoSection :coilList="coilList" />
<div class="section-gap" />
<DepartmentOpinionSection :taskList="taskList" @refresh="refreshTaskList" />
<div class="section-gap" />
<HandlingSchemeSection :content="currentRow.planContent" :editable="currentRow.flowStatus === 3" @save="handleSavePlan" />
<div class="section-gap" />
<ExecutionFeedbackSection :executeList="executeList" @refresh="refreshExecuteList" />
</div>
</div>
</template>
</DragResizePanel>
<el-dialog :title="title" :visible.sync="open" width="650px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="售后编号" prop="complaintNo">
<el-input v-model="form.complaintNo" placeholder="请输入售后编号" :disabled="!!form.acceptId" />
</el-form-item>
<el-form-item label="投诉日期" prop="complaintDate">
<el-date-picker clearable v-model="form.complaintDate" type="date" value-format="yyyy-MM-dd"
placeholder="请选择投诉日期" style="width:100%" />
</el-form-item>
<el-form-item label="投诉情况" prop="complaintContent">
<el-input v-model="form.complaintContent" type="textarea" :rows="4" placeholder="请输入投诉情况描述" />
</el-form-item>
<el-form-item label="客户诉求" prop="customerDemand">
<el-input v-model="form.customerDemand" type="textarea" :rows="3" placeholder="请输入客户诉求" />
</el-form-item>
<el-form-item label="关联钢卷">
<CoilSelector :multiple="true" :filters="{ status: 1 }" placeholder="选择钢卷" @confirm="handleCoilConfirm">
<el-button type="primary" size="small"><i class="el-icon-search"></i> 选择钢卷</el-button>
</CoilSelector>
<div v-if="formCoilList.length > 0" style="margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px;">
<div v-for="(coil, index) in formCoilList" :key="coil.coilId || index"
style="display: flex; align-items: center; gap: 4px;">
<CurrentCoilNo :currentCoilNo="coil.currentCoilNo || coil.coilNo || ''" />
<el-button type="text" icon="el-icon-close" size="mini" @click="removeCoil(index)"></el-button>
</div>
</div>
</el-form-item>
<el-form-item label="凭证文件" prop="file">
<file-upload v-model="form.file" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<el-dialog title="选择下发部门" :visible.sync="deptDialogVisible" width="400px" append-to-body>
<el-checkbox-group v-model="selectedDeptIds">
<el-checkbox v-for="item in deptOptions" :key="item.deptId" :label="item.deptId">{{ item.deptName }}</el-checkbox>
</el-checkbox-group>
<div slot="footer" class="dialog-footer">
<el-button @click="deptDialogVisible = false"> </el-button>
<el-button :loading="dispatchLoading" type="primary" @click="confirmFeedbackDispatch"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listComplaintAccept, getComplaintAccept, addComplaintAccept, updateComplaintAccept, delComplaintAccept, opinionDispatch, feedbackDispatch } from "@/api/flow/complaintAccept";
import { listComplaintTask } from "@/api/flow/complaintTask";
import { listAcceptCoilRel, addAcceptCoilRel, delAcceptCoilRel } from "@/api/flow/acceptCoilRel";
import { listPlanExecuteRel } from "@/api/flow/planExecuteRel";
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
import CoilSelector from "@/components/CoilSelector/index.vue";
import CurrentCoilNo from "@/components/KLPService/Renderer/CurrentCoilNo.vue";
import DragResizePanel from "@/components/DragResizePanel/index.vue";
import HeaderControlSection from "./components/HeaderControlSection.vue";
import BasicInfoSection from "./components/BasicInfoSection.vue";
import ContractInfoSection from "./components/ContractInfoSection.vue";
import CoilInfoSection from "./components/CoilInfoSection.vue";
import DepartmentOpinionSection from "./components/DepartmentOpinionSection.vue";
import HandlingSchemeSection from "./components/HandlingSchemeSection.vue";
import ExecutionFeedbackSection from "./components/ExecutionFeedbackSection.vue";
import FlowOverviewSection from "./components/FlowOverviewSection.vue";
export default {
name: "AftermarketObjection",
components: {
CoilSelector, CurrentCoilNo, DragResizePanel,
HeaderControlSection, BasicInfoSection, ContractInfoSection,
CoilInfoSection, DepartmentOpinionSection, HandlingSchemeSection, ExecutionFeedbackSection, FlowOverviewSection
},
dicts: ['coil_quality_status'],
data() {
return {
buttonLoading: false,
pdfLoading: false,
loading: true,
detailLoading: false,
coilLoading: false,
showSearch: true,
total: 0,
dataList: [],
currentRow: null,
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
complaintNo: undefined,
flowStatus: undefined
},
form: {},
formCoilList: [],
coilList: [],
taskList: [],
executeList: [],
deptDialogVisible: false,
dispatchLoading: false,
selectedDeptIds: [],
deptOptions: [
{ deptId: 1, deptName: '生产部' },
{ deptId: 2, deptName: '质量部' },
{ deptId: 3, deptName: '销售部' }
],
rules: {
complaintNo: [{ required: true, message: "请输入售后编号", trigger: "blur" }],
complaintDate: [{ required: true, message: "请选择投诉日期", trigger: "blur" }],
complaintContent: [{ required: true, message: "请输入投诉情况", trigger: "blur" }],
customerDemand: [{ required: true, message: "请输入客户诉求", trigger: "blur" }]
}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listComplaintAccept(this.queryParams).then(response => {
this.dataList = response.rows;
this.total = response.total;
this.loading = false;
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.queryParams.complaintNo = undefined;
this.queryParams.flowStatus = undefined;
this.handleQuery();
},
handleRowClick(row) {
this.currentRow = row;
this.loadDetail(row.acceptId);
},
loadDetail(acceptId) {
this.detailLoading = true;
getComplaintAccept(acceptId).then(response => {
this.currentRow = response.data;
this.loadRelData(acceptId);
}).finally(() => { this.detailLoading = false; });
},
loadRelData(acceptId) {
this.loadCoilList(acceptId);
listComplaintTask({ acceptId, pageNum: 1, pageSize: 999 }).then(r => {
this.taskList = r.rows || [];
});
listPlanExecuteRel({ acceptId, pageNum: 1, pageSize: 999 }).then(r => {
this.executeList = r.rows || [];
});
},
loadCoilList(acceptId) {
this.coilLoading = true;
listAcceptCoilRel({ acceptId, pageNum: 1, pageSize: 999 }).then(r => {
this.coilList = r.rows || [];
}).finally(() => { this.coilLoading = false; });
},
getDeptName(deptId) {
const map = { 1: '生产部', 2: '质量部', 3: '销售部' };
return map[deptId] || '部门' + deptId;
},
handleAdd() {
this.reset();
this.formCoilList = [];
// 根据当前日期自动生成售后编号,格式: SH + yyyyMMddHHmmss
const now = new Date();
const pad = (n, len) => String(n).padStart(len, '0');
const dateStr = [
now.getFullYear(),
pad(now.getMonth() + 1, 2),
pad(now.getDate(), 2),
pad(now.getHours(), 2),
pad(now.getMinutes(), 2),
pad(now.getSeconds(), 2)
].join('');
this.form.complaintNo = 'SH' + dateStr;
// 自动填写当前日期
this.form.complaintDate = this.parseTime(now, '{y}-{m}-{d}');
this.open = true;
this.title = "新增售后单";
},
handleUpdate(row) {
this.reset();
const acceptId = row.acceptId;
getComplaintAccept(acceptId).then(response => {
this.form = response.data;
listAcceptCoilRel({ acceptId, pageNum: 1, pageSize: 999 }).then(r => {
this.formCoilList = (r.rows || []).map(rel => ({ coilId: rel.coilId, currentCoilNo: (rel.coilInfo && rel.coilInfo.currentCoilNo) || '' }));
});
this.open = true;
this.title = "修改售后单";
});
},
reset() {
this.form = {
acceptId: undefined,
complaintNo: undefined,
complaintDate: undefined,
complaintContent: undefined,
customerDemand: undefined,
file: undefined,
auditStatus: undefined,
auditOpinion: undefined,
auditUserId: undefined,
auditTime: undefined,
flowStatus: undefined,
principalUserId: undefined,
planContent: undefined,
remark: undefined
};
this.formCoilList = [];
this.resetForm("form");
},
cancel() {
this.open = false;
this.reset();
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
const formData = { ...this.form, coilIds: this.formCoilList.map(c => c.coilId) };
if (this.form.acceptId != null) {
updateComplaintAccept(formData).then(() => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => { this.buttonLoading = false; });
} else {
addComplaintAccept(formData).then(() => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => { this.buttonLoading = false; });
}
}
});
},
handleDelete(row) {
const acceptIds = row.acceptId;
this.$modal.confirm('是否确认删除售后编号为"' + row.complaintNo + '"的数据项?').then(() => {
this.loading = true;
return delComplaintAccept(acceptIds);
}).then(() => {
this.loading = false;
this.getList();
if (this.currentRow && this.currentRow.acceptId === row.acceptId) {
this.currentRow = null;
}
this.$modal.msgSuccess("删除成功");
}).catch(() => { }).finally(() => { this.loading = false; });
},
handleExport() {
this.download('flow/complaintAccept/export', { ...this.queryParams }, `售后单_${new Date().getTime()}.xlsx`);
},
handleOpinionDispatch() {
this.$modal.confirm('确认将此售后单的意见下发至各部门?').then(() => {
return opinionDispatch(this.currentRow.acceptId);
}).then(() => {
this.$modal.msgSuccess("意见下发成功");
this.loadDetail(this.currentRow.acceptId);
this.getList();
}).catch(() => { });
},
handleFeedbackDispatch() {
this.selectedDeptIds = [];
this.deptDialogVisible = true;
},
confirmFeedbackDispatch() {
if (this.selectedDeptIds.length === 0) {
this.$modal.msgWarning('请至少选择一个部门');
return;
}
this.dispatchLoading = true;
const deptIds = this.selectedDeptIds.join(',');
feedbackDispatch(this.currentRow.acceptId, deptIds).then(() => {
this.$modal.msgSuccess("执行下发成功");
this.deptDialogVisible = false;
this.loadDetail(this.currentRow.acceptId);
this.getList();
}).finally(() => { this.dispatchLoading = false; });
},
handleRefreshDetail() {
if (this.currentRow && this.currentRow.acceptId) {
this.loadDetail(this.currentRow.acceptId);
}
},
async handlePrint() {
const element = this.$el.querySelector('.detail-content');
if (!element) return;
this.pdfLoading = true;
try {
// 临时隐藏操作按钮
element.classList.add('pdf-exporting');
const canvas = await html2canvas(element, {
scale: 2,
useCORS: true,
logging: false,
backgroundColor: '#ffffff'
});
// 恢复按钮
element.classList.remove('pdf-exporting');
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF('p', 'mm', 'a4');
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (canvas.height * pdfWidth) / canvas.width;
const pageHeight = pdf.internal.pageSize.getHeight();
// 多页处理
if (pdfHeight <= pageHeight) {
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
} else {
let posY = 0;
const ratio = pdfWidth / canvas.width;
const pageCanvasHeight = pageHeight / ratio;
while (posY < canvas.height) {
if (posY > 0) pdf.addPage();
const pieceCanvas = document.createElement('canvas');
pieceCanvas.width = canvas.width;
pieceCanvas.height = Math.min(pageCanvasHeight, canvas.height - posY);
const ctx = pieceCanvas.getContext('2d');
ctx.drawImage(canvas, 0, posY, canvas.width, pieceCanvas.height, 0, 0, canvas.width, pieceCanvas.height);
const pieceData = pieceCanvas.toDataURL('image/png');
pdf.addImage(pieceData, 'PNG', 0, 0, pdfWidth, pieceCanvas.height * ratio);
posY += pageCanvasHeight;
}
}
pdf.save(`${this.currentRow?.complaintNo || '售后单'}_处理记录.pdf`);
this.$modal.msgSuccess('PDF 导出成功');
} catch (err) {
console.error('PDF 导出失败:', err);
this.$modal.msgError('PDF 导出失败');
element.classList.remove('pdf-exporting');
} finally {
this.pdfLoading = false;
}
},
handleSavePlan(planContent) {
updateComplaintAccept({ acceptId: this.currentRow.acceptId, planContent }).then(() => {
this.$modal.msgSuccess("处理方案保存成功");
this.loadDetail(this.currentRow.acceptId);
});
},
refreshTaskList() {
if (this.currentRow && this.currentRow.acceptId) {
listComplaintTask({ acceptId: this.currentRow.acceptId, pageNum: 1, pageSize: 999 }).then(r => {
this.taskList = r.rows || [];
});
}
},
refreshExecuteList() {
if (this.currentRow && this.currentRow.acceptId) {
listPlanExecuteRel({ acceptId: this.currentRow.acceptId, pageNum: 1, pageSize: 999 }).then(r => {
this.executeList = r.rows || [];
});
}
},
handleCoilConfirm(coils) {
this.formCoilList = [...coils];
},
removeCoil(index) {
this.formCoilList.splice(index, 1);
},
handleSelectorConfirm(coils) {
if (!coils || coils.length === 0) return;
const existIds = this.coilList.map(r => r.coilId);
const toAdd = coils.filter(c => !existIds.includes(c.coilId));
if (toAdd.length === 0) {
this.$modal.msgWarning("所选钢卷已全部存在");
return;
}
const addPromises = toAdd.map(c => addAcceptCoilRel({ acceptId: this.currentRow.acceptId, coilId: c.coilId }));
Promise.all(addPromises).then(() => {
this.$modal.msgSuccess("添加成功");
this.loadCoilList(this.currentRow.acceptId);
});
},
handleRemoveCoil(row) {
this.$modal.confirm('确认移除钢卷"' + (row.coilInfo.currentCoilNo || row.coilId) + '"').then(() => {
return delAcceptCoilRel(row.relId);
}).then(() => {
this.$modal.msgSuccess("移除成功");
this.loadCoilList(this.currentRow.acceptId);
}).catch(() => { });
}
}
};
</script>
<style scoped>
.objection-container {
height: calc(100vh - 84px);
}
.left-panel {
display: flex;
flex-direction: column;
height: 100%;
background: #f5f7fa;
border-right: 1px solid #e4e7ed;
}
.panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 14px 8px;
background: #f5f7fa;
}
.header-title {
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 600;
color: #303133;
}
.header-title i {
color: #409eff;
font-size: 16px;
}
.header-filter {
width: 130px;
}
.search-row {
display: flex;
align-items: center;
gap: 6px;
padding: 0 14px 10px;
background: #f5f7fa;
}
.list-body {
flex: 1;
overflow-y: auto;
padding: 0 6px;
}
.list-item {
display: flex;
align-items: center;
padding: 10px 12px;
margin-bottom: 2px;
cursor: pointer;
border-radius: 6px;
transition: all 0.15s;
}
.list-item:hover {
background: #ebeef5;
}
.list-item.active {
background: #d9ecff;
}
.list-item.active .item-title {
color: #409eff;
font-weight: 600;
}
.item-main {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 3px;
}
.item-title {
font-size: 13px;
font-weight: 500;
color: #303133;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.item-sub {
font-size: 12px;
color: #909399;
}
.item-meta {
flex-shrink: 0;
margin: 0 8px;
}
.item-actions {
flex-shrink: 0;
opacity: 0;
transition: opacity 0.15s;
}
.list-item:hover .item-actions {
opacity: 1;
}
.list-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60px 0;
color: #c0c4cc;
font-size: 13px;
gap: 8px;
}
.list-empty i {
font-size: 32px;
}
.list-footer {
border-top: 1px solid #e4e7ed;
padding: 2px 8px 0;
background: #f5f7fa;
}
/* ========== 右侧面板 — Word 文档风格 ========== */
.right-panel {
height: 100%;
overflow-y: auto;
padding: 12px 16px;
background: #faf8f5; /* 暖白纸张底色 */
}
.right-panel .detail-content {
margin: 0 auto;
background: #ffffff;
padding: 28px 32px 36px;
box-shadow: 0 1px 4px rgba(0,0,0,0.06), 0 2px 12px rgba(0,0,0,0.04);
min-height: 100%;
}
.empty-tip {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: #909399;
font-size: 14px;
gap: 8px;
}
.detail-section {
margin-bottom: 20px;
}
.detail-section-label {
font-size: 11px;
font-weight: 600;
color: #8c8c8c;
margin-bottom: 4px;
letter-spacing: 0.8px;
text-transform: uppercase;
font-family: 'Georgia', 'Times New Roman', serif;
}
.detail-section-text {
font-size: 14px;
color: #1a1a1a;
line-height: 1.8;
word-break: break-all;
padding-bottom: 12px;
border-bottom: 1px solid #eeeae4;
}
/* 文档级通用 section 标题 */
.section-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
width: 100%;
font-size: 15px;
font-weight: 700;
color: #1a1a1a;
margin: 22px 0 12px 0;
padding: 0 0 10px 0;
border-bottom: 1px solid #d4d0c8;
display: flex;
align-items: center;
gap: 10px;
letter-spacing: 0.3px;
}
.section-title:first-child {
margin-top: 0;
}
.section-title .en-sub {
font-size: 11px;
font-weight: 400;
color: #8c8c8c;
letter-spacing: 0.5px;
font-family: 'Georgia', 'Times New Roman', serif;
font-style: italic;
}
.section-title i {
font-size: 16px;
color: #1a3c6e;
}
.empty-data {
color: #8c8c8c;
font-size: 13px;
padding: 8px 0;
font-style: italic;
}
.plan-content {
padding: 12px 16px;
background: #faf8f5;
border: 1px solid #e8e4de;
border-radius: 2px;
font-size: 13px;
line-height: 1.8;
color: #1a1a1a;
}
.section-gap {
height: 16px;
}
/* 正式表格覆写 */
.right-panel .el-table {
border: 1px solid #e8e4de !important;
border-radius: 2px !important;
font-size: 12px !important;
}
.right-panel .el-table thead th {
background-color: #2c3e50 !important;
color: #ffffff !important;
font-weight: 600 !important;
font-size: 11px !important;
letter-spacing: 0.5px !important;
border-bottom: none !important;
font-family: 'Georgia', 'Times New Roman', serif;
}
.right-panel .el-table thead th .cell {
color: #ffffff !important;
}
.right-panel .el-table__body tr:hover > td {
background-color: #f7f5f0 !important;
}
.right-panel .el-table--border td {
border-right: 1px solid #f0ece6 !important;
}
.right-panel .el-table--border th {
border-right: 1px solid #3a5166 !important;
}
.right-panel .el-table td {
padding: 6px 4px !important;
color: #3a3a3a !important;
}
.right-panel .el-divider--horizontal {
margin: 8px 0 4px;
background-color: #e0dcd6;
}
/* el-tag 文档风格微调 */
.right-panel .el-tag {
border-radius: 2px;
font-family: 'Georgia', 'Times New Roman', serif;
letter-spacing: 0.3px;
}
.right-panel .el-tag--mini {
padding: 0 6px;
line-height: 20px;
height: 20px;
}
.right-panel .el-tag--small {
padding: 0 8px;
}
/* ===== PDF 导出时隐藏操作按钮 ===== */
.detail-content.pdf-exporting .doc-header-right .el-button {
display: none !important;
}
.detail-content.pdf-exporting .el-button--text {
display: none !important;
}
.detail-content.pdf-exporting .el-table__fixed,
.detail-content.pdf-exporting .el-table__fixed-right {
display: none !important;
}
</style>