😎优化 table/index.vue 组件的打印样式

This commit is contained in:
zuohuaijun 2025-09-19 02:01:29 +08:00
parent a9804b08da
commit 0a414a06c5
4 changed files with 139 additions and 31 deletions

View File

@ -26,7 +26,7 @@
<template #default> <template #default>
<div class="tool-box"> <div class="tool-box">
<el-tooltip :content="t('message.list.dragToSort')" placement="top-start"> <el-tooltip :content="t('message.list.dragToSort')" placement="top-start">
<SvgIcon name="fa fa-question-circle-o" :size="17" class="ml11" color="#909399" /> <SvgIcon style="position: absolute; right: 15px; line-height: 32px" name="fa fa-question-circle-o" :size="17" class="ml11 cursor-pointer" color="#909399" />
</el-tooltip> </el-tooltip>
<el-checkbox v-model="state.checkListAll" :indeterminate="state.checkListIndeterminate" class="ml10 mr1" :label="t('message.list.columnDisplay')" @change="onCheckAllChange" /> <el-checkbox v-model="state.checkListAll" :indeterminate="state.checkListIndeterminate" class="ml10 mr1" :label="t('message.list.columnDisplay')" @change="onCheckAllChange" />
<el-checkbox v-model="getConfig.isSerialNo" class="ml12 mr1" :label="t('message.list.seq')" /> <el-checkbox v-model="getConfig.isSerialNo" class="ml12 mr1" :label="t('message.list.seq')" />
@ -34,8 +34,8 @@
</div> </div>
<el-scrollbar> <el-scrollbar>
<div ref="toolSetRef" class="tool-sortable"> <div ref="toolSetRef" class="tool-sortable">
<div class="tool-sortable-item" v-for="v in columns" :key="v.prop" v-show="!v.hideCheck" :data-key="v.prop"> <div class="tool-sortable-item" v-for="v in columns" :key="v.prop" :data-key="v.prop" :data-fixed="v.hideCheck ?? false">
<i class="fa fa-arrows-alt handle cursor-pointer"></i> <i class="fa fa-arrows-alt handle"></i>
<el-checkbox v-model="v.isCheck" size="default" class="ml12 mr8" :label="v.label" @change="onCheckChange" /> <el-checkbox v-model="v.isCheck" size="default" class="ml12 mr8" :label="v.label" @change="onCheckChange" />
</div> </div>
</div> </div>
@ -142,6 +142,7 @@ import { exportExcel } from '/@/utils/exportExcel';
import printJs from 'print-js'; import printJs from 'print-js';
import formatter from '/@/components/table/formatter.vue'; import formatter from '/@/components/table/formatter.vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { EmptyObjectType } from '/@/types/global';
// //
const props = defineProps({ const props = defineProps({
@ -319,42 +320,78 @@ const exportData = (data: Array<EmptyObjectType>) => {
}; };
// //
const onPrintTable = () => { const onPrintTable = () => {
// https://printjs.crabbly.com/#documentation let printDiv = document.createElement('div');
// let printTitle = document.createElement('div');
let tableTh = ''; let printTable = document.createElement('table');
let tableTrTd = ''; let printTableHeader = document.createElement('thead');
let tableTd: any = {}; let printTableBody = document.createElement('tbody');
//
setHeader.value.forEach((v: any) => { //
if (v.prop === 'action') { setHeader.value.forEach((col: EmptyObjectType) => {
if (col.prop === 'action' || !col.isCheck) {
return; return;
} }
tableTh += `<th class="table-th">${v.label}</th>`; let th = document.createElement('th');
th.innerText = col.label;
th.classList.add('print-table-th');
th.style.width = col.width ? col.width + 'px' : 'auto';
th.style.minWidth = col.minWidth ? col.minWidth + 'px' : 'auto';
printTableHeader.appendChild(th);
}); });
//
state.data.forEach((val: any, key: any) => { //
if (!tableTd[key]) tableTd[key] = []; state.data.forEach((row: EmptyObjectType) => {
setHeader.value.forEach((v: any) => { let tr = document.createElement('tr');
if (v.prop === 'action') { tr.classList.add('print-table-tr');
setHeader.value.forEach((col: EmptyObjectType) => {
if (col.prop === 'action' || !col.isCheck) {
return; return;
} }
if (v.type === 'text') {
tableTd[key].push(`<td class="table-th table-center">${val[v.prop]}</td>`); let td = document.createElement('td');
} else if (v.type === 'image') { td.classList.add('print-table-td');
tableTd[key].push(`<td class="table-th table-center"><img src="${val[v.prop]}" style="width:${v.width}px;height:${v.height}px;"/></td>`); if (col.type === 'image') {
let img = document.createElement('img');
img.classList.add('print-table-img');
// img.src = row[col.prop];
// img.style.width = col.width + 'px';
// img.style.height = col.height + 'px';
td.appendChild(img);
tr.appendChild(td);
} else { } else {
tableTd[key].push(`<td class="table-th table-center">${val[v.prop]}</td>`); td.innerText = getProperty(row, col.prop);
td.style.textAlign = col.align ? col.align : 'left';
tr.appendChild(td);
} }
}); });
tableTrTd += `<tr>${tableTd[key].join('')}</tr>`; printTableBody.appendChild(tr);
}); });
//
printTable.appendChild(printTableHeader);
printTable.appendChild(printTableBody);
printTable.classList.add('print-table');
//
if (props.config.printName) {
printTitle.classList.add('print-table-title');
printTitle.innerText = props.config.printName;
printDiv.appendChild(printTitle);
} else {
printTitle.style.display = 'none';
}
printDiv.appendChild(printTable);
printJs({ printJs({
printable: `<div style=display:flex;flex-direction:column;text-align:center><h3>${props.printName}</h3></div><table border=1 cellspacing=0><tr>${tableTh}${tableTrTd}</table>`, printable: printDiv,
type: 'raw-html', type: 'html',
css: ['//at.alicdn.com/t/c/font_2298093_rnp72ifj3ba.css', '//unpkg.com/element-plus/dist/index.css'], //header: props.config.printName,
style: `@media print{.mb15{margin-bottom:15px;}.el-button--small i.iconfont{font-size: 12px !important;margin-right: 5px;}}; .table-th{word-break: break-all;white-space: pre-wrap;}.table-center{text-align: center;}`, scanStyles: false,
css: ['/@/theme/media/printTable.css'],
}); });
printDiv.remove();
}; };
// //
const onRefreshTable = () => { const onRefreshTable = () => {
@ -365,9 +402,25 @@ const onRefreshTable = () => {
const onSetTable = () => { const onSetTable = () => {
nextTick(() => { nextTick(() => {
const sortable = Sortable.create(toolSetRef.value, { const sortable = Sortable.create(toolSetRef.value, {
handle: '.handle', //handle: '.handle',
dataIdAttr: 'data-key', dataIdAttr: 'data-key',
animation: 150, animation: 150,
onStart: () => {
//
toolSetRef.value.children.forEach((element: HTMLElement) => {
if (element.dataset.fixed === 'false') {
element.classList.add('tool-sortable-item-draggable');
}
});
},
onMove: (evt) => {
//
const srcItem = evt.dragged.dataset.fixed; //
const targetItem = evt.related.dataset.fixed; // ()
if (srcItem === 'true' || targetItem === 'true') {
return false;
}
},
onEnd: () => { onEnd: () => {
const headerList: EmptyObjectType[] = []; const headerList: EmptyObjectType[] = [];
sortable.toArray().forEach((val: any) => { sortable.toArray().forEach((val: any) => {
@ -375,7 +428,13 @@ const onSetTable = () => {
if (v.prop === val) headerList.push({ ...v }); if (v.prop === val) headerList.push({ ...v });
}); });
}); });
emit('sortHeader', headerList); //emit('sortHeader', headerList);
state.columns = headerList;
//
toolSetRef.value.children.forEach((element: HTMLElement) => {
element.classList.remove('tool-sortable-item-draggable');
});
}, },
}); });
}); });

View File

@ -1,7 +1,7 @@
<template> <template>
<el-popover placement="bottom" width="300" trigger="hover"> <el-popover placement="bottom" width="300" trigger="hover">
<template #reference> <template #reference>
<el-text type="primary" class="cursor-default"> <el-text type="primary" class="cursor-pointer">
<el-icon><ele-InfoFilled /></el-icon>{{ t('message.list.detail') }} <el-icon><ele-InfoFilled /></el-icon>{{ t('message.list.detail') }}
</el-text> </el-text>
</template> </template>

View File

@ -0,0 +1,37 @@
@media print {
.print-table-title {
text-align: center;
font-size: 24px;
font-weight: bold;
margin: 10px 0;
}
.print-table {
width: 100%;
border-collapse: collapse;
background-color: antiquewhite;
border: #000 1px solid;
}
.print-table-th,
.print-table-td {
border: 1px solid #000;
padding: 6px 8px;
word-break: break-all;
white-space: pre-wrap;
}
.print-table-th {
font-weight: bold;
text-align: center;
}
.print-table-tr {
}
.print-table-td {
}
.print-table-img {
}
}
@page {
size: auto;
margin: 7mm 10mm;
}

View File

@ -3,6 +3,7 @@
.tool-box { .tool-box {
display: flex; display: flex;
border-bottom: 1px solid var(--el-border-color-lighter); border-bottom: 1px solid var(--el-border-color-lighter);
margin-bottom: 5px;
box-sizing: border-box; box-sizing: border-box;
color: var(--el-text-color-primary); color: var(--el-text-color-primary);
height: 40px; height: 40px;
@ -11,11 +12,13 @@
.tool-sortable { .tool-sortable {
max-height: 303px; max-height: 303px;
.tool-sortable-item { .tool-sortable-item {
height: var(--el-checkbox-height, 32px);
display: flex; display: flex;
box-sizing: border-box; box-sizing: border-box;
color: var(--el-text-color-primary); color: var(--el-text-color-primary);
align-items: center; align-items: center;
padding: 0 12px; padding: 0 12px;
cursor: grab;
&:hover { &:hover {
background: var(--el-fill-color-lighter); background: var(--el-fill-color-lighter);
} }
@ -23,5 +26,14 @@
opacity: 0.7; opacity: 0.7;
} }
} }
.tool-sortable-item-draggable[data-fixed='false'] {
background-color: var(--el-color-warning-light-9);
}
.sortable-ghost {
background: var(--el-fill-color-lighter);
border: 1px dashed var(--w-e-toolbar-disabled-color) !important;
opacity: 0.3; /* 减淡颜色,使其半透明 */
}
} }
} }