蒋珅 пре 1 година
родитељ
комит
38e095b2da
6 измењених фајлова са 437 додато и 71 уклоњено
  1. 6 6
      package-lock.json
  2. 2 2
      package.json
  3. 9 1
      src/api/axios.js
  4. 66 0
      src/pages/report/fixGetPDF.js
  5. 350 58
      src/pages/report/index.vue
  6. 4 4
      yarn.lock

+ 6 - 6
package-lock.json

@@ -20,10 +20,10 @@
         "echarts": "^5.2.2",
         "element-plus": "^2.2.26",
         "file-saver": "^2.0.5",
-        "html2canvas": "^1.0.0-rc.7",
+        "html2canvas": "^1.4.1",
         "jsencrypt": "^3.2.1",
         "json-bigint": "^1.0.0",
-        "jspdf": "^2.3.1",
+        "jspdf": "^2.5.1",
         "moment": "^2.29.1",
         "q": "^1.5.1",
         "screenfull": "^6.0.0",
@@ -2927,7 +2927,7 @@
     },
     "node_modules/html2canvas": {
       "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+      "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
       "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
       "dependencies": {
         "css-line-break": "^2.1.0",
@@ -3366,7 +3366,7 @@
     },
     "node_modules/jspdf": {
       "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz",
+      "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz",
       "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
       "dependencies": {
         "@babel/runtime": "^7.14.0",
@@ -8018,7 +8018,7 @@
     },
     "html2canvas": {
       "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+      "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
       "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
       "requires": {
         "css-line-break": "^2.1.0",
@@ -8382,7 +8382,7 @@
     },
     "jspdf": {
       "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz",
+      "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz",
       "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
       "requires": {
         "@babel/runtime": "^7.14.0",

+ 2 - 2
package.json

@@ -20,10 +20,10 @@
     "echarts": "^5.2.2",
     "element-plus": "^2.2.26",
     "file-saver": "^2.0.5",
-    "html2canvas": "^1.0.0-rc.7",
+    "html2canvas": "^1.4.1",
     "jsencrypt": "^3.2.1",
     "json-bigint": "^1.0.0",
-    "jspdf": "^2.3.1",
+    "jspdf": "^2.5.1",
     "moment": "^2.29.1",
     "q": "^1.5.1",
     "screenfull": "^6.0.0",

+ 9 - 1
src/api/axios.js

@@ -1,3 +1,11 @@
+/*
+ * @Author: 蒋珅 11455645+jiang-shena@user.noreply.gitee.com
+ * @Date: 2023-06-12 14:02:04
+ * @LastEditors: 蒋珅 11455645+jiang-shena@user.noreply.gitee.com
+ * @LastEditTime: 2023-06-12 14:45:11
+ * @FilePath: \PowerAnalysis\src\api\axios.js
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
 import axios from 'axios';
 import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
 import { nextTick } from "vue";
@@ -7,7 +15,7 @@ import JSONBIG from 'json-bigint';
 var loading = null;
 const service = axios.create({
     baseURL: baseURL,
-    timeout: 2000000,
+    timeout: 2000,
     headers: { 'Content-Type': 'application/json' },
     transformResponse: [
         function (data) {

+ 66 - 0
src/pages/report/fixGetPDF.js

@@ -0,0 +1,66 @@
+// 页面导出为pdf格式
+import html2Canvas from 'html2canvas';
+import jsPDF from 'jspdf';
+
+const htmlToPdf = {
+  getPdf(title, loading) {
+    // loading = true;
+    console.log(loading);
+    html2Canvas(document.querySelector('#pdfDom'), {
+      allowTaint: false,
+      taintTest: false,
+      logging: false,
+      useCORS: true,
+      dpi: window.devicePixelRatio * 4, //将分辨率提高到特定的DPI 提高四倍
+      scale: 4, //按比例增加分辨率
+    }).then((canvas) => {
+      var pdf = new jsPDF('p', 'mm', 'a4'); //A4纸,纵向
+      var ctx = canvas.getContext('2d'),
+        a4w = 190,
+        a4h = 272, //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
+        imgHeight = Math.floor((a4h * canvas.width) / a4w), //按A4显示比例换算一页图像的像素高度
+        renderedHeight = 0;
+
+      while (renderedHeight < canvas.height) {
+        var page = document.createElement('canvas');
+        page.width = canvas.width;
+        page.height = Math.min(imgHeight, canvas.height - renderedHeight); //可能内容不足一页
+
+        //用getImageData剪裁指定区域,并画到前面创建的canvas对象中
+        page
+          .getContext('2d')
+          .putImageData(
+            ctx.getImageData(
+              0,
+              renderedHeight,
+              canvas.width,
+              Math.min(imgHeight, canvas.height - renderedHeight),
+            ),
+            0,
+            0,
+          );
+        pdf.addImage(
+          page.toDataURL('image/jpeg', 1.0),
+          'JPEG',
+          10,
+          10,
+          a4w,
+          Math.min(a4h, (a4w * page.height) / page.width),
+        ); //添加图像到页面,保留10mm边距
+
+        renderedHeight += imgHeight;
+        if (renderedHeight < canvas.height) {
+          pdf.addPage(); //如果后面还有内容,添加一个空页
+        }
+        // delete page;
+      }
+      //保存文件
+      pdf.save(title + '.pdf');
+      // loading = false;
+      console.log(loading);
+    });
+  },
+};
+
+export default htmlToPdf;
+

+ 350 - 58
src/pages/report/index.vue

@@ -1,73 +1,365 @@
 <template>
-	<div class="bg-white py-[10px] px-[10px] relative">
-        <div class="mb-[20px]">
-            <el-form class="" :inline="true" >
-                <el-form-item label="场站" class="!mb-0">
-                    <el-select v-model="queryForm.station" clear class="w-[150px]">
-                        <el-option v-for="item in stationList" :key="item.id" :label="item.title" :value="item.id"></el-option>
-                    </el-select>
-                </el-form-item>
-                <el-form-item label="开始时间" class="!mb-0">
-                    <el-date-picker type="month" class="!w-[150px]" v-model="queryForm.st"></el-date-picker>
-                </el-form-item>
-                <el-form-item label="结束时间" class="!mb-0">
-                    <el-date-picker type="month" class="!w-[150px]" v-model="queryForm.et"></el-date-picker>
-                </el-form-item>
-                <el-form-item class="!mb-0">
-                    <submit-btn @submit="funQuery" desc="查询"></submit-btn>
-                </el-form-item>
-            </el-form>
-        </div>
-	</div>
-    <div class="mb-[20px] mt-[20px]">
-        <el-table :data="tableData"
-            stripe
-            size="small" v-loading="props.loading"
-            :style="{ width: '100%'}">
-            <el-table-column align="center" prop="station" label="场站名称"/>
-            <el-table-column align="center" prop="time" label="场站名称"/>
-            <el-table-column align="center" label="操作">
-                <template slot-scope="scope">
-                    <el-button
-                        size="mini"
-                        @click="handleEdit(scope.$index, scope.row)">下载</el-button>
-                    <el-button
-                        size="mini"
-                        @click="handleDownload(scope.$index, scope.row)">查看详情</el-button>
-                    </template>
-            </el-table-column>
-        </el-table>
+  <div class="bg-white py-[10px] px-[10px] relative">
+    <div class="mb-[20px]">
+      <el-form class="" :inline="true">
+        <el-form-item label="场站" class="!mb-0">
+          <el-select v-model="station" clearable class="w-[150px]">
+            <el-option
+              v-for="item in stationList"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="开始" class="!mb-0 ml-2">
+          <el-date-picker
+            v-model="val1"
+            @change="BeginChange(val1)"
+            type="month"
+            value-format="YYYY-MM"
+            placeholder="选择日期"
+          >
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="结束" class="!mb-0">
+          <el-date-picker
+            v-model="value2"
+            @change="EndChange(value2)"
+            type="month"
+            value-format="YYYY-MM"
+            placeholder="选择日期"
+          >
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item class="!mb-0">
+          <el-button type="primary" @click="addform">查询</el-button>
+        </el-form-item>
+      </el-form>
     </div>
+  </div>
+  <div class="mb-[20px] mt-[20px]">
+    <el-table
+      :data="tableData"
+      stripe
+      size="small"
+      :border="true"
+      :style="{ width: '100%' }"
+    >
+      <el-table-column
+        width="250"
+        resizable
+        align="center"
+        type="index"
+        label="序号"
+      />
+      <el-table-column
+        width="350"
+        resizable
+        align="center"
+        prop="station"
+        label="场站名称"
+      />
+      <el-table-column
+        width="350"
+        resizable
+        align="center"
+        prop="time"
+        label="时间"
+      />
+      <el-table-column
+        width="350"
+        resizable
+        align="center"
+        prop="wtidcount"
+        label="风机数量"
+      />
+      <el-table-column width="350" resizable align="center" label="操作">
+        <template #default="scope">
+          <el-button size="small" @click="handleEdit(scope.$index, scope.row)"
+            >下载</el-button
+          >
+          <el-button
+            size="small"
+            type="danger"
+            @click="handleDelete(scope.$index, scope.row)"
+            >查看报告</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+  <div id="pdfDom">
+  <el-dialog
+    v-model="centerDialogVisible"
+    title="风电场性能分析报告"
+    width="50%"
+    center
+  >
+    <p>
+      <span>场站:{{ nbdata.name }}</span>
+      <span class="ml-79">风机型号:{{ nbdata.model }}</span>
+    </p>
+    <p>
+      <span>风机数量:{{ nbdata.quantity }}</span>
+      <span class="ml-87">装机容量(MW):{{ nbdata.capacity }}</span>
+    </p>
+    <p>
+      <span>报告生成日期:{{ time }}</span>
+      <span class="ml-74">数据分析周期:{{ eltime }}</span>
+    </p>
+    <h3 style="font-weight: bolder; font-size: 18px; color: black">概述:</h3>
+    <p class="ml-7">
+      报告基于曲线偏差率、静态偏差对风、容量系数、停机时长、分别对场站{{ nbdata.quantity }}台风机进行了性能分析,其中有{{wtcount}}台风机指标严重异常,信息如下:
+    </p>
+    <h3 style="font-weight: bolder; font-size: 18px; color: black">
+      1、曲线偏差率
+    </h3>
+    <p class="ml-7">
+      曲线偏差率对不同风速区间的实际功率和保证功率做偏差率分析,高偏差率表明存在需要进一步调查潜在问题,偏差率负值表明实际功率低于保证功率
+    </p>
+
+    <el-table
+      :data="curve"
+      :span-method="objectSpanMethod"
+      border
+      style="width: 100%; margin-top: 20px"
+    >
+      <el-table-column
+        prop="section"
+        align="center"
+        label="风速区间"
+        width="180"
+      />
+      <el-table-column prop="module" align="center" label="偏差率" />
+      <el-table-column prop="wtidcount" align="center" label="风机数量" />
+      <el-table-column prop="windturbine" align="center" label="风机编号" />
+    </el-table>
+    <h3 style="font-weight: bolder; font-size: 18px; color: black">
+      2、静态偏航对风
+    </h3>
+    <p class="ml-7">
+      静态偏航对风指风机的叶片与风向之间的偏差,偏差角度过大表明对风存在问题,以下为5-10m风速区间的对风误差
+    </p>
+    <el-table
+      :data="staticwind"
+      :span-method="objectSpanMethod"
+      border
+      style="width: 100%; margin-top: 20px"
+    >
+      <el-table-column
+        prop="section"
+        align="center"
+        label="严重程度"
+        width="180"
+      />
+      <el-table-column prop="wtidcount" align="center" label="风机数量" />
+      <!-- <el-table-column prop="amount1" label="风机数量" /> -->
+      <el-table-column prop="windturbine" align="center" label="风机编号" />
+    </el-table>
+    <h3 style="font-weight: bolder; font-size: 18px; color: black">
+      3、容量系数
+    </h3>
+    <p class="ml-7">
+      容量系数是风机发电量能力的指标,数值越低,说明发电效率越低
+    </p>
+    <el-table
+      :data="mrlxs"
+      :span-method="objectSpanMethod"
+      border
+      style="width: 100%; margin-top: 20px"
+    >
+      <el-table-column
+        prop="section"
+        align="center"
+        label="容量系数"
+        width="180"
+      />
+      <!-- <el-table-column prop="name" label="偏差率" /> -->
+      <el-table-column prop="wtidcount" align="center" label="风机数量" />
+      <el-table-column prop="windturbine" align="center" label="风机编号" />
+    </el-table>
+    <h3 style="font-weight: bolder; font-size: 18px; color: black">
+      4、停机时间
+    </h3>
+    <p class="ml-7">
+      小风速下停机时间越长反应出低风速风机切入不及时,暴风天气不停机反应出风机切出不及时
+    </p>
+    <el-table
+      :data="stoptime"
+      :span-method="objectSpanMethod"
+      border
+      style="width: 100%; margin-top: 20px"
+    >
+      <el-table-column
+        prop="section"
+        align="center"
+        label="风速区间"
+        width="180"
+      />
+
+      <el-table-column prop="wtidcount" align="center" label="风机数量" />
+      <el-table-column prop="remark" align="center" label="累计时间(h)" />
+      <el-table-column prop="windturbine" align="center" label="风机编号" />
+    </el-table>
+    <!-- <h3 style="font-weight: bolder; font-size: 18px; color: black">
+      5、损失电量
+    </h3>
+    <p class="ml-7">
+      损失电量指因故障或维护等原因导致风机未能正常发电,损失电量占比越高,存在的问题越明显
+    </p>
+    <el-table
+      :data="tableData1"
+      :span-method="objectSpanMethod"
+      border
+      style="width: 100%; margin-top: 20px"
+    >
+      <el-table-column prop="id" align="center" label="损失占比" width="180" />
+
+      <el-table-column prop="amount1" align="center" label="风机数量" />
+      <el-table-column prop="amount2" align="center" label="风机编号" />
+    </el-table> -->
+    <h3 style="font-weight: bolder; font-size: 18px; color: black">
+      结论及建议
+    </h3>
+    <p class="ml-7">
+      综上统计周期内数据分析,{{ nbdata.name }}的{{hjwtid}}台风机出现频率最高为{{hjcount}}次。
+    </p>
+
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="centerDialogVisible = false">取消</el-button>
+        <!-- <el-button type="primary" @click="centerDialogVisible = false">
+          确定
+        </el-button> -->
+        <el-button @click="exportPDF" type="primary" :loading="loading">导出 PDF</el-button>
+      </span>
+    </template>
+  </el-dialog>
+  </div>
 </template>
 
 <script setup name="report">
-import request from '@/api/axios.js'
-import { ref } from 'vue';
-
-const queryForm = ref({
-	station: '',
-	st: Date.now() - 30 * 24 * 60 * 60 * 1000,
-	et: Date.now(),
-	interval: 3
-})
+import request from "@/api/axios.js";
+import jsPDF from 'jspdf';
+import html2canvas from 'html2canvas';
+import htmlToPdf from "./fixGetPDF";
+import { ref, onMounted, reactive } from "vue";
+
+const curve = ref([]);
+const mrlxs = ref([]);
+const staticwind = ref([]);
+const stoptime = ref([]);
+const nbdata = ref({});
+const loading=ref(false)
+const exportPDF = () => {   
+	 loading.value = true;
+	 // 调用htmlToPdf工具函数
+     htmlToPdf.getPdf('分析报告');
+     // 定时器模拟按钮loading动画的时间
+      setTimeout(() => {
+        loading.value = false;
+        ElMessage.success('打印成功!');
+      }, 1000);
+      centerDialogVisible.value=false
+}
+
+      
+
+
+
+
+
+
+const centerDialogVisible = ref(false);
 /**场站 */
 const stationList = ref([]);
 const funGetStation = async () => {
-	const res = await request.get("/base/station")
-	stationList.value = res.data
-}
+  const res = await request.get("/base/station");
+  stationList.value = res.data;
+};
 /**查询表格数据 */
-const tableData = ref()
-const funQuery = async () => {
-    const res = await request.get('/report/list', { params: {station: queryForm.station,st: queryForm.st,et: queryForm.et} })
-    if (res.code == 200){
-        tableData = res.data
-    }
-}
+const tableData = ref();
+const station = ref("");
+const addform = async () => {
+  const res = await request.get(
+    `/report/list?station=${station.value}&st=${val1.value}&et=${value2.value}`
+  );
+
+  //    res.data.forEach((ele)=>{
+  //        ele.time=ele.time.slice(0, 7);
+  //    })
+  tableData.value = res.data;
+};
+
+let val1 = ref();
+let value2 = ref();
+const BeginChange = (val) => {
+  console.log(val);
+  val1.value = val;
+  // console.log(val);
+};
+const EndChange = (val) => {
+  // console.log(val);
+  value2.value = val;
+};
+let time = ref();
+let eltime = ref();
+let wtcount=ref()
+let hjwtid=ref()
+let hjcount=ref()
+const handleDelete = async (index, row) => {
+  time.value = row.time;
+  //   console.log(index, row)
+  centerDialogVisible.value = true;
+  const res = await request.get(
+    `/report/info?station=${row.station}&date=${row.time}`
+  );
+  nbdata.value = res.data.station;
+  //    console.log('nb',nbdata.value);
+  res.data.info.curve.forEach((ele) => {
+    ele.module = "偏差率负值";
+  });
+//   res.data.info.stoptime.forEach((ele)=>{
+//       ele.remark=ele.remark/60
+//   })
+  
+  curve.value = res.data.info.curve;
+  mrlxs.value = res.data.info.mrlxs;
+  staticwind.value = res.data.info.staticwind;
+  stoptime.value = res.data.info.stoptime;
+  eltime.value = res.data.time;
+  wtcount.value = res.data.wtcount;
+  hjwtid.value = res.data.hjwtid;
+  hjcount.value = res.data.hjcount;
+};
 
+const getTime1 = (val) => {
+  //时间戳处理,val=1是默认开始时间(当前月第一天),val=2是默认结束时间(今天)
+  var date = new Date();
+  var year = date.getFullYear(),
+    month = date.getMonth() + 1,
+    day = date.getDate();
+  month >= 1 && month <= 9 ? (month = "0" + month) : "";
+  day >= 0 && day <= 9 ? (day = "0" + day) : "";
+  var begin = year + "-" + '05';
+  var end = year + "-" + month;
+  if (val == 1) {
+    return begin;
+  } else if (val == 2) {
+    return end;
+  }
+};
+onMounted(() => {
+  funGetStation();
+ 
+  val1.value = getTime1(1);
+  value2.value = getTime1(2);
+   addform()
+});
 /**created */
 funGetStation();
 // onActivated(() => {
 //     funQuery();
 // })
-</script>
+</script>

+ 4 - 4
yarn.lock

@@ -1898,9 +1898,9 @@
     "capital-case" "^1.0.4"
     "tslib" "^2.0.3"
 
-"html2canvas@^1.0.0-alpha.12", "html2canvas@^1.0.0-rc.5", "html2canvas@^1.0.0-rc.7":
+"html2canvas@^1.0.0-alpha.12", "html2canvas@^1.0.0-rc.5", "html2canvas@^1.4.1":
   "integrity" "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA=="
-  "resolved" "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz"
+  "resolved" "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz"
   "version" "1.4.1"
   dependencies:
     "css-line-break" "^2.1.0"
@@ -2187,9 +2187,9 @@
     "promise-polyfill" "8.1.0"
     "stackblur-canvas" "2.2.0"
 
-"jspdf@^2.3.1":
+"jspdf@^2.5.1":
   "integrity" "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA=="
-  "resolved" "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz"
+  "resolved" "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz"
   "version" "2.5.1"
   dependencies:
     "@babel/runtime" "^7.14.0"