feat(crm/contract): 优化产品表格表头展示与导出配置功能

1.  将产品表格表头文本拆分为多行显示,优化视觉排版
2.  调整表格列的grid布局宽度适配新的表头样式
3.  新增产品导出列的自定义编辑与重置功能,支持自定义表头文本
4.  重构导出预览的表头生成逻辑,支持动态渲染自定义列名与适配宽度
This commit is contained in:
2026-06-22 13:06:46 +08:00
parent 119b9105c7
commit 2e79a5beb0
2 changed files with 43 additions and 31 deletions

View File

@@ -6,9 +6,11 @@
<div style="font-weight: bold; margin-bottom: 10px; font-size: 14px;">产品表列配置</div>
<el-checkbox v-model="selectAllColumns" :indeterminate="columnIndeterminate" @change="handleSelectAllColumns"
style="margin-bottom: 8px;">全选</el-checkbox>
<div v-for="col in columnConfigs" :key="col.key" style="margin-bottom: 6px;">
<el-checkbox v-model="col.checked" @change="onColumnChange">{{ col.label }}</el-checkbox>
<div v-for="col in columnConfigs" :key="col.key" style="margin-bottom: 6px; display: flex; align-items: center; gap: 4px;">
<el-checkbox v-model="col.checked" @change="onColumnChange" style="flex-shrink: 0;"></el-checkbox>
<el-input v-model="col.label" size="mini" style="flex: 1; min-width: 0;" @change="generatePreviewHtml"></el-input>
</div>
<el-button size="mini" style="margin-bottom: 8px;" @click="resetColumnLabels">重置表头</el-button>
<el-divider />
<div style="font-weight: bold; margin-bottom: 10px; font-size: 14px;">附加行配置</div>
<el-checkbox v-model="selectAllRows" :indeterminate="rowIndeterminate" @change="handleSelectAllRows"
@@ -77,16 +79,16 @@ export default {
selectAllColumns: true,
columnIndeterminate: false,
columnConfigs: [
{ key: 'spec', label: '规格mm', checked: true },
{ key: 'material', label: '材质', checked: true },
{ key: 'quantity', label: '数量(吨)', checked: true },
{ key: 'taxPrice', label: '含税单价元/吨', checked: true },
{ key: 'taxDivisor', label: '税率除数', checked: true },
{ key: 'noTaxPrice', label: '无税单价元/吨', checked: true },
{ key: 'taxTotal', label: '含税总额(元)', checked: true },
{ key: 'noTaxTotal', label: '无税总额(元)', checked: true },
{ key: 'taxAmount', label: '税额(元)', checked: true },
{ key: 'remark', label: '备注', checked: true },
{ key: 'spec', label: '规格(mm)', defaultLabel: '规格(mm)', checked: true },
{ key: 'material', label: '材质', defaultLabel: '材质', checked: true },
{ key: 'quantity', label: '数量(吨)', defaultLabel: '数量(吨)', checked: true },
{ key: 'taxPrice', label: '含税单价(元/吨)', defaultLabel: '含税单价(元/吨)', checked: true },
{ key: 'taxDivisor', label: '税率除数', defaultLabel: '税率除数', checked: true },
{ key: 'noTaxPrice', label: '无税单价(元/吨)', defaultLabel: '无税单价(元/吨)', checked: true },
{ key: 'taxTotal', label: '含税总额(元)', defaultLabel: '含税总额(元)', checked: true },
{ key: 'noTaxTotal', label: '无税总额(元)', defaultLabel: '无税总额(元)', checked: true },
{ key: 'taxAmount', label: '税额(元)', defaultLabel: '税额(元)', checked: true },
{ key: 'remark', label: '备注', defaultLabel: '备注', checked: true },
],
selectAllRows: true,
rowIndeterminate: false,
@@ -120,6 +122,10 @@ export default {
this.columnIndeterminate = false;
this.generatePreviewHtml();
},
resetColumnLabels() {
this.columnConfigs.forEach(col => { col.label = col.defaultLabel; });
this.generatePreviewHtml();
},
onColumnChange() {
const checkedCount = this.columnConfigs.filter(c => c.checked).length;
this.selectAllColumns = checkedCount === this.columnConfigs.length;
@@ -143,17 +149,24 @@ export default {
const hasCol = (key) => activeCols.some(c => c.key === key);
const hasRow = (key) => activeRows.some(r => r.key === key);
const colWidthMap = {
spec: 80,
material: 60,
quantity: 55,
taxPrice: 70,
taxDivisor: 45,
noTaxPrice: 70,
taxTotal: 70,
noTaxTotal: 70,
taxAmount: 55,
remark: 80,
};
let headerCells = '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:30px;">序号</th>';
if (hasCol('spec')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:80px;">规格(mm)</th>';
if (hasCol('material')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:60px;">材质</th>';
if (hasCol('quantity')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:55px;">数量(吨)</th>';
if (hasCol('taxPrice')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:70px;">含税单价(元/吨)</th>';
if (hasCol('taxDivisor')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:45px;">税率除数</th>';
if (hasCol('noTaxPrice')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:70px;">无税单价(元/吨)</th>';
if (hasCol('taxTotal')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:70px;">含税总额(元)</th>';
if (hasCol('noTaxTotal')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:70px;">无税总额(元)</th>';
if (hasCol('taxAmount')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:55px;">税额(元)</th>';
if (hasCol('remark')) headerCells += '<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:80px;">备注</th>';
activeCols.forEach(col => {
const width = colWidthMap[col.key] || 60;
headerCells += `<th style="border:1px solid #000;padding:5px 6px;font-weight:bold;width:${width}px;">${col.label}</th>`;
});
const colCount = activeCols.length + 1;
let bodyRows = '';

View File

@@ -19,15 +19,15 @@
<!-- 第二行为表头 -->
<div class="table-row">
<div class="table-cell">序号</div>
<div class="table-cell">规格mm</div>
<div class="table-cell">规格<br>mm</div>
<div class="table-cell">材质</div>
<div class="table-cell">数量</div>
<div class="table-cell">含税单价/</div>
<div class="table-cell">数量<br></div>
<div class="table-cell">含税单价<br>/</div>
<div class="table-cell">税率除数</div>
<div class="table-cell">无税单价/</div>
<div class="table-cell">含税总额</div>
<div class="table-cell">无税总额</div>
<div class="table-cell">税额</div>
<div class="table-cell">无税单价<br>/</div>
<div class="table-cell">含税总额<br></div>
<div class="table-cell">无税总额<br></div>
<div class="table-cell">税额<br></div>
<div class="table-cell">
备注
<el-button v-if="!readonly" type="primary" size="mini" icon="el-icon-plus" @click="addProduct"
@@ -343,12 +343,11 @@ export default {
font-weight: bold;
display: flex;
align-items: center;
}
.table-row {
display: grid;
grid-template-columns: 45px 100px 90px 75px 100px 90px 100px 110px 110px 110px 1fr;
grid-template-columns: 45px 100px 100px 90px 100px 90px 110px 110px 110px 110px 1fr;
border-bottom: 1px solid #e4e7ed;
}