|
@@ -0,0 +1,512 @@
|
|
|
+<template>
|
|
|
+ <div class="reportBox">
|
|
|
+ <div class="outlineBox">
|
|
|
+ <div class="btnBox">
|
|
|
+ <el-dropdown
|
|
|
+ trigger="click"
|
|
|
+ @command="callFn"
|
|
|
+ popper-class="psarDropdown"
|
|
|
+ >
|
|
|
+ <el-button style="color: #05bb4c" size="small" type="text"
|
|
|
+ >导出
|
|
|
+ <el-icon><arrow-down /></el-icon>
|
|
|
+ </el-button>
|
|
|
+ <template #dropdown>
|
|
|
+ <el-dropdown-menu>
|
|
|
+ <el-dropdown-item command="exportPDF">PDF</el-dropdown-item>
|
|
|
+ <el-dropdown-item command="exportWord">WORD</el-dropdown-item>
|
|
|
+ </el-dropdown-menu>
|
|
|
+ </template>
|
|
|
+ </el-dropdown>
|
|
|
+ <!-- <el-button type="success" size="mini" @click="exportPDF"
|
|
|
+ >导出PDF</el-button
|
|
|
+ > -->
|
|
|
+ </div>
|
|
|
+ <template v-if="reportTitle">
|
|
|
+ <p
|
|
|
+ class="songti font fw"
|
|
|
+ style="
|
|
|
+ width: 100%;
|
|
|
+ padding: 12px 24px;
|
|
|
+ color: #b3bdc0;
|
|
|
+ background: rgba(96, 103, 105, 0.2);
|
|
|
+ cursor: pointer;
|
|
|
+ margin: 0;
|
|
|
+ color: #05bb4c;
|
|
|
+ "
|
|
|
+ @click="
|
|
|
+ nodeClick({
|
|
|
+ label: `国家能源集团宁夏新能源开发有限公司${reportTitle}`,
|
|
|
+ })
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ reportTitle }}
|
|
|
+ </p>
|
|
|
+ </template>
|
|
|
+ <el-tree
|
|
|
+ :data="treeData"
|
|
|
+ :props="{
|
|
|
+ children: 'children',
|
|
|
+ label: 'label',
|
|
|
+ }"
|
|
|
+ style="height: calc(100% - 48px); overflow-y: scroll"
|
|
|
+ @node-click="nodeClick"
|
|
|
+ >
|
|
|
+ <template #default="{ node, data }">
|
|
|
+ <span class="font songti fw">{{ data.index }}{{ node.label }}</span>
|
|
|
+ </template>
|
|
|
+ </el-tree>
|
|
|
+ </div>
|
|
|
+ <div class="resizeLine">
|
|
|
+ <el-divider direction="vertical" />
|
|
|
+ <el-icon :size="24" color="#eee"><DCaret /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div class="contentBox">
|
|
|
+ <div class="pagePadding A4">
|
|
|
+ <div class="page">
|
|
|
+ <template v-if="reportTitle">
|
|
|
+ <h1
|
|
|
+ :id="`${reportName}${reportTitle}`"
|
|
|
+ class="songti mainTitle fw"
|
|
|
+ style="margin-bottom: 0"
|
|
|
+ >
|
|
|
+ {{ currentCompany }}{{ reportName }}
|
|
|
+ </h1>
|
|
|
+ <h1 :id="reportTitle" class="songti mainTitle fw">
|
|
|
+ {{ reportTitle }}
|
|
|
+ </h1>
|
|
|
+ </template>
|
|
|
+ <el-card
|
|
|
+ :id="pItem.label"
|
|
|
+ v-for="pItem in treeData"
|
|
|
+ :key="pItem.index"
|
|
|
+ >
|
|
|
+ <p class="songti title fw">
|
|
|
+ {{ pItem.index || "" }}{{ pItem.label }}
|
|
|
+ </p>
|
|
|
+ <p
|
|
|
+ class="fangsong indent"
|
|
|
+ style="margin-bottom: 5px"
|
|
|
+ v-for="(cItem, cIndex) in pItem.content"
|
|
|
+ :key="cIndex"
|
|
|
+ >
|
|
|
+ {{ cItem }}
|
|
|
+ </p>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import Get_PDF from "@tools/fixGetPDF";
|
|
|
+import docxtemplater from "docxtemplater";
|
|
|
+import { saveAs } from "file-saver";
|
|
|
+import JSZipUtils from "jszip-utils";
|
|
|
+import PizZip from "pizzip";
|
|
|
+import { getApiEconReport } from "@/api/monthlyPerformanceAnalysis.js";
|
|
|
+export default {
|
|
|
+ name: "EconomyReport",
|
|
|
+ components: {},
|
|
|
+
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ locationHref: "",
|
|
|
+ reportTitle: "",
|
|
|
+ reportName: "",
|
|
|
+ treeData: [
|
|
|
+ {
|
|
|
+ label: "发电量完成情况",
|
|
|
+ children: [],
|
|
|
+ content: [],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "资源及理论发电量平衡分析",
|
|
|
+ children: [],
|
|
|
+ content: [],
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ label: "故障及损失分析",
|
|
|
+ children: [],
|
|
|
+ content: [],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "性能损失分析",
|
|
|
+ children: [],
|
|
|
+ content: [],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "厂用电量分析",
|
|
|
+ children: [],
|
|
|
+ content: [],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "场站问题总结和建议",
|
|
|
+ children: [],
|
|
|
+ content: [],
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ sourceData: {},
|
|
|
+ currentWpid: "",
|
|
|
+ currentCompany: "",
|
|
|
+ currentYear: "",
|
|
|
+ currentMonth: "",
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ created() {
|
|
|
+ this.locationHref = location.href;
|
|
|
+ let treeData = this.initTreeData(
|
|
|
+ JSON.parse(JSON.stringify(this.treeData || []))
|
|
|
+ );
|
|
|
+ this.treeData = treeData;
|
|
|
+ },
|
|
|
+
|
|
|
+ mounted() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.initMouseEvent();
|
|
|
+ if (this.$route.hash) {
|
|
|
+ this.pageScroll(this.$route.hash.replace(/^\#/, ""));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ init(row) {
|
|
|
+ this.reportName = row.stationName;
|
|
|
+ this.getContentData();
|
|
|
+ },
|
|
|
+ // 初始化树形
|
|
|
+ initTreeData(treeData, parentIdx = "") {
|
|
|
+ treeData.forEach((ele, idx) => {
|
|
|
+ ele.index = `${parentIdx}${idx + 1}.`;
|
|
|
+ if (ele.children?.length) {
|
|
|
+ return this.initTreeData(ele.children, ele.index);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return treeData;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 初始化鼠标事件
|
|
|
+ initMouseEvent() {
|
|
|
+ const resize = document.querySelector(".resizeLine");
|
|
|
+ const left = document.querySelector(".outlineBox");
|
|
|
+ const right = document.querySelector(".contentBox");
|
|
|
+ const box = document.querySelector(".reportBox");
|
|
|
+ const svgPath = resize.querySelector(".el-icon path");
|
|
|
+
|
|
|
+ left.style.width = getComputedStyle(left, null).width;
|
|
|
+ right.style.width = getComputedStyle(right, null).width;
|
|
|
+ resize.onmousedown = (e) => {
|
|
|
+ const startX = e.clientX;
|
|
|
+ resize.left = resize.offsetLeft;
|
|
|
+ svgPath.style.fill = "#05bb4c";
|
|
|
+ svgPath.style.transform = "scale(1.5)";
|
|
|
+ svgPath.style.transformOrigin = "center center";
|
|
|
+ svgPath.style.transition = "0.2s";
|
|
|
+ document.onmousemove = (e) => {
|
|
|
+ var endX = e.clientX;
|
|
|
+ const maxT = box.clientWidth - resize.offsetWidth;
|
|
|
+ let moveLen = resize.left + (endX - startX);
|
|
|
+ if (moveLen < 250) moveLen = 250;
|
|
|
+ if (moveLen > maxT - 1000) moveLen = maxT - 1000;
|
|
|
+
|
|
|
+ resize.style.left = moveLen;
|
|
|
+ left.style.width = `${moveLen}px`;
|
|
|
+ right.style.width = `${box.clientWidth - moveLen - 8}px`;
|
|
|
+ };
|
|
|
+ document.onmouseup = () => {
|
|
|
+ svgPath.style.fill = "#eee";
|
|
|
+ svgPath.style.transform = "scale(1)";
|
|
|
+ svgPath.style.transformOrigin = "center center";
|
|
|
+ svgPath.style.transition = "0.2s";
|
|
|
+ document.onmousemove = null;
|
|
|
+ document.onmouseup = null;
|
|
|
+ resize.releaseCapture && resize.releaseCapture();
|
|
|
+ };
|
|
|
+ resize.setCapture && resize.setCapture();
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 树形点击
|
|
|
+ nodeClick(node) {
|
|
|
+ const label = node.label;
|
|
|
+ location.hash = `${this.$route.path}#${label}`;
|
|
|
+ this.pageScroll(label);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 页面滚动至锚点
|
|
|
+ pageScroll(id) {
|
|
|
+ document.getElementById(id)?.scrollIntoView({ behavior: "smooth" });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 数据请求
|
|
|
+ getContentData() {
|
|
|
+ let params = {
|
|
|
+ wpid: this.currentWpid,
|
|
|
+ year: this.currentYear,
|
|
|
+ month: this.currentMonth,
|
|
|
+ };
|
|
|
+ getApiEconReport(params).then(({ data }) => {
|
|
|
+ this.sourceData = data;
|
|
|
+ this.treeData.forEach((pEle) => {
|
|
|
+ const content = data[pEle.label] || [];
|
|
|
+ if (content.length) {
|
|
|
+ content.forEach((cEle) => {
|
|
|
+ pEle.content.push(cEle);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.reportTitle = data?.["标题"]?.[0] || "";
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 下拉列表调用函数
|
|
|
+ callFn(command) {
|
|
|
+ this[command]();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 导出 PDF
|
|
|
+ exportPDF() {
|
|
|
+ this.BASE.showLoading({
|
|
|
+ text: "正在导出...请稍后...",
|
|
|
+ });
|
|
|
+ setTimeout(() => {
|
|
|
+ Get_PDF.getPdf(
|
|
|
+ document.querySelector(".contentBox .page"),
|
|
|
+ "2023年3月经济运行分析报告"
|
|
|
+ );
|
|
|
+ this.BASE.closeLoading();
|
|
|
+ }, 50);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 导出 WORD
|
|
|
+ exportWord() {
|
|
|
+ let wordData = {};
|
|
|
+ for (let key in this.sourceData) {
|
|
|
+ if (key === "标题") {
|
|
|
+ wordData[key] = this.sourceData[key][0];
|
|
|
+ } else {
|
|
|
+ let dataItem = [];
|
|
|
+ this.sourceData[key].forEach((content) => {
|
|
|
+ dataItem.push({ content });
|
|
|
+ });
|
|
|
+ wordData[key] = dataItem;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 读取并获得模板文件的二进制内容
|
|
|
+ JSZipUtils.getBinaryContent(
|
|
|
+ "./static/template/wordTemplate.docx",
|
|
|
+ function (error, content) {
|
|
|
+ if (error) {
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建一个PizZip实例,内容为模板的内容
|
|
|
+ let zip = new PizZip(content);
|
|
|
+ // 创建并加载docxtemplater实例对象
|
|
|
+ let doc = new docxtemplater(zip, { linebreaks: true });
|
|
|
+ // doc.attachModule(new ImageModule(opts));
|
|
|
+
|
|
|
+ doc.setData(wordData);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 用模板变量的值替换所有模板变量
|
|
|
+ doc.render();
|
|
|
+ } catch (error) {
|
|
|
+ // 抛出异常
|
|
|
+ let e = {
|
|
|
+ message: error.message,
|
|
|
+ name: error.name,
|
|
|
+ stack: error.stack,
|
|
|
+ properties: error.properties,
|
|
|
+ };
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
|
|
|
+ let out = doc.getZip().generate({
|
|
|
+ type: "blob",
|
|
|
+ mimeType:
|
|
|
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
|
+ });
|
|
|
+ // 将目标文件对象保存为目标类型的文件,并命名
|
|
|
+ saveAs(out, "2023年3月经济运行分析报告.docx");
|
|
|
+ }
|
|
|
+ );
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ watch: {},
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="less" scoped>
|
|
|
+.reportBox {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .outlineBox {
|
|
|
+ width: calc(25% - 8px);
|
|
|
+ height: 100%;
|
|
|
+ float: left;
|
|
|
+
|
|
|
+ .btnBox {
|
|
|
+ width: 97%;
|
|
|
+ margin: 0 1.5% 12px 1.5%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .resizeLine {
|
|
|
+ width: 6px;
|
|
|
+ height: 100%;
|
|
|
+ cursor: w-resize;
|
|
|
+ float: left;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .el-icon {
|
|
|
+ position: absolute;
|
|
|
+ left: calc(50% - 12px);
|
|
|
+ top: calc(50% - 12px);
|
|
|
+ transform: rotate(90deg);
|
|
|
+ transition: 0.2s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-divider--vertical {
|
|
|
+ width: 2px;
|
|
|
+ margin: 0 2px;
|
|
|
+ height: 100%;
|
|
|
+ transition: 0.2s;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:active .el-divider--vertical {
|
|
|
+ background: #05bb4c;
|
|
|
+ transition: 0.2s;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .contentBox {
|
|
|
+ float: right;
|
|
|
+ width: 75%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: flex-start;
|
|
|
+ overflow-y: scroll;
|
|
|
+
|
|
|
+ .mainTitle {
|
|
|
+ font-size: 30px;
|
|
|
+ width: 90%;
|
|
|
+ margin: 0 5% 20px 5%;
|
|
|
+ text-align: center;
|
|
|
+ color: #000;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page {
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .pagePadding {
|
|
|
+ padding: 20mm;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .A4 {
|
|
|
+ width: 210mm;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-card {
|
|
|
+ border-color: transparent;
|
|
|
+ color: #000;
|
|
|
+
|
|
|
+ .el-card__body {
|
|
|
+ p {
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.font {
|
|
|
+ width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+.fw {
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+
|
|
|
+.songti {
|
|
|
+ font-family: SimSun, 宋体;
|
|
|
+ font-size: 18.7px;
|
|
|
+ line-height: 2;
|
|
|
+}
|
|
|
+
|
|
|
+.fangsong {
|
|
|
+ font-family: FangSong, 仿宋;
|
|
|
+ font-size: 18.7px;
|
|
|
+ line-height: 2;
|
|
|
+}
|
|
|
+
|
|
|
+.indent {
|
|
|
+ text-indent: 2em;
|
|
|
+}
|
|
|
+
|
|
|
+.title {
|
|
|
+ font-size: 22px;
|
|
|
+ line-height: 2;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+<style lang="less">
|
|
|
+.contentBox {
|
|
|
+ .el-card {
|
|
|
+ .el-card__body {
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .el-card.is-always-shadow {
|
|
|
+ box-shadow: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.el-popper.is-light.psarDropdown {
|
|
|
+ background: rgb(22, 30, 30);
|
|
|
+ border: 1px solid #05bb4c;
|
|
|
+
|
|
|
+ .el-scrollbar__wrap > ul {
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-dropdown-menu {
|
|
|
+ padding: 0;
|
|
|
+ background: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-dropdown-menu__item {
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-dropdown-menu__item:hover {
|
|
|
+ color: #05bb4c;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-popper__arrow {
|
|
|
+ &::before {
|
|
|
+ border-top-color: #05bb4c !important;
|
|
|
+ border-left-color: #05bb4c !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|