此方法是调用打印机方法,需要自己选择导出为PDF。
被导出的PDF转为Docx后,内容支持修改。
被打印页面最外层容器禁止使用 overflow 属性。
涉及 echarts 时,使用 getDataURL() 方法将 echarts 转换为图片展示。
使用此方法需要额外写一份被打印页面的内容。
水印的文字长度需满足 can.width = ??; 的长度,比如水印长度文字长度为 320,则can.width = 320;,如果文字长度未占满水印容器长度的话,导出的PDF转成 Docx 后,水印会被转换未图片,可以被删除。
如果使用了 el-table,打印/导出时需使用 table 写,否则会出现样式错乱、不显示 el-table 等问题
为强制分页
@media print {
tr {
page-break-inside: avoid; /* 禁止跨行分页 */
}
}
usePrint.js
// 打印类属性、方法定义
// import FileSaver from "file-saver";
// import htmlDocx from "html-docx-fixed/dist/html-docx";
const Print = function (dom, options) {
options = options || {};
if (!(this instanceof Print)) return new Print(dom, options);
this.conf = {
isAllStyle: false, // 是否加载当前页面所有样式
styleStr: "", // 设置样式字符串
setDomHeightArr: [], // 需要动态获取并设置高度的 元素
echartDomArr: [], // echart dom
donotPrint: false, // 仅获取到dom
donotPrintCallback: null, // 仅返回dom
fileName: "", // 导出文件名称
documentTitle: "", // 浏览器页签标题(与 fileName 属性配合使用)
printBeforeFn: null, // 打印前回调
printDoneCallBack: null, // 打印后回调
};
for (const key in this.conf) {
if (key && options.hasOwnProperty(key)) {
this.conf[key] = options[key];
}
}
if (typeof dom === "string") {
this.dom = document.querySelector(dom);
} else {
this.dom = this.isDOM(dom) ? dom : dom.$el;
}
if (this.conf.setDomHeightArr && this.conf.setDomHeightArr.length) {
this.setDomHeight(this.conf.setDomHeightArr);
}
this.init();
};
Print.prototype = {
/**
* 初始化
*/
init: function () {
var content = this.getStyle() + this.getHtml();
this.writeIframe(content);
},
/**
* 配置属性扩展
* @param {Object} obj
* @param {Object} obj2
*/
extendOptions: function (obj, obj2) {
for (var k in obj2) {
obj[k] = obj2[k];
}
return obj;
},
/**
复制原网页所有的样式
*/
getStyle: function () {
var str = "";
if (this.conf.isAllStyle) {
let styles = document.querySelectorAll("style,link");
for (var i = 0; i < styles.length; i++) {
str += styles[i].outerHTML;
}
}
// .no-print 选定不显示的区域
// .containBg 主要配合实现打印水印,能让背景正常显示
str += ``;
return str;
},
// 表单赋值
getHtml: function () {
var inputs = document.querySelectorAll("input");
var textareas = document.querySelectorAll("textarea");
var selects = document.querySelectorAll("select");
// debugger
for (var k = 0; k < inputs.length; k++) {
if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
if (inputs[k].checked == true) {
inputs[k].setAttribute("checked", "checked");
} else {
inputs[k].removeAttribute("checked");
}
} else if (inputs[k].type == "text") {
inputs[k].setAttribute("value", inputs[k].value);
} else {
inputs[k].setAttribute("value", inputs[k].value);
}
}
for (var k2 = 0; k2 < textareas.length; k2++) {
if (textareas[k2].type == "textarea") {
textareas[k2].innerHTML = textareas[k2].value;
}
}
for (var k3 = 0; k3 < selects.length; k3++) {
if (selects[k3].type == "select-one") {
var child = selects[k3].children;
for (var i in child) {
if (child[i].tagName == "OPTION") {
if (child[i].selected == true) {
child[i].setAttribute("selected", "selected");
} else {
child[i].removeAttribute("selected");
}
}
}
}
}
/** 分页符,导出为word时可以在需要分页的地方加入
* 来进行分页操作 【page-break-after是无效的】,由于浏览器引擎会自动转成 break-(before|after): page所以获取到后得转换回来
* */let resDOM = this.dom.innerHTML;
resDOM = resDOM.replace(
/break-(before|after):\s*page/g,
`page-break-$1: always`
);
return resDOM;
},
/**
创建iframe
*/
writeIframe: function (content) {
// 方法二:
var _this = this;
var w,
doc,
iframe = document.createElement("iframe"),
f = document.body.appendChild(iframe);
if (_this.conf.fileName) {
document.title = _this.conf.fileName;
}
iframe.id = "myIframe";
iframe.setAttribute(
"style",
"position:absolute;width:0;height:0;top:-10px;left:-10px;"
);
w = f.contentWindow || f.contentDocument;
doc = f.contentDocument || f.contentWindow.document;
doc.open();
doc.write(`${content}`);
doc.close();
iframe.onload = function () {
if (_this.conf.donotPrint) {
_this.conf.donotPrintCallback && _this.conf.donotPrintCallback({ doc });
// let converted = htmlDocx.asBlob(doc.documentElement.outerHTML);
// FileSaver.saveAs(converted, `${_this.conf.fileName || "test"}.doc`);
} else {
// 弹出前,回调
if (_this.conf.printBeforeFn) {
_this.conf.printBeforeFn({ doc });
}
_this.drawEchartImg(doc).then(() => {
_this.toPrint(w);
setTimeout(function () {
document.body.removeChild(iframe);
document.title = _this.conf.documentTitle
// 弹出后,回调
if (_this.conf.printDoneCallBack) {
_this.conf.printDoneCallBack();
}
}, 100);
});
}
};
},
/**
* 项目用到echarts,需要获取图片,来打印
* @param {Object} doc iframe window
*/
drawEchartImg (doc) {
return new Promise((resolve, reject) => {
if (this.conf.echartDomArr && this.conf.echartDomArr.length > 0) {
this.conf.echartDomArr.forEach((e) => {
const dom = doc.querySelector("#" + e.$el.id);
const img = new Image();
const w = dom.offsetWidth + "px";
const H = dom.offsetHeight + "px";
img.style.width = w;
img.style.height = H;
img.src = e.imgSrc;
dom.innerHTML = "";
dom.appendChild(img);
});
}
resolve();
});
},
/**
打印
*/
toPrint: function (frameWindow) {
try {
setTimeout(function () {
frameWindow.focus();
try {
if (!frameWindow.document.execCommand("print", false, null)) {
frameWindow.print();
}
} catch (e) {
frameWindow.print();
}
frameWindow.close();
}, 10);
} catch (err) {
console.log("err", err);
}
},
isDOM:
typeof HTMLElement === "object"
? function (obj) {
return obj instanceof HTMLElement;
}
: function (obj) {
return (
obj &&
typeof obj === "object" &&
obj.nodeType === 1 &&
typeof obj.nodeName === "string"
);
},
/**
* 设置指定dom元素高度,通过获取该dom元素现有高度,并设置
* @param {Array} arr
*/
setDomHeight (arr) {
if (arr && arr.length) {
arr.forEach((name) => {
const domArr = document.querySelectorAll(name);
// debugger
domArr.forEach((dom) => {
dom.style.height = dom.offsetHeight + "px";
});
});
}
},
};
export function usePrint (dom, options) {
Print(dom, options);
}
<template>
<div class="container">
<div class="print-btn-class">
<el-button type="primary" @click="printPDF">打印/导出PDF</el-button>
</div>
<div class="echarts_class" id="echarts_line"></div>
<el-form ref="form" :model="ruleForm" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="ruleForm.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="ruleForm.delivery"></el-switch>
</el-form-item>
</el-form>
<div class="echarts_class" id="echarts_bar"></div>
<el-form ref="form" :model="ruleForm1" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="ruleForm1.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="ruleForm1.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm1.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="ruleForm1.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="ruleForm1.delivery"></el-switch>
</el-form-item>
</el-form>
<el-table :data="tableData" border style="width: 100%">
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
<!-- 打印/导出 -->
<printEchartsFomItem style="display: none;" ref="print_echarts_fomItemRef" :echarts_line_image="echarts_line_image" :echarts_bar_image="echarts_bar_image">
</printEchartsFomItem>
</div>
</template>
<script>
import * as echarts from 'echarts';
import { usePrint } from '@/utils/usePrint'
import printEchartsFomItem from './components/print_echarts_fomItem.vue'
export default {
name: '',
props: {},
components: {
printEchartsFomItem
},
data () {
return {
ruleForm: {
name: '王小虎',
region: '',
date1: '2016-05-02',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
ruleForm1: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
echartsLine: null,
echartsBar: null,
echarts_line_image: null,
echarts_bar_image: null,
tableData: [{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}]
}
},
computed: {},
watch: {},
created () { },
mounted () {
this.echartsLine = echarts.init(document.getElementById('echarts_line'));
let optionLine = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}
]
};
optionLine && this.echartsLine.setOption(optionLine);
// ------------------------------------------------------------------
this.echartsBar = echarts.init(document.getElementById('echarts_bar'));
let optionBar = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'bar'
}
]
};
optionBar && this.echartsBar.setOption(optionBar);
},
methods: {
printPDF () {
// pixelRatio 放大倍数
this.echarts_line_image = this.echartsLine.getDataURL({ type: "png", pixelRatio: 1, backgroundColor: "#fff" });
this.echarts_bar_image = this.echartsBar.getDataURL({ type: "png", pixelRatio: 1, backgroundColor: "#fff" });
this.$nextTick(() => {
usePrint(this.$refs.print_echarts_fomItemRef, { isAllStyle: true, fileName: '打印_导出表', documentTitle: document.title, printDoneCallBack: this.printCompleteCallBack() })
})
},
printCompleteCallBack () {
console.log('打印完成/取消');
}
},
}
</script>
<style scoped lang="less">
.container {
height: 100%;
overflow: auto;
.echarts_class {
width: 100%;
height: 300px;
}
.print-btn-class {
width: 100%;
text-align: center;
}
}
</style>
print_echarts_fomItem.vue
<template>
<div class="container reportPage-content" id="containerId">
<div v-waterMarker="{ text:'水印水印水印水印水印' }" class="containBg waterBox">
<img class="echarts_img_class" :src="echarts_line_image" alt="">
<el-form ref="form" :model="ruleForm" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="ruleForm.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="ruleForm.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="ruleForm.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<!-- 分页符 -->
<!-- <div style="page-break-before:always;"></div> -->
<img class="echarts_img_class" :src="echarts_bar_image" alt="">
<el-form ref="form" :model="ruleForm1" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="ruleForm1.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="ruleForm1.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm1.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="ruleForm1.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="ruleForm1.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="ruleForm1.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<div v-for="(item, index) in 1" :key="index">
<table id="data-table">
<!-- <colgroup>
<col v-for="(th, indexH) in tableColumn" :key="indexH" style="width: 10%;">
</colgroup> -->
<thead>
<tr>
<th :style="indexH < 2 ? 'width:180px' : ''" v-for="(th, indexH) in tableColumn" :key="indexH">{{ th.label }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(tr, indexR) in tableData" :key="indexR">
<td v-for="(th, indexH) in tableColumn" :key="indexH">{{ tr[th.key] || '/' }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'print_echarts_fomItem',
props: {
echarts_line_image: {},
echarts_bar_image: {},
},
components: {},
data () {
return {
ruleForm: {
name: '王小虎',
region: '',
date1: '2016-05-02',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
ruleForm1: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
tableColumn: [
{ label: '日期', key: 'date', },
{ label: '姓名', key: 'name', },
{ label: '地址', key: 'address', },
],
tableData: [
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
}
},
computed: {},
watch: {},
directives: {
waterMarker: (el, binding, vnode) => {
vnode.context.addWaterMarker(
binding.value.text,
el,
binding.value.font,
binding.value.textColor)
}
},
created () { },
mounted () {
this.preventWatermarkRemoval()
},
methods: {
addWaterMarker (str, parentNode, font, textColor) {
// 水印文字,父元素,字体,文字颜色
let can = document.createElement("canvas");
parentNode.appendChild(can);
can.width = 320;
can.height = 250;
can.style.display = "none";
let cans = can.getContext("2d");
cans.rotate((-20 * Math.PI) / 180);
cans.font = font || "24px Microsoft";
cans.fillStyle = textColor || "rgba(180, 180, 180, 0.7)";
cans.textAlign = "left";
cans.textBaseline = "Middle";
cans.fillText(str, can.width / 10, can.height / 2);
parentNode.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")";
},
// 阻止通过控制台去除水印
preventWatermarkRemoval () {
// 获取需要观察的节点
const target = document.querySelector('.container');
// 观察器配置
const config = {
attributes: true, // 监听目标元素属性的变化
childList: true, // 监听目标原型子节点的变化
subtree: false // 是否观察后代的变化。默认false
};
// 创建观察器
const observer = new MutationObserver((abc) => {
// console.log(abc);
// 获取背景图片
const bgi = target?.style?.backgroundImage;
if (!bgi) {
// 当背景被取消后,重新添加
this.initWatermark();
}
});
// 开始观察
observer.observe(target, config);
// 停止观察
observer.disconnect()
}
},
}
</script>
<style scoped lang="less">
.waterBox {
min-height: 100%;
padding: 12px;
}
.echarts_img_class {
width: 100%;
height: 300px;
display: inline-block;
}
table {
width: 100%;
table-layout: fixed;
border-collapse: collapse !important;
th,
td {
height: 48px;
min-height: 48px;
box-sizing: border-box;
padding: 8px;
text-align: center;
border: 1px solid rgba(128, 128, 128, 0.8);
}
&:not(:first-of-type) {
border-top: none;
}
}
</style>
<template>
<div class="container">
<el-button type="primary" @click="printPDF">打印/导出PDF</el-button>
<div class="echarts_class" id="echarts_line"></div>
<el-form ref="ruleFormRef" :model="ruleForm" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="ruleForm.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="ruleForm.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="ruleForm.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<div class="echarts_class" id="echarts_bar"></div>
<el-form ref="ruleForm1Ref" :model="ruleForm1" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="ruleForm1.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="ruleForm1.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm1.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="ruleForm1.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="ruleForm1.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="ruleForm1.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<el-table :data="tableData" border style="width: 100%">
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
<!-- 打印/导出 -->
<printEchartsFomItem style="display: none;" ref="print_echarts_fomItemRef" id="printBox" :echarts_line_image="echarts_line_image"
:echarts_bar_image="echarts_bar_image"></printEchartsFomItem>
</div>
</template>
<script setup name="setup">
import { nextTick, onMounted, ref } from 'vue'
import * as echarts from 'echarts';
import printEchartsFomItem from './components/printEchartsFomItem.vue'
import { usePrint } from '@/utils/usePrint'
const ruleForm = ref(
{
name: '活动名称',
region: '',
date1: '2016-05-02',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
)
const ruleForm1 = ref(
{
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
)
const echartsLine = ref()
const echartsBar = ref()
const echarts_line_image = ref()
const echarts_bar_image = ref()
const tableData = ref([{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}])
onMounted(() => {
echartsLine.value = echarts.init(document.getElementById('echarts_line'));
let optionLine = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}
]
};
optionLine && echartsLine.value.setOption(optionLine);
// ------------------------------------------------------------------
echartsBar.value = echarts.init(document.getElementById('echarts_bar'));
let optionBar = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'bar'
}
]
};
optionBar && echartsBar.value.setOption(optionBar);
})
// 打印
const print_echarts_fomItemRef = ref()
const printPDF = () => {
// pixelRatio 放大倍数
echarts_line_image.value = echartsLine.value.getDataURL({ type: "png", pixelRatio: 1, backgroundColor: "#fff" });
echarts_bar_image.value = echartsBar.value.getDataURL({ type: "png", pixelRatio: 1, backgroundColor: "#fff" });
nextTick(() => {
usePrint(print_echarts_fomItemRef.value, { isAllStyle: true, fileName:'打印_导出表', documentTitle: document.title, printDoneCallBack: printCompleteCallBack })
})
}
const printCompleteCallBack = () =>{
console.log('打印完成/取消');
}
</script>
<style scoped lang="less">
.container {
height: 100%;
overflow: auto;
.echarts_class {
width: 100%;
height: 300px;
}
.print-btn-class {
width: 100%;
text-align: center;
}
}
</style>
print_echarts_fomItem.vue
<template>
<div class="reportPage-content">
<div v-waterMarker="{ text:'水印水印水印水印水印' }" class="containBg waterBox">
<img class="echarts_img_class" :src="echarts_line_image" alt="">
<el-form ref="ruleFormRef" :model="ruleForm" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="ruleForm.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="ruleForm.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="ruleForm.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<!-- 分页符 -->
<!-- <div style="page-break-before:always;"></div> -->
<img class="echarts_img_class" :src="echarts_bar_image" alt="">
<el-form ref="ruleForm1Ref" :model="ruleForm1" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="ruleForm1.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="ruleForm1.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm1.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="ruleForm1.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="ruleForm1.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="ruleForm1.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<div v-for="(item, index) in 1" :key="index">
<table id="data-table">
<!-- <colgroup>
<col v-for="(th, indexH) in tableColumn" :key="indexH" style="width: 10%;">
</colgroup> -->
<thead>
<tr>
<th :style="indexH < 2 ? 'width:180px' : ''" v-for="(th, indexH) in tableColumn" :key="indexH">{{ th.label }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(tr, indexR) in tableData" :key="indexR">
<td v-for="(th, indexH) in tableColumn" :key="indexH">{{ tr[th.key] || '/' }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script setup name="setup">
import { onMounted, ref } from 'vue'
const props = defineProps({
echarts_line_image: {},
echarts_bar_image: {},
})
const ruleForm = ref(
{
name: '活动名称',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
)
const ruleForm1 = ref(
{
name: '活动名称',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
)
const tableColumn = ref([
{ label: '日期', key: 'date', },
{ label: '姓名', key: 'name', },
{ label: '地址', key: 'address', },
])
const tableData = ref([
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
])
onMounted(() => {
preventWatermarkRemoval()
})
// 自定义指令 -> 添加水印
const vWaterMarker = (el, binding) => {
// 水印文字,父元素,字体,文字颜色
let can = document.createElement("canvas");
el.appendChild(can);
can.width = 320;
can.height = 250;
can.style.display = "none";
let cans = can.getContext("2d");
cans.rotate((-20 * Math.PI) / 180);
cans.font = "24px Microsoft";
cans.fillStyle = "rgba(180, 180, 180, 0.7)";
cans.textAlign = "left";
cans.textBaseline = "Middle";
cans.fillText(binding.value.text, can.width / 10, can.height / 2);
el.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")";
};
// 阻止通过控制台去除水印
const preventWatermarkRemoval = () => {
// 获取需要观察的节点
const target = document.querySelector('.container');
// 观察器配置
const config = {
attributes: true, // 监听目标元素属性的变化
childList: true, // 监听目标原型子节点的变化
subtree: false // 是否观察后代的变化。默认false
};
// 创建观察器
const observer = new MutationObserver((e) => {
// 获取背景图片
const bgi = target?.style?.backgroundImage;
if (!bgi) {
// 当背景被取消后,重新添加
this.initWatermark();
}
});
// 开始观察
observer.observe(target, config);
// 停止观察
observer.disconnect()
}
</script>
<style scoped lang="less">
.waterBox {
min-height: 100%;
padding: 12px;
}
.echarts_img_class {
width: 100%;
height: 300px;
display: inline-block;
}
table {
width: 100%;
table-layout: fixed;
border-collapse: collapse !important;
th,
td {
height: 48px;
min-height: 48px;
box-sizing: border-box;
padding: 8px;
text-align: center;
border: 1px solid rgba(128, 128, 128, 0.8);
}
&:not(:first-of-type) {
border-top: none;
}
}
@media print {
@page {
margin: 0; /* 设置页面边距为 0 */
}
body {
margin: 0; /* 设置 body 边距为 0 */
}
/* 隐藏页眉和页脚 */
header,
footer {
display: none;
}
}
</style>