瀏覽代碼

2022-12-03 init

moccus 2 年之前
父節點
當前提交
4ca451541d
共有 100 個文件被更改,包括 66433 次插入3 次删除
  1. 1 3
      .gitignore
  2. 220 0
      src/App.vue
  3. 25 0
      src/api/agcAbout.js
  4. 18 0
      src/api/curveAnalyse.js
  5. 12 0
      src/api/economy.js
  6. 9 0
      src/api/factoryMonitor.js
  7. 68 0
      src/api/home.js
  8. 191 0
      src/api/monthlyPerformanceAnalysis.js
  9. 81 0
      src/api/performance.js
  10. 28 0
      src/api/stateMonitor.js
  11. 二進制
      src/assets/img/title_bg.png
  12. 二進制
      src/assets/img/title_left_bg.png
  13. 二進制
      src/assets/img/title_right_bg.png
  14. 1 0
      src/assets/style/main.less
  15. 78 0
      src/assets/style/table.less
  16. 86 0
      src/background.js
  17. 166 0
      src/components/canvesMap/index.vue
  18. 476 0
      src/components/chart/combination/area-line-chart.vue
  19. 447 0
      src/components/chart/combination/multiple-bar-line-chart.vue
  20. 479 0
      src/components/chart/line/multiple-line-chart.vue
  21. 233 0
      src/components/chart/pie/dual-pie-chart.vue
  22. 382 0
      src/components/chart/radar/direction-radar-chart.vue
  23. 372 0
      src/components/chart/radar/radar-chart.vue
  24. 111 0
      src/components/coms/panel/panel.vue
  25. 201 0
      src/components/coms/table/table.vue
  26. 398 0
      src/components/curveAnalyse/multiple-bar-chart.vue
  27. 112 0
      src/components/curveAnalyse/panel.vue
  28. 51 0
      src/components/excel.vue
  29. 171 0
      src/components/headerNav/index.vue
  30. 12 0
      src/components/inlayMenu/index.vue
  31. 98 0
      src/components/menuNav/index.vue
  32. 11 0
      src/components/submitBtn.vue
  33. 184 0
      src/components/tree.vue
  34. 10 0
      src/data/areaData.json
  35. 1 0
      src/data/dot.json
  36. 33 0
      src/data/flower.json
  37. 14211 0
      src/data/lineNew.json
  38. 1513 0
      src/data/table.json
  39. 16830 0
      src/element-theme/index-white.scss
  40. 16884 0
      src/element-theme/index.scss
  41. 1 0
      src/helper/README.md
  42. 9 0
      src/helper/data.js
  43. 26 0
      src/helper/partten.js
  44. 28 0
      src/helper/util.js
  45. 69 0
      src/main.js
  46. 32 0
      src/registerServiceWorker.js
  47. 399 0
      src/router/index.js
  48. 23 0
      src/store/index.js
  49. 279 0
      src/tools/basicTool.js
  50. 12 0
      src/tools/excel/exportExcel.js
  51. 36 0
      src/tools/export-word.js
  52. 101 0
      src/tools/htmlToPdf.js
  53. 16 0
      src/tools/js-xlsx.js
  54. 26 0
      src/tools/partten.js
  55. 27 0
      src/tools/util.js
  56. 47 0
      src/utils/auth.js
  57. 70 0
      src/utils/downXlsx.js
  58. 70 0
      src/utils/request.js
  59. 55 0
      src/views/Home/components/instrumentCom.vue
  60. 49 0
      src/views/Home/components/mapDetial.vue
  61. 220 0
      src/views/Home/components/powerEcharts.vue
  62. 496 0
      src/views/Home/components/safeEcoPower.vue
  63. 705 0
      src/views/Home/components/sdMap.vue
  64. 201 0
      src/views/Home/components/windChartCom.vue
  65. 230 0
      src/views/Home/components/windLightDetial.vue
  66. 675 0
      src/views/Home/components/windSpeedCom.vue
  67. 110 0
      src/views/Home/components/windlightSimple.vue
  68. 230 0
      src/views/Home/index.vue
  69. 393 0
      src/views/curveDeviation/rateAnalysis/chartTheme.json
  70. 114 0
      src/views/curveDeviation/rateAnalysis/components/chart.vue
  71. 126 0
      src/views/curveDeviation/rateAnalysis/components/lineChart.vue
  72. 117 0
      src/views/curveDeviation/rateAnalysis/components/scatterSingleChart.vue
  73. 29 0
      src/views/curveDeviation/rateAnalysis/components/search.vue
  74. 449 0
      src/views/curveDeviation/rateAnalysis/index.vue
  75. 398 0
      src/views/dataFilter/chartTheme.json
  76. 321 0
      src/views/dataFilter/combine/components/current-scatter-chart.vue
  77. 53 0
      src/views/dataFilter/combine/components/search.vue
  78. 52 0
      src/views/dataFilter/combine/components/table.vue
  79. 537 0
      src/views/dataFilter/combine/index.vue
  80. 321 0
      src/views/dataFilter/lineAnalysis/components/current-scatter-chart.vue
  81. 53 0
      src/views/dataFilter/lineAnalysis/components/search.vue
  82. 52 0
      src/views/dataFilter/lineAnalysis/components/table.vue
  83. 537 0
      src/views/dataFilter/lineAnalysis/index.vue
  84. 102 0
      src/views/dataFilter/prepare/components/search.vue
  85. 53 0
      src/views/dataFilter/prepare/components/table.vue
  86. 153 0
      src/views/dataFilter/prepare/index.vue
  87. 61 0
      src/views/dataFilter/process/components/search.vue
  88. 53 0
      src/views/dataFilter/process/components/table.vue
  89. 199 0
      src/views/dataFilter/process/index.vue
  90. 13 0
      src/views/economicsOperation/benchmarkingManagement/companyBenchmarking/index.vue
  91. 291 0
      src/views/economicsOperation/benchmarkingManagement/compontent/bar-line-chart.vue
  92. 255 0
      src/views/economicsOperation/benchmarkingManagement/compontent/dayinfo.vue
  93. 15 0
      src/views/economicsOperation/benchmarkingManagement/index.vue
  94. 746 0
      src/views/economicsOperation/benchmarkingManagement/intervalBenchmarking/index.vue
  95. 13 0
      src/views/economicsOperation/benchmarkingManagement/loseRate/index.vue
  96. 490 0
      src/views/economicsOperation/benchmarkingManagement/performanceRankingList/decision1Mx.vue
  97. 477 0
      src/views/economicsOperation/benchmarkingManagement/performanceRankingList/index.vue
  98. 767 0
      src/views/economicsOperation/benchmarkingManagement/projectBenchmarking/index.vue
  99. 747 0
      src/views/economicsOperation/benchmarkingManagement/siteBenchmarking/index.vue
  100. 0 0
      src/views/economicsOperation/benchmarkingManagement/standAloneBenchmarking/index.vue

+ 1 - 3
.gitignore

@@ -23,6 +23,4 @@ pnpm-debug.log*
 *.sw?
 
 #Electron-builder output
-/dist_electron
-
-/src/**/*
+/dist_electron

+ 220 - 0
src/App.vue

@@ -0,0 +1,220 @@
+<template>
+  <!-- <el-header v-if="showHeader === 'block'">
+    <ul class="header">
+      <p class="header_logo">
+        <img src="img/logo-main.png" alt="" srcset="" style="width: 163px;height: 40px">
+        <span>|</span>
+        新能源区域集控运行管理系统
+      </p>
+      <router-link v-for="(item, index) in firstLevelTitle" :to="item.path" :key="index">
+        <li class="header_right_title" @click="headerCheck(index)" :class="{ active: headerIndex === index }">
+          {{ item.titleName }}
+        </li>
+      </router-link>
+      <li class="bell_ic">
+        <i class="icon-bell"></i>
+      </li>
+      <li class="account_ic">
+        <i class="icon-account"></i>
+        <span class="tit">admin</span>
+        <span class="form"></span>
+      </li>
+    </ul>
+  </el-header>
+  <canves-map class="canves_map" v-if="showHeader === 'none'" /> -->
+  <div @mousemove="funMove">
+    <router-view />
+  </div>
+</template>
+<script setup>
+const funMove = () => {
+  window.postMessage(event.clientX, '*')
+}
+// import CanvesMap from "@/components/canvesMap/index";
+// export default {
+//   name: 'homePage',
+//   data() {
+//     return {
+//       showHeader: "block",
+//       firstLevelTitle: [
+//         { titleName: '首页', path: '/' },
+//         { titleName: '安全监控', path: '/stateMonitor' },
+//         { titleName: '经济运行', path: '/economicsOperation' }],
+//       headerIndex: 0,
+//     };
+//   },
+//   components: {
+//     CanvesMap,
+//   },
+//   created() {
+//   },
+//   methods: {
+//     headerCheck(index) {
+//       this.headerIndex = index
+//     }
+
+//   },
+//   mounted() {
+//     setTimeout(() => {
+//       this.showHeader = "block"
+//     }, 3500)
+
+//   }
+// }
+</script>
+<style lang="less">
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+  width: 200px;
+  min-height: 400px;
+}
+
+@import "../public/css/base.css";
+@import "../public/css/style.css";
+@import "../public/css/common.css";
+
+@keyframes canves_map {
+  0% {
+    opacity: 1
+  }
+
+  75% {
+    opacity: 1
+  }
+
+  100% {
+    opacity: 0
+  }
+
+}
+
+.canves_map {
+  animation: canves_map 3.5s linear;
+}
+
+.el-header {
+  height: 59px;
+  width: 100%;
+  line-height: 59px;
+  background: rgba(4, 11, 23, .3);
+  z-index: 9;
+  border-bottom: 1px solid;
+  border-image: -webkit-linear-gradient(10deg, transparent, rgba(26, 124, 205, 0), rgba(26, 124, 205, 1)) 2 1;
+  border-image: -moz-linear-gradient(10deg, transparent, rgba(26, 124, 205, 0), rgba(26, 124, 205, 1)) 2 1;
+  border-image: -o-linear-gradient(10deg, transparent, rgba(26, 124, 205, 0), rgba(26, 124, 205, 1)) 2 1;
+  border-image: linear-gradient(10deg, transparent, rgba(26, 124, 205, 0), rgba(26, 124, 205, 1)) 2 1;
+
+  .header {
+    display: flex;
+    width: 100%;
+    justify-content: flex-end;
+    margin-left: 15px;
+
+    .active {
+      color: #1C98FE;
+      background: url(/img/header/check.png);
+    }
+
+    .header_logo {
+      color: #ffffff;
+      font-size: 22px;
+      font-weight: bold;
+      display: flex;
+      align-items: cneter;
+
+      span {
+        margin: 0 10px;
+        font-weight: normal;
+      }
+    }
+
+    p {
+      position: absolute;
+      left: 30px
+    }
+
+    li {
+      text-align: center;
+      line-height: 32px;
+      margin-top: 15px;
+      width: 109px;
+      height: 32px;
+      font-size: 14px;
+      font-weight: 400;
+      color: #B3B3B3;
+      margin-right: 10px;
+
+      span {
+        color: rgba(28, 153, 255, 1);
+        font-size: 14px;
+      }
+
+      i {
+        font-size: 19px;
+        color: rgba(28, 153, 255, 1)
+      }
+
+      .icon-account {
+        //margin-left: 49px;
+        margin-right: 8px;
+      }
+
+      .form {
+        width: 0;
+        height: 0;
+        border: 5px solid transparent;
+        border-bottom: none;
+        border-top-color: rgba(28, 153, 255, 1);
+        position: relative;
+        top: 9px;
+        left: 8px;
+
+      }
+
+      &:hover {
+        color: #1C98FE;
+        background: url(/img/header/check.png);
+      }
+    }
+
+    .account_ic {
+      position: relative;
+      top: 3px;
+
+      &:hover {
+        color: #1C98FE;
+        background: none;
+
+      }
+    }
+
+    .tit {
+      position: relative;
+      top: -4px;
+      left: -5px
+    }
+
+    .bell_ic {
+      width: 20px;
+      top: 3px;
+      position: relative;
+
+      &:hover {
+        color: #1C98FE;
+        background: none;
+      }
+
+      > ::after {
+        content: '';
+        position: absolute;
+        top: 8px;
+        right: 5px;
+        width: 5px;
+        height: 5px;
+        background: #E95447;
+        border-radius: 50%;
+      }
+
+    }
+  }
+}
+</style>

+ 25 - 0
src/api/agcAbout.js

@@ -0,0 +1,25 @@
+import request from '@/utils/request'
+
+// 获取电场卡片列表
+export function GetElectricFieldCards(data){
+    return request({
+        url: `/assets/GetSubstationListGroupByCompayCode`,
+        method: 'post',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+          },
+        data,
+        
+    })
+}
+// 每3秒获取实时数据
+
+export function GetRealData(data){
+    return request({
+        url: `/realTime/GetRtValuesByTagName`,
+        method: 'post',
+        data: {
+            tagName: data,
+        },
+    })
+}

+ 18 - 0
src/api/curveAnalyse.js

@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+//公司
+export function companys() {
+    return request({
+        url: `/benchmarking/companys`,
+        method: 'get',
+    })
+}
+
+//专题分析-MTBF分析  "124.70.75.91:6060/specific/mtbfList?companys=SD_SXNY_ZGS&type=-1&year=2022",
+export function mtbfList(data) {
+    return request({
+        url: `/specific/mtbfList?companys=${data.companys}&type=${data.type}&year=${data.year}`,
+        method: 'get',
+    })
+}
+

+ 12 - 0
src/api/economy.js

@@ -0,0 +1,12 @@
+import request from "@/utils/request";
+
+//获取
+const homePage = (data) => {
+    return request({
+        url: `/economy/home-page?regionId=${data.regionId}&staType=${data.staType}&dateType=${data.dateType}&pointCode=${data.pointCode}&foreignKeyId=${data.foreignKeyId}&companyId=${data.companyId}`,
+        method: 'get',
+    })
+}
+export default {
+    homePage
+}

+ 9 - 0
src/api/factoryMonitor.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+//根据场站编码获取table数据
+export function GetCompanyEquipmentsIndicator(data) {
+    return request({
+        url: `/assets/GetPowerStationDataTagList?powerStationCode=${data.powerStationCode}&uniformCode=${data.uniformCode}`,
+        method: 'get',
+    })
+}

+ 68 - 0
src/api/home.js

@@ -0,0 +1,68 @@
+import request from '@/utils/request'
+
+// 获取区域和子公司
+export function getOrganization() {
+    return request({
+        url: '/assets/GetCompanyList',
+        method: 'GET'
+    })
+}
+
+// 根据公司查询资产
+export function GetComoanyAssets(data) {
+    return request({
+        url: `/assets/GetComoanyAssets?companyCode=${data.companyCode}&type=${data.type}`,
+        method: 'get',
+    })
+}
+
+//获取实时指标数据
+export function GetRealTimeValues(data) {
+    return request({
+        url: `/realTime/GetRealTimeValues?companyCode=${data.companyCode}&uniformCode=${data.uniformCode}`,
+        method: 'get',
+    })
+}
+//获取计算数据
+export function GetCalcValues(data) {
+    return request({
+        url: `/realTime/GetCalcValues?companyCode=${data.companyCode}&uniformCode=${data.uniformCode}`,
+        method: 'get',
+    })
+}
+
+// 获取实时发电量
+export function GetPlanValues(data) {
+    return request({
+        url: `/assets/GetFDLPlanValues?companyCode=${data.companyCode}&planDate=${data.planDate}`,
+        method: 'get',
+    })
+}
+//获取设备状态
+export function GetRealTimeStaValues(data) {
+    return request({
+        url: `/realTime/GetRealTimeValuesAll?companyCode=${data.companyCode}`,
+        method: 'get',
+    })
+}
+//获取曲线数据
+export function GetCurveValues(data) {
+    return request({
+        url: `/realTime/GetCurveValues?companyCode=${data.companyCode}&uniformCode=${data.uniformCode}&intervalTime=${data.intervalTime}`,
+        method: 'get',
+    })
+}
+// 获取地图电场编号
+export function GetPowerStation(data) {
+    return request({
+        url: `/assets/GetPowerStation?companyCode=${data.companyCode}&stationType=${data.stationType}`,
+        method: 'get',
+    })
+}
+//根据场站编码获取资产信息
+export function GetPowerStationAssets(data) {
+    return request({
+        url: `/assets/GetPowerStationAssets?stationCode=${data.stationCode}`,
+        method: 'get',
+    })
+}

+ 191 - 0
src/api/monthlyPerformanceAnalysis.js

@@ -0,0 +1,191 @@
+import request from '@/utils/request'
+
+// 获取公司列表
+export function getApicompanyslist(params) {
+    return request({
+        url: '/benchmarking/companys',
+        method: 'GET'
+    })
+}
+// 获取场站列表
+export function getApiwpByCplistlist(params) {
+    return request({
+        url: `/benchmarking/wpByCplist?companyids=${params.companyid}`,
+        method: 'GET'
+    })
+}
+// 获取单机性能总览------列表
+export function getApiwindturbinegoodnesslist(params) {
+    return request({
+        url: '/goodness/windturbinegoodness',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}
+// 获取单机性能总览------历史列表
+export function getApihistorywindturbinegoodnesslist(params) {
+    return request({
+        url: '/goodness/goodhistorylist',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}
+// 获取单机性能详情------查询功率曲线数据信息
+export function getApifindWtRealPowerChar(params) {
+    return request({
+        url: `/goodness/findWtRealPowerChar?recorddate=${params.recorddate}&wtId=${params.wtId}`,
+        method: 'GET'
+    })
+}
+// 获取单机性能详情------获得曲线区间区分功能数据
+export function getApigetplotBands(params) {
+    return request({
+        url: `/goodness/getplotBands?recorddate=${params.recorddate}&wtId=${params.wtId}`,
+        method: 'GET'
+    })
+}
+// 获取单机性能详情------获取区域弹出列表信息
+export function getApiplotBandAjax(params) {
+    return request({
+        url: `/goodness/plotBandAjax?beginDate=${params.beginDate}&endDate=${params.endDate}&wtId=${params.wtId}`,
+        method: 'GET'
+    })
+}
+// 获取单机性能详情------获取24小时功率曲线
+export function getApifindRealPowerCharBy24(params) {
+    return request({
+        url: `/goodness/findRealPowerCharBy24?recorddate=${params.recorddate}&wtId=${params.wtId}`,
+        method: 'GET'
+    })
+}
+// 获取单机性能详情------单台风机当日报警记录
+export function getApibjjllist(params) {
+    return request({
+        url: '/goodness/bjjllist',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}
+// 获取单机性能详情------单台风机当日故障停机记录
+export function getApigzjllist(params) {
+    return request({
+        url: '/goodness/gzjllist',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}
+// 获取单机性能详情------单台风机当日限电记录
+export function getApixdjllist(params) {
+    return request({
+        url: '/goodness/xdjllist',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}
+// 获取单机性能详情------查询明细页面显示信息
+export function getApiwadAjax(params) {
+    return request({
+        url: `/goodness/wadAjax?recorddate=${params.recorddate}&wtId=${params.wtId}`,
+        method: 'GET'
+    })
+}
+// 获取单机性能详情------单台风机当月报警排行
+export function getApibjphlist(params) {
+    return request({
+        url: '/goodness/bjphlist',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}
+// 获取单机性能详情------获取明细页面功率曲线
+export function getApiglchat(params) {
+    return request({
+        url: `/goodness/glchat?recorddate=${params.recorddate}&wtId=${params.wtId}`,
+        method: 'GET'
+    })
+}
+// 获取单机性能详情------获取风机风资源
+export function getApifjfzy(params) {
+    return request({
+        url: `/goodness/fjfzy?recorddate=${params.recorddate}&wtId=${params.wtId}`,
+        method: 'GET'
+    })
+}
+
+
+
+
+
+
+
+
+
+// 获取单机月度分析数据------列表
+export function getApisingleanalysisMainlist(params) {
+    return request({
+        url: '/singleanalysis/singleanalysisMain',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}
+// 获取单机月度分析数据------查询单机性能分析子页面
+export function getApisingleanalysisSub(params) {
+    return request({
+        url: '/singleanalysis/singleanalysisSub',
+        method: 'GET',
+        params
+    })
+}
+// 单机信息总览图表接口(3个) 发电量和风速、五项损失、静风频率和待机时间
+export function getApisingleanalysisChart(params) {
+    return request({
+        url: '/singleanalysis/singleanalysisChart',
+        method: 'GET',
+        params
+    })
+}
+
+
+// 获取切入切出管理------列表
+export function getApioutputSpeedlist(params) {
+    return request({
+        url: '/outputspeed/outputSpeedlist',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}
+// 获取切入切出管理------历史列表
+export function getApioutputSpeedhistorylist(params) {
+    return request({
+        url: '/outputspeed/outputspeedhistorylist',
+        method: 'POST',
+        headers:{
+            'content-type':'application/x-www-form-urlencoded' // FormData格式传参
+        },
+        params
+    })
+}

+ 81 - 0
src/api/performance.js

@@ -0,0 +1,81 @@
+import request from '@/utils/request'
+
+//获取场站
+export function getStation(data) {
+    return request({
+        url: `/benchmarking/wpByCplist?companyids=${data.companyids}`,
+        method: 'get',
+    })
+}
+
+//获取项目
+export function getProject(data) {
+    return request({
+        url: `/benchmarking/pjByWplist?wpids=${data.wpids}`,
+        method: 'get',
+    })
+}
+
+//获取线路
+export function getLine(data) {
+    return request({
+        url: `/benchmarking/lnByPjlist?pjids=${data.pjids}`,
+        method: 'get',
+    })
+}
+
+//风机绩效榜
+export function performance(data) {
+    return request({
+        url: `/benchmarking/performance?companyid=${data.companyid}&getype=${data.getype}&sttype=${data.sttype}&beginDate=${data.beginDate}&endDate=${data.endDate}&wpids=${data.wpids}&projectids=${data.projectids}&lineids=${data.lineids}`,
+        method: 'get',
+    })
+}
+
+//风机绩效榜明细
+export function performanceMX(data) {
+    return request({
+        url: `/benchmarking/performanceMX?companyid=${data.companyid}&getype=${data.getype}&sttype=${data.sttype}&beginDate=${data.beginDate}&endDate=${data.endDate}&wpids=${data.wpids}&projectids=${data.projectids}&lineids=${data.lineids}`,
+        method: 'get',
+    })
+}
+
+//场际对标
+export function cjdb(data) {
+    return request({
+        url: `/benchmarking/cjdb?companys=${data.companys}&type=${data.type}&wpids=${data.wpids}&beginDate=${data.beginDate}&endDate=${data.endDate}&target=${data.target}&sort=${data.sort}`,
+        method: 'get',
+    })
+}
+
+//对标详情
+export function details(data) {
+    return request({
+        url: `/benchmarking/details?id=${data.id}&beginDate=${data.beginDate}&endDate=${data.endDate}&target=${data.target}&sort=${data.sort}`,
+        method: 'get',
+    })
+}
+
+//场际对标
+export function cndb(data) {
+    return request({
+        url: `/benchmarking/cndb?companys=${data.companys}&type=${data.type}&wpid=${data.wpids}&beginDate=${data.beginDate}&endDate=${data.endDate}&target=${data.target}&sort=${data.sort}`,
+        method: 'get',
+    })
+}
+
+//项目对标
+export function xmdb(data) {
+    return request({
+        url: `/benchmarking/xmdb?companys=${data.companys}&type=${data.type}&wpids=${data.wpids}&projectids=${data.projectids}&beginDate=${data.beginDate}&endDate=${data.endDate}&target=${data.target}&sort=${data.sort}`,
+        method: 'get',
+    })
+}
+
+//线路对标
+export function xldb(data) {
+    return request({
+        url: `/benchmarking/xldb?companys=${data.companys}&type=${data.type}&wpids=${data.wpids}&projectids=${data.projectids}&lineids=${data.lineids}&beginDate=${data.beginDate}&endDate=${data.endDate}&target=${data.target}&sort=${data.sort}`,
+        method: 'get',
+    })
+}

+ 28 - 0
src/api/stateMonitor.js

@@ -0,0 +1,28 @@
+import request from "@/utils/request";
+
+//获取
+export function GetEquipmentListGroupByPowerStation(data) {
+    return request({
+        url: `/assets/GetEquipmentListGroupByPowerStation?companyCode=${data.companyCode}&stationType=${data.stationType}`,
+        method: 'get',
+    })
+}
+
+//获取设备台数数量
+export function GetRtValuesByTagName(data1) {
+    return request({
+        url: '/realTime/GetRtValuesByTagName',
+        data: {
+            tagName: data1,
+        },
+        method: 'post',
+    })
+}
+
+//获取明细矩阵测点
+export function GetEquipmentListDetailsByPowerStation(data) {
+    return request({
+        url: `/assets/GetEquipmentListDetailsByPowerStation?companyCode=${data.companyCode}&stationType=${data.stationType}`,
+        method: 'get',
+    })
+}

二進制
src/assets/img/title_bg.png


二進制
src/assets/img/title_left_bg.png


二進制
src/assets/img/title_right_bg.png


+ 1 - 0
src/assets/style/main.less

@@ -0,0 +1 @@
+@import "./table.less";

+ 78 - 0
src/assets/style/table.less

@@ -0,0 +1,78 @@
+// 自定义table
+@titleGray: #9ca5a8;
+@rowGray: #606769;
+@darkBack: #536268;
+@fontsize-s: 1.296vh;
+@green: #05bb4c;
+@yellow: #f8de5b;
+@blue: #597ef7;
+
+.com-table {
+    width: 100%;
+    border-collapse: collapse;
+
+    thead {
+        tr {
+            display: table;
+            table-layout: fixed;
+            width: 100%;
+
+            th {
+                background-color: fade(@darkBack, 20%);
+                height: 30px;
+                line-height: 30px;
+                color: @titleGray;
+                font-weight: 400;
+                font-size: @fontsize-s;
+                position: sticky;
+                top: 0;
+                cursor: pointer;
+
+                &.light,
+                &.always-light {
+                    color: @green;
+                }
+            }
+        }
+    }
+
+    tbody {
+        display: block;
+
+        tr {
+            display: table;
+            table-layout: fixed;
+            width: 100%;
+
+            &:nth-child(2n) {
+                background-color: fade(@rowGray, 20%);
+            }
+
+            td {
+                padding: 4px;
+                color: @rowGray;
+                text-align: center;
+                font-size: @fontsize-s;
+                white-space: nowrap;
+                overflow: hidden;
+                text-overflow: ellipsis;
+
+                &>span {
+                    white-space: nowrap;
+                    overflow: hidden;
+                    text-overflow: ellipsis;
+                }
+
+                &.light,
+                &.always-light {
+                    color: @green !important;
+                }
+
+                &.num {
+                    font-family: "Bicubik";
+                    font-weight: 400;
+                }
+            }
+        }
+    }
+}

+ 86 - 0
src/background.js

@@ -0,0 +1,86 @@
+'use strict'
+
+import { app, protocol, BrowserWindow } from 'electron'
+import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
+import installExtension, { VUEJS3_DEVTOOLS } from 'electron-devtools-installer'
+const isDevelopment = process.env.NODE_ENV !== 'production'
+
+// Scheme must be registered before the app is ready
+protocol.registerSchemesAsPrivileged([
+  { scheme: 'app', privileges: { secure: true, standard: true } }
+])
+
+async function createWindow() {
+  // Create the browser window.
+  const win = new BrowserWindow({
+    width: 800,
+    height: 600,
+    frame:false,
+    fullscreen:true,
+    webPreferences: {
+      
+      // Use pluginOptions.nodeIntegration, leave this alone
+      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
+      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
+      contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
+      nodeIntegration: true,
+      contextIsolation: false,
+      enableRemoteModule: true,   // 打开remote模块
+    }
+  })
+
+  if (process.env.WEBPACK_DEV_SERVER_URL) {
+    // Load the url of the dev server if in development mode
+    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
+    if (!process.env.IS_TEST) win.webContents.openDevTools()
+  } else {
+    createProtocol('app')
+    // Load the index.html when not in development
+    win.loadURL('app://./index.html')
+  }
+}
+
+// Quit when all windows are closed.
+app.on('window-all-closed', () => {
+  // On macOS it is common for applications and their menu bar
+  // to stay active until the user quits explicitly with Cmd + Q
+  if (process.platform !== 'darwin') {
+    app.quit()
+  }
+})
+
+app.on('activate', () => {
+  // On macOS it's common to re-create a window in the app when the
+  // dock icon is clicked and there are no other windows open.
+  if (BrowserWindow.getAllWindows().length === 0) createWindow()
+})
+
+// This method will be called when Electron has finished
+// initialization and is ready to create browser windows.
+// Some APIs can only be used after this event occurs.
+app.on('ready', async () => {
+  if (isDevelopment && !process.env.IS_TEST) {
+    // Install Vue Devtools
+    try {
+      await installExtension(VUEJS3_DEVTOOLS)
+    } catch (e) {
+      console.error('Vue Devtools failed to install:', e.toString())
+    }
+  }
+  createWindow()
+})
+
+// Exit cleanly on request from parent process in development mode.
+if (isDevelopment) {
+  if (process.platform === 'win32') {
+    process.on('message', (data) => {
+      if (data === 'graceful-exit') {
+        app.quit()
+      }
+    })
+  } else {
+    process.on('SIGTERM', () => {
+      app.quit()
+    })
+  }
+}

+ 166 - 0
src/components/canvesMap/index.vue

@@ -0,0 +1,166 @@
+<template>
+    <div class="svg-map-nx">
+        <p class="header_logo">
+            <img src="img/logo-main.png" alt="" srcset="" style="width: 163px;height: 40px">
+            <span>|</span>
+            新能源区域集控运行管理系统
+        </p>
+        <svg
+                version="1.1"
+                xmlns="http://www.w3.org/2000/svg"
+                xmlns:xlink="http://www.w3.org/1999/xlink"
+                x="50%"
+                y="50%"
+                viewBox="40 60 660 490"
+                xml:space="preserve"
+
+
+        >
+                <g>
+        <image
+                style="overflow: visible"
+                width="890"
+                height="400"
+                xlink:href="img/images/map.png"
+                transform="matrix(1 0 0 1 -113 60.6679)"
+        />
+                    <image
+                            @mouseenter="bacNone"
+                            @mouseleave="bacNones"
+                            width="67"
+                            x="84.7%"
+                            y="34.4%"
+                            id="map-main"
+                            xlink:href="img/images/shandong.png"
+                            transform="matrix(1 0 0 1 -113 60.6679)"
+                    />
+                    <image
+                            width="33"
+                            x="84%"
+                            y="25%"
+                            id="map-main"
+                            xlink:href="img/images/sis.png"
+                            transform="matrix(1 0 0 1 -113 60.6679)"
+                    />
+                    <image
+                            width="33"
+                            x="82.3%"
+                            y="29%"
+                            id="map-main"
+                            xlink:href="img/images/beijing.png"
+                            transform="matrix(1 0 0 1 -113 60.6679)"
+                    />
+                </g>
+            <path
+                    d="m-3.322,40.05304c0,0 19.44135,-9.38001 19.00932,40.93096" transform="matrix(1 0 0 1 460 170)"
+                    stroke='#FF8300' stroke-width='.7px' stroke-dasharray='3 2 ' fill='none'></path>
+
+            <g>
+               <circle cx="476.5" cy="255" r="2" fill="#ffffff"/>
+                <circle cx="476.5" cy="255" r="3.5" style="fill:none; stroke:#FEC448; stroke-width:.5;"/>
+                <circle cx="476.5" cy="255" r="6" style="fill:none; stroke:#FEC448; stroke-width:.3;">
+                <animate
+                        attributeType="XML"
+                        attributeName="r"
+                        values="6;7;7.5;7;6"
+                        dur="2s"
+                        repeatCount="indefinite"
+                />
+            </circle>
+           </g>
+            <g class="ceshi">
+                    <image
+                            style="overflow: visible"
+                            width="23"
+                            height="30"
+                            x="68.4%"
+                            y="42.3%"
+                            id="map-main"
+                            xlink:href="img/images/ray.png"
+                    />
+                        </g>
+      </svg>
+        <img class="island_chart" src="img/home/island_chart.png"/>
+    </div>
+</template>
+
+
+<script>
+    export default {
+        name: 'canvesMap',//厂站监视
+        data() {
+            return {}
+
+        },
+        methods: {},
+
+    }
+</script>
+
+<style lang="less" scoped>
+  .header_logo {
+    color: #ffffff;
+    font-size: 22px;
+    font-weight: bold;
+    left: 30px;
+    top: 15px;
+    position: fixed;
+
+    span {
+      margin: 0 10px;
+      font-weight: normal;
+    }
+  }
+
+  .svg-map-nx {
+    width: 80%;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    margin: auto;
+  }
+
+  .ceshi {
+    transform-origin: 68.9% 44.7%;
+    transform: rotate(-104deg);
+    width: 50px;
+    height: 50px;
+    top: 20px;
+    left: 20px;
+    background: #1a7ccd;
+    animation: nxMapUpCircle 3s linear forwards;
+  }
+
+  @keyframes nxMapUpCircle {
+    0% {
+      transform-origin: 68.9% 44.7%;
+      transform: rotate(-104deg);
+    }
+    25% {
+      transform-origin: 68.9% 44.8%;
+      transform: translate(4px, -2px) rotate(-103deg);
+    }
+
+    50% {
+      transform-origin: 68.9% 44.8%;
+      transform: translate(8px, -2px) rotate(-18deg)
+    }
+
+    75% {
+      transform: translate(13px, 25px) rotate(-2deg);
+    }
+
+    100% {
+      transform: translate(13px, 25px) rotate(-2deg)
+    }
+  }
+
+  .island_chart {
+    position: absolute;
+    bottom: -20px;
+    right: 166px;
+  }
+
+
+</style>

+ 476 - 0
src/components/chart/combination/area-line-chart.vue

@@ -0,0 +1,476 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/helper/util.js";
+import partten from "@/helper/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "multiple-bar-chart",
+  componentName: "multiple-bar-chart",
+  props: {
+    width: {
+      type: String,
+      default: "100%",
+    },
+    height: {
+      type: String,
+      default: "800px",
+    },
+    lineData: {
+      type: Array,
+      default: () => [
+        {
+          text: "日发电量",
+          value: [
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "2",
+              value: 2,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+            {
+              text: "4",
+              value: 3,
+            },
+            {
+              text: "5",
+              value: 3,
+            },
+            {
+              text: "6",
+              value: 3,
+            },
+            {
+              text: "7",
+              value: 3,
+            },
+            {
+              text: "8",
+              value: 3,
+            },
+            {
+              text: "9",
+              value: 3,
+            },
+            {
+              text: "10",
+              value: 3,
+            },
+            {
+              text: "11",
+              value: 3,
+            },
+            {
+              text: "12",
+              value: 3,
+            },
+            {
+              text: "13",
+              value: 3,
+            },
+            {
+              text: "14",
+              value: 3,
+            },
+            {
+              text: "15",
+              value: 3,
+            },
+            {
+              text: "16",
+              value: 3,
+            },
+          ],
+        },
+        {
+          text: "上网电量",
+          value: [
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "2",
+              value: 2,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+            {
+              text: "4",
+              value: 3,
+            },
+            {
+              text: "5",
+              value: 4,
+            },
+            {
+              text: "6",
+              value: 5,
+            },
+            {
+              text: "7",
+              value: 6,
+            },
+            {
+              text: "8",
+              value: 7,
+            },
+            {
+              text: "9",
+              value: 8,
+            },
+            {
+              text: "10",
+              value: 7,
+            },
+            {
+              text: "11",
+              value: 9,
+            },
+            {
+              text: "12",
+              value: 2,
+            },
+            {
+              text: "13",
+              value: 3,
+            },
+            {
+              text: "14",
+              value: 5,
+            },
+            {
+              text: "15",
+              value: 12,
+            },
+            {
+              text: "16",
+              value: 11,
+            },
+          ],
+        },
+      ],
+    },
+    areaData: {
+      type: Array,
+      default: () => [
+        {
+          name: "1",
+          start: 0,
+          end: 100,
+          state: "green",
+        },
+        {
+          name: "1",
+          start: 100,
+          end: 200,
+          state: "red",
+        },
+        {
+          name: "1",
+          start: 200,
+          end: 300,
+          state: "yellow",
+        },
+        {
+          name: "2",
+          start: 300,
+          end: 800,
+          state: "green",
+        },
+        {
+          name: "3",
+          start: 800,
+          end: 9000,
+          state: "green",
+        },
+      ],
+    },
+    // 单位
+    units: {
+      type: Array,
+      default: () => ["健康趋势", "风机健康状态数量"],
+    },
+    // 显示 legend
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 颜色
+    color: {
+      type: Array,
+      default: () => ["#323E6F", "#1DA0D7", "#02BB4C", "#DB5520", "#EDB32F", "#EDEB2F"],
+    },
+  },
+  data () {
+    return {
+      id: "",
+      chart: null,
+    };
+  },
+  computed: {
+    legend () {
+      let data = [];
+      this.lineData.forEach((value, index) => {
+        data.push(value.text);
+      });
+      return data;
+    },
+    xAxisData () {
+      let data = [];
+      if (this.lineData.length > 0)
+        this.lineData[0].value.forEach((value, index) => {
+          data.push(value.text);
+        });
+      return data;
+    },
+    areaChartData () {
+      let data = [];
+      for (var i = 0; i < this.areaData.length; i++) {
+        let item = this.areaData[i];
+        var color = item.color || item.state;
+        data.push({
+          name: item.name,
+          value: [item.start, item.end, item.end - item.start],
+          itemStyle: {
+            normal: {
+              color: color,
+            },
+          },
+          exData: item,
+        });
+      }
+      return data;
+    },
+    areaMax () {
+      let max = 0;
+      this.areaData.forEach((value) => {
+        if (max < value.end) max = value.end;
+      });
+      return max;
+    },
+  },
+  methods: {
+    renderItem (params, api) {
+      var start = api.coord([api.value(0)]);
+      var end = api.coord([api.value(1)]);
+      var height = api.size([0, 1])[1];
+
+      var rectShape = echarts.graphic.clipRectByRect(
+        {
+          x: start[0],
+          y: start[1] - height / 2,
+          width: end[0] - start[0],
+          height: height,
+        },
+        {
+          x: params.coordSys.x,
+          y: params.coordSys.y,
+          width: params.coordSys.width,
+          height: params.coordSys.height,
+        }
+      );
+
+      return (
+        rectShape && {
+          type: "rect",
+          transition: ["shape"],
+          shape: rectShape,
+          style: api.style(),
+        }
+      );
+    },
+    initChart () {
+      let that = this;
+      let chart = echarts.init(this.$el);
+      let option = {
+        color: this.color,
+        grid: {
+          left: 40,
+          right: 40,
+          bottom: 10,
+          top: 32,
+          containLabel: true,
+        },
+        tooltip: {
+          show: true,
+          trigger: "axis",
+          axisPointer: {
+            type: "cross",
+          },
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            color: "#fff",
+            fontSize: 14,
+          },
+        },
+        legend: {
+          show: this.showLegend,
+          data: this.legend,
+          right: 120,
+          icon: "ract",
+          itemWidth: 8,
+          itemHeight: 8,
+          inactiveColor: partten.getColor("gray"),
+          textStyle: {
+            color: '#fff',
+            fontSize: 12,
+          },
+        },
+        xAxis: [
+          {
+            type: "category",
+            axisLabel: {
+              color: '#fff',
+            },
+            axisLine: {
+              show: false,
+            },
+            axisTick: {
+              show: false,
+            },
+            data: this.xAxisData,
+          },
+          {
+            show: false,
+            min: 0,
+            max: this.areaMax,
+            axisLabel: {
+              show: false,
+              formatter: function (val) {
+                return Math.max(0, val - 0) + " ms";
+              },
+            },
+          },
+        ],
+        yAxis: [
+          {
+            type: "value",
+            name: this.units[0],
+            axisLabel: {
+              formatter: "{value} ",
+              color: '#fff'
+            },
+            nameTextStyle: {
+                color: '#fff',
+            },
+            axisLine: {
+              type: "dashed",
+              lineStyle: {
+                color: partten.getColor("gray"),
+              },
+              width: 5,
+            },
+            axisTick: {
+              show: false,
+            },
+            splitLine: {
+              lineStyle: {
+                type: "dashed",
+                dashOffset: 10,
+                color: partten.getColor("gray") + 80,
+              },
+            },
+          },
+          {
+            data: this.areaData.length>0 ? [this.areaData[0].name] : '',
+            axisLabel: { show: false },
+          },
+        ],
+        series: [],
+      };
+
+      // line data
+      if (this.lineData.length > 0) {
+        this.lineData.forEach((value, index) => {
+          option.series.push({
+            name: value.text,
+            type: "line",
+            data: value.value,
+            smooth: true, //平滑展示
+            yAxisIndex: 0,
+            // lineStyle: {
+            //   color: partten.getColor("green"),
+            // },
+            // itemStyle: {
+            //   color: partten.getColor("green"),
+            // },
+          });
+        });
+      }
+
+      // 区域
+      if (this.areaData && this.areaData.length > 0) {
+        option.series.push({
+          type: "custom",
+          renderItem: this.renderItem,
+          yAxisIndex: 1,
+          xAxisIndex: 1,
+          itemStyle: {
+            opacity: 0.2,
+          },
+          tooltip: {
+            show: false,
+            formatter: function (params) {
+              return params.marker + params.name + ": " + params.value[2] + "s";
+            },
+          },
+          encode: {
+            x: [1, 2],
+            y: 0,
+          },
+          data: this.areaChartData,
+        });
+      }
+
+      chart.setOption(option);
+
+      return chart;
+    },
+  },
+  emits: {
+    areaClick: null,
+  },
+  created () {
+    this.id = "pie-chart-" + util.newGUID();
+  },
+  mounted () {
+    this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      let that = this;
+      let chart = this.initChart();
+      chart.on("click", function(e, p) {
+        if (e.seriesType == "custom") {
+          that.$emit("areaClick", { data: e.data.exData });
+        }
+      });
+    });
+  },
+  updated () {
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+};
+</script>
+
+<style lang="less">
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 447 - 0
src/components/chart/combination/multiple-bar-line-chart.vue

@@ -0,0 +1,447 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/helper/util.js";
+import partten from "@/helper/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "multiple-bar-chart",
+  componentName: "multiple-bar-chart",
+  props: {
+    width: {
+      type: String,
+      default: "100%",
+    },
+    height: {
+      type: String,
+      default: "13.889vh",
+    },
+    // 传入数据
+    newbarData: {
+      type: Array,
+      default: () => [
+        {
+          title: "日发电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1日",
+              value: 1,
+            },
+            {
+              text: "2日",
+              value: 2,
+            },
+            {
+              text: "3日",
+              value: 1,
+            },
+            {
+              text: "4日",
+              value: 3,
+            },
+            {
+              text: "5日",
+              value: 3,
+            },
+            {
+              text: "6日",
+              value: 3,
+            },
+            {
+              text: "7日",
+              value: 3,
+            },
+          ],
+        },
+        {
+          title: "上网电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1日",
+              value: 1,
+            },
+            {
+              text: "2日",
+              value: 2,
+            },
+            {
+              text: "3日",
+              value: 1,
+            },
+            {
+              text: "4日",
+              value: 3,
+            },
+            {
+              text: "5日",
+              value: 3,
+            },
+            {
+              text: "6日",
+              value: 3,
+            },
+            {
+              text: "7日",
+              value: 3,
+            },
+          ],
+        },
+        {
+          title: "购网电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1日",
+              value: 1,
+            },
+            {
+              text: "2日",
+              value: 2,
+            },
+            {
+              text: "3日",
+              value: 1,
+            },
+            {
+              text: "4日",
+              value: 3,
+            },
+            {
+              text: "5日",
+              value: 3,
+            },
+            {
+              text: "6日",
+              value: 3,
+            },
+            {
+              text: "7日",
+              value: 3,
+            },
+          ],
+        },
+        {
+          title: "风速",
+          yAxisIndex: 1,
+          value: [
+            {
+              text: "1日",
+              value: 1,
+            },
+            {
+              text: "2日",
+              value: 2,
+            },
+            {
+              text: "3日",
+              value: 1,
+            },
+            {
+              text: "4日",
+              value: 3,
+            },
+            {
+              text: "5日",
+              value: 3,
+            },
+            {
+              text: "6日",
+              value: 3,
+            },
+            {
+              text: "7日",
+              value: 3,
+            },
+          ],
+        },
+      ],
+    },
+    newlineData: {
+      type: Object,
+      default: () => {
+        return {
+          name: "风速",
+          unit: "km",
+          data: [200, 800, 400, 500, 800, 700, 800, 900, 200],
+        };
+      },
+    },
+    // 单位
+    units: {
+      type: Array,
+      default: () => ["(万KWh)", "(风速)"],
+    },
+    // 显示 legend
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 颜色
+    color: {
+      type: Array,
+      default: () => [
+        "#05bb4c",
+        "#4b55ae",
+        "#fa8c16",
+        "#f8de5b",
+        "#1a93cf",
+        "#c531c7",
+        "#bd3338",
+      ],
+    },
+    showAnimation: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      firstAnimation: true,
+    //   newbarData: null,
+    //   newlineData: null
+    };
+  },
+//   watch: {
+//     barData: {
+//       handler(newValue, oldValue) {
+//         this.newbarData = newValue;
+//         this.initChart();
+//       },
+//       deep: true,
+//     },
+//     lineData : {
+//       handler(newValue, oldValue) {
+//         this.newlineData = newValue;
+//         this.initChart();
+//       },
+//       deep: true,
+//     },
+//   },
+  computed: {
+    legend() {
+      return this.newbarData.map((t) => {
+        return t.title;
+      });
+    },
+    xdata() {
+      let result = [];
+      if (
+        this.newbarData &&
+        this.newbarData.length > 0 &&
+        this.newbarData[0].value.length > 0
+      ) {
+        result = this.newbarData[0].value.map((t) => {
+          return t.text;
+        });
+      }
+      return result;
+    },
+    ydata() {
+      let result = [];
+      this.units.forEach((value, index) => {
+        let data = null;
+        if (index == 0) {
+          data = {
+            type: "value",
+            name: value,
+            nameTextStyle: {
+                color: '#fff',
+            },
+            axisLabel: {
+              formatter: "{value} ",
+              color: '#fff',
+              fontSize: 12,
+            },
+            //分格线
+            splitLine: {
+              lineStyle: {
+                color: "#5a6162",
+                type: "dashed",
+              },
+            },
+          };
+        } else {
+          data = {
+            type: "value",
+            name: value,
+            nameTextStyle: {
+                color: '#fff',
+            },
+            axisLabel: {
+              formatter: "{value}",
+              color: '#fff',
+              fontSize: 12,
+            },
+            //分格线
+            splitLine: {
+              show: false,
+            },
+          };
+        }
+
+        result.push(data);
+      });
+
+      return result;
+    },
+    series() {
+      let result = [];
+      if (this.newbarData && this.newbarData.length > 0) {
+        this.newbarData.forEach((value, index) => {
+          result.push({
+            name: value.title,
+            type: "bar",
+            barWidth: "10%",
+            animation: this.firstAnimation && this.showAnimation,
+            yAxisIndex: value.yAxisIndex,
+            data: value.value.map((t) => {
+              return t.value;
+            }),
+          });
+        });
+      }
+      return result;
+    },
+  },
+  methods: {
+    resize() {},
+    initChart() {
+      let chart = echarts.init(this.$el);
+
+      let option = {
+        color: this.color,
+        tooltip: {
+          trigger: "axis",
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            color: "#fff",
+            fontSize: 12,
+          },
+        },
+        legend: {
+          show: this.showLegend,
+          data: this.legend,
+          right: 56,
+          icon: "ract",
+          itemWidth: 8,
+          itemHeight: 8,
+          inactiveColor: partten.getColor("gray"),
+          textStyle: {
+            color: '#fff',
+            fontSize: 12,
+          },
+        },
+        grid: {
+          top: 32,
+          left: 40,
+          right: this.ydata.length > 1 ? 40 : 14,
+          bottom: 24,
+        },
+        xAxis: [
+          {
+            type: "category",
+            data: this.xdata,
+            axisPointer: {
+              type: "shadow",
+            },
+            axisLabel: {
+                color: '#fff',
+                fontSize: 12,
+            },
+          },
+        ],
+        yAxis: this.ydata,
+        series: this.series,
+      };
+
+      // line data
+      if (this.newlineData && this.newlineData.data) {
+          if (this.newlineData.data.length > 0) {
+            option.yAxis.push({
+                type: "value",
+                name: this.newlineData.name,
+                nameTextStyle: {
+                    color: '#fff',
+                },
+                axisLabel: {
+                    formatter: "{value} ",
+                    color: '#fff'
+                },
+                axisLine: {
+                    show: false,
+                },
+                axisTick: {
+                    show: false,
+                },
+                splitLine: {
+                    show: false,
+                    lineStyle: {
+                    type: "dashed",
+                    dashOffset: 10,
+                    },
+                },
+            });
+            option.series.push({
+              name: this.newlineData.name,
+              type: "line",
+              data: this.newlineData.data,
+              smooth: true, //平滑展示
+              yAxisIndex: option.yAxis.length - 1,
+              lineStyle: {
+                color: partten.getColor("yellow"),
+              },
+              itemStyle: {
+                color: partten.getColor("yellow"),
+              },
+            });
+          }
+      }
+
+      chart.clear();
+      chart.setOption(option);
+
+      this.resize = function () {
+        chart.resize();
+      };
+
+      window.addEventListener("resize", this.resize);
+    },
+  },
+  created() {
+    this.id = "pie-chart-" + util.newGUID();
+    // this.newbarData = this.barData;
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+    //   this.initChart();
+      this.firstAnimation = false;
+    });
+  },
+  updated() {
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style lang="less">
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 479 - 0
src/components/chart/line/multiple-line-chart.vue

@@ -0,0 +1,479 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/helper/util.js";
+import partten from "@/helper/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "multiple-line-chart",
+  componentName: "multiple-line-chart",
+  props: {
+    width: {
+      type: String,
+      default: "100%",
+    },
+    height: {
+      type: String,
+      default: "13.889vh",
+    },
+    // 数据
+    list: {
+      type: Array,
+      default: () => [
+        {
+          title: "日发电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "2",
+              value: 2,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+            {
+              text: "4",
+              value: 4,
+            },
+            {
+              text: "5",
+              value: 6,
+            },
+            {
+              text: "6",
+              value: 2,
+            },
+            {
+              text: "7",
+              value: 3,
+            },
+            {
+              text: "8",
+              value: 8,
+            },
+            {
+              text: "9",
+              value: 3,
+            },
+            {
+              text: "10",
+              value: 2,
+            },
+            {
+              text: "11",
+              value: 5,
+            },
+            {
+              text: "12",
+              value: 8,
+            },
+            {
+              text: "13",
+              value: 3,
+            },
+            {
+              text: "14",
+              value: 9,
+            },
+            {
+              text: "15",
+              value: 3,
+            },
+            {
+              text: "16",
+              value: 2,
+            },
+            {
+              text: "17",
+              value: 1,
+            },
+            {
+              text: "18",
+              value: 3,
+            },
+            {
+              text: "19",
+              value: 4,
+            },
+            {
+              text: "20",
+              value: 9,
+            },
+            {
+              text: "21",
+              value: 2,
+            },
+            {
+              text: "22",
+              value: 1,
+            },
+            {
+              text: "23",
+              value: 2,
+            },
+            {
+              text: "24",
+              value: 3,
+            },
+            {
+              text: "25",
+              value: 3,
+            },
+            {
+              text: "26",
+              value: 4,
+            },
+            {
+              text: "27",
+              value: 9,
+            },
+            {
+              text: "28",
+              value: 7,
+            },
+            {
+              text: "29",
+              value: 4,
+            },
+            {
+              text: "30",
+              value: 1,
+            },
+            {
+              text: "31",
+              value: 2,
+            },
+          ],
+        },
+        {
+          title: "上网电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1",
+              value: 1,
+            },
+            {
+              text: "2",
+              value: 2,
+            },
+            {
+              text: "3",
+              value: 1,
+            },
+            {
+              text: "4",
+              value: 3,
+            },
+          ],
+        },
+        {
+          title: "购网电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1",
+              value: 1,
+            },
+          ],
+        },
+        {
+          title: "风速",
+          yAxisIndex: 1,
+          value: [
+            {
+              text: "1",
+              value: 100,
+            },
+            {
+              text: "2",
+              value: 200,
+            },
+            {
+              text: "1",
+              value: 100,
+            },
+            {
+              text: "2",
+              value: 400,
+            },
+          ],
+        },
+      ],
+    },
+    // 单位
+    units: {
+      type: Array,
+      default: () => ["(MW)", "(风速)"],
+    },
+    showLegend: {
+      type: Boolean,
+      default: false,
+    },
+    hoverType: {
+      type: String,
+      default: "item",
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      color: ["#05bb4c", "#4b55ae", "#fa8c16", "#f8de5b", "#1a93cf", "#c531c7", "#bd3338", "#05bb4c", "#4b55ae", "#fa8c16", "#f8de5b", "#1a93cf", "#c531c7", "#bd3338"],
+    };
+  },
+  computed: {
+    datas() {
+      return this.list.map((t) => {
+        return t.value;
+      });
+    },
+    legend() {
+      return this.list.map((t) => {
+        return t.title;
+      });
+    },
+    xdata() {
+      if (this.list.length > 0)
+        return this.list[0].value.map((t) => {
+          console.log('list0:',this.list[0])
+          console.log('tvalue:',t.value)
+          // return t.text;
+          return t.value
+        });
+      return [];
+    },
+    series() {
+      let result = [];
+
+      this.list.forEach((value, index) => {
+        console.log('list:',this.list)
+        result.push({
+          name: value.title,
+          type: "line",
+          smooth: true,
+          showSymbol: false,
+          zlevel: index,
+          lineStyle: {
+            normal: {
+              // color: index != 0 ? partten.getColor("gray") : this.color[index],
+                color: partten.getColor("gray"), 
+              width: 1,
+            },
+            emphasis: {
+              color: this.color[index],
+            },
+          },
+          areaStyle: {
+            normal: {
+              color:
+                index == 0
+                  ? new echarts.graphic.LinearGradient(
+                      0,
+                      0,
+                      0,
+                      1,
+                      [
+                        {
+                          offset: 0,
+                          color: this.hexToRgba(this.color[index], 0.3),
+                        },
+                        {
+                          offset: 1,
+                          color: this.hexToRgba(this.color[index], 0.1),
+                        },
+                      ],
+                      false
+                    )
+                  : "transparent",
+              shadowColor: this.hexToRgba(this.color[index], 0.1),
+              shadowBlur: 10,
+            },
+            emphasis: {
+              color: new echarts.graphic.LinearGradient(
+                0,
+                0,
+                0,
+                1,
+                [
+                  {
+                    offset: 0,
+                    color: this.hexToRgba(this.color[index], 0.3),
+                  },
+                  {
+                    offset: 1,
+                    color: this.hexToRgba(this.color[index], 0.1),
+                  },
+                ],
+                false
+              ),
+              shadowColor: this.hexToRgba(this.color[index], 0.1),
+              shadowBlur: 10,
+            },
+          },
+          tooltip: {
+            show: true,
+            position: [10, 10],
+          },
+          yAxisIndex: value.yAxisIndex,
+          data: value.value.map((t) => {
+            return t.value;
+          }),
+        });
+      });
+
+      return result;
+    },
+    yAxis() {
+      let result = [];
+      console.log('units:',this.units)
+      this.units.forEach((value, index) => {
+        result.push({
+          type: "value",
+          name: value,
+          nameTextStyle: {
+                color: '#fff',
+            },
+          axisLabel: {
+            formatter: "{value}",
+            fontSize: util.vh(14),
+            color:'#fff'
+          },
+          axisLine: {
+            show: false,
+          },
+          //分格线
+          splitLine: {
+            show: index == 0,
+            lineStyle: {
+              color: partten.getColor("gray"),
+              type: "dashed",
+            },
+          },
+        });
+      });
+      console.log('result:',result)
+      return result;
+      
+    },
+  },
+  methods: {
+    hexToRgba(hex, opacity) {
+      let rgbaColor = "";
+      let reg = /^#[\da-f]{6}$/i;
+      if (reg.test(hex)) {
+        rgbaColor = `rgba(${parseInt("0x" + hex.slice(1, 3))},${parseInt("0x" + hex.slice(3, 5))},${parseInt("0x" + hex.slice(5, 7))},${opacity})`;
+      }
+      return rgbaColor;
+    },
+    resize() {},
+    initChart() {
+      let chart = echarts.init(this.$el);
+
+      let option = {
+        color: this.color,
+        tooltip: {
+          trigger: this.hoverType,
+          axisPointer:
+            this.hoverType != "item"
+              ? {
+                  type: "cross",
+                }
+              : {},
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: "#fff",
+          },
+        },
+        legend: {
+          show: this.showLegend,
+          data: this.legend,
+          right: 56,
+          icon: "circle",
+          itemWidth: 6,
+          inactiveColor: partten.getColor("gray"),
+          textStyle: {
+            color: '#fff',
+            fontSize: 12,
+          },
+        },
+        grid: {
+          top: 32,
+          left: 40,
+          right: 40,
+          bottom: 24,
+        },
+        xAxis: [
+          {
+            name:"(m/s)",
+            type: "category",
+            nameTextStyle: {
+                color: '#fff',
+            },
+            boundaryGap: false,
+            axisLabel: {
+              formatter: "{value}",
+              fontSize: util.vh(14),
+              textStyle: {
+                color: '#fff,'
+              },
+            },
+            axisLine: {
+              show: false,
+            },
+            data: this.xdata,
+          },
+        ],
+        yAxis: this.yAxis,
+        series: this.series,
+      };
+      console.log('this:',this)
+      chart.clear();
+      chart && option && chart.setOption(option);
+      this.resize = function() {
+        chart.resize();
+      };
+      window.addEventListener("resize", this.resize);
+      chart.resize();
+    },
+  },
+  created() {
+    this.$nextTick(() => {
+      this.id = "pie-chart-" + util.newGUID();
+    });
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    });
+  },
+  updated() {
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style lang="less">
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 233 - 0
src/components/chart/pie/dual-pie-chart.vue

@@ -0,0 +1,233 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/helper/util.js";
+import partten from "@/helper/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "dsah-pie",
+  componentName: "dsah-pie",
+  props: {
+    width: {
+      type: String,
+      default: "100%",
+    },
+    height: {
+      type: String,
+      default: "18.519vh",
+    },
+    // 内部饼图数据
+    innerData: {
+      type: Array,
+      default: () => [
+        {
+          value: 700,
+          unit: "个",
+          name: "行业大类1",
+        },
+        {
+          value: 679,
+          unit: "个",
+          name: "行业大类2",
+        },
+        {
+          value: 1548,
+          unit: "个",
+          name: "行业大类3",
+        },
+      ],
+    },
+    // 外部饼图数据
+    outerData: {
+      type: Array,
+      default: () => [
+        {
+          value: 310,
+          unit: "个",
+          name: "邮件营销",
+        },
+        {
+          value: 234,
+          unit: "个",
+          name: "联盟广告",
+        },
+        {
+          value: 335,
+          unit: "个",
+          name: "视频广告",
+        },
+        {
+          value: 548,
+          unit: "个",
+          name: "百度",
+        },
+        {
+          value: 351,
+          unit: "个",
+          name: "谷歌",
+        },
+      ],
+    },
+    // 颜色
+    color: {
+      type: String,
+      default: "green",
+    },
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+    };
+  },
+  computed: {},
+  methods: {
+    initChart() {
+      let that = this;
+      let legend1 = this.innerData.map((v) => v.name);
+      let legend2 = this.outerData.map((v) => v.name);
+      let legendData = [...legend1, ...legend2];
+
+      let option = {
+        color: ["#1893ce", "#edbf00", "#039178", "#ae4802", "#ea8b00"],
+        tooltip: {
+          trigger: "item",
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            color: "#fff",
+            fontSize: util.vh(16),
+          },
+        },
+        grid: {
+          top: 32,
+          left: 60,
+          right: 40,
+          bottom: 24,
+        },
+        legend: {
+          show: this.showLegend,
+          orient: "vertical", //纵向图例
+          right: "16",
+          bottom: 32,
+          itemWidth: 15,
+          itemHeight: 15,
+          formatter: (name) => {
+            if (that.innerData.length) {
+              const item = that.innerData.filter((item) => item.name === name)[0];
+              return `{name|${name}:}{value| ${item.value}}`;
+            }
+          },
+          //icon: 'circle',
+          itemGap: 12, //图例item间距
+          textStyle: {
+            color: partten.getColor("gray"),
+            fontSize: util.vh(14),
+            rich: {
+              name: {
+                color: partten.getColor("gray"),
+                fontSize: 12,
+              },
+              value: {
+                color: partten.getColor("grayl"),
+                fontSize: 12,
+              },
+            },
+          },
+          data: legend1,
+        },
+        series: [
+          {
+            name: "",
+            type: "pie",
+            center: ["40%", "50%"],
+            radius: [0, "35%"],
+            itemStyle: {
+              normal: {},
+            },
+            label: {
+              normal: {
+                show: false,
+              },
+            },
+            labelLine: {
+              normal: {
+                show: false,
+              },
+            },
+            data: this.innerData,
+          },
+          {
+            name: "",
+            type: "pie",
+            center: ["40%", "50%"],
+            radius: ["55%", "95%"],
+            data: this.outerData,
+            labelLine: {
+              normal: {
+                // length: 40,
+                // length2: 120,
+                lineStyle: {
+                  color: "#fff",
+                  fontSize: util.vh(14),
+                },
+              },
+            },
+            itemStyle: {
+              normal: {
+                borderWidth: util.vh(14),
+                borderColor: "#071812",
+              },
+            },
+            label: {
+              normal: {
+                formatter: (params) => {
+                  return "{percent|" + params.percent.toFixed(2) + "%}";
+                },
+                padding: [0, 0, 0, 0],
+                rich: {
+                  color: "#ffffff" + "cc",
+                  percent: {
+                    fontSize: util.vh(14),
+                    color: "#ffffff" + "cc",
+                  },
+                },
+              },
+            },
+          },
+        ],
+      };
+
+      this.chart.setOption(option);
+    },
+  },
+  created() {
+    this.id = "pie-chart-" + util.newGUID();
+  },
+  mounted() {
+    this.$el.style.width = this.width;
+    this.$el.style.height = this.height;
+    this.chart = echarts.init(this.$el);
+    this.initChart();
+  },
+  updated() {
+    this.initChart();
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: block;
+  margin: auto;
+}
+</style>

+ 382 - 0
src/components/chart/radar/direction-radar-chart.vue

@@ -0,0 +1,382 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/helper/util.js";
+import partten from "@/helper/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "dsah-pie",
+  componentName: "dsah-pie",
+  props: {
+    // 宽度 默认9.722vh
+    width: {
+      type: String,
+      default: "100%",
+    },
+    // 高度 默认9.722vh
+    height: {
+      type: String,
+      default: "7.4074vh",
+    },
+    // 标题
+    title: {
+      type: String,
+      default: "标题",
+    },
+    // 值
+    value: {
+      type: Number,
+      default: 90,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      indicator: [
+        {
+          name: "北",
+          max: 100,
+        },
+        {
+          name: "北北西",
+          max: 100,
+        },
+        {
+          name: "北西",
+          max: 100,
+        },
+        {
+          name: "西北西",
+          max: 100,
+        },
+        {
+          name: "西",
+          max: 100,
+        },
+        {
+          name: "西南西",
+          max: 100,
+        },
+        {
+          name: "南西",
+          max: 100,
+        },
+        {
+          name: "南南西",
+          max: 100,
+        },
+        {
+          name: "南",
+          max: 100,
+        },
+        {
+          name: "南南东",
+          max: 100,
+        },
+        {
+          name: "东南",
+          max: 100,
+        },
+        {
+          name: "东南东",
+          max: 100,
+        },
+        {
+          name: "东",
+          max: 100,
+        },
+        {
+          name: "东北东",
+          max: 100,
+        },
+        {
+          name: "北东",
+          max: 100,
+        },
+        {
+          name: "北北东",
+          max: 100,
+        },
+      ],
+    };
+  },
+  computed: {},
+  methods: {
+    initChart() {
+      let option = {
+        grid: {
+          left: 40,
+          right: 40,
+          bottom: "40%",
+          top: "40%",
+          containLabel: false,
+        },
+        radar: [
+          // 最低层 80
+          {
+            radius: "70%",
+            center: ["50%", "50%"],
+            splitNumber: 1,
+            nameGap: "10",
+            name: {
+              textStyle: {
+                color: '#fff',
+                fontSize: 12,
+              },
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                color: "transparent",
+              },
+            },
+            indicator: this.indicator,
+          },
+          // 次外层 70 - 80
+          {
+            radius: ["60%", "70%"],
+            center: ["50%", "50%"],
+            startAngle: 90,
+            splitNumber: 2,
+            name: {
+              show: false,
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+                shadowBlur: 1,
+                shadowColor: "#fff",
+                shadowOffsetX: 0.5,
+                shadowOffsetY: 1,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray") + 40,
+                shadowColor: "#fff",
+                shadowBlur: 0,
+                shadowOffsetX: 0.5,
+                shadowOffsetY: 0.5,
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                color: "transparent",
+              },
+            },
+            indicator: this.indicator,
+          },
+          // 渐变层 40 - 70
+          {
+            radius: ["30%", "60%"],
+            center: ["50%", "50%"],
+            splitNumber: 1,
+            name: {
+              show: false,
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray"),
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                shadowBlur: 4,
+                color: {
+                  type: "radial",
+                  x: 0.5,
+                  y: 0.5,
+                  r: 0.5,
+                  colorStops: [
+                    {
+                      offset: 0.5,
+                      color: "transparent", // 0% 处的颜色
+                    },
+                    {
+                      offset: 1,
+                      color: partten.getColor("green") + 60, // 100% 处的颜色
+                    },
+                  ],
+                  global: false, // 缺省为 false
+                },
+              },
+            },
+            indicator: this.indicator,
+          },
+          // 内层 0 - 40
+          {
+            radius: "30%",
+            center: ["50%", "50%"],
+            splitNumber: 1,
+            name: {
+              show: false,
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray"),
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                shadowBlur: 4,
+                color: "transparent",
+              },
+            },
+            indicator: this.indicator,
+          },
+        ],
+        series: [
+          // 进度条
+          {
+            z: 1,
+            name: "内部(环形)进度条",
+            type: "gauge",
+            radius: "70%",
+            splitNumber: 5,
+            axisLine: {
+              lineStyle: {
+                color: [
+                  [
+                    this.value / 360,
+                    new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+                      {
+                        offset: 0,
+                        color: partten.getColor(this.color) + 10,
+                      },
+                      {
+                        offset: 1,
+                        color: partten.getColor(this.color) + 99,
+                      },
+                    ]),
+                  ],
+                  [1, "transparent"],
+                ],
+                width: 40,
+              },
+            },
+            startAngle: 90,
+            endAngle: 450,
+            clockwise: true,
+            axisLabel: {
+              show: false,
+            },
+            axisTick: {
+              show: false,
+            },
+            splitLine: {
+              show: false,
+            },
+            pointer: {
+              show: false,
+            },
+          },
+          // 指针
+          {
+            name: "指针",
+            type: "gauge",
+            z: 2,
+            min: 0,
+            max: 360,
+            radius: "100%",
+            startAngle: 90,
+            endAngle: 360 + 90,
+            clockwise: false,
+            axisLine: {
+              show: false,
+            },
+            tooltip: {
+              show: false,
+            },
+            axisLabel: {
+              show: false,
+            },
+            axisTick: {
+              show: false,
+            },
+            splitLine: {
+              show: false,
+            },
+            detail: {
+              show: false,
+            },
+            title: {
+              //标题
+              show: false
+            },
+            data: [
+              {
+                value: this.value,
+              },
+            ],
+            itemStyle: {
+              normal: {
+                color: "#fff",
+              },
+            },
+            pointer: {
+              show: true,
+              length: "70%",
+              radius: "0%",
+              width: util.vh(3), //指针粗细
+              offsetCenter: ["0%", "0%"],
+            },
+            animationDuration: 1000,
+          },
+        ],
+      };
+
+      this.chart.setOption(option);
+    },
+  },
+  created() {
+    this.id = "pie-chart-" + util.newGUID();
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.chart = echarts.init(this.$el);
+      this.initChart();
+    });
+  },
+  updated() {
+    this.initChart();
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: block;
+  margin: auto;
+}
+</style>

+ 372 - 0
src/components/chart/radar/radar-chart.vue

@@ -0,0 +1,372 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/helper/util.js";
+import partten from "@/helper/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "radar-chart",
+  componentName: "radar-chart",
+  props: {
+    // 宽度 默认9.722vh
+    width: {
+      type: String,
+      default: "100%",
+    },
+    // 高度 默认9.722vh
+    height: {
+      type: String,
+      default: "7.4074vh",
+    },
+    // 标题
+    title: {
+      type: String,
+      default: "标题",
+    },
+    // 值
+    value: {
+      type: Object,
+      default: () => {
+        return {
+          indicator: [
+            // "北(0.0/0.0)",
+            // "北北西(0.0/0.0)",
+            // "北西(0.0/0.0)",
+            // "西北西(0.0/0.0)",
+            // "西(0.0/0.0)",
+            // "西南西(0.0/0.0)",
+            // "南西(0.0/0.0)",
+            // "南南西(0.0/0.0)",
+            // "南(0.0/0.0)",
+            // "南南东(0.0/0.0)",
+            // "东南(0.0/0.0)",
+            // "东南东(0.0/0.0)",
+            // "东(0.0/0.0)",
+            // "东北东(0.0/0.0)",
+            // "北东(0.0/0.0)",
+            // "北北东(0.0/0.0)",
+          ],
+          data: [
+            {
+              value: [44200, 14200, 20000, 35000, 50000, 38000, 44200, 14200, 20000, 35000, 50000, 38000, 44200, 14200, 20000, 35000, 50000, 38000, 20000, 35000, 50000, 38000],
+              name: "NAME",
+            },
+          ],
+        };
+      },
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      lineStyles: [
+        {
+          areaStyle: {
+            color: "rgba(75,85,174, 0.9)",
+          },
+          lineStyle: {
+            color: "rgba(255,255,255, 0.85)",
+          },
+          itemStyle: {
+            color: "rgba(75,85,174, 0.5)",
+            borderColor: "rgba(255,255,255, 0.5)",
+            borderWidth: 0.5,
+          },
+        },
+      ],
+    };
+  },
+  computed: {},
+  methods: {
+    initChart() {
+      let chart = echarts.init(this.$el);
+
+      let maxValue = -1;
+      if (this.value.data)
+        this.value.data.forEach((item, index) => {
+          item.value.forEach((value) => {
+            if (value > maxValue) {
+              maxValue = value;
+            }
+          });
+          item.areaStyle = this.lineStyles[index % this.lineStyles.length].areaStyle;
+          item.lineStyle = this.lineStyles[index % this.lineStyles.length].lineStyle;
+          item.itemStyle = this.lineStyles[index % this.lineStyles.length].itemStyle;
+        });
+      maxValue *= 1.5;
+
+      let indicator = [];
+      if (this.value.indicator)
+        this.value.indicator.forEach((item) => {
+          indicator.push({ name: item, max: maxValue });
+        });
+
+      let baseSize = 65;
+
+      let option = {
+        grid: {
+          left: 0,
+          right: 0,
+          bottom: 0,
+          top: 0,
+        },
+        tooltip: {
+          trigger: "item",
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            color: "#fff",
+            fontSize: util.vh(16),
+          },
+          position: ['80%', '0%']
+        },
+        radar: [
+          // 最低层 90
+          {
+            radius: baseSize + "%",
+            center: ["50%", "50%"],
+            splitNumber: 1,
+            nameGap: "4",
+            name: {
+              textStyle: {
+                color: '#fff',
+                fontSize: 12,
+                padding: [0, 16],
+              },
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                color: "transparent",
+              },
+            },
+            indicator: indicator,
+          },
+          // 次外层 80 - 90
+          {
+            radius: ["55%", "65%"],
+            center: ["50%", "50%"],
+            startAngle: 90,
+            splitNumber: 2,
+            name: {
+              show: false,
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+                shadowBlur: 1,
+                shadowColor: "#fff",
+                shadowOffsetX: 0.5,
+                shadowOffsetY: 1,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray") + 40,
+                shadowColor: "#fff",
+                shadowBlur: 0,
+                shadowOffsetX: 0.5,
+                shadowOffsetY: 0.5,
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                color: "transparent",
+              },
+            },
+            indicator: indicator,
+          },
+          // 渐变层 40 - 80
+          {
+            radius: ["30%", "55%"],
+            center: ["50%", "50%"],
+            splitNumber: 1,
+            name: {
+              show: false,
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray"),
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                shadowBlur: 4,
+                color: {
+                  type: "radial",
+                  x: 0.5,
+                  y: 0.5,
+                  r: 0.5,
+                  colorStops: [
+                    {
+                      offset: 0.5,
+                      color: "transparent", // 0% 处的颜色
+                    },
+                    {
+                      offset: 1,
+                      color: partten.getColor("green") + 60, // 100% 处的颜色
+                    },
+                  ],
+                  global: false, // 缺省为 false
+                },
+              },
+            },
+            indicator: indicator,
+          },
+          // 渐变层 0 - 40
+          {
+            radius: ["0%", "30%"],
+            center: ["50%", "50%"],
+            splitNumber: 1,
+            name: {
+              show: false,
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray"),
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                shadowBlur: 4,
+                color: {
+                  type: "radial",
+                  x: 0.5,
+                  y: 0.5,
+                  r: 0.5,
+                  colorStops: [
+                    {
+                      offset: 0.5,
+                      color: "transparent", // 0% 处的颜色
+                    },
+                    {
+                      offset: 1,
+                      color: partten.getColor("green") + 60, // 100% 处的颜色
+                    },
+                  ],
+                  global: false, // 缺省为 false
+                },
+              },
+            },
+            indicator: indicator,
+          },
+          // 内层 0 - 50
+          {
+            radius: "50%",
+            center: ["50%", "50%"],
+            splitNumber: 1,
+            name: {
+              show: false,
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray"),
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                shadowBlur: 4,
+                color: "transparent",
+              },
+            },
+            indicator: indicator,
+          },
+          // 内层 0 - 45
+          {
+            radius: "35%",
+            center: ["50%", "50%"],
+            splitNumber: 1,
+            name: {
+              show: false,
+            },
+            axisLine: {
+              lineStyle: {
+                color: partten.getColor("gray") + 40,
+              },
+            },
+            splitLine: {
+              lineStyle: {
+                width: 1,
+                color: partten.getColor("gray"),
+              },
+            },
+            splitArea: {
+              areaStyle: {
+                shadowBlur: 4,
+                color: "transparent",
+              },
+            },
+            indicator: indicator,
+          },
+        ],
+        series: [
+          {
+            name: this.title,
+            type: "radar",
+            data: this.value.data,
+          },
+        ],
+      };
+
+      chart.setOption(option);
+    },
+  },
+  created() {
+    this.id = "pie-chart-" + util.newGUID();
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    });
+  },
+  updated() {
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: block;
+  margin: auto;
+}
+</style>

+ 111 - 0
src/components/coms/panel/panel.vue

@@ -0,0 +1,111 @@
+<template>
+  <div class="com-panel" :class="{ 'no-title': !hasTitle, line: showLine }">
+    <div v-if="hasTitle" class="panel-header">
+      <div class="panel-title">
+        <i v-if="hasIcon" class="panel-icon" :class="icon"></i>
+        {{ title }}
+      </div>
+      <div class="panel-tools">{{ subTitle }}</div>
+    </div>
+    <div class="panel-body" :class="{ blur: bgBlur }">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "com-panel",
+  componentName: "com-panel",
+  props: {
+    // 标题
+    title: String,
+    // 图标
+    icon: String,
+    // 副标题
+    subTitle: String,
+    showLine: {
+      type: Boolean,
+      default: true,
+    },
+    bgBlur: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  computed: {
+    // 是否存在标题
+    // 标题为空时 不显示标题框
+    hasTitle() {
+      if (this.title) return true;
+      return false;
+    },
+    // 是否存在图标
+    hasIcon() {
+      if (this.icon) return true;
+      return false;
+    },
+  },
+};
+</script>
+<style lang="less">
+.com-panel {
+  &.line {
+    border-left: 1px solid #606769;
+  }
+
+  &.line:before {
+    content: " ";
+    width: 3px;
+    height: 3px;
+    float: left;
+    background: #c9c9c9;
+    margin: 0.185vh 0.556vh 0vh 0.185vh;
+  }
+
+  &.no-title {
+    border-left: 0vh;
+  }
+
+  &.no-title::before {
+    display: none;
+  }
+
+  .panel-header {
+    display: flex;
+    font-size: 12px;
+    padding-left: 1.185vh;
+    background: rgba(255, 255, 255, 10%);
+    line-height: 27px;
+    margin-bottom: 0.7407vh;
+
+    .panel-title {
+      color: fade(#fff, 75);
+      flex: 1 1 auto;
+      .panel-icon {
+        margin-right: 0.741vh;
+      }
+    }
+
+    .panel-tools {
+      flex: 0 0 auto;
+      color: #ffffff4d;
+      padding: 0 0.741vh;
+      font-size: 12px;
+      letter-spacing: 0.093vh;
+    }
+  }
+
+  .panel-body {
+    position: relative;
+  }
+
+  &.line .panel-body {
+    padding-left: 1.185vh;
+  }
+
+  &.no-title .panel-body {
+    padding-left: 0vh;
+  }
+}
+</style>

+ 201 - 0
src/components/coms/table/table.vue

@@ -0,0 +1,201 @@
+<template>
+  <table class="com-table">
+    <thead>
+      <tr>
+        <th v-for="(col, index) of data.column" :key="index" :class="{ light: col.is_light }" :style="{ width: col.width }" @click="onSort(col)">
+          {{ col.name }}
+        </th>
+      </tr>
+    </thead>
+    <el-scrollbar>
+      <tbody :style="{ height: height }">
+        <tr v-for="(row, index) of tableData" :key="index">
+          <td
+            v-for="(col, i) of data.column"
+            :key="i"
+            :style="{ width: col.width }"
+            :class="{ light: hoverRow == row || hoverCol == col, num: col.is_num, 'always-light': col.is_light || row.is_light }"
+            @mouseenter="hover(row, col)"
+            @mouseleave="leave()"
+          >
+            <component :is="col.type ? col.type : 'span'" v-bind="col.props" v-html="template(col, row[col.field])" @click="onClick(col, row)"> </component>
+          </td>
+        </tr>
+      </tbody>
+    </el-scrollbar>
+    <el-pagination class="mg-t-8" v-if="pageable" @current-change="handleCurrentChange" :current-page="currentPage" :page-size="pageSize" :total="data.total" v-bind="elPaggingProps"> </el-pagination>
+  </table>
+</template>
+
+<script>
+export default {
+  // 名称
+  name: "ComTable",
+  // 使用组件
+  components: {},
+  // 传入参数
+  props: {
+    data: {
+      type: Object,
+      default: {},
+    },
+    // hover 样式
+    showHover: {
+      type: Boolean,
+      default: true,
+    },
+    // 列高亮
+    showColHover: {
+      type: Boolean,
+      default: false,
+    },
+    canScroll: {
+      type: Boolean,
+      default: true,
+    },
+    pageSize: {
+      type: Number,
+      default: 0,
+    },
+    height: {
+      type: String,
+      default: "",
+    },
+    // 新增 支持 pagging 组件
+    elPaggingProps: {
+      type: Object,
+      default: () => {
+        return {
+          layout: "total, sizes, prev, pager, next, jumper",
+          // "page-sizes": [100, 200, 300, 400],
+        };
+      },
+    },
+  },
+  // 自定义事件
+  emits: {
+    // 分页事件
+    onPagging: null,
+  },
+  // 数据
+  data() {
+    return {
+      hoverRow: -1,
+      hoverCol: -1,
+      sortCol: "",
+      sortType: "",
+      currentPage: 1,
+    };
+  },
+  computed: {
+    tableData() {
+      let that = this;
+      if (this.sortCol == "") {
+        return this.data.data;
+      } else {
+        let data = this.data.data;
+
+        data.sort((a, b) => {
+          let rev = 1;
+          if (that.sortType == "ASC") rev = 1;
+          else if (that.sortType == "DESC") rev = -1;
+
+          if (a[that.sortCol] > b[that.sortCol]) return rev * 1;
+          if (a[that.sortCol] < b[that.sortCol]) return rev * -1;
+          return 0;
+        });
+        return data;
+      }
+    },
+    pageable() {
+      return this.pageSize != 0;
+    },
+    pages() {
+      if (this.pageable) return parseInt(this.data.total / this.pageSize) + 1;
+      else return 0;
+    },
+    startRow() {
+      if (this.pageable) return (this.currentPage - 1) * this.pageSize;
+      else return 0;
+    },
+    endRow() {
+      if (this.pageable) return this.currentPage * this.pageSize;
+      else return this.data.data.length;
+    },
+  },
+  // 函数
+  methods: {
+    clearCheckBox(time){
+      this.$nextTick(()=>{
+        setTimeout(()=>{
+          const domArray = document.querySelectorAll(".curCheckBox");
+          for(let i=0;i<domArray.length;i++){
+            domArray[i].checked=false;
+          }
+        },(time || 300));
+      });
+    },
+    onClick(col, data) {
+      if (col.click) col.click(event, data);
+    },
+    onSort(col) {
+      if (col.sortable == true) {
+        this.sortCol = col.field;
+        switch (this.sortType) {
+          case "":
+            this.sortType = "DESC";
+            break;
+          case "DESC":
+            this.sortType = "ASC";
+            break;
+          case "ASC":
+            this.sortType = "";
+            break;
+        }
+      }
+    },
+    template(col, data) {
+      if (!col.template) return data;
+      else return col.template(data);
+    },
+    hover(row, col) {
+      if (this.showHover) {
+        this.hoverRow = row;
+        if (this.showColHover) this.hoverCol = col;
+      }
+    },
+    leave() {
+      this.hoverRow = -1;
+      this.hoverCol = -1;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.$emit("onPagging", {
+        pageIndex: this.currentPage,
+        pageSize: this.pageSize,
+        start: this.startRow,
+        end: this.endRow,
+      });
+    },
+  },
+  // 生命周期钩子
+  beforeCreate() {
+    // 创建前
+  },
+  created() {
+    // 创建后
+  },
+  beforeMount() {
+    // 渲染前
+  },
+  mounted() {
+    // 渲染后
+  },
+  beforeUpdate() {},
+  updated() {},
+};
+</script>
+
+<style lang="less">
+@import "../../../assets/style/table.less";
+</style>

+ 398 - 0
src/components/curveAnalyse/multiple-bar-chart.vue

@@ -0,0 +1,398 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/helper/util.js";
+import partten from "@/helper/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "multiple-bar-chart",
+  componentName: "multiple-bar-chart",
+  props: {
+    pillarName: {
+      type: String,
+      default: "",
+    },
+    width: {
+      type: String,
+      default: "100%",
+    },
+    height: {
+      type: String,
+      default: "13.889vh",
+    },
+    // 传入数据
+    list: {
+      type: Array,
+      default: () => [
+        {
+          title: "日发电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1日",
+              value: 1,
+            },
+          ],
+        },
+        {
+          title: "上网电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1日",
+              value: 1,
+            },
+            {
+              text: "2日",
+              value: 2,
+            },
+            {
+              text: "3日",
+              value: 1,
+            },
+            {
+              text: "4日",
+              value: 3,
+            },
+            {
+              text: "5日",
+              value: 3,
+            },
+            {
+              text: "6日",
+              value: 3,
+            },
+            {
+              text: "7日",
+              value: 3,
+            },
+          ],
+        },
+        {
+          title: "购网电量",
+          yAxisIndex: 0,
+          value: [
+            {
+              text: "1日",
+              value: 1,
+            },
+            {
+              text: "2日",
+              value: 2,
+            },
+            {
+              text: "3日",
+              value: 1,
+            },
+            {
+              text: "4日",
+              value: 3,
+            },
+            {
+              text: "5日",
+              value: 3,
+            },
+            {
+              text: "6日",
+              value: 3,
+            },
+            {
+              text: "7日",
+              value: 3,
+            },
+          ],
+        },
+        {
+          title: "风速",
+          yAxisIndex: 1,
+          value: [
+            {
+              text: "1日",
+              value: 1,
+            },
+            {
+              text: "2日",
+              value: 2,
+            },
+            {
+              text: "3日",
+              value: 1,
+            },
+            {
+              text: "4日",
+              value: 3,
+            },
+            {
+              text: "5日",
+              value: 3,
+            },
+            {
+              text: "6日",
+              value: 3,
+            },
+            {
+              text: "7日",
+              value: 3,
+            },
+          ],
+        },
+      ],
+    },
+    // 单位
+    units: {
+      type: Array,
+      default: () => ["(万KWh)", "(风速)"],
+    },
+    // 显示 legend
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 颜色#
+    color: {
+      type: Array,
+      default: () => [
+        "#05bb4c",
+        "#4b55ae",
+        "#fa8c16",
+        "#f8de5b",
+        "#1a93cf",
+        "#c531c7",
+        "#bd3338",
+      ],
+    },
+    showAnimation: {
+      type: Boolean,
+      default: true,
+    },
+    // 柱子最大宽度
+    barMaxWidth: {
+      type: Number || String,
+      default: 0,
+    },
+    // 柱子间距
+    barGap: {
+      type: Number || String,
+      default: 0,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      firstAnimation: true,
+    };
+  },
+  computed: {
+    legend() {
+      return this.list.map((t) => {
+        return t.title;
+      });
+    },
+    xdata() {
+      let result = [];
+      if (this.list && this.list.length > 0 && this.list[0].value.length > 0) {
+        result = this.list[0].value.map((t) => {
+          return t.text;
+        });
+      }
+      return result;
+    },
+    ydata() {
+      let result = [];
+      this.units.forEach((value, index) => {
+        let data = null;
+        if (index == 0) {
+          data = {
+            type: "value",
+            name: value,
+            axisLabel: {
+              formatter: "{value} ",
+              fontSize: 12,
+              textStyle: {
+                color: "#A9A9AA"
+              },
+            },
+            //分格线
+            splitLine: {
+              lineStyle: {
+                color: "#5a6162",
+                type: "dashed",
+              },
+            },
+          };
+        } else {
+          data = {
+            type: "value",
+            name: value,
+            axisLabel: {
+              formatter: "{value}",
+              fontSize: 12,
+              textStyle: {
+                color:"rgb(116,124,128)",
+              },
+            },
+            //分格线
+            splitLine: {
+              show: false,
+            },
+          };
+        }
+
+        result.push(data);
+      });
+
+      return result;
+    },
+    series() {
+      let result = [];
+      if (this.list && this.list.length > 0) {
+        this.list.forEach((value, index) => {
+          let seriesItem = {
+            name: value.title,
+            type: "bar",
+            barWidth: "8%",
+            animation: this.firstAnimation && this.showAnimation,
+            yAxisIndex: value.yAxisIndex,
+            data: value.value.map((t) => {
+              return t.value;
+            }),
+          };
+          if (this.barMaxWidth) {
+            seriesItem.barMaxWidth = this.barMaxWidth;
+          } else {
+            seriesItem.barWidth = "8%";
+          }
+
+          if (this.barGap) {
+            seriesItem.barGap = this.barGap;
+          }
+          result.push(seriesItem);
+        });
+      }
+      return result;
+    },
+  },
+  methods: {
+    resize() {
+      this.initChart();
+    },
+    initChart() {
+      let _this = this
+      let chart = echarts.init(this.$el);
+      let pillarName = this.pillarName
+      let option = {
+        color: this.color,
+        axisLabel:{
+          textStyle:{//改变xy轴上文字的颜色
+              color:"#A9A9AA"
+          }
+        },
+        tooltip: {
+          trigger: "axis",
+          backgroundColor: "#1C0C00",
+          borderColor: "#fff",
+          textStyle: {
+            color: "#A9A9AA",
+            fontSize: 12,
+          },
+          formatter:function(params){
+            return `<div style="text-align: left;">
+                      <div style="color:#fff">${pillarName}</div>
+                      <div style="color:#fff">${params[0].seriesName}:${params[0].value}</div>
+                      <div style="color:#fff">${params[1].seriesName}:${params[1].value}</div>
+                    </div>`
+          }
+        },
+        legend: {
+          show: this.showLegend,
+          data: this.legend,
+          right: 56,
+          icon: "ract",
+          itemWidth: 8,
+          itemHeight: 8,
+          inactiveColor: "#A9A9AA",
+          textStyle: {
+            fontSize: 12,
+            color: "#A9A9AA",
+          },
+        },
+        grid: {
+          top: 32,
+          left: 8,
+          right: 8,
+          bottom: 0,
+          containLabel: true,
+        },
+        xAxis: [
+          {
+            type: "category",
+            data: this.xdata,
+            nameLocation: "center",
+            axisPointer: {
+              type: "shadow",
+            },
+            axisLabel: {
+              interval: 0,
+              fontSize: 12,
+              textStyle: {
+                color: "#A9A9AA"
+              },
+            },
+          },
+        ],
+        yAxis: this.ydata,
+        series: this.series,
+      };
+
+      chart.clear();
+      chart.setOption(option);
+
+      this.resize = function () {
+        chart.resize();
+      };
+
+      window.addEventListener("resize", this.resize);
+    },
+  },
+  created() {
+ 
+    this.$nextTick(() => {
+      this.id = "pie-chart-" + util.newGUID();
+    });
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+      this.firstAnimation = false;
+    });
+  },
+  updated() {
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+
+  watch: {
+    "$store.state.themeName"() {
+      this.initChart();
+    },
+  },
+};
+</script>
+
+<style lang="less">
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 112 - 0
src/components/curveAnalyse/panel.vue

@@ -0,0 +1,112 @@
+<template>
+  <div class="com-panel" :class="{ 'no-title': !hasTitle, line: showLine }">
+    <div v-if="hasTitle" class="panel-header">
+      <div class="panel-title">
+        <i v-if="hasIcon" class="panel-icon" :class="icon"></i>
+        {{ title }}
+      </div>
+      <div class="panel-tools">{{ subTitle }}</div>
+    </div>
+    <div class="panel-body" :class="{ blur: bgBlur }">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "com-panel",
+  componentName: "com-panel",
+  props: {
+    // 标题
+    title: String,
+    // 图标
+    icon: String,
+    // 副标题
+    subTitle: String,
+    showLine: {
+      type: Boolean,
+      default: true,
+    },
+    bgBlur: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  computed: {
+    // 是否存在标题
+    // 标题为空时 不显示标题框
+    hasTitle() {
+      if (this.title) return true;
+      return false;
+    },
+    // 是否存在图标
+    hasIcon() {
+      if (this.icon) return true;
+      return false;
+    },
+  },
+};
+</script>
+<style lang="less">
+.com-panel {
+  &.line {
+    border-left: 1px solid gray;
+  }
+
+  &.line:before {
+    content: " ";
+    width: 3px;
+    height: 3px;
+    float: left;
+    background: #c9c9c9;
+    margin: 0.185vh 0.556vh 0vh 0.185vh;
+  }
+
+  &.no-title {
+    border-left: 0vh;
+  }
+
+  &.no-title::before {
+    display: none;
+  }
+
+  .panel-header {
+    display: flex;
+    font-size: 14px;
+    padding-left: 1.185vh;
+    background: rgba(255, 255, 255, 10%);
+    line-height: 27px;
+    margin-bottom: 0.7407vh;
+    height: 27px;
+
+    .panel-title {
+      color: fade(#fff, 75);
+      flex: 1 1 auto;
+      .panel-icon {
+        margin-right: 0.741vh;
+      }
+    }
+
+    .panel-tools {
+      flex: 0 0 auto;
+      color: #ffffff4d;
+      padding: 0 0.741vh;
+      font-size: 12px;
+      letter-spacing: 0.093vh;
+    }
+  }
+
+  .panel-body {
+    position: relative;
+  }
+
+  &.line .panel-body {
+    padding-left: 1.185vh;
+  }
+
+  &.no-title .panel-body {
+    padding-left: 0vh;
+  }
+}
+</style>

+ 51 - 0
src/components/excel.vue

@@ -0,0 +1,51 @@
+<script setup name="excel">
+import { ref, watch } from 'vue';
+const props = defineProps({
+	data:{
+		type: Array,
+		default: () => [],
+	},
+	height: {
+		type: String,
+		default: '400px',
+	},
+	showCheckbox: {
+		type: Boolean,
+		default: false,
+	},
+	checkIds: {
+		type: Array,
+		default: () => [],
+	}
+})
+const excelCheckIds = ref([])
+const currentId = ref('')
+const emits = defineEmits(['excelChange', 'checkChange'])
+const funExcelChange = (obj) => {
+	currentId.value = obj.id
+	emits('excelChange', obj)
+}
+watch(() => props.checkIds, (newVal, oldVal) => {  //监听外部checkIds 赋值当前全选
+	excelCheckIds.value = newVal
+})
+const funCheckChange = (checkArr) => {
+	emits('checkChange', { checkArr, data: props.data })  //抛出当前选择checkIds,  和当前的childs数据项
+}
+</script>
+<template>
+	<div class="overflow-auto shadow rounded-[6px] bg-[rgba(0,0,0,0.3)] shadow-blue-500 pl-[6px] pt-[6px] pb-[6px]"
+		:style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+		<el-empty v-if="!props.data.length" description="暂无数据" />
+		<el-checkbox-group size="small" v-model="excelCheckIds" v-if="props.showCheckbox" @change="funCheckChange">
+			<el-checkbox :class="{'!bg-[#1E5AA3]': currentId === item.id}" size="small" class="hover:bg-[#1E5AA3] !mr-0 py-[3px] w-full" :label="item.id" v-for="item in props.data" :key="item.name">
+				<span class="whitespace-nowrap cursor-pointer text-white text-[12px] align-middle inline-flex items-center"
+					@click.stop="funExcelChange(item)"><el-icon class="mr-[4px] !text-[rgb(71,179,71)]"><Document /></el-icon>{{ item.name }}</span>
+			</el-checkbox>
+		</el-checkbox-group>
+		<div v-else>
+			<div
+				class="hover:bg-[#1E5AA3] whitespace-nowrap text-white pl-[8px] py-[3px] w-full cursor-pointer leading-[10px] inline-flex items-center h-[24px] text-[12px]"
+				v-for="item in props.data" :key="item.name" :class="{'!bg-[#1E5AA3]': currentId === item.id}" @click="funExcelChange(item)"><el-icon class="mr-[4px] !text-[rgb(71,179,71)]"><Document /></el-icon>{{ item.name }}</div>
+		</div>
+	</div>
+</template>

+ 171 - 0
src/components/headerNav/index.vue

@@ -0,0 +1,171 @@
+<template>
+  <div>
+    <ul>
+      <li @click="headerCheck(0)" :class="{active:headerIndex==0}">
+        <i class="active_icon icon-menu"></i>
+        <span>全部</span>
+      </li>
+      <li @click="headerCheck(-1)" :class="{active:headerIndex==-1,forbidden:parentNode?.ZFJTS==0}">
+        <i class="icon-fan"></i>
+        <span>风电</span>
+      </li>
+      <li @click="headerCheck(-2)"  :class="{active:headerIndex==-2,forbidden:parentNode?.ZGFTS==0}">
+        <i class="icon-photovoltaic"></i>
+        <span>光伏</span>
+      </li>
+      <div class="rightTitle">
+        <li class="nav_right" :class="{active:headerIndexs==-1}" @click="headerChecks(-1,parentNode.code)" @dblclick="hideChild()">
+          <i class="active_icon icon-enterprise"></i>
+          <span>{{parentNode && parentNode.aname }}</span>
+        </li>
+        <li v-for="(item,index) in childNode" :key="index" class="nav_right" @click="headerChecks(index,item.code)"
+            :class="{active:headerIndexs===index}" v-show="isShows">
+          <span>{{parentNode && item.aname }}</span>
+        </li>
+      </div>
+    </ul>
+  </div>
+</template>
+
+<script>
+import {getOrganization} from "@api/home";
+
+
+export default {
+  name: 'HomeNav',//首页标题栏
+  props: {
+  },
+  data() {
+    return {
+      OrganizationList:[],
+      headerIndex: 0,
+      headerIndexs: -1,
+      isShow: true,
+      isShows: true,
+      nodeCode:'',
+      activeNode:'',
+    }
+  },
+ async created() {
+   await this.getOrganizationList();
+   await this.$emit('firstRender', this.headerIndex,this.nodeCode, this.activeNode,this.parentNode.ZFJTS,this.parentNode.ZGFTS);
+  },
+  methods: {
+    async getOrganizationList() {
+      const data = await getOrganization();
+      this.OrganizationList = data;
+      this.nodeCode=data[0].code;
+      this.activeNode=this.nodeCode+this.headerIndex;
+    },
+    headerCheck(index) {
+      this.headerIndex = index;
+      this.activeNode = this.nodeCode + this.headerIndex;
+      this.$emit('firstRender', this.headerIndex,this.nodeCode, this.activeNode);
+      this.$emit('typeFlag',index===0?'all':index===-1?'wind':'sun')
+
+    },
+    headerChecks(index, code) {
+      this.headerIndexs = index
+      this.nodeCode = code;
+      this.activeNode = this.nodeCode + this.headerIndex;
+      this.$emit('firstRender', this.headerIndex,this.nodeCode, this.activeNode);
+      this.$emit('company',code)
+
+    },
+    hideChild() {
+      this.isShows = !this.isShows
+    },
+  },
+  computed: {
+    parentNode() {
+      const datas = this.OrganizationList.filter((item) => {
+        return item.preCode == ''
+      })
+      return datas[0];
+    },
+    childNode() {
+      const datas = this.OrganizationList.filter((item) => {
+        return item.preCode != ''
+      })
+      return datas;
+    },
+  }
+}
+</script>
+
+<style lang="less" scoped>
+ul {
+  user-select: none;
+  display: flex;
+  .forbidden{
+    background: #666666;
+    opacity: .5;
+    span{
+      color: #B3B3B3;
+    }
+  }
+  .active {
+    background: rgba(0, 70, 199, 0.4);
+
+    .active_icon {
+      color: rgba(28, 153, 255, 1);
+    }
+
+    span {
+      color: #FFFFFF;;
+    }
+
+  }
+
+  li {
+    padding: 0 14px;
+    height: 25px;
+    line-height: 25px;
+    background: rgba(0, 70, 199, 0.2);
+    border-radius: 16px;
+    text-align: center;
+    margin-right: 15px;
+    margin-top: 16px;
+    cursor: pointer;
+
+    span {
+      width: 29px;
+      height: 12px;
+      font-size: 14px;
+      font-family: Microsoft YaHei;
+      font-weight: 400;
+      color: #B3B3B3;
+
+    }
+
+    i {
+      font-size: 16px;
+      color: #B3B3B3;
+      position: relative;
+      margin-right: 9px;
+      vertical-align: -9%;
+    }
+
+  }
+
+  .nav_right {
+    transition: 0.3s;
+  }
+
+  .nav_right:first-of-type {
+    margin-left: 60px;
+  }
+
+  p {
+    width: 60px;
+  }
+
+  .rightTitle {
+    position: fixed;
+    left: 300px;
+    display: flex;
+  }
+
+}
+
+</style>

+ 12 - 0
src/components/inlayMenu/index.vue

@@ -0,0 +1,12 @@
+<template>
+    <div class="menu">
+        11
+    </div>
+</template>
+<style lang="less" scoped>
+.menu{
+    width: 50px;
+    height: 435px;
+    background-color: #0046C7;
+}
+</style>

文件差異過大導致無法顯示
+ 98 - 0
src/components/menuNav/index.vue


+ 11 - 0
src/components/submitBtn.vue

@@ -0,0 +1,11 @@
+<script setup name="submitBtn">
+const props = defineProps({
+	desc: {
+		type: String,
+		default: ''
+	}
+})
+</script>
+<template>
+	<div class="h-[24px] flex justify-center items-center text-white bg-[rgba(0,70,199,0.5)] px-[15px] cursor-pointer text-[14px] rounded-[13px]">{{props.desc}}</div>
+</template>

+ 184 - 0
src/components/tree.vue

@@ -0,0 +1,184 @@
+<template>
+	<div class="shadow rounded-[6px] shadow-blue-500 bg-[rgba(0,0,0,0.3)]" :style="{
+		height:
+			typeof props.height === 'string' ? props.height : props.height + 'px',
+		overflowY: 'hidden'
+	}">
+		<el-input class="pb-[10px]" v-model="filterText" placeholder="输入关键字过滤" @input="funfilterChange" />
+		<el-tree ref="treeRef" :style="{ height: `calc(${props.height} - 46px)`, overflow: 'auto' }" icon=""
+			:data="props.data" :show-checkbox="props.showCheckbox" default-expand-all node-key="id" highlight-current
+			:props="defaultProps" :current-node-key="''" @check="funCheckChange" :expand-on-click-node="false"
+			@node-click="funCurrentChange" :filter-node-method="funTreeFilter">
+			<template #default="{ node, data }">
+				<p v-if="node.level === 1" class="flex justify-between items-center text-[12px]"
+					:class="[props.showCheckbox ? 'w-[84%]' : 'w-[90%]']">
+					<span>{{ node.label }}</span>
+					<el-icon class="!text-[rgb(64,158,255)]" title="刷新" @click.stop="emits('refresh')">
+						<RefreshRight />
+					</el-icon>
+				</p>
+				<el-dropdown ref="dropdown1" v-else size="small" trigger="contextmenu" @command="funCommand"
+					style="margin-right: 30px">
+					<span class="el-dropdown-link text-white text-[12px] flex items-center">
+						<el-icon class="mr-[4px] !text-[#E6A23C]">
+							<Folder v-if="!node.expanded || (node.isLeaf && !node.isCurrent)" />
+							<FolderOpened v-else />
+						</el-icon>
+						{{ node.label }}
+					</span>
+					<template #dropdown>
+						<el-dropdown-menu>
+							<el-dropdown-item class="text-[#409EFF]" v-if="data.childs && data.childs.length"
+								:command="{ type: 'export', data, node }">导出
+							</el-dropdown-item>
+							<el-dropdown-item class="text-[#F56C6C]" :command="{ type: 'delete', data, node }">删除</el-dropdown-item>
+						</el-dropdown-menu>
+					</template>
+				</el-dropdown>
+			</template>
+		</el-tree>
+
+		<!--
+			   <div class="buttons">
+				   <el-button @click="getCheckedNodes">get by node</el-button>
+				   <el-button @click="getCheckedKeys">get by key</el-button>
+				   <el-button @click="setCheckedNodes">set by node</el-button>
+				   <el-button @click="setCheckedKeys">set by key</el-button>
+				   <el-button @click="resetChecked">reset</el-button>
+			   </div>
+		   -->
+	</div>
+</template>
+<script setup name="search">
+import { ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import request,{baseURL} from '@/utils/request'
+const emits = defineEmits(["currentChange", "checkChange", "refresh"]);
+const props = defineProps(
+	{
+		data: {
+			type: Array,
+			default: () => []
+		},
+		height: {
+			type: Number,
+			default: 400
+		},
+		showCheckbox: {
+			type: Boolean,
+			default: false
+		},
+	}
+);
+
+const treeRef = ref();
+const filterText = ref("");
+/**输入框过滤 */
+const funfilterChange = () => {
+	treeRef.value.filter(filterText.value);
+};
+const funTreeFilter = (value, data) => {
+	if (!value) return true;
+	return data.label.includes(value);
+};
+/**选中节点变化 */
+const funCurrentChange = (current, currentNode) => {
+	emits("currentChange", { current, currentNode });
+};
+/**复选框选中变化 */
+const funCheckChange = (
+	current,
+	{ checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys }
+) => {
+	emits("checkChange", {
+		current,
+		checkedNodes,
+		checkedKeys,
+		halfCheckedNodes,
+		halfCheckedKeys,
+	});
+};
+//右键时, command菜单
+const funCommand = async ({ type, data, node }) => {
+	switch (type) {
+		case "export":
+			ElMessageBox.confirm("确认导出当前节点的所有数据?", "导出", {
+				confirmButtonText: "确认",
+				cancelButtonText: "取消",
+				type: "warning",
+			}).then(() => {
+				const a = document.createElement("a");
+				const childs = data.childs.map((o) => o.id);
+				a.href =
+					baseURL + "/data/option/download?ids=" + childs.join(",");
+				a.download = "";
+				a.click();
+			});
+			break;
+		case "delete":
+			ElMessageBox.confirm("确认删除当前节点的所有数据?", "删除", {
+				confirmButtonText: "确认",
+				cancelButtonText: "取消",
+				type: "warning",
+			}).then(async () => {
+				let deleteArr = [];
+				const repeatArr = (arr, deleteArr) => {
+					for (const unit of arr) {
+						if (unit.childs?.length) {
+							deleteArr.push(...unit.childs.map((o) => o.id));
+						} else if (unit.children?.length) {
+							repeatArr(unit.children, deleteArr);
+						}
+					}
+				};
+				if (data.childs?.length) {
+					deleteArr = data.childs.map((o) => o.id);
+				} else if (data.children?.length) {
+					repeatArr(data.children, deleteArr);
+				}
+				const res = await request.get("/data/option/delete", {
+					params: { ids: deleteArr.join(",") },
+				}); //删除当前节点
+				if (res.code === 200) {
+					ElMessage.success(res.msg);
+					emits("refresh");
+				}
+			});
+
+			break;
+	}
+};
+
+const getCheckedNodes = () => {
+	console.log(treeRef.value.getCheckedNodes(false, false));
+};
+const getCheckedKeys = () => {
+	console.log(treeRef.value.getCheckedKeys(false));
+};
+const setCheckedNodes = () => {
+	treeRef.value.setCheckedNodes(
+		[
+			{
+				id: 5,
+				label: "Level two 2-1",
+			},
+			{
+				id: 9,
+				label: "Level three 1-1-1",
+			},
+		],
+		false
+	);
+};
+const setCheckedKeys = () => {
+	treeRef.value.setCheckedKeys([3], false);
+};
+const resetChecked = () => {
+	treeRef.value.setCheckedKeys([], false);
+};
+
+const defaultProps = {
+	children: "children",
+	label: "label",
+};
+</script>

+ 10 - 0
src/data/areaData.json

@@ -0,0 +1,10 @@
+{
+    "msg": "成功",
+    "code": 200,
+    "data": {
+	"pcl5": 0.65,
+	"pcl10": 0.65,
+	"pcl12": 0.65,
+	"pcl25": 0.65
+     }   
+}

文件差異過大導致無法顯示
+ 1 - 0
src/data/dot.json


+ 33 - 0
src/data/flower.json

@@ -0,0 +1,33 @@
+{
+	"msg": "成功",
+	"code": 200,
+	"data": [{
+		"count": [
+			[13, 8, 10, 13, 21, 41, 105, 129, 138, 102, 50, 11, 20, 14, 22, 16],
+			[16, 20, 10, 7, 6, 16, 126, 720, 1062, 262, 46, 10, 5, 12, 8, 7],
+			[0, 0, 0, 0, 0, 4, 30, 390, 448, 88, 4, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 9, 69, 99, 19, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 1, 1, 30, 31, 4, 1, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 2, 7, 11, 2, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+		],
+		"wt": "NG01_01",
+		"roses": [
+			[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+			[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+			[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+		]
+	}]
+}

文件差異過大導致無法顯示
+ 14211 - 0
src/data/lineNew.json


文件差異過大導致無法顯示
+ 1513 - 0
src/data/table.json


文件差異過大導致無法顯示
+ 16830 - 0
src/element-theme/index-white.scss


文件差異過大導致無法顯示
+ 16884 - 0
src/element-theme/index.scss


+ 1 - 0
src/helper/README.md

@@ -0,0 +1 @@
+# 仅用于处理数据 例如时间日期格式化 生成GUID 单位处理等

+ 9 - 0
src/helper/data.js

@@ -0,0 +1,9 @@
+
+const get = name => {
+    let json = require(`@/assets/dataService/${name}.json`);
+    return json;
+}
+
+export default {
+    get
+}

+ 26 - 0
src/helper/partten.js

@@ -0,0 +1,26 @@
+// Color 常量
+const color = [
+    { key: "green", value: "#05BB4C" },
+    { key: "yellow", value: "#F8DE5B" },
+    { key: "gray", value: "#606769" },
+    { key: "grayl", value: "#B3BDC0" },
+    { key: "purple", value: "#4B55AE" },
+    { key: "orange", value: "#e17e23" },
+    { key: "blue", value: "#1a93cf" },
+    { key: "red", value: "#BA3237" },
+    { key: "pink", value: "#c531c7" },
+	{ key: "cyan", value: "#1cbbb4" },
+	{ key: "brown", value: "#a5673f" },
+	{ key: "mauve", value: "#9c26b0" },
+	{ key: "deepblue", value: "#36348e" },
+];
+
+function getColor(key) {
+	if(!color.some(ele=>{ return ele.key === key })) key = "green";
+    return color.find((t) => { return t.key == key }).value;
+}
+
+export default {
+    color,
+    getColor
+}

+ 28 - 0
src/helper/util.js

@@ -0,0 +1,28 @@
+
+// 新建GUID
+const newGUID = () => {
+    let d = new Date().getTime();
+    let uid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
+        let r = (d + Math.random() * 16) % 16 | 0;
+        d = Math.floor(d / 16);
+        return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
+    });
+    return uid;
+}
+
+const copy = (obj) => {
+    return JSON.parse(JSON.stringify(obj));
+}
+
+
+
+// px to vh
+const vh = function (px) {
+    return window.innerHeight * px / 1080;
+}
+
+export default {
+    newGUID,
+    copy,
+    vh
+}

+ 69 - 0
src/main.js

@@ -0,0 +1,69 @@
+import {
+	createApp
+} from "vue";
+import App from "./App.vue";
+import router from "./router";
+import store from "./store";
+import "font-awesome/css/font-awesome.min.css";
+// 引入 element-ui
+import ElementPlus from "element-plus";
+import 'windi.css'
+// 引入element 自定义css
+import 'element-plus/dist/index.css'
+import "./element-theme/index.scss"; 
+import locale from "element-plus/lib/locale/lang/zh-cn";
+import * as ElementPlusIconsVue from '@element-plus/icons-vue'
+import axios from 'axios'
+//引入字体
+import '../public/css/font.css'
+import { ElMessage } from 'element-plus'
+const app = createApp(App)
+/**阻止多次重复点击指令  延时暂定5秒 示例 v-prevdbclick:arg='func' */
+const messageToast = () => { //作为eventListener时, 必须使用外部定义函数
+	ElMessage.error('5秒内请勿重复点击')
+}
+const funListener = (el, binding) => {
+	let time = null
+	el.removeEventListener('click', messageToast)
+	el.addEventListener('click', () => {
+		binding.value()
+		el.addEventListener('click', messageToast, false)
+		time = setTimeout(() => {
+			clearTimeout(time)
+			funListener(el, binding)
+		}, Number(binding.arg) || 5000)
+	}, {
+		once: true
+	})
+}
+Date.prototype.formatDate = function (fmt) {
+    let o = {
+      "M+": this.getMonth() + 1, //月份 
+      "d+": this.getDate(), //日 
+      "h+": this.getHours(), //小时 
+      "m+": this.getMinutes(), //分 
+      "s+": this.getSeconds(), //秒 
+      "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
+      "S": this.getMilliseconds() //毫秒 
+    };
+    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+    for (let k in o)
+      if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+    return fmt;
+  }
+app.directive('prevdbclick', {
+	mounted(el, binding) {
+		funListener(el, binding)
+	}
+})
+for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+	app.component(key, component)
+}
+app.config.globalProperties.$axios = axios;
+window.__STATICVUE__ = app;
+window.__STATICVUE__.use(ElementPlus, {
+	locale
+});
+window.__STATICVUE__.use(store);
+window.__STATICVUE__.use(router);
+window.__STATICVUE__.mount('#app');

+ 32 - 0
src/registerServiceWorker.js

@@ -0,0 +1,32 @@
+/* eslint-disable no-console */
+
+import { register } from 'register-service-worker'
+
+if (process.env.NODE_ENV === 'production') {
+  register(`${process.env.BASE_URL}service-worker.js`, {
+    ready () {
+      console.log(
+        'App is being served from cache by a service worker.\n' +
+        'For more details, visit https://goo.gl/AFskqB'
+      )
+    },
+    registered () {
+      console.log('Service worker has been registered.')
+    },
+    cached () {
+      console.log('Content has been cached for offline use.')
+    },
+    updatefound () {
+      console.log('New content is downloading.')
+    },
+    updated () {
+      console.log('New content is available; please refresh.')
+    },
+    offline () {
+      console.log('No internet connection found. App is running in offline mode.')
+    },
+    error (error) {
+      console.error('Error during service worker registration:', error)
+    }
+  })
+}

+ 399 - 0
src/router/index.js

@@ -0,0 +1,399 @@
+import { createRouter, createWebHashHistory  } from 'vue-router'
+
+const routes = [
+    {
+        path: '/dataFilter',
+        redirect:'/dataFilter/prepare',
+        name: 'dataFilter',
+        meta: {
+            title: '数据准备',
+            icon: 'icon-Simple-matrix'
+        },
+        children: [
+            {
+                path: 'prepare',
+                component: () => import('@/views/dataFilter/prepare/index'),
+                name: 'dataFilterPrepare',
+                meta: {
+                    title: '数据准备',
+                    icon: ''
+                },
+            },
+            {
+                path: 'process',
+                component: () => import('@/views/dataFilter/process/index'),
+                name: 'dataFilterProcess',
+                meta: {
+                    title: '数据预处理',
+                    icon: ''
+                },
+            },
+        ]
+    },
+    {
+        path: '/dataAnalysis',
+        redirect:'/dataAnalysis/combine',
+        name: 'dataAnalysis',
+        meta: {
+            title: '数据分析',
+            icon: 'icon-Simple-matrix'
+        },
+        children: [
+            {
+                path: 'combine',
+                component: () => import('@/views/dataFilter/combine/index'),
+                name: 'dataFilterCombine',
+                meta: {
+                    title: '功率曲线拟合分析',
+                    icon: ''
+                },
+            },
+            {
+                path: 'rateAnalysis',
+                component: () => import('@/views/curveDeviation/rateAnalysis/index'),
+                name: 'dataFilterRateAnalysis',
+                meta: {
+                    title: '风资源分析',
+                    icon: ''
+                },
+            },
+            {
+                path: 'lineAnalysis',
+                component: () => import('@/views/dataFilter/lineAnalysis/index'),
+                name: 'dataFilterLineAnalysis',
+                meta: {
+                    title: '曲线偏差率分析',
+                    icon: ''
+                },
+            },
+        ]
+    },
+    // {
+    //     path: '/',
+    //     component: () => import('@/views/Home'),
+    //     name: 'Home',
+    //     meta: {
+    //         title: '首页',
+    //         icon: ''
+    //     }
+    // },
+    //     {
+    //         path: '/stateMonitor',
+    //         redirect:'/stateMonitor/simpleMatrix',
+    //         component: () => import('@/views/stateMonitor'),
+    //         name: 'stateMonitor',
+    //         meta: {
+    //             title: '安全监控',
+    //             icon: ''
+    //         },
+    //         children:[
+    //             {
+    //                 path: 'simpleMatrix',
+    //                 component: () => import('@/views/stateMonitor/simpleMatrix'),
+    //                 name: 'simpleMatrix',
+    //                 meta: {
+    //                     title: '基础矩阵',
+    //                     icon: 'icon-Simple-matrix'
+    //                 }
+    //             },
+    //             {
+    //                 path: 'detailMatrix',
+    //                 component: () => import('@/views/stateMonitor/detailMatrix'),
+    //                 name: 'detailMatrix',
+    //                 meta: {
+    //                     title: '明细矩阵',
+    //                     icon: 'icon-Detailed-matrix'
+    //                 }
+    //             },
+    //             {
+    //                 path: 'factoryMonitor',
+    //                 redirect:'factoryMonitor/facHome',
+    //                 component: () => import('@/views/stateMonitor/factoryMonitor'),
+    //                 name: 'factoryMonitor',
+    //                 meta: {
+    //                     title: '厂站监视',
+    //                     icon: 'icon-Single-station-surveillance'
+    //                 },
+    //                 children:[
+    //                     {
+    //                         path: 'facHome',
+    //                         // redirect:'facHome/home',
+    //                         component: () => import('@/views/stateMonitor/factoryMonitor/facHome'),
+    //                         name: 'facHome',
+    //                         meta: {
+    //                             title: '首页',
+    //                             icon: ''
+    //                         },
+    //                         children:[{
+    //                             path: 'dataDetial',
+    //                             component: () => import('@/views/stateMonitor/factoryMonitor/facHome/dataDetial'),
+    //                             name: 'dataDetial',
+    //                             meta: {
+    //                                 title: '',
+    //                                 icon: ''
+    //                             },
+    //                         },
+    //                             {
+    //                                 path: 'home',
+    //                                 component: () => import('@/views/stateMonitor/factoryMonitor/facHome/home'),
+    //                                 name: 'home',
+    //                                 meta: {
+    //                                     title: '',
+    //                                     icon: ''
+    //                                 },
+    //                             },
+    //                         ]
+    //                     },
+    //                     {
+    //                     path: 'windPowerPlant',
+    //                     component: () => import('@/views/stateMonitor/factoryMonitor/windPowerPlant'),
+    //                     name: 'windPowerPlant',
+    //                     meta: {
+    //                         title: '风电场站',
+    //                         icon: ''
+    //                     },
+    //                 },
+    //                     {
+    //                         path: 'photovoltaic',
+    //                         component: () => import('@/views/stateMonitor/factoryMonitor/photovoltaic'),
+    //                         name: 'photovoltaic',
+    //                         meta: {
+    //                             title: '光伏场站',
+    //                             icon: ''
+    //                         },
+    //                     }
+    //                 ]
+    //             },
+    //             {
+    //                 path: 'synthesizeTargetSystem',
+    //                 component: () => import('@/views/stateMonitor/synthesizeTargetSystem'),
+    //                 name: 'synthesizeTargetSystem',
+    //                 meta: {
+    //                     title: '综合指标',
+    //                     icon: 'icon-Composite-indicator'
+    //                 }
+    //             },
+    //             {
+    //                 path: 'AGCMonitor',
+    //                 component: () => import('@/views/stateMonitor/AGCMonitor'),
+    //                 name: 'AGCMonitor',
+    //                 meta: {
+    //                     title: 'AGC监视',
+    //                     icon: 'icon-Composite-indicator'
+    //                 }
+    //             },
+    //             {
+    //                 path: 'monitorState',
+    //                 component: () => import('@/views/stateMonitor/monitorState'),
+    //                 name: 'monitorState',
+    //                 meta: {
+    //                     title: '运行状态',
+    //                     icon: 'icon-State-monitoring'
+    //                 }
+    //             }
+    //         ]
+    //     },
+    //     {
+    //         path: '/economicsOperation',
+    //         redirect:'/economicsOperation/homePage',
+    //         component: () => import('@/views/economicsOperation'),
+    //         name: 'economicsOperation',
+    //         meta: {
+    //             title: '经济运行',
+    //             icon: ''
+    //         },
+    //         children: [
+    //             {
+    //                 path: 'homePage',
+    //                 component: () => import('@/views/economicsOperation/homePage'),
+    //                 name: 'homePage',
+    //                 meta: {
+    //                     title: '首页',
+    //                     icon: 'icon-Simple-matrix'
+    //                 }
+    //             },
+    //             {
+    //                 path: 'benchmarkingManagement',
+    //                 redirect:'benchmarkingManagement/performanceRankingList',
+    //                 component: () => import('@/views/economicsOperation/benchmarkingManagement'),
+    //                 name: 'benchmarkingManagement',
+    //                 meta: {
+    //                     title: '对标管理',
+    //                     icon: 'icon-Simple-matrix'
+    //                 },
+    //                 children: [
+    //                     {
+    //                     path: 'performanceRankingList',
+    //                     component: () => import('@/views/economicsOperation/benchmarkingManagement/performanceRankingList'),
+    //                     name: 'performanceRankingList',
+    //                     meta: {
+    //                         title: '风机绩效榜',
+    //                         icon: ''
+    //                     },
+    //                 },
+    //                 {
+    //                     path: "/benchmarkingManagement/decision1Mx", //风机绩效榜明细
+    //                     name: "benchmarkingManagement",
+    //                     component: () =>
+    //                         import( /* webpackChunkName: "decision1Mx" */ "@/views/economicsOperation/benchmarkingManagement/performanceRankingList/decision1Mx"),
+    //                 },
+    //                     {
+    //                     path: 'loseRate',
+    //                     component: () => import('@/views/economicsOperation/benchmarkingManagement/loseRate'),
+    //                     name: 'loseRate',
+    //                     meta: {
+    //                         title: '五项损失率',
+    //                         icon: ''
+    //                     },
+    //                 },
+    //                     {
+    //                     path: 'companyBenchmarking',
+    //                     component: () => import('@/views/economicsOperation/benchmarkingManagement/companyBenchmarking'),
+    //                     name: 'companyBenchmarking',
+    //                     meta: {
+    //                         title: '公司对标',
+    //                         icon: ''
+    //                     },
+    //                 },
+    //                     {
+    //                     path: 'siteBenchmarking',
+    //                     component: () => import('@/views/economicsOperation/benchmarkingManagement/siteBenchmarking'),
+    //                     name: 'siteBenchmarking',
+    //                     meta: {
+    //                         title: '场内对标',
+    //                         icon: ''
+    //                     },
+    //                 },
+    //                     {
+    //                     path: 'intervalBenchmarking',
+    //                     component: () => import('@/views/economicsOperation/benchmarkingManagement/intervalBenchmarking'),
+    //                     name: 'intervalBenchmarking',
+    //                     meta: {
+    //                         title: '场际对标',
+    //                         icon: ''
+    //                     },
+    //                 },
+    //                     {
+    //                         path: 'projectBenchmarking',
+    //                         component: () => import('@/views/economicsOperation/benchmarkingManagement/projectBenchmarking'),
+    //                         name: 'projectBenchmarking',
+    //                         meta: {
+    //                             title: '项目对标',
+    //                             icon: ''
+    //                         },
+    //                     },
+    //                     {
+    //                         path: 'wiringBenchmarking',
+    //                         component: () => import('@/views/economicsOperation/benchmarkingManagement/wiringBenchmarking'),
+    //                         name: 'wiringBenchmarking',
+    //                         meta: {
+    //                             title: '线路对标',
+    //                             icon: ''
+    //                         },
+    //                     },{
+    //                         path: 'standAloneBenchmarking',
+    //                         component: () => import('@/views/economicsOperation/benchmarkingManagement/standAloneBenchmarking'),
+    //                         name: 'standAloneBenchmarking',
+    //                         meta: {
+    //                             title: '单机对标',
+    //                             icon: ''
+    //                         },
+    //                     }]
+    //             },
+    //             {
+    //                 path: 'efficiency',
+    //                 redirect:'efficiency/restorationEfficiency',
+    //                 component: () => import('@/views/economicsOperation/efficiency'),
+    //                 name: 'efficiency',
+    //                 meta: {
+    //                     title: '三率',
+    //                     icon: 'icon-Simple-matrix'
+    //                 },
+    //                 children: [
+    //                     {
+    //                         path: 'restorationEfficiency',
+    //                         component: () => import('@/views/economicsOperation/efficiency/restorationEfficiency'),
+    //                         name: 'restorationEfficiency',
+    //                         meta: {
+    //                             title: '复位及时率',
+    //                             icon: ''
+    //                         },
+    //                     },
+    //                     {
+    //                         path: 'consumeEfficiency',
+    //                         component: () => import('@/views/economicsOperation/efficiency/consumeEfficiency'),
+    //                         name: 'consumeEfficiency',
+    //                         meta: {
+    //                             title: '消缺及时率',
+    //                             icon: ''
+    //                         },
+    //                     },
+    //                     {
+    //                         path: 'stateEfficiency',
+    //                         component: () => import('@/views/economicsOperation/efficiency/stateEfficiency'),
+    //                         name: 'stateEfficiency',
+    //                         meta: {
+    //                             title: '状态转换率',
+    //                             icon: ''
+    //                         },
+    //                     }
+    //                 ]
+    //             },
+    //             {
+    //                 path: 'performanceAnalyse',
+    //                 redirect:'performanceAnalyse/standAloneAnalyse',
+    //                 component: () => import('@/views/economicsOperation/performanceAnalyse'),
+    //                 name: 'performanceAnalyse',
+    //                 meta: {
+    //                     title: '性能分析',
+    //                     icon: 'icon-Simple-matrix'
+    //                 },
+    //                 children: [
+    //                     {
+    //                         path: 'standAloneAnalyse',
+    //                         component: () => import('@/views/economicsOperation/performanceAnalyse/standAloneAnalyse'),
+    //                         name: 'standAloneAnalyse',
+    //                         meta: {
+    //                             title: '单机性能分析',
+    //                             icon: ''
+    //                         },
+    //                     },
+    //                     {
+    //                         path: 'monthlyAnalysis',
+    //                         component: () => import('@/views/economicsOperation/performanceAnalyse/monthlyAnalysis'),
+    //                         name: 'monthlyAnalysis',
+    //                         meta: {
+    //                             title: '单机月度分析',
+    //                             icon: ''
+    //                         },
+    //                     },
+    //                     {
+    //                         path: 'performanceAssess',
+    //                         component: () => import('@/views/economicsOperation/performanceAnalyse/performanceAssess'),
+    //                         name: 'performanceAssess',
+    //                         meta: {
+    //                             title: '性能等级评估',
+    //                             icon: ''
+    //                         },
+    //                     },
+    //                     {
+    //                         path: 'cutInAndOutAnalysis',
+    //                         component: () => import('@/views/economicsOperation/performanceAnalyse/cutInAndOutAnalysis'),
+    //                         name: 'cutInAndOutAnalysis',
+    //                         meta: {
+    //                             title: '切入切出分析',
+    //                             icon: ''
+    //                         },
+    //                     }
+    //                 ]
+    //             }
+    //         ]
+    //     }
+]
+
+const router = createRouter({
+  history: createWebHashHistory(),
+  routes
+})
+
+export default router

+ 23 - 0
src/store/index.js

@@ -0,0 +1,23 @@
+import { createStore } from 'vuex'
+
+// 创建一个新的 store 实例
+const store = createStore({
+     // 值的存储  获取: this.$store.state.xxxx
+     state() {
+          return {
+              
+          }
+     },
+
+     //计算state的值  获取: this.$store.getters.xxxx
+     getters: {
+         
+     },
+
+     // 数据更新 使用: this.$store.commit('函数名','val')
+     mutations: {
+     
+     }
+})
+
+export default store

+ 279 - 0
src/tools/basicTool.js

@@ -0,0 +1,279 @@
+let loadingStatus = null;
+
+import {
+    ElMessage,
+    ElLoading,
+} from "element-plus";
+
+export default {
+    /**
+     * 页面顶部出现消息提示
+     * @param {Object} options 传入一个对象为配置项,其中:
+     * @param {Boolean} showClose 是否显示可手动关闭的 x 于提示框右侧,默认 false
+     * @param {Boolean} center 消息提示内容是否居中,默认 true
+     * @param {String} msg 消息提示的内容
+     * @param {String} type 消息提示的类型,可选值为 ['success(成功)','warning(警告)','error(错误)',或者直接传入空字符串],默认 error
+     */
+    showMsg(options) {
+        ElMessage({
+            showClose: (options.showClose == true || options.showClose == false) ? options.showClose : false,
+            center: (options.center == true || options.center == false) ? options.center : true,
+            message: options.msg,
+            type: (options.type || options.type === '') ? options.type : 'error'
+        });
+    },
+
+    /**
+     * 显示防穿透点击 loading 蒙版
+     * @param {Objectr} opt 传入一个对象为配置项,其中:
+     * @param {String} target 此蒙版需要绑定的 DOM 标签 ID 或者 CLASS 或者 TAGNAME,默认绑在 body 上
+     * @param {Boolean} body 是否插入蒙版至 boyd 上,默认 true
+     * @param {Boolean} fullscreen 蒙版是否全屏蒙住整个 html 页面,默认 true
+     * @param {Boolean} lock 蒙版出现时,是否锁定屏幕滚动,默认 false
+     * @param {String} text 蒙版上显示的提示文本
+     * @param {String} background 蒙版的背景颜色,写死 50% 透明度的纯黑色
+     */
+    showLoading(opt) {
+        let options = opt || {};
+        loadingStatus = ElLoading.service({
+            target: options.target || 'body',
+            body: (options.body == true || options.body == false) ? options.body : false,
+            fullscreen: (options.fullscreen == true || options.fullscreen == false) ? options.fullscreen : true,
+            lock: (options.lock == true || options.lock == false) ? options.lock : false,
+            text: options.text || '请稍等...',
+            background: 'rgba(0,0,0,.5)',
+        });
+    },
+
+    /**
+     * 获取标签上的自定义属性
+     * @param {any} node 传入 字符串 或 标准DOM对象 或 jQuery DOM对象 ,函数自动判断传入的类型并返回其 dataset 属性。
+     */
+    getCurrentData(node) {
+        // 如果传入的是 jQuery 对象
+        if (window.jQuery && node instanceof jQuery) {
+            return node[0].dataset;
+        } else {
+            // 判断传入的是否是标准 DOM 对象
+            let isDom = (typeof node === 'object') ?
+                function (obj) {
+                    return obj instanceof HTMLElement;
+                } :
+                function (obj) {
+                    return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
+                };
+
+            // 如果是标准 DOM 对象,输出 dataset
+            if (isDom(node)) {
+                return node.dataset;
+            } else {
+                // 如果是不是,则表示传入的是字符串,根据字符串取 DOM 后输出 dataset
+                let dom = document.querySelector(node);
+                return dom.dataset;
+            }
+        }
+    },
+
+    /**
+     * 关闭loading
+     */
+    closeLoading() {
+        loadingStatus?.close();
+    },
+
+    /**
+     * 深拷贝 json 数组
+     * @param {Array} jsonArray 传入 Json 数组,返回一个指向新指针拷贝份数据
+     */
+    deepCopy(jsonArray) {
+        return JSON.parse(JSON.stringify(jsonArray));
+    },
+
+    /**
+     * 根据后端返回的 ID 遍历树形结构包装组件编辑用数据函数
+     * @param {String} key 需要找到的 ID
+     * @param {Array} treeData 树形 Array
+     */
+    getTreeDeepArr(key, treeData) {
+
+        let arr = []; // 在递归时操作的数组
+        let returnArr = []; // 存放结果的数组
+        let depth = 0; // 定义全局层级
+
+        // 定义递归函数
+        function childrenEach(childrenData, depthN) {
+
+            for (var j = 0; j < childrenData.length; j++) {
+
+                depth = depthN; // 将执行的层级赋值 到 全局层级
+                arr[depthN] = (childrenData[j].id);
+
+                if (childrenData[j].id == key) {
+
+                    // returnArr = arr; // 原写法不行, 因 此赋值存在指针关系
+                    returnArr = arr.slice(0, depthN + 1); //将目前匹配的数组,截断并保存到结果数组
+                    break;
+
+                } else {
+
+                    if (childrenData[j].children) {
+
+                        depth++;
+                        childrenEach(childrenData[j].children, depth);
+
+                    }
+
+                }
+
+            }
+
+            return returnArr;
+
+        }
+
+        return childrenEach(treeData, depth);
+
+    },
+
+    /**
+     * 获取数据的类型
+     * @param {any} options 传入一个数据,返回其类型 (object, array, string, number等)
+     */
+    getType(options) {
+        return Object.prototype.toString.call(options).slice(8, Object.prototype.toString.call(options).length - 1).toLowerCase();
+    },
+
+    /**
+     * 控制页面滚动到指定位置
+     * @param {Object} options 传入一个配置项,其中:
+     * @param {String} el 需要滚动的 DOM 元素选择器,可以为 CLASS 或 ID
+     * @param {Number} scrollTop 需要滚动到顶部的位置,数值越低滚动的越靠近顶部,默认 0
+     * @param {Number} scrollLeft 需要滚动到顶部的位置,数值越低滚动的越靠近顶部,默认 0
+     * @param {Number} speed 滚动到指定位置需要的时间 (动画时间),默认 200
+     * @param {Function} success 滚动执行完毕后的回调函数
+     */
+    scrollTo(options) {
+        if (!options || !options.el) {
+            this.showMsg({
+                msg: 'scrollTo() 方法需要传入 el 属性'
+            });
+            return;
+        }
+        if ($(options.el)[0] && ($(options.el)[0].scrollHeight > (window.innerHeight || document.documentElement.clientHeight))) {
+            $(options.el).animate({
+                scrollTop: options.scrollTop || 0,
+                scrollLeft: options.scrollLeft || 0,
+            }, options.speed || 200, () => {
+                options.success && options.success();
+            });
+        } else {
+            options.success && options.success();
+        }
+    },
+
+
+
+    // JS 触发全屏功能
+    requestFullscreen() {
+        //全屏
+        const docElm = document.documentElement;
+        //W3C
+        if (docElm.requestFullscreen) {
+            docElm.requestFullscreen();
+        }
+
+        //FireFox
+        else if (docElm.mozRequestFullScreen) {
+            docElm.mozRequestFullScreen();
+        }
+
+        //Chrome等
+        else if (docElm.webkitRequestFullScreen) {
+            docElm.webkitRequestFullScreen();
+        }
+
+        //IE11
+        else if (docElm.msRequestFullscreen) {
+            docElm.msRequestFullscreen();
+        }
+    },
+
+    /**
+     * 颜色进制转换  16 <--> 10 互转
+     * @param {String} colorStr 传入一个颜色字符串, 16进制 或者 10进制 ,返回转换后的结果,例:传入 #1890ff ,返回 rgb(24, 144, 255),反之亦然
+     */
+    replaceColor(colorStr) {
+        if (!colorStr) return '';
+
+        let colorString = colorStr.replace(/#|rgb|\(|\)|\|;|\s+/g, "");
+
+        if (colorString.indexOf(",") === -1) {
+            let color10 = [];
+            for (let i = 0; i < colorString.length; i++) {
+                if (!((i + 1) % 2)) {
+                    color10.push(parseInt((colorString[i - 1] + colorString[i]), 16));
+                }
+            }
+            return "rgb(" + color10.toString() + ")";
+        } else {
+            let colorArray = colorString.split(',');
+            let color16 = '';
+            colorArray.forEach(ele => {
+                color16 += (parseInt(ele).toString(16));
+            });
+            return "#" + color16;
+        }
+    },
+
+    // 正则表达式
+    regs: {
+        // 是否为手机号
+        isPhone: /^1(3|4|5|6|7|8|9)\d{9}$/,
+        // 是否为合法 15 或 18 位身份证号
+        isIdentityCard: /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/,
+        // 是否是邮箱
+        isMail: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/,
+        // 是否是数字
+        isNumber: /^(-?\d+)(\.\d+)?$/
+    },
+
+    elCkeck: {
+        isNumber(rule, value, callback) {
+            if (value === '') {
+                callback(new Error('该值不可为空'));
+            } else if (!/^(-?\d+)(\.\d+)?$/.test(value)) {
+                callback(new Error('输入有误,仅支持输入数字'));
+            } else {
+                callback();
+            }
+        },
+        validatePass(rule, value, callback) {
+            let strength = 0;
+            // const reg = /(?=.*[0-9])|(?=.*[a-z])|(?=.*[A-Z])|(?=.*[\~\!\@\#\$\%\^\&\*\(\)\_\+\-\=\[\]\{\}\\\|\:\"\;\'\<\>\,\.\?\/\x22])/;
+            const reg = ".*[!@*#$\-_()+=&¥^<>~`].*";
+            if (value.length >= 8) {
+                if (/\d/.test(value)) {
+                    strength++;
+                }
+                if (/[a-z]/.test(value)) {
+                    strength++;
+                }
+                if (/[A-Z]/.test(value)) {
+                    strength++;
+                }
+                if (/.*[!@*#$\-_()+=&¥^<>~`].*/.test(value)) {
+                    strength++;
+                }
+                if (strength < 3) {
+                    // 密码种类少于 3 类
+                    callback(new Error("密码至少包含数字、小写字母、大写字母、特殊字符中的三种"));
+                }else{
+                    callback();
+                }
+            } else {
+                // 密码为空
+                callback(new Error("密码必须至少8位"));
+            }
+        }
+    }
+}

+ 12 - 0
src/tools/excel/exportExcel.js

@@ -0,0 +1,12 @@
+// 导出的方法  tHeader => 设置Excel的表格第一行的标题  filterVal => 对象的属性key值 被导出listData => 导出数据  => 导出(文件)名称
+import { export_json_to_excel } from "/@/assets/excel/Export2Excel"; //引入文件
+
+export function outExportExcel(tHeader = [], filterVal = [], listData = [], exportName = new Date().getTime()) {
+    // 注意这个Export2Excel路径
+    const data = formatJson(filterVal, listData);
+    export_json_to_excel(tHeader, data, exportName);
+}
+
+function formatJson(filterVal, jsonData) {
+    return jsonData.map(v => filterVal.map(j => v[j]))
+}

+ 36 - 0
src/tools/export-word.js

@@ -0,0 +1,36 @@
+const Export2Word = (elementStr, filename = '') => {
+  var preHtml = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'><head><meta charset='utf-8'><title>Export HTML To Doc</title></head><body>";
+  var postHtml = "</body></html>";
+  var html = preHtml + elementStr + postHtml;
+
+  var blob = new Blob(['\ufeff', html], {
+    type: 'application/msword'
+  });
+
+  // Specify link url
+  var url = 'data:application/vnd.ms-word;charset=utf-8,' + encodeURIComponent(html);
+
+  // Specify file name
+  filename = filename ? filename + '.doc' : 'document.doc';
+
+  // Create download link element
+  var downloadLink = document.createElement("a");
+
+  document.body.appendChild(downloadLink);
+
+  if (navigator.msSaveOrOpenBlob) {
+    navigator.msSaveOrOpenBlob(blob, filename);
+  } else {
+    // Create a link to the file
+    downloadLink.href = url;
+
+    // Setting the file name
+    downloadLink.download = filename;
+
+    //triggering the function
+    downloadLink.click();
+  }
+
+  document.body.removeChild(downloadLink);
+}
+export default Export2Word

+ 101 - 0
src/tools/htmlToPdf.js

@@ -0,0 +1,101 @@
+import html2canvas from 'html2canvas';
+import JsPDF from 'jspdf';
+
+/**
+ * @param  ele          要生成 pdf 的DOM元素(容器)
+ * @param  padfName     PDF文件生成后的文件名字
+ * */
+
+function downloadPDF(ele, pdfName) {
+    // debugger
+    ele.style.background = '#000'
+
+    let eleW = ele.offsetWidth; // 获得该容器的宽
+    let eleH = ele.offsetHeight; // 获得该容器的高
+
+
+    let eleOffsetTop = ele.offsetTop+50; // 获得该容器到文档顶部的距离
+    let eleOffsetLeft = ele.offsetLeft; // 获得该容器到文档最左的距离
+
+    var canvas = document.createElement("canvas");
+    var abs = 0;
+
+    let win_in = document.documentElement.clientWidth || document.body.clientWidth; // 获得当前可视窗口的宽度(不包含滚动条)
+    let win_out = window.innerWidth; // 获得当前窗口的宽度(包含滚动条)
+
+    if (win_out > win_in) {
+        // abs = (win_o - win_i)/2;    // 获得滚动条长度的一半
+        abs = (win_out - win_in) / 2; // 获得滚动条宽度的一半
+        // console.log(a, '新abs');
+    }
+
+    canvas.width = eleW * 2; // 将画布宽&&高放大两倍
+    canvas.height = eleH * 2;
+
+
+
+
+    var context = canvas.getContext("2d");
+
+    context.scale(2, 2);
+
+    context.translate(-eleOffsetLeft - abs, -eleOffsetTop);
+    // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
+    // translate的时候,要把这个差值去掉
+
+    // html2canvas(element).then( (canvas)=>{ //报错
+    // html2canvas(element[0]).then( (canvas)=>{
+    html2canvas(ele, {
+        dpi: 300,
+        scale: 2,
+        // allowTaint: true,  //允许 canvas 污染, allowTaint参数要去掉,否则是无法通过toDataURL导出canvas数据的
+        useCORS: true //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
+    }).then((canvas) => {
+
+        var contentWidth = canvas.width;
+        var contentHeight = canvas.height;
+        //一页pdf显示html页面生成的canvas高度;
+        var pageHeight = contentWidth / 592.28 * 841.89;
+        //未生成pdf的html页面高度
+        var leftHeight = contentHeight;
+        //页面偏移
+        var position = 0;
+        //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
+        var imgWidth = 595.28;
+        var imgHeight = 595.28 / contentWidth * contentHeight;
+
+        var pageData = canvas.toDataURL('image/jpeg', 1.0);
+
+
+
+        var pdf = new JsPDF('', 'pt', 'a4');
+
+        //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
+        //当内容未超过pdf一页显示的范围,无需分页
+        if (leftHeight < pageHeight) {
+            //在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;
+            pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
+            // pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight);
+        } else { // 分页
+            while (leftHeight > 0) {
+                pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
+                leftHeight -= pageHeight;
+                position -= 841.89;
+                //避免添加空白页
+                if (leftHeight > 0) {
+                    pdf.addPage();
+                }
+            }
+        }
+
+        //可动态生成
+        pdf.save(pdfName);
+    })
+
+
+}
+
+
+export default {
+    downloadPDF
+}

文件差異過大導致無法顯示
+ 16 - 0
src/tools/js-xlsx.js


+ 26 - 0
src/tools/partten.js

@@ -0,0 +1,26 @@
+// Color 常量
+const color = [
+    { key: "green", value: "#05BB4C" },
+    { key: "yellow", value: "#F8DE5B" },
+    { key: "gray", value: "#606769" },
+    { key: "grayl", value: "#B3BDC0" },
+    { key: "purple", value: "#4B55AE" },
+    { key: "orange", value: "#e17e23" },
+    { key: "blue", value: "#1a93cf" },
+    { key: "red", value: "#BA3237" },
+    { key: "pink", value: "#c531c7" },
+	{ key: "cyan", value: "#1cbbb4" },
+	{ key: "brown", value: "#a5673f" },
+	{ key: "mauve", value: "#9c26b0" },
+];
+
+function getColor(key) {
+    if (!key)
+        key = "green"
+    return color.find((t) => { return t.key == key }).value;
+}
+
+export default {
+    color,
+    getColor
+}

+ 27 - 0
src/tools/util.js

@@ -0,0 +1,27 @@
+// 新建GUID
+const newGUID = () => {
+    let d = new Date().getTime();
+    let uid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
+        let r = (d + Math.random() * 16) % 16 | 0;
+        d = Math.floor(d / 16);
+        return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
+    });
+    return uid;
+}
+
+const copy = (obj) => {
+    return JSON.parse(JSON.stringify(obj));
+}
+
+
+
+// px to vh
+const vh = function(px) {
+    return window.innerHeight * px / 1080;
+}
+
+export default {
+    newGUID,
+    copy,
+    vh
+}

+ 47 - 0
src/utils/auth.js

@@ -0,0 +1,47 @@
+import Cookies from 'js-cookie'
+import dayjs from "dayjs";
+const timeKey = 'hrsaas-timestamp-key'
+// 设置时间戳的存储变量
+const TokenKey = 'hrsaas-ihrm-token'
+
+export function getToken() {
+    return Cookies.get(TokenKey)
+}
+// 本地存储token
+export function setToken(token) {
+    return Cookies.set(TokenKey, token)
+}
+// 本地删除token
+export function removeToken() {
+    return Cookies.remove(TokenKey)
+}
+// 获取时间戳
+export function getTimeStamp() {
+    return Cookies.get(timeKey)
+}
+// 设置时间戳
+export function setTimeStamp() {
+    return Cookies.set(timeKey, Date.now())
+}
+
+// 时间格式化
+export function parseTime(){
+    var myDate = new Date()
+    const formatObj = {
+        year: myDate.getFullYear(),
+        month: (myDate.getMonth() + 1)>=10 ? (myDate.getMonth()+1): '0'+(myDate.getMonth()+1),
+        day: myDate.getDate()>=10 ? myDate.getDate() :'0'+myDate.getDate(),
+    }
+return  formatObj.year+'-'+formatObj.month+'-'+formatObj.day;
+}
+//获取1天前时间
+export function getStampTime(){
+    let stamp1 = new Date(new Date().setHours(0, 0, 0, 0));
+    stamp1= dayjs(stamp1).format("YYYY-MM-DD HH:mm:ss")
+    let stamp2 = new Date(new Date().setHours(0, 0, 0, 0) + 24 * 60 * 60 * 1000);
+    stamp2= dayjs(stamp2).format("YYYY-MM-DD HH:mm:ss")
+    return {
+        startTime:stamp1,
+        endTime:stamp2
+    };
+}

+ 70 - 0
src/utils/downXlsx.js

@@ -0,0 +1,70 @@
+import  * as XLSX from 'xlsx'
+import { saveAs } from 'file-saver'
+import  * as XLSXD from 'xlsx-js-style'
+
+const exportExcel = (el, header, title) => {
+    let $e = el
+    try {
+        let $table = $e.querySelector('.el-table__fixed')
+        if(!$table) {
+            $table = $e
+        }
+        const wb = XLSX.utils.table_to_book($table, {raw:true})
+        if (wb && wb.Sheets.Sheet1) {
+            let as = ['!cols', '!fullref', '!merges', '!ref', '!rows']
+            let bs = header
+            for(let i in wb.Sheets.Sheet1) {
+                if (as.indexOf(i)<0) {
+                    if (bs.indexOf(wb.Sheets.Sheet1[i].v)>=0) {
+                        wb.Sheets.Sheet1[i].s = {
+                            font:{
+                                name: '微软雅黑',
+                                sz: 11,
+                                bold: true,
+                                color: {rgb: 'ffffff'}
+                            },
+                            alignment: {
+                                horizontal: 'center',
+                                vertical: 'center'
+                            },
+                            fill:{fgColor: {rgb: '4f81bd'}}
+                        }
+                        if (i === 'A1') {
+                            wb.Sheets.Sheet1['!cols'].push({wch: 30})
+                        } else if (i === 'B1') {
+                            wb.Sheets.Sheet1['!cols'].push({wch: 20})
+                        } else {
+                            wb.Sheets.Sheet1['!cols'].push({wch: 15})
+                        }
+                    } else {
+                        wb.Sheets.Sheet1[i].s = {
+                            font:{
+                                name: '微软雅黑',
+                                sz: 10,
+                                bold: false,
+                                color: {rgb: '000000'}
+                            },
+                            alignment: {
+                                horizontal: 'center',
+                                vertical: 'center'
+                            },
+                            // fill:{fgColor: {rgb: '4f81bd'}}
+                        }
+                    }
+                }
+            }
+        }
+
+        const wbout = XLSXD.write(wb, {bookType: 'xlsx', bookSST:true, type: 'array'})
+        saveAs(
+            new Blob([wbout],{type: 'application/octet-stream'}),
+            `${title}.xlsx`,
+        )
+    } catch (e) {
+        if (typeof console !== 'undefined') console.error(e)
+    }
+}
+
+export default {
+    exportExcel
+}

+ 70 - 0
src/utils/request.js

@@ -0,0 +1,70 @@
+// 1.引入axios
+import axios from 'axios'
+import { Message } from 'element-plus'
+import store from '@/store'
+import router from '@/router'
+import { getTimeStamp } from './auth'
+const TimeOut = 3600 // 定义时间戳单位秒3600
+// 2.创建axios实例
+// const baseURL = 'http://192.168.10.4:9002'
+const baseURL = 'http://192.168.10.4:9002'
+const socketURL = 'ws://192.168.10.4:9002'
+const outerURL = 'http://124.70.75.91:6060'
+const service = axios.create({
+    // baseURL: process.env.VUE_APP_BASE_API,
+    baseURL: baseURL,
+    timeout: 15 * 1000 // 超时时间
+})
+// 3.配置拦截器:请求拦截器、响应拦截器
+// 请求拦截器
+service.interceptors.request.use(config => {
+    // cofig是请求的配置信息,必须要返回的
+    // 注入token
+    // if (store.getters.token) {
+    //     // 有token的时候检查时间戳是否超时
+    //     if (isCheckTimeOut()) {
+    //         // token超时
+    //         store.dispatch('user/logout') // 清理token
+    //         router.push('/login') // 跳转登录页
+    //         return Promise.reject(new Error('token超时')) // 返回一个错误对象
+    //     }
+    //     config.headers.Authorization = `Bearer ${store.getters.token}`
+    // }
+    return config
+}, error => {
+    // return Promise.reject(error)
+})
+// 响应拦截器
+service.interceptors.response.use(response => { // 配置成功和失败的处理方法
+    const { status, statusText, data } = response
+    // // 根据success的成功与否决定下面的操作
+    // // 判断校验的成功失败
+    if (data) {
+        return data.data
+    } else {
+        // Message.error(data.msg) // 提示错误信息
+        // return Promise.reject(new Error(message)) // 返回错误对象
+    }
+}, error => {
+    // 接口的成功失败
+    // if (error.response && error.response.data && error.response.data.code === 10002) {
+    //     // 表示token超时,后端返回的超时
+    //     store.dispatch('user/logout') // 退出登录,删除token
+    //     router.push('/login') // 调转登录页
+    // } else {
+    //     Message.error(error.message)
+    // }
+    return Promise.reject(error) // 返回执行错误
+})
+// function isCheckTimeOut() {
+//     const currentTime = Date.now()
+//     const timeStamp = getTimeStamp()
+//     return (currentTime - timeStamp) / 1000 > TimeOut
+// }
+// 4.导出创建的实例
+export default service
+export {
+    baseURL,
+    socketURL,
+    outerURL
+}

+ 55 - 0
src/views/Home/components/instrumentCom.vue

@@ -0,0 +1,55 @@
+<template>
+  <div class="img">
+    <img src="../../../../public/img/home/pointer.png"  :style="{transform: windSpeedRota}"  />
+    <div class="information">{{data.SSPJFS && data.SSPJFS.toFixed(2) }}</div>
+    <div class="unit">m/s</div>
+  </div>
+</template>
+<script>
+export default {
+  props:['data'],
+  data(){
+    return{
+
+    }
+  },
+  computed:{
+    // 实时风速
+    windSpeedRota(){
+      let count=this.data?.SSPJFS/25;
+      return  Number((310*count+50).toFixed(0))?'rotateZ('+ Number((310*count+50).toFixed(0)) + 'deg)' : 'rotateZ(50deg)';
+    },
+  }
+}
+
+</script>
+<style scoped lang="less">
+.img {
+  position: relative;
+  width: 84px;
+  height: 84px;
+  background: url("../../../../public/img/home/instrumentPanel.png") no-repeat;
+img{
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: rotateZ(360deg);
+  transform-origin: left top;
+}
+.information{
+  font-size: 14px;
+  color: #2B99FF;
+  font-family: "Bicubik";
+  position: absolute;
+  width: 100%;
+  top: 32px;
+}
+>.unit{
+  width: 100%;
+  color: #7D838C;
+  text-align: center;
+  position: absolute;
+  top: 58px;
+}
+}
+</style>

+ 49 - 0
src/views/Home/components/mapDetial.vue

@@ -0,0 +1,49 @@
+<template>
+  <g>
+    <rect :x="Number(setX)+6" :y="Number(setY)+22" width="144" height="69" rx="3" ry="3" style="fill:rgba(0, 0, 0, 0.7);stroke:#145387;stroke-width:0.5px;">
+    </rect>
+    <image width="7" height="7" :x="Number(setX)+14" :y="Number(setY)+28" xlink:href="img/home/arrows.png"></image>
+    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
+      <text :x="Number(setX)+24" :y="Number(setY)+34" fill="#FFFFFF" font-size="6">{{data&&data.find(val => val.CZBM === code)?.CZMC}}</text>
+      <text :x="Number(setX)+14" :y="Number(setY)+45" fill="#999999" font-size="5">装机容量</text>
+      <text :x="Number(setX)+45" :y="Number(setY)+45" fill="#fff" font-size="5">{{(data&&data.find(val => val.CZBM === code)?.ZZJRL/1000)?.toFixed(2)}}</text>
+      <text :x="Number(setX)+65" :y="Number(setY)+45" fill="#999999" font-size="5">MW</text>
+      <text :x="Number(setX)+86" :y="Number(setY)+45" fill="#999999" font-size="5">设备台数</text>
+      <text :x="Number(setX)+110" :y="Number(setY)+45" fill="#fff" font-size="5">{{data&&data.find(val => val.CZBM === code)?.ZZJSL}}</text>
+      <text :x="Number(setX)+118" :y="Number(setY)+45" fill="#999999" font-size="5">台</text>
+      <text :x="Number(setX)+14" :y="Number(setY)+58" fill="#999999" font-size="5">首批并网时间</text>
+      <text :x="Number(setX)+50" :y="Number(setY)+58" fill="#fff" font-size="5">{{data&&data.find(val => val.CZBM === code)?.SPBWSJ}}</text>
+      <text :x="Number(setX)+14" :y="Number(setY)+70" fill="#999999" font-size="5">整场投运时间</text>
+      <text :x="Number(setX)+50" :y="Number(setY)+70" fill="#fff" font-size="5">{{data&&data.find(val => val.CZBM === code)?.ZCTYSJ}}</text>
+      <text :x="Number(setX)+14" :y="Number(setY)+84" fill="#999999" font-size="5">地理位置</text>
+      <text :x="Number(setX)+50" :y="Number(setY)+84" fill="#fff" font-size="5">经度{{data&&data.find(val => val.CZBM === code)?.DQJD}},纬度{{data&&data.find(val => val.CZBM === code)?.DQWD}}</text>
+
+<!--      <text :x="Number(setX)+50" :y="Number(setY)+90" fill="#fff" font-size="5">{{data&&data.find(val => val.CZBM === code)?.CZYXZT}}</text>-->
+    </svg>
+  </g>
+</template>
+
+<script>
+export default {
+  name:'mapDetial',
+  props:{
+    data:{
+      type:Object,
+      required:false,
+    },
+    code:String,
+    setX:{
+      type: Number,
+      required: true,
+    },
+    setY:{
+      type: Number,
+      required: true,
+    },
+  },
+}
+</script>
+
+<style>
+
+</style>

+ 220 - 0
src/views/Home/components/powerEcharts.vue

@@ -0,0 +1,220 @@
+<template>
+<!--    72小时功率曲线-->
+    <p class="powerTitle">24小时功率曲线</p>
+    <div id="main" :style="{ width: '870px', height: '110px' }"></div>
+</template>
+
+<script>
+    import * as echarts from 'echarts';
+    import dayjs from "dayjs";
+export default {
+  name:'powerEcharts',
+  props:{
+    CurveValues: {
+      type: Array,
+      required: true,
+    },
+  },
+  mounted() {
+       this.$nextTick(()=>{
+         this.getChart();
+       })
+    },
+  data(){
+    return{
+      emptyData:[],
+    }
+  },
+  methods:{
+    getChart(){
+      var chartDom = document.getElementById('main');
+      var myChart = echarts.init(chartDom);        // 绘制图表
+      var options= {
+        title: {},
+        axisLine: {
+          lineStyle: {
+            color: '#272729', //x轴的颜色
+            width: 2, //轴线的宽度
+          },
+        },
+        tooltip: {
+          // formatter: '{a} <br/>{b} : {c}',
+          trigger: 'axis',
+          "backgroundColor": "rgba(0, 0, 0, 0.3)",
+          textStyle: {
+            color: "white" //设置文字颜色
+          },
+        },
+        legend: {
+          top: '6%',
+          right: '2%',
+          textStyle: {
+            fontSize: '12',
+            color: '#A4A4A5'
+          },
+          orient: 'vertical',
+          icon: 'roundRect',
+          itemWidth: 5,
+          itemHeight: 5,
+          itemGap: 7
+        },
+        xAxis: {
+
+          // type: 'category',
+          // name: 'x',
+          axisLabel:{
+            interval: 7,
+            showMinLabel: true,
+            showMaxLabel: true,
+            textStyle: {
+              color: '#606769',
+            },
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#606769', //x轴的颜色
+              width: 1, //轴线的宽度
+            },
+          },
+          splitLine: { show: false },
+          data: this.getTimeStanp,
+
+        },
+        yAxis: {
+          type: 'value',
+          splitNumber:3,
+          splitLine: {
+            show: false
+          },
+          axisLabel: {
+            show: true,
+            textStyle: {
+              color: '#606769',
+            },
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#606769', // y轴的颜色
+              width: 1, //y轴线的宽度
+            },
+          },
+        },
+        grid: [
+          {
+            left: 65,
+            right: 100,
+            top: 10,
+            bottom: 30
+          }
+        ],
+        series: [
+          {
+            name: '预测功率',
+            type: 'line',
+            smooth: true,
+            symbol: 'none',
+            lineStyle: {
+              width: 1
+            },
+            color:'#05BB4C',
+            data: this.getData(this.CurveValues[0]),
+          },
+          {
+            name: '保证功率',
+            type: 'line',
+            smooth: true,
+            symbol: 'none',
+            lineStyle: {
+              width: 1
+            },
+            color:'#FF5378',
+            data: this.getData(this.CurveValues[1]),
+          },
+          {
+            name: '应发功率',
+            type: 'line',
+            smooth: true,
+            symbol: 'none',
+            lineStyle: {
+              width: 1
+            },
+            color:'#FF8700FF',
+            data: this.getData(this.CurveValues[2]),
+          },
+          {
+            name: '实际功率',
+            type: 'line',
+            smooth: true,
+            symbol: 'none',
+            lineStyle: {
+              width: 1,
+            },
+            color:'#1C99FFFF',
+            textStyle:{
+              color:"red"
+            },
+            data: this.getData(this.CurveValues[3])
+          },
+
+        ]
+      }
+      myChart.setOption(options);
+    },
+    //处理数据
+    getData(datas){
+      let data=[];
+      //查询的测点没有数据情况
+      if(datas && datas.length>0){
+        datas.forEach(item=>{
+          let result;
+          if(item.value){
+            result=item.value.toFixed(2);
+          }else {
+            result=item.value;
+          }
+          data.push(result);
+        })
+        return data;
+      }else {
+        return this.emptyData;
+      }
+    },
+  },
+  computed:{
+    getTimeStanp(){
+      // 当日0点时间
+      var timeStamp=[];
+      let stamp = new Date(new Date().setHours(0, 0, 0, 0)).getTime();
+      for(let i=0;i<96;i++){
+        timeStamp.push( dayjs(stamp).format("HH:mm"));
+        this.emptyData.push('0');
+        stamp = parseInt(stamp)+(15 * 60 * 1000);
+      }
+      timeStamp.push('24:00');
+      this.emptyData.push('0');
+      return timeStamp;
+    },
+  },
+  watch:{
+    'CurveValues':{
+      handler() {
+        this.getChart();
+      },
+    }
+  }
+
+}
+
+</script>
+
+<style lang="less" scoped>
+    .powerTitle {
+      font-size: 16px;
+      font-family: "思源黑体";
+      font-weight: 400;
+      color: #FFFFFF;
+      padding-top: 16px;
+      padding-left: 27px;
+
+    }
+</style>

+ 496 - 0
src/views/Home/components/safeEcoPower.vue

@@ -0,0 +1,496 @@
+<template>
+  <div class="safe_power">
+      <div class="con">
+        <div class="count">
+          <p class="day_mes">安全天数</p>
+          <p class='day_val'> {{datadisposetoFix0(RealTimeValues,'AQTS','')}}<span>天</span></p>
+        </div>
+        <div>
+          <p class="day_mes">资产统计</p>
+          <p class='day_val'>{{datadisposetoFix2(comoanyAssets,'ZCTJ',1000)}}<span>MW</span></p>
+        </div>
+        <div>
+          <p v-show="headerIndex==0 || headerIndex==-1" class="pv_mes">风电<span>{{datadisposetoFix2(comoanyAssets,'FDRL',1000)}}</span><span
+              class="pv_unit">MW</span></p>
+          <p v-show="headerIndex==0 || headerIndex==-2" class="pv_mes">光伏<span id="pv">{{datadisposetoFix2(comoanyAssets,'GFRL',1000)}}</span><span
+              class="pv_unit">MW</span></p>
+        </div>
+      </div>
+      <div class="qty"  @mouseenter="switchShow=true" @mouseleave="switchShow=false">
+        <ul>
+          <li v-show="headerIndex==0 || headerIndex==-1" >
+            <img src="/img/images/downF.png">
+            <img src="/img/images/windup.png" class="qty_img">
+            <p class="qty_tit">风场数量
+              <sapn class='qty_value'> {{datadispose(comoanyAssets,'ZFDCS')}}</sapn>
+              <span class="qty_u">个</span></p>
+            <div class="qty_content">
+              <p class="qty_imag">风机台数<span class="qty_val"> {{datadispose(comoanyAssets,'ZFDZJS')}} </span><span
+                  class="qty_unit">台</span></p>
+              <p class="qty_imag">陆地风机<span class="qty_val"> {{datadispose(comoanyAssets,'ZFDZJSLD')}} </span><span
+                  class="qty_unit">台</span></p>
+              <p class="qty_imag">海上风机<span class="qty_val"> {{datadispose(comoanyAssets,'ZFDZJSHS')}} </span><span
+                  class="qty_unit">台</span></p>
+            </div>
+          </li>
+          <li class="line" v-show="headerIndex==0" ></li>
+          <li v-show="headerIndex==0 || headerIndex==-2">
+            <img src="/img/images/downg.png">
+            <img src="/img/images/ptyup.png" class="qty_img">
+            <p class="qty_tit">光伏数量
+              <sapn class='qty_value' id="pv">{{ datadispose(comoanyAssets,'ZGFCS')}}</sapn>
+              <span class="qty_u">个</span></p>
+            <div class="qty_content">
+              <p class="qty_imag">逆变器<span class="qty_val"> {{datadispose(comoanyAssets,'ZGFZJS')}} </span><span class="qty_unit">台</span>
+              </p>
+              <p class="qty_imag">集中式<span class="qty_val"> {{datadispose(comoanyAssets,'ZGFZJSJZ')}} </span><span
+                  class="qty_unit">台</span></p>
+              <p class="qty_imag">分布式<span class="qty_val"> {{ datadispose(comoanyAssets,'ZZCSTS')}} </span><span class="qty_unit">台</span>
+              </p>
+            </div>
+          </li>
+        </ul>
+        <div class="switch0n" v-show="switchShow" @mouseenter="switchShow=true" @mouseleave="switchShow=true" >
+          <div> <img src="@/../public/img/home/arrows.png"> 接入情况</div>
+          <ul>
+            <li v-show="headerIndex==0 || headerIndex==-1" >
+              <img src="/img/images/downF.png">
+              <img src="/img/images/windup.png" class="qty_img">
+              <p class="qty_tit">风场数量
+                <sapn class='qty_value'> {{ datadispose(comoanyAssets,'JRFC')}}</sapn>
+                <span class="qty_u">个</span></p>
+              <div class="qty_content">
+                <p class="qty_imag">风机台数<span class="qty_val"> {{datadispose(comoanyAssets,'FJTS')}} </span><span
+                    class="qty_unit">台</span></p>
+                <p class="qty_imag">陆地风机<span class="qty_val"> {{datadispose(comoanyAssets,'LDTS')}} </span><span
+                    class="qty_unit">台</span></p>
+                <p class="qty_imag">海上风机<span class="qty_val"> {{datadispose(comoanyAssets,'HSFJ')}} </span><span
+                    class="qty_unit">台</span></p>
+              </div>
+            </li>
+            <li class="line" v-show="headerIndex==0"></li>
+            <li v-show="headerIndex==0 || headerIndex==-2">
+              <img src="/img/images/downg.png">
+              <img src="/img/images/ptyup.png" class="qty_img">
+              <p class="qty_tit">光伏数量
+                <sapn class='qty_value' id="pv"> {{ datadispose(comoanyAssets,'JRGF')}}</sapn>
+                <span class="qty_u">个</span></p>
+              <div class="qty_content">
+                <p class="qty_imag">逆变器<span class="qty_val"> {{datadispose(comoanyAssets,'GFTS')}} </span><span class="qty_unit">台</span>
+                </p>
+                <p class="qty_imag">集中式<span class="qty_val"> {{datadispose(comoanyAssets,'JZSTS')}} </span><span
+                    class="qty_unit">台</span></p>
+                <p class="qty_imag">分布式<span class="qty_val"> {{ datadispose(comoanyAssets,'ZCSTS')}} </span><span class="qty_unit">台</span>
+                </p>
+              </div>
+            </li>
+          </ul>
+        </div>
+      </div>
+
+      <div class="ecoName">
+        <p class="ecoTitle">社会贡献<span>万吨</span></p>
+        <ul>
+          <li class="eco_count">
+            <i class="icon-coal"></i>
+            <p class="eco_val">{{datadisposetoFix2(CalcValues,'JYM')}}</p>
+            <p class="eco_name">煤</p>
+          </li>
+          <li class="eco_count">
+            <i class="icon-water"></i>
+            <p class="eco_val">{{datadisposetoFix2(CalcValues,'JYS')}}</p>
+            <p class="eco_name">水</p>
+          </li>
+          <li class="eco_count">
+            <i class="icon-Carbon-dioxide"></i>
+            <p class="eco_val">{{datadisposetoFix2(CalcValues,'CO2')}}</p>
+            <p class="eco_name">二氧化碳</p>
+          </li>
+          <li class="eco_count">
+            <i class="icon-Sulfur-dioxide"></i>
+            <p class="eco_val">{{datadisposetoFix2(CalcValues,'SO2')}}</p>
+            <p class="eco_name">二氧化硫</p>
+          </li>
+        </ul>
+      </div>
+      <div class="my_echarts">
+        <power-echarts :CurveValues="CurveValues" />
+      </div>
+  </div>
+</template>
+
+<script>
+import powerEcharts from "./powerEcharts";
+
+export default {
+  name: 'Home',//首页
+  components: {
+    powerEcharts
+  },
+  props: {
+    comoanyAssets: {
+      type: Object,
+      required: true,
+    },
+    RealTimeValues: {
+      type: Object,
+      required: true,
+    },
+    CalcValues: {
+      type: Object,
+      required: false,
+    },
+    CurveValues: {
+      type: Array,
+      required: true,
+    },
+    headerIndex:{
+      type:[String,Number],
+      required:true,
+    },
+    windPowerCount:{
+      type:[String,Number],
+      required:true,
+    },
+    photovoltaicCount:{
+      type:[String,Number],
+      required:true,
+    }
+  },
+  data() {
+    return {
+      switchShow:false,
+    }
+  },
+  methods: {
+    datadisposetoFix2(obj, str,coefficient) {
+      if (obj) {
+        if (obj[str] == '' && obj[str] !== 0) {
+          return '-'
+        } else{
+          if(coefficient){
+            return typeof obj[str]=='number' ? (obj[str]/coefficient).toFixed(2) : obj[str]/coefficient;
+          }else {
+            return typeof obj[str]=='number' ? obj[str].toFixed(2) : obj[str];
+          }
+        }
+      } else {
+        return '-'
+      }
+    },
+    datadisposetoFix0(obj, str,coefficient) {
+      if (obj) {
+        if (obj) {
+          if (obj[str] == '' && obj[str] !== 0) {
+            return '-'
+          } else{
+            if(coefficient){
+              return typeof obj[str]=='number' ? (obj[str]/coefficient).toFixed(2) : obj[str]/coefficient;
+            }else {
+              return typeof obj[str]=='number' ? obj[str].toFixed(0) : obj[str];
+            }
+          }
+        } else {
+          return '-'
+        }
+      }
+    },
+    datadispose(obj, str) {
+      if (obj) {
+        if (obj[str] === '' && obj[str] !== 0) {
+          return '-'
+        } else {
+          return obj[str];
+        }
+      } else {
+        return '-'
+      }
+    },
+  },
+  computed:{
+  }
+}
+</script>
+
+<style lang="less" scoped>
+@keyframes move {
+  0% {
+    top: 0px;
+  }
+  20% {
+    top: -1px
+  }
+  40% {
+    top: -2px
+  }
+  80% {
+    top: -1px
+  }
+  100% {
+    top: 0px
+  }
+
+}
+
+@keyframes safe_power {
+  0% {
+    margin-left: -320px;
+  }
+
+
+  100% {
+    margin-left: 0;
+  }
+
+}
+
+.safe_power {
+
+  animation: safe_power 2.5s linear;
+}
+
+
+.day_mes {
+  font-size: 20px;
+  font-weight: 400;
+  color: #FFFFFF;
+}
+
+.con {
+  position: absolute;
+    top:60px;
+    z-index: 99;
+  }
+
+  .count {
+    margin: 20px 0 5px;
+  }
+
+  #pv {
+    color: #FF8300;
+  }
+
+  .day_val {
+    font-size: 35px;
+    font-family: Bicubik;
+    color: #1C99FF;
+
+    span {
+      font-size: 12px;
+      color: #1C99FF;
+      margin-left: 10px;
+      font-family: '思源黑体';
+    }
+  }
+
+  .pv_mes {
+    font-size: 14px;
+    font-weight: 400;
+    color: #FFFFFF;
+
+    span {
+      font-size: 16px;
+      font-family: Bicubik;
+      color: #1C99FF;
+      margin: 0 10px 0 6px;
+    }
+
+    .pv_unit {
+      font-size: 12px;
+      color: #5E6269;
+      margin: 0;
+      font-family: 思源黑体;
+    }
+  }
+
+  .qty {
+    background: rgba(0, 0, 0, 0.3);
+    border-radius: 8px;
+    top: 318px;
+    position: absolute;
+    padding: 20px 10px;
+    z-index: 999;
+      .qty_img {
+        position: relative;
+        left: -39px;
+        top: 1px;
+        animation: move 1s infinite linear;
+    }
+
+    .qty_content {
+      margin-top: -25px;
+    }
+
+    ul {
+      display: flex;
+
+      li {
+        width: 170px;
+        height: 154px;
+        margin-left: 20px;
+        line-height: 30px;
+      }
+
+      .line{
+        border-right: 1px dashed #252E43;
+        width: 1px;
+        margin-left: 0;
+        margin-right: 5px;
+      }
+    }
+
+    .qty_tit {
+      font-size: 14px;
+      position: relative;
+      left: 75px;
+      bottom: 50px;
+      color: #999999;
+
+      .qty_u {
+        position: relative;
+        top: 23px;
+        left: -38px;
+      }
+    }
+
+    .qty_value {
+      font-size: 14px;
+      position: relative;
+      top: 26px;
+      left: -54px;
+      color: #1C99FF;
+      font-family:'AgencyFB-Reg';
+      font-weight: bold;
+
+      .qty_u {
+        font-size: 12px;
+        color: #999999;
+        margin-left: 20px;
+      }
+    }
+
+    .qty_imag {
+      font-size: 14px;
+      color: #999999;
+
+      .qty_val {
+        font-family: 'AgencyFB-Reg';
+        font-weight: bold;
+        color: #FFFFFF;
+        margin: 0 20px;
+      }
+
+      .qty_unit {
+        font-size: 12px;
+        color: #999999;
+      }
+    }
+
+    .qty_imag:first-of-type {
+      margin-top: 10px;
+    }
+  }
+
+  .ecoName {
+    width: 373px;
+    height: 138px;
+    background: rgba(0, 0, 0, .3);
+    border-radius: 8px;
+    top: 530px;
+    position: absolute;
+    z-index: 99;
+
+
+    i {
+      font-size: 16px;
+      color: #1C99FF;
+    }
+
+
+    .ecoTitle {
+      width: 335px;
+      height: 45px;
+      border-bottom: 1px solid #252E43;
+      margin: 0 auto;
+      font-size: 16px;
+      font-weight: 400;
+      color: #FFFFFF;
+      line-height: 45px;
+      position: relative;
+
+      span {
+        position: absolute;
+        right: 0;
+        font-size: 12px;
+        font-family: Source Han Sans SC;
+        color: #B1B1B1;
+      }
+    }
+
+    ul {
+      display: flex;
+      text-align: center;
+      width: 310px;
+      height: 92px;
+      margin: 0 auto;
+      justify-content: space-between;
+      align-items: center;
+
+      .eco_count {
+        line-height: 23px;
+
+        .eco_val {
+          font-size: 14px;
+          font-family: SourceHanSansCN;
+          color: #FFFFFF;
+        }
+
+        .eco_name {
+          font-size: 12px;
+          color: #B3B3B3;;
+        }
+      }
+    }
+  }
+
+  .my_echarts {
+    width: 873px;
+    background: rgba(0, 0, 0, .3);
+    border-radius: 6px;
+    position: absolute;
+    bottom: 50px;
+    z-index: 99;
+  }
+  .switch0n{
+    position: absolute;
+    top: 40%;
+    left: 80%;
+    backdrop-filter: blur(5px);
+    z-index: 110;
+    font-size: 16px;
+    color: #fff;
+    background: rgba(0, 0, 0, 0.3);
+    border-radius: 8px;
+    padding: 20px 10px;
+    border: 1px solid #145387;
+    >div{
+      margin-bottom: 10px;
+      >img{
+        margin-right: 10px;
+        vertical-align: -4%;
+      }
+    }
+  }
+
+@media screen and (min-height: 1020px) {
+  .con{
+    top: 98px;
+  }
+  .qty{
+    top: 380px;
+  }
+  .ecoName{
+    top: 600px;
+  }
+}
+</style>

文件差異過大導致無法顯示
+ 705 - 0
src/views/Home/components/sdMap.vue


+ 201 - 0
src/views/Home/components/windChartCom.vue

@@ -0,0 +1,201 @@
+<template>
+  <div class="home_card" >
+    <!-- <div class="header"> <img src="@/../public/img/home/arrows.png"> {{CurveTitle}}曲线</div> -->
+    <div class="windChart" >
+       <div :id="chartId" :style="{ width: width, height: height }"></div>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as echarts from 'echarts';
+import dayjs from "dayjs";
+export default {
+  name:'windChartCom',
+  props:{
+    width:{
+      type:String,
+      default:'100%',
+    },
+    height:{
+      type:String,
+      default:'70vh',
+    },
+    CurveTitle:{
+      type:String,
+      required:true,
+    },
+    chartShow:{
+      type:Boolean,
+      required:true,
+      default:false,
+    },
+    windCurveValues: {
+      type: Array,
+      required: true,
+    },
+    chartId:{
+      type:String,
+      required:true,
+    }
+  },
+ async created() {
+  },
+  mounted() {
+    this.$nextTick(()=>{
+      this.getChart();
+    })
+  },
+  data(){
+    return{
+      emptyData:[],
+    }
+  },
+  methods:{
+    getChart(){
+      var chartDom = document.getElementById(this.chartId);
+      var myChart = echarts.init(chartDom);        // 绘制图表
+      var options= {
+        title: {},
+        tooltip: {
+          trigger: 'axis',
+          "backgroundColor": "rgba(0, 0, 0, 0.3)",
+          textStyle: {
+            color: "white" //设置文字颜色
+          },
+        },
+        legend: {
+          top: '6%',
+          right: '2%',
+          textStyle: {
+            fontSize: '12',
+            color: '#A4A4A5'
+          },
+          orient: 'vertical',
+          icon: 'roundRect',
+          itemWidth: 5,
+          itemHeight: 5,
+          itemGap: 7
+        },
+        xAxis: {
+          // type: 'category',
+          // name: 'x',
+          axisLabel:{
+            interval:11,
+            showMinLabel: true,
+            showMaxLabel: true,
+            textStyle: {
+              color: '#606769',
+            },
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#606769', //x轴的颜色
+              width: 1, //轴线的宽度
+            },
+          },
+          splitLine: { show: false },
+          data: this.getTimeStanp,
+
+        },
+        yAxis: {
+          type: 'value',
+          splitNumber:3,
+          splitLine: {
+            show: false,
+            textStyle: {
+              color: '#606769',
+            },
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#606769', // y轴的颜色
+              width: 1, //y轴线的宽度
+            },
+          },
+        },
+        grid: [
+          {
+            left: 40,
+            right: 40,
+            top: 20,
+            bottom: 30
+          }
+        ],
+        series: [
+          {
+            name:this.CurveTitle,
+            type: 'line',
+            smooth: true,
+            symbol: 'none',
+            areaStyle: {
+              opacity: 0.7,
+              color: new echarts.graphic.LinearGradient(0, 0, 2, 1, [
+                {
+                  offset: 0,
+                  color: 'rgba(53, 150, 235, 1)'
+                },
+                {
+                  offset: 1,
+                  color: 'rgba(18, 32, 50, 0.2)'
+                }
+              ])
+            },
+            lineStyle: {
+              width: 1
+            },
+            color:'#3596EB',
+            data: this.getData(this.windCurveValues[0]),
+          }
+        ]
+      }
+      myChart.setOption(options);
+    },
+    //处理数据
+    getData(datas){
+      let data=[];
+      //查询的测点没有数据情况
+      if(datas && datas.length>0){
+        datas.forEach(item=>{
+          let result;
+          if(item.value){
+            result=item.value.toFixed(2);
+          }else {
+            result=item.value;
+          }
+          data.push(result);
+        })
+        return data;
+      }else {
+        return this.emptyData;
+      }
+    },
+  },
+  computed:{
+    getTimeStanp(){
+      // 当日0点时间
+      var timeStamp=[];
+      let stamp = new Date(new Date().setHours(0, 0, 0, 0)).getTime();
+      for(let i=0;i<96;i++){
+        timeStamp.push( dayjs(stamp).format("HH:mm"));
+        this.emptyData.push('0');
+        stamp = parseInt(stamp)+(15 * 60 * 1000);
+      }
+      timeStamp.push('24:00');
+      return timeStamp;
+    },
+  },
+  watch:{
+    'windCurveValues':{
+      handler() {
+        this.getChart();
+      },
+    }
+  }
+
+}
+
+</script>
+
+<style lang="less" scoped>
+</style>

+ 230 - 0
src/views/Home/components/windLightDetial.vue

@@ -0,0 +1,230 @@
+<template>
+  <el-row class="card_detail">
+    <el-row> <el-col>{{datadisposetoFix0(dataDetial,'DJTS')}}</el-col>
+      <el-col>{{datadisposetoFix0(dataDetial,'YXTS')}}</el-col>
+      <el-col>{{datadisposetoFix0(dataDetial,'XDTS')}}</el-col>
+      <el-col>{{datadisposetoFix0(dataDetial,'GZTJTS')}}</el-col>
+      <el-col>{{datadisposetoFix0(dataDetial,'JXTJTS')}}</el-col>
+      <el-col>{{datadisposetoFix0(dataDetial,'TXZDTS')}}</el-col>
+      <el-col>{{datadisposetoFix0(dataDetial,'SLTS')}}</el-col>
+    </el-row>
+    <el-row>
+      <el-col><span>待机</span></el-col>
+      <el-col><span>运行</span></el-col>
+      <el-col><span>限电</span></el-col>
+      <el-col><span>故障</span></el-col>
+      <el-col><span>检修</span></el-col>
+      <el-col><span>离线</span></el-col>
+      <el-col><span>受累</span></el-col>
+    </el-row>
+    <el-row>
+      <el-col>
+        <div>
+          <div>待风</div><div>{{datadisposetoFix0(dataDetial,'DJTSMX')}}</div>
+          <div>手动停</div><div>{{datadisposetoFix0(dataDetial,'SDTJTSMX')}}</div>
+        </div>
+      </el-col>
+      <el-col>
+        <div>
+          <div>发电</div><div>{{datadisposetoFix0(dataDetial,'XNTSMX')}}</div>
+          <div>降出力</div><div>{{datadisposetoFix0(dataDetial,'QXJCLTSMX')}}</div>
+        </div>
+      </el-col>
+      <el-col>
+        <div>
+          <div>降出力</div><div>{{datadisposetoFix0(dataDetial,'XDJCLTSMX')}}</div>
+          <div>停机</div><div>{{datadisposetoFix0(dataDetial,'XDTJTSMX')}}</div>
+        </div>
+      </el-col>
+      <el-col>
+        <div>
+          <div>停机</div><div>{{datadisposetoFix0(dataDetial,'GZTSMX')}}</div>
+          <div>受累</div><div>{{datadisposetoFix0(dataDetial,'CNSLGZTSMX')}}</div>
+        </div>
+      </el-col>
+      <el-col>
+        <div>
+          <div>停机</div><div>{{datadisposetoFix0(dataDetial,'JXTSMX')}}</div>
+          <div>受累</div><div>{{datadisposetoFix0(dataDetial,'CNSLJXTSMX')}}</div>
+        </div>
+      </el-col>
+      <el-col>
+        <div>
+          <div>离线</div><div>{{datadisposetoFix0(dataDetial,'LXTSMX')}}</div>
+          <div>未知</div><div>{{datadisposetoFix0(dataDetial,'TXZDTSMX')}}</div>
+        </div>
+      </el-col>
+      <el-col>
+        <div>
+          <div>电网</div><div>{{datadisposetoFix0(dataDetial,'CWSLDWTSMX')}}</div>
+          <div>环境</div><div>{{datadisposetoFix0(dataDetial,'CWSLTQTSMX')}}</div>
+        </div>
+      </el-col>
+    </el-row>
+  </el-row>
+</template>
+<script>
+export default {
+  props:{
+    dataDetial:{
+      type:Object,
+      required:true,
+      default:null,
+    }
+  },
+  data(){
+    return{
+
+    }
+  },
+  methods:{
+    datadisposetoFix0(obj, str,coefficient) {
+      if (obj) {
+        if (obj) {
+          if (obj[str] == '' && obj[str] !== 0) {
+            return '-'
+          } else{
+            if(coefficient){
+              return typeof obj[str]=='number' ? (obj[str]/coefficient).toFixed(2) : obj[str]/coefficient;
+            }else {
+              return typeof obj[str]=='number' ? obj[str].toFixed(0) : obj[str];
+            }
+          }
+        } else {
+          return '-'
+        }
+      }
+    },
+  }
+}
+
+</script>
+<style lang="less" scoped>
+.card_detail{
+  padding: 0;
+  >.el-row {
+    width: 100%;
+    > .el-col {
+      flex: 1;
+      text-align: center;
+    }
+  }
+  >.el-row:first-child{
+    font-family: Bicubik;
+    font-size: 14px;
+    .el-col:nth-child(1){
+      color: #05BB4C;
+    }
+    .el-col:nth-child(2){
+      color: #1986E0;
+    }
+    .el-col:nth-child(3){
+      color: #C530C8;
+    }
+    .el-col:nth-child(4){
+      color: #BA3237;
+    }
+    .el-col:nth-child(5){
+      color: #F7870E;
+    }
+    .el-col:nth-child(6){
+      color: #fff;
+    }
+    .el-col:nth-child(7){
+      color: #565656;
+    }
+  }
+  >.el-row:nth-child(2){
+    margin-top: 6px;
+    .el-col{
+      color: #fff;
+      span{
+        display:block;
+        width: 48px;
+        height: 20px;
+        background-color: #1986E0;
+      }
+    }
+    .el-col:nth-child(1){
+      span{
+        background-color: #05BB4C;
+      }
+    }
+    .el-col:nth-child(2){
+      span{
+        background-color: #1986E0;
+      }
+    }
+    .el-col:nth-child(3){
+      span{
+        background-color: #C530C8;
+      }
+    }
+    .el-col:nth-child(4){
+      span{
+        background-color: #BA3237;
+      }
+    }
+    .el-col:nth-child(5){
+      span{
+        background-color: #F7870E;
+      }
+    }
+    .el-col:nth-child(6){
+      span{
+        background-color: #B3B3B3;
+      }
+    }
+    .el-col:nth-child(7){
+      span{
+        background-color: #565656;
+      }
+    }
+  }
+  >.el-row:nth-child(3){
+    margin-top: 4px;
+    .el-col{
+      >div{
+        width: 48px;
+        height: 140px;
+        background: linear-gradient(to bottom,rgba(25, 134, 224, 0.3),transparent,transparent);
+        color: #fff;
+        backdrop-filter: blur(5px);
+        >div:nth-child(odd){
+          color: #fff;
+          line-height: 48px;
+          font-size: 14px;
+        }
+      }
+    }
+    .el-col:nth-child(1)>div:last-child{
+      color: #05BB4C;
+      background: linear-gradient(to bottom,#05BB4C,transparent,transparent);
+    }
+    .el-col:nth-child(2)>div:last-child{
+      color: #1986E0;
+      background: linear-gradient(to bottom,#1986E0,transparent,transparent);
+    }
+    .el-col:nth-child(3)>div:last-child{
+      color: #C530C8;
+      background: linear-gradient(to bottom,#C530C8,transparent,transparent);
+    }
+    .el-col:nth-child(4)>div:last-child{
+      color: #BA3237;
+      background: linear-gradient(to bottom,#BA3237,transparent,transparent);
+    }
+    .el-col:nth-child(5)>div:last-child{
+      color:#F7870E;
+      background: linear-gradient(to bottom,#F7870E,transparent,transparent);
+    }
+    .el-col:nth-child(6)>div:last-child{
+      color:#fff;
+      background: linear-gradient(to bottom,#B3B3B3,transparent,transparent);
+    }
+    .el-col:nth-child(7)>div:last-child{
+      color:#FFF;
+      background: linear-gradient(to bottom,#565656,transparent,transparent);
+    }
+  }
+}
+</style>

+ 675 - 0
src/views/Home/components/windSpeedCom.vue

@@ -0,0 +1,675 @@
+<template>
+  <div class="card wind_card">
+    <el-row>
+      <el-col v-show="headerIndex == 0 || headerIndex == '-1'">
+        <div class="grid-content">
+          <div class="img" @click="handleClick('SSPJFS', '实时风速')">
+            <img src="../../../../public/img/home/pointer.png" :style="{ transform: windSpeedRota }" />
+            <div class="information">{{ datadisposetoFix2(RealTimeValues, 'SSPJFS') }}</div>
+            <div class="unit">m/s</div>
+          </div>
+          <p>实时风速</p>
+        </div>
+      </el-col>
+      <el-col v-show="headerIndex == 0 || headerIndex == '-2'">
+        <div class="grid-content" @click="handleClick('SSPJGZD', '光照指数')">
+          <div class="img">
+            <img src="../../../../public/img/home/pointer.png" :style="{ transform: illuminationRota }" />
+            <div class="information">{{ datadisposetoFix2(RealTimeValues, 'SSPJGZD') }}</div>
+            <div class="unit">kj/m2</div>
+          </div>
+          <p>光照指数</p>
+        </div>
+      </el-col>
+      <el-col>
+        <div class="grid-content" @click="handleClick('SSZGL', '实际功率')">
+          <div class="img">
+            <img src="../../../../public/img/home/pointer.png" :style="{ transform: actualPowerRota }" />
+            <div class="information">{{ datadisposetoFix2(RealTimeValues, 'SSZGL') }}</div>
+            <div class="unit">MW</div>
+          </div>
+          <p>实际功率</p>
+        </div>
+      </el-col>
+      <el-col>
+        <div class="grid-content" @click="handleClick('SSZNHGLZS', '理论功率')">
+          <div class="img">
+            <img src="../../../../public/img/home/pointer.png" :style="{ transform: ideaPowerRota }" />
+            <div class="information">{{ datadisposetoFix2(RealTimeValues, 'SSZNHGLZS') }}</div>
+            <div class="unit">MW</div>
+          </div>
+          <p>理论功率</p>
+        </div>
+      </el-col>
+      <el-col v-if="headerIndex == '-1' || headerIndex == '-2'">
+        <div class="grid-content" @click="handleClick('SSZBZGL', '保证功率')">
+          <div class="img">
+            <img src="../../../../public/img/home/pointer.png" :style="{ transform: guarantee }" />
+            <div class="information">{{ datadisposetoFix2(RealTimeValues, 'SSZBZGL', 1000) }}</div>
+            <div class="unit">MW</div>
+          </div>
+          <p>保证功率</p>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+  <div>
+    <el-dialog :title="showName" v-model="dialogVisible" width="70%" top="10vh" custom-class="modal"
+      :close-on-click-modal="false">
+      <div class="body">
+        <windChartCom :windCurveValues="chartsData" chartId="windChar" />
+      </div>
+    </el-dialog>
+  </div>
+  <div class="card electric_card">
+    <el-header>
+      <span class="title"></span>
+      <soan class="unit">(单位:万kWh)</soan>
+    </el-header>
+    <el-row>
+      <el-col :span="4">日发电量</el-col>
+      <el-col :span="14">
+        <div class="electric">
+          <div class="progress_bar" :style="{ width: getDayEfficiency }">
+            <span class="count">{{ datadisposetoFix2(RealTimeValues, 'RFDL') }}</span>
+            <span class="img"></span>
+          </div>
+        </div>
+      </el-col>
+      <el-col :span="4">{{ getDayEfficiency }}</el-col>
+    </el-row>
+    <el-row>
+      <el-col :span="4">月发电量</el-col>
+      <el-col :span="14">
+        <div class="electric">
+          <div class="progress_bar" :style="{ width: getMonthEfficiency }">
+            <span class="count">{{ datadisposetoFix2(RealTimeValues, 'YFDL') }}</span>
+            <span class="img"></span>
+          </div>
+        </div>
+      </el-col>
+      <el-col :span="4">{{ getMonthEfficiency }}</el-col>
+    </el-row>
+    <el-row>
+      <el-col :span="4">年发电量</el-col>
+      <el-col :span="14">
+        <div class="electric">
+          <div class="progress_bar" :style="{ width: getYearEfficiency }">
+            <span class="count">{{ datadisposetoFix2(RealTimeValues, 'NFDL') }}</span>
+            <span class="img"></span>
+          </div>
+        </div>
+      </el-col>
+      <el-col :span="4">{{ getYearEfficiency }}</el-col>
+    </el-row>
+    <el-row class="summarize">
+      <el-col :span="11" class="left">
+        <p>月利用小时</p>
+        <p>
+          <span> {{ datadisposetoFix2(CalcValues, 'YLYXS') }} </span>
+          <span>小时</span>
+        </p>
+      </el-col>
+      <el-col :span="1" class="line"></el-col>
+      <el-col :span="11" class="right">
+        <p>年利用小时</p>
+        <p>
+          <span>{{ datadisposetoFix2(CalcValues, 'NLYXS') }}</span>
+          <span>小时</span>
+        </p>
+      </el-col>
+    </el-row>
+  </div>
+  <div class="card station_card">
+    <el-row class="card_header" v-if="RealTimeStaValues && RealTimeStaValues.FJ">
+      <el-col :span="12">
+        <img src="@/../public/img/home/windmill.png" />
+        <span>{{ datadispose(comoanyAssets, 'FJTS') }}</span>台
+      </el-col>
+      <el-col :span="12">
+        场站<span>{{ datadispose(comoanyAssets, 'JRFC') }}</span>个
+      </el-col>
+    </el-row>
+    <windLightDetial v-if="RealTimeStaValues && !RealTimeStaValues.GF && RealTimeStaValues.FJ"
+      :dataDetial="RealTimeStaValues.FJ"></windLightDetial>
+    <windlightSimple v-if="RealTimeStaValues && RealTimeStaValues.FJ && RealTimeStaValues.GF"
+      :dataSimple="RealTimeStaValues.FJ" />
+    <el-row class="card_header" v-if="RealTimeStaValues && RealTimeStaValues.GF">
+      <el-col :span="12">
+        <img src="@/../public/img/home/station.png" />
+        <span>{{ datadispose(comoanyAssets, 'JRGF') }}</span>台
+      </el-col>
+      <el-col :span="12">
+        场站<span>{{ datadispose(comoanyAssets, 'JRGF') }}</span>个
+      </el-col>
+    </el-row>
+    <windLightDetial v-if="RealTimeStaValues && !RealTimeStaValues.FJ && RealTimeStaValues.GF"
+      :dataDetial="RealTimeStaValues.GF"></windLightDetial>
+    <windlightSimple v-if="RealTimeStaValues && RealTimeStaValues.FJ && RealTimeStaValues.GF"
+      :dataSimple="RealTimeStaValues.GF" />
+  </div>
+</template>
+
+<script>
+import {
+  GetCurveValues,
+} from '@/api/home'
+import windChartCom from './windChartCom'
+import instrumentCom from './instrumentCom'
+import windLightDetial from './windLightDetial'
+import windlightSimple from './windlightSimple'
+export default {
+  name: 'windSpeedCom',//首页
+  components: {
+    windChartCom,
+    instrumentCom,
+    windLightDetial,
+    windlightSimple
+  },
+  props: {
+    comoanyAssets: {
+      type: Object,
+      required: true,
+    },
+    RealTimeValues: {
+      type: Object,
+      required: true,
+    },
+    CalcValues: {
+      type: Object,
+      required: true,
+    },
+    RealTimeStaValues: {
+      type: Object,
+      required: true,
+    },
+    headerIndex: {
+      type: [String, Number],
+      required: true,
+    },
+    PlanValues: {
+      type: Object,
+      required: true,
+    },
+    activeNode: String,
+    nodeCode: String,
+  },
+  created() {
+  },
+  data() {
+    return {
+      windChartShow: false,
+      lightChartShow: false,
+      practicalChartShow: false,
+      theoryChartShow: false,
+      guaranteeChartShow: false,
+      dialogVisible: false,
+      showName: '',
+      chartsData: [],
+    }
+  },
+  methods: {
+    handleClick(tag, val) {
+      this.showName = val
+      this.dialogVisible = true
+      this.getCurveValues(tag)
+    },
+    async getCurveValues(tag) {
+      let flag = 'comp'
+      let str = this.activeNode.substring(this.activeNode.length - 5, this.activeNode.length - 2);
+      if (str == 'STA') {
+        flag = 'stations';
+      };
+      let data = await GetCurveValues({ companyCode: flag == 'comp' ? this.activeNode : this.nodeCode, uniformCode: tag, intervalTime: '900' });
+      this.chartsData = data
+    },
+    datadisposetoFix2(obj, str, coefficient) {
+      if (obj) {
+        if (obj[str] == '' && obj[str] !== 0) {
+          return '-'
+        } else {
+          if (coefficient) {
+            return typeof obj[str] == 'number' ? (obj[str] / coefficient).toFixed(2) : obj[str] / coefficient;
+          } else {
+            return typeof obj[str] == 'number' ? obj[str].toFixed(2) : obj[str];
+          }
+        }
+      } else {
+        return '-'
+      }
+    },
+    datadisposetoFix0(obj, str, coefficient) {
+      if (obj) {
+          if (obj[str] == '' && obj[str] !== 0) {
+            return '-'
+          } else {
+            if (coefficient) {
+              return typeof obj[str] == 'number' ? (obj[str] / coefficient).toFixed(2) : obj[str] / coefficient;
+            } else {
+              return typeof obj[str] == 'number' ? obj[str].toFixed(0) : obj[str];
+            }
+          }
+        } else {
+          return '-'
+        }
+    },
+    datadispose(obj, str) {
+      if (obj) {
+        if (obj[str] === '' && obj[str] !== 0) {
+          return '-'
+        } else {
+          return obj[str];
+        }
+      } else {
+        return '-'
+      }
+    },
+  },
+  computed: {
+    // 理论功率
+    ideaPowerRota() {
+      let count = this.RealTimeValues?.SSPJGZD / 1000 / this.comoanyAssets?.ZCTJ;
+      let result = Number((310 * count + 50).toFixed(0));
+      if (result) {
+        if (result > 310) {
+          return 'rotateZ(310deg)'
+        } else {
+          return 'rotateZ(' + Number((310 * count + 50).toFixed(0)) + 'deg)'
+        }
+      } else {
+        return 'rotateZ(50deg)'
+      }
+      // return  Number((310*count+50).toFixed(0))?'rotateZ('+ Number((310*count+50).toFixed(0)) + 'deg)' : 'rotateZ(50deg)';
+    },
+    // 实时风速
+    windSpeedRota() {
+      let count = this.RealTimeValues?.SSPJFS / 25;
+      let result = Number((310 * count + 50).toFixed(0));
+      if (result) {
+        if (result > 310) {
+          return 'rotateZ(310deg)'
+        } else {
+          return 'rotateZ(' + Number((310 * count + 50).toFixed(0)) + 'deg)'
+        }
+      } else {
+        return 'rotateZ(50deg)'
+      }
+    },
+    // 实际功率
+    actualPowerRota() {
+      let count = this.RealTimeValues?.SSZGL / 1000 / this.comoanyAssets?.ZCTJ;
+      let result = Number((310 * count + 50).toFixed(0));
+      if (result) {
+        if (result > 310) {
+          return 'rotateZ(310deg)'
+        } else {
+          return 'rotateZ(' + Number((310 * count + 50).toFixed(0)) + 'deg)'
+        }
+      } else {
+        return 'rotateZ(50deg)'
+      }
+    },
+    // 光照指数
+    illuminationRota() {
+      let count = this.RealTimeValues?.SSGZQD / 1200;
+      let result = Number((310 * count + 50).toFixed(0));
+      if (result) {
+        if (result > 310) {
+          return 'rotateZ(310deg)'
+        } else {
+          return 'rotateZ(' + Number((310 * count + 50).toFixed(0)) + 'deg)'
+        }
+      } else {
+        return 'rotateZ(50deg)'
+      }
+    },
+    //总保证功率
+    guarantee() {
+      let count = this.RealTimeValues.SSZBZGL / 1000 / this.comoanyAssets.ZCTJ;
+      let result = Number((310 * count + 50).toFixed(0));
+      if (result) {
+        if (result > 310) {
+          return 'rotateZ(310deg)'
+        } else {
+          return 'rotateZ(' + Number((310 * count + 50).toFixed(0)) + 'deg)'
+        }
+      } else {
+        return 'rotateZ(50deg)'
+      }
+    },
+    //日发电率
+    getDayEfficiency() {
+      if (this.PlanValues.RJHFDL  || this.RealTimeValues?.RFDL ) {
+        if (this.PlanValues.RJHFDL == '') {
+          return '100%';
+        } else {
+          let data = (this.RealTimeValues?.RFDL / this.PlanValues?.RJHFDL) * 100;
+          return data.toFixed(2) + '%';
+        }
+      } else {
+        return '-';
+      }
+    },
+    getMonthEfficiency() {
+      if (this.PlanValues.YJHFDL || this.RealTimeValues?.YFDL) {
+        if (this.PlanValues.YJHFDL == '') {
+          return '100%';
+        } else {
+          let data = (this.RealTimeValues?.YFDL / this.PlanValues.YJHFDL) * 100;
+          return data.toFixed(2) + '%';
+        }
+      } else {
+        return '-'
+      }
+    },
+    getYearEfficiency() {
+      if (this.PlanValues.NJHFDL || this.RealTimeValues?.NFDL ) {
+        if (this.PlanValues.NJHFDL == '') {
+          return '100%';
+        } else {
+          let data = (this.RealTimeValues?.NFDL / this.PlanValues.NJHFDL) * 100;
+          return data.toFixed(2) + '%';
+        }
+      } else {
+        return '-'
+      }
+    },
+  },
+}
+</script>
+
+<style  lang="less" scoped>
+.body {
+  height: 70vh;
+  // background-color: #000000;
+}
+
+@keyframes card {
+  0% {
+    right: -360px;
+  }
+
+  20% {
+    right: -300px;
+  }
+
+  100% {
+    right: 40px;
+  }
+
+}
+
+.card {
+  animation: card 2.5s linear;
+}
+
+.wind_card {
+  z-index: 140;
+  height: 158px;
+
+  .el-col {
+    flex: 1;
+    position: relative;
+  }
+
+  .grid-content {
+    text-align: center;
+    position: absolute;
+
+    .img {
+      position: relative;
+      width: 84px;
+      height: 84px;
+      background: url("../../../../public/img/home/instrumentPanel.png") no-repeat;
+
+      img {
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: rotateZ(360deg);
+        transform-origin: left top;
+      }
+
+      .information {
+        font-size: 14px;
+        color: #2B99FF;
+        font-family: "Bicubik";
+        position: absolute;
+        width: 100%;
+        top: 32px;
+      }
+
+      >.unit {
+        width: 100%;
+        color: #7D838C;
+        text-align: center;
+        position: absolute;
+        top: 58px;
+      }
+    }
+  }
+}
+
+.electric_card {
+  height: 320px;
+  top: 288px;
+  right: 40px;
+  padding: 24px 0px;
+  z-index: 99;
+
+  .el-row {
+    align-items: center;
+    margin-bottom: 31px;
+
+    .el-col:first-child {
+      text-align: right;
+      margin-right: 10px;
+      color: #B3B3B3;
+    }
+
+    .el-col:last-child {
+      text-align: left;
+      margin-left: 10px;
+      font-size: 14px;
+      font-family: "Bicubik";
+    }
+  }
+
+  .el-row:nth-child(2) {
+    .electric {
+      .progress_bar {
+        background: linear-gradient(90deg, #561F00, #853000, #F78712);
+
+        .img {
+          background: url("../../../../public/img/home/generatingCapacityDay.png") no-repeat;
+        }
+      }
+
+      .count {
+        color: #FF8300;
+      }
+    }
+  }
+
+  .el-header {
+    display: flex;
+    justify-content: space-between;
+
+    .title {
+      font-size: 16px;
+      font-family: 'SourceHanSansSC-Regular';
+    }
+
+    .unit {
+      color: #B1B1B1;
+    }
+  }
+
+  .electric {
+    width: 100%;
+    height: 4.5px;
+    background-color: rgba(142, 176, 255, 0.2);
+
+    .progress_bar {
+      position: relative;
+      height: 100%;
+      max-width: 100%;
+      background: linear-gradient(90deg, #001442, #1C99FF);
+
+      .img {
+        background: url("../../../../public/img/home/generatingCapacityMonth.png") no-repeat;
+        position: absolute;
+        display: inline-block;
+        width: 39px;
+        height: 39px;
+        top: -17px;
+        right: -22px;
+        transform: scale(0.8);
+      }
+
+      .count {
+        position: absolute;
+        top: -30px;
+        right: -22px;
+        font-size: 14px;
+        color: #2B99FF;
+        font-family: 'Bicubik';
+        font-weight: bolder;
+      }
+
+      .dot {
+        display: inline-block;
+        width: 22.4px;
+        height: 22.4px;
+        border-radius: 50%;
+        border: 1px solid #FF8300;
+        background-color: #573E27;
+        position: absolute;
+        right: -11px;
+        top: -9px;
+        text-align: center;
+        line-height: 22.4px;
+
+        .dots_center {
+          display: inline-block;
+          width: 12px;
+          height: 12px;
+          border-radius: 50%;
+          background-color: #FEC448;
+          box-shadow: 0px 0px 13px 12px #e77409a8;
+        }
+      }
+
+      .percentage {
+        position: absolute;
+        top: -8px;
+        right: -50px;
+        font-family: 'Bicubik';
+      }
+    }
+  }
+
+  .summarize {
+    position: absolute;
+    bottom: 0;
+    margin-bottom: 0;
+    width: 100%;
+    height: 80px;
+    background-color: rgba(0, 0, 0, 0.2);
+    border-bottom-left-radius: 8px;
+    border-bottom-right-radius: 8px;
+    color: #B3B3B3;
+    padding-left: 26px;
+    justify-content: space-between;
+
+    .left {
+      text-align: left !important;
+    }
+
+    .right {
+      text-align: left !important;
+      font-size: 12px !important;
+    }
+
+    p:last-child {
+      margin-top: 8px;
+
+      span:first-child {
+        font-size: 18px;
+        color: #FFFFFF;
+        display: inline-block;
+        width: 110px;
+        text-align: left;
+        font-family: 'Bicubik';
+      }
+    }
+
+    .line {
+      max-width: 1px;
+      height: 48px;
+      background: #333333;
+    }
+  }
+}
+
+.station_card {
+  height: 302px;
+  top: 618px;
+  right: 40px;
+  padding: 24px 14px;
+  color: #7D838C;
+  z-index: 99;
+
+  >.card_header {
+    line-height: 48px;
+
+    .el-col:first-child {
+      img {
+        margin-right: 30px;
+        vertical-align: -10%;
+      }
+
+      span {
+        font-size: 20px;
+        color: #1986E0;
+        display: inline-block;
+        width: 70px;
+        font-family: Bicubik;
+        line-height: 33px;
+      }
+    }
+
+    .el-col:last-child {
+      text-align: right;
+
+      span {
+        padding: 0 6px;
+        font-size: 20px;
+        text-align: center;
+        font-family: AgencyFB-Reg-Light;
+        color: #FFFFFF;
+        line-height: 33px;
+      }
+    }
+  }
+
+  >.el-row:last-child {
+    border: none;
+    margin-bottom: 0;
+  }
+}
+
+@media screen and (min-height: 1020px) {
+  .wind_card {
+    top: 160px;
+  }
+
+  .electric_card {
+    top: 350px;
+  }
+
+  .station_card {
+    top: 700px;
+  }
+}
+</style>

+ 110 - 0
src/views/Home/components/windlightSimple.vue

@@ -0,0 +1,110 @@
+<template>
+  <el-row class="card_simple">
+    <el-col>
+      <div>待机</div>
+      <div>{{ datadisposetoFix0(dataSimple,'DJTS')}}</div>
+    </el-col>
+    <el-col>
+      <div>运行</div>
+      <div> {{datadisposetoFix0(dataSimple,'YXTS')}} </div>
+    </el-col>
+    <el-col>
+      <div>限电</div>
+      <div>{{datadisposetoFix0(dataSimple,'XDTS')}}</div>
+    </el-col>
+    <el-col>
+      <div>故障</div>
+      <div>{{datadisposetoFix0(dataSimple,'JXTJTS')}}</div>
+    </el-col>
+    <el-col>
+      <div>检修</div>
+      <div>{{datadisposetoFix0(dataSimple,'GZTJTS')}}</div>
+    </el-col>
+    <el-col>
+      <div>离线</div>
+      <div>{{datadisposetoFix0(dataSimple,'TXZDTS')}}</div>
+    </el-col>
+    <el-col>
+      <div>受累</div>
+      <div>{{datadisposetoFix0(dataSimple,'SLTS')}}</div>
+    </el-col>
+  </el-row>
+</template>
+<script>
+export default {
+  props:{
+    dataSimple:{
+      type:Object,
+      required:false,
+      default:null,
+    }
+  },
+  data(){
+    return{
+
+    }
+  },
+  methods:{
+    datadisposetoFix0(obj, str,coefficient) {
+      if (obj) {
+        if (obj) {
+          if (obj[str] == '' && obj[str] !== 0) {
+            return '-'
+          } else{
+            if(coefficient){
+              return typeof obj[str]=='number' ? (obj[str]/coefficient).toFixed(2) : obj[str]/coefficient;
+            }else {
+              return typeof obj[str]=='number' ? obj[str].toFixed(0) : obj[str];
+            }
+          }
+        } else {
+          return '-'
+        }
+      }
+    },
+  }
+}
+
+</script>
+<style lang="less" scoped>
+.card_simple{
+  text-align: center;
+  border-bottom: 1px solid #333333;
+  padding-bottom: 20px;
+  margin-top: 10px;
+  margin-bottom: 20px;
+  .el-col{
+    flex: 1;
+    >div:first-child{
+      font-family: AgencyFB-Reg;
+      font-size: 14px;
+    }
+    >div:last-child{
+      font-size: 16px;
+      font-family: AgencyFB-Reg;
+      line-height: 30px;
+    }
+  }
+  .el-col:nth-child(1)>div:last-child{
+    color: #1C99FF;
+  }
+  .el-col:nth-child(2)>div:last-child{
+    color: #F7870E;
+  }
+  .el-col:nth-child(3)>div:last-child{
+    color: #FF5378;
+  }
+  .el-col:nth-child(4)>div:last-child{
+    color: #B3B3B3;
+  }
+  .el-col:nth-child(5)>div:last-child{
+    color:#05BB4C;
+  }
+  .el-col:nth-child(6)>div:last-child{
+    color:#FFF950;
+  }
+  .el-col:nth-child(7)>div:last-child{
+    color:#FFF;
+  }
+}
+</style>

+ 230 - 0
src/views/Home/index.vue

@@ -0,0 +1,230 @@
+<template>
+  <div id="home" class="body">
+    <headerNav class="headerNav" @firstRender="firstRender" @dataToggle="dataToggle" @typeFlag="typeFlag"
+      @company="company" />
+    <transition name="fade">
+      <SafeEcoPower :comoanyAssets="comoanyAssets" :RealTimeValues="RealTimeValues" :CalcValues="CalcValues"
+        :CurveValues="CurveValues" :windPowerCount="windPowerCount" :photovoltaicCount="photovoltaicCount"
+        :headerIndex="headerIndex" class="s" />
+    </transition>
+    <sd-map :PowerStation="PowerStation" @showAirData="showAirData" ref="sdMap" />
+    <windSpeedCom :comoanyAssets="comoanyAssets" :RealTimeValues="RealTimeValues" :CalcValues="CalcValues"
+      :RealTimeStaValues="RealTimeStaValues" :PlanValues="PlanValues" :headerIndex="headerIndex"
+      :activeNode="activeNode" :nodeCode="nodeCode" />
+  </div>
+</template>
+
+<script>
+import {
+  GetComoanyAssets,
+  GetRealTimeValues,
+  GetCalcValues,
+  GetPlanValues,
+  GetRealTimeStaValues,
+  GetCurveValues,
+  GetPowerStation,
+  GetPowerStationAssets
+} from '@/api/home'
+import headerNav from "@/components/headerNav/index";
+import windSpeedCom from './components/windSpeedCom';
+import SafeEcoPower from "./components/safeEcoPower";
+import SdMap from "./components/sdMap";
+
+export default {
+  name: 'Home',//首页
+  components: {
+    headerNav,
+    windSpeedCom,
+    SafeEcoPower,
+    SdMap,
+  },
+  data() {
+    return {
+      comoanyAssets: null,
+      RealTimeValues: null,
+      CalcValues: null,
+      RealTimeStaValues: {},
+      PlanValues: {},
+      PowerStation: [],
+      CurveValues: [],
+      headerIndex: '',
+      nodeCode: '',
+      activeNode: '',
+      chinaMap: "1",
+      shandongMap: "0",
+      windPowerCount: '',
+      photovoltaicCount: '',
+      timer1: '',
+      timer2: ''
+
+    }
+  },
+  methods: {
+    //首次加载
+    async firstRender(headerIndex, nodeCode, activeNode, windPowerCount, photovoltaicCount) {
+      this.headerIndex = headerIndex;
+      this.nodeCode = nodeCode;
+      this.activeNode = activeNode;
+      windPowerCount ? (this.windPowerCount = windPowerCount) : '';
+      photovoltaicCount ? (this.photovoltaicCount = photovoltaicCount) : '';
+      this.getComoanyAssets(); //获取公司资产信息
+      this.getPowerStation();//获取场站风机
+      this.getData()
+    },
+    getData() {
+      this.getRealTimeValues();
+      this.getCalcValues();
+      this.getPlanValues();
+      this.getRealTimeStaValues();
+      this.getCurveValues();
+    },
+    //查询资产
+    async getComoanyAssets() {
+      const data = await GetComoanyAssets({ companyCode: this.nodeCode, type: this.headerIndex })
+      this.comoanyAssets = data;
+    },
+    //获取地图电场编号
+    async getPowerStation() {
+      const data = await GetPowerStation({ companyCode: this.nodeCode, stationType: this.headerIndex });
+      this.PowerStation = data;
+    },
+    //根据场站编码获取资产信息
+    async getPowerStationAssets(params) {
+      const data = await GetPowerStationAssets({ stationCode: params });
+      this.comoanyAssets = data;
+    },
+    // 获取Vestore数据
+    async getRealTimeValues() {
+      let data;
+      let flag = 'comp'
+      let str = this.activeNode.substring(this.activeNode.length - 5, this.activeNode.length - 2);
+      if (str == 'STA') {
+        flag = 'stations';
+      };
+      if (flag == 'comp') {
+        data = await GetRealTimeValues({ companyCode: this.activeNode, uniformCode: 'AQTS,SSZGL,SSPJGZD,SSZNHGLZS,SSPJFS,RFDL,YFDL,NFDL,SSZBZGL' })
+      } else {
+        data = await GetRealTimeValues({ companyCode: this.nodeCode, uniformCode: 'AQTS,SSZGL,SSPJGZD,SSZNHGLZS,SSPJFS,RFDL,YFDL,NFDL,SSZBZGL' })
+      }
+      this.RealTimeValues = data;
+    },
+    // 获取计算数据
+    async getCalcValues() {
+      let data;
+      let flag = 'comp'
+      let str = this.activeNode.substring(this.activeNode.length - 5, this.activeNode.length - 2);
+      if (str == 'STA') {
+        flag = 'stations';
+      };
+      if (flag == 'comp') {
+        data = await GetCalcValues({ companyCode: this.activeNode, uniformCode: 'JYM,JYS,CO2,SO2,YLYXS,NLYXS' })
+      } else {
+        data = await GetCalcValues({ companyCode: this.nodeCode, uniformCode: 'JYM,JYS,CO2,SO2,YLYXS,NLYXS' })
+      }
+      this.CalcValues = data;
+    },
+    //获取计划发电量
+    async getPlanValues() {
+      let data;
+      let flag = 'comp'
+      let str = this.activeNode.substring(this.activeNode.length - 5, this.activeNode.length - 2);
+      if (str == 'STA') {
+        flag = 'stations';
+      };
+      if (flag == 'comp') {
+        data = await GetPlanValues({ companyCode: this.activeNode, planDate: ' ' });
+      } else {
+        data = await GetPlanValues({ companyCode: this.nodeCode, planDate: ' ' });
+      }
+      this.PlanValues = data;
+    },
+    //获取风机光伏具体情况
+    async getRealTimeStaValues() {
+      let data;
+      data = await GetRealTimeStaValues({ companyCode: this.activeNode });
+      console.log(data);
+      this.RealTimeStaValues = data;
+    },
+    //获取曲线数据
+    async getCurveValues(){
+      let data1;
+      let flag = 'comp'
+      let str = this.activeNode.substring(this.activeNode.length - 5, this.activeNode.length - 2);
+      if (str == 'STA') {
+        flag = 'stations';
+      };
+      if (flag == 'comp') {
+        data1 = await GetCurveValues({ companyCode: this.activeNode, uniformCode: 'ZYCGL,SSZBZGL,SSZNHGLZS,SSZGL', intervalTime: '900' });
+      } else {
+        data1 = await GetCurveValues({ companyCode: this.nodeCode, uniformCode: 'ZYCGL,SSZBZGL,SSZNHGLZS,SSZGL', intervalTime: '900' });
+      }
+      this.CurveValues = data1;
+    },
+
+    typeFlag(value) {
+      this.$refs.sdMap.handleClick(value)
+    },
+    company(value) {
+      this.$refs.sdMap.handleCompanyClick(value)
+    },
+    //风场光伏场站切换
+    showAirData(code, type) {
+      //根据场站编码获取资产信息
+      this.nodeCode = code;
+      this.headerIndex = type;
+      this.activeNode = code + type;
+      this.getPowerStationAssets(code);
+      this.getData()
+    }
+  },
+  mounted() {
+    this.timer1 = setInterval(() => {
+      this.getRealTimeValues();
+      this.getCalcValues();
+      this.getRealTimeStaValues();
+    }, 5000)
+    this.timer2 = setInterval(() => {
+      this.getCurveValues();
+      this.getPlanValues();
+    }, 5 * 60 * 1000)
+  },
+  unmounted() {
+    clearInterval(this.timer1);
+    clearInterval(this.timer2);
+    this.timer1 = null;
+    this.timer2 = null;
+  },
+}
+</script>
+
+<style lang="less" scoped>
+#home {
+  position: relative;
+  width: 100%;
+  padding-left: 40px;
+  height: calc(100% - 59px);
+  //background-repeat: no-repeat;
+  //background-size: 126%;
+  //background-position: 35% 70%;
+  background: url("../../../public/img/images/background01.png") no-repeat;
+  background-size: cover;
+
+  .headerNav {
+    position: absolute;
+    z-index: 99;
+  }
+
+  .fade-enter-from {
+    left: -100px;
+  }
+
+  .fade-enter-to {
+    left: 100px;
+  }
+
+  .fade-enter {
+    opacity: 0;
+    background-color: rgba(7, 17, 27, 0);
+  }
+}
+</style>

+ 393 - 0
src/views/curveDeviation/rateAnalysis/chartTheme.json

@@ -0,0 +1,393 @@
+
+{
+	"color": [
+			"#3fb1e3",
+			"#6be6c1",
+			"#626c91",
+			"#a0a7e6",
+			"#c4ebad",
+			"#96dee8"
+	],
+	"backgroundColor": "rgba(252,252,252,0)",
+	"textStyle": {},
+	"title": {
+			"textStyle": {
+					"color": "#B3B3B3"
+			},
+			"subtextStyle": {
+					"color": "#B3B3B3"
+			}
+	},
+	"line": {
+			"itemStyle": {
+					"borderWidth": "2"
+			},
+			"lineStyle": {
+					"width": "2"
+			},
+			"symbolSize": "8",
+			"symbol": "emptyCircle",
+			"smooth": true
+	},
+	"radar": {
+			"itemStyle": {
+					"borderWidth": "2"
+			},
+			"lineStyle": {
+					"width": "3"
+			},
+			"symbolSize": "8",
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"bar": {
+			"itemStyle": {
+					"barBorderWidth": 0,
+					"barBorderColor": "#ccc"
+			}
+	},
+	"pie": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"scatter": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"boxplot": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"parallel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"sankey": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"funnel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"gauge": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"candlestick": {
+			"itemStyle": {
+					"color": "#e6a0d2",
+					"color0": "transparent",
+					"borderColor": "#e6a0d2",
+					"borderColor0": "#3fb1e3",
+					"borderWidth": "2"
+			}
+	},
+	"graph": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			},
+			"lineStyle": {
+					"width": "1",
+					"color": "#cccccc"
+			},
+			"symbolSize": "8",
+			"symbol": "emptyCircle",
+			"smooth": false,
+			"color": [
+					"#3fb1e3",
+					"#6be6c1",
+					"#626c91",
+					"#a0a7e6",
+					"#c4ebad",
+					"#96dee8"
+			],
+			"label": {
+					"color": "#ffffff"
+			}
+	},
+	"map": {
+			"itemStyle": {
+					"areaColor": "#eeeeee",
+					"borderColor": "#aaaaaa",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#ffffff"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "rgba(63,177,227,0.25)",
+							"borderColor": "#3fb1e3",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#3fb1e3"
+					}
+			}
+	},
+	"geo": {
+			"itemStyle": {
+					"areaColor": "#eeeeee",
+					"borderColor": "#aaaaaa",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#ffffff"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "rgba(63,177,227,0.25)",
+							"borderColor": "#3fb1e3",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#3fb1e3"
+					}
+			}
+	},
+	"categoryAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#b3b3b386"
+					}
+			},
+			"axisTick": {
+					"show": false,
+					"lineStyle": {
+							"color": "#b3b3b386"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#b3b3b386"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#b3b3b386"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.05)",
+									"rgba(200,200,200,0.02)"
+							]
+					}
+			}
+	},
+	"valueAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#b3b3b386"
+					}
+			},
+			"axisTick": {
+					"show": false,
+					"lineStyle": {
+							"color": "#b3b3b386"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#b3b3b386",
+					"fontSize": 10
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#b3b3b386"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.05)",
+									"rgba(200,200,200,0.02)"
+							]
+					}
+			}
+	},
+	"logAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#cccccc"
+					}
+			},
+			"axisTick": {
+					"show": false,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#999999"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#eeeeee"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.05)",
+									"rgba(200,200,200,0.02)"
+							]
+					}
+			}
+	},
+	"timeAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#cccccc"
+					}
+			},
+			"axisTick": {
+					"show": false,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#999999"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#eeeeee"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.05)",
+									"rgba(200,200,200,0.02)"
+							]
+					}
+			}
+	},
+	"toolbox": {
+			"iconStyle": {
+					"borderColor": "#999999"
+			},
+			"emphasis": {
+					"iconStyle": {
+							"borderColor": "#666666"
+					}
+			}
+	},
+	"legend": {
+			"textStyle": {
+					"color": "#999999"
+			}
+	},
+	"tooltip": {
+			"axisPointer": {
+					"lineStyle": {
+							"color": "#cccccc",
+							"width": 1
+					},
+					"crossStyle": {
+							"color": "#cccccc",
+							"width": 1
+					}
+			}
+	},
+	"timeline": {
+			"lineStyle": {
+					"color": "#626c91",
+					"width": 1
+			},
+			"itemStyle": {
+					"color": "#626c91",
+					"borderWidth": 1
+			},
+			"controlStyle": {
+					"color": "#626c91",
+					"borderColor": "#626c91",
+					"borderWidth": 0.5
+			},
+			"checkpointStyle": {
+					"color": "#3fb1e3",
+					"borderColor": "#3fb1e3"
+			},
+			"label": {
+					"color": "#626c91"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"color": "#626c91"
+					},
+					"controlStyle": {
+							"color": "#626c91",
+							"borderColor": "#626c91",
+							"borderWidth": 0.5
+					},
+					"label": {
+							"color": "#626c91"
+					}
+			}
+	},
+	"visualMap": {
+			"color": [
+					"#2a99c9",
+					"#afe8ff"
+			]
+	},
+	"dataZoom": {
+			"backgroundColor": "rgba(255,255,255,0)",
+			"dataBackgroundColor": "rgba(222,222,222,1)",
+			"fillerColor": "rgba(114,230,212,0.25)",
+			"handleColor": "#cccccc",
+			"handleSize": "100%",
+			"textStyle": {
+					"color": "#999999"
+			}
+	},
+	"markPoint": {
+			"label": {
+					"color": "#ffffff"
+			},
+			"emphasis": {
+					"label": {
+							"color": "#ffffff"
+					}
+			}
+	}
+}

+ 114 - 0
src/views/curveDeviation/rateAnalysis/components/chart.vue

@@ -0,0 +1,114 @@
+<script setup>
+import util from "@tools/util";
+import chartTheme from './../chartTheme.json'
+import { ref, toRaw, computed, onMounted, watch } from 'vue';
+import * as echarts from 'echarts'
+const chartId = 'chart-' + util.newGUID(); //chartId
+const chartIns = ref(null)  //chart 实例
+const props = defineProps({
+	xAxis: {
+		type: Object,
+		required: true,
+		default: () => ({})
+	},
+	series: {
+		type: Array,
+		required: true
+	},
+	height: {
+		type: String,
+		required: false,
+		default: '500px'
+	},
+	width: {
+		type: String,
+		required: false,
+		default: '500px'
+	},
+	title: {
+		type: String,
+		required: false
+	},
+	subtext: {
+		type: String,
+		required: false
+	},
+	isRadar: {  //是否显示雷达图
+		type: Boolean,
+		required: false,
+		default: false
+	}
+})
+
+/**定义option */
+const option = computed({
+	get() {
+		return {
+			title: {
+				text: props.title || '',
+				subtext: props.subtext || '',
+				top: 10,
+				left: 30,
+			},
+			angleAxis: props.xAxis || {},
+			radiusAxis: {},
+			radar: props.isRadar?  [  //雷达图设定区域
+				{
+					indicator: props.xAxis.data || [],
+					center: ['60%','50%'],
+					radius: '70%',
+					splitLine: {
+						show: false,
+					},
+					splitArea: {
+						show: false
+					}
+				},
+			]: {},
+			polar: {
+				radius: '70%',
+				center: ['60%','50%']
+			},
+			tooltip: {
+				formatter: (params) => {
+					return params.componentSubType==='radar'? `${params.name}` : `${params.seriesName}m<br/>${params.value>1? '频次:'+ params.value: ''}`
+				},
+				confine: true
+			},
+			series: props.series || [],
+			legend: {
+				show: true,
+				orient: 'vertical',
+				left: 30,
+				// itemWidth: 16,
+				// itemHeight: 10,
+				textStyle: {
+					// fontSize: util.vh(10)
+				},
+				top: 'middle',
+				data: ['0-2.5','2.5-5','5-7.5','7.5-10','10-12.5','12.5-15','15-17.5','17.5-20','20-22.5','22.5-25','25-inf']
+			}
+		}
+	},
+	set(val) { }
+})
+watch(() => option, (newVal, oldVal) => {
+	if (chartIns.value) {
+		const echartIns = toRaw(chartIns.value)
+		echartIns.setOption(newVal.value)
+	}
+}, { deep: true })
+
+onMounted(() => {
+	echarts.registerTheme('chartTheme', chartTheme)
+	const echartIns =	echarts.init(document.getElementById(chartId),'chartTheme') 
+	chartIns.value = echartIns
+	echartIns.setOption(option.value)
+	window.addEventListener('resize', () => {
+		echartIns.resize()
+	})
+})
+</script>
+<template>
+	<div :id="chartId" :style="{ height: props.height, width: props.width }"></div>
+</template>

+ 126 - 0
src/views/curveDeviation/rateAnalysis/components/lineChart.vue

@@ -0,0 +1,126 @@
+<script setup>
+import util from "@tools/util";
+import chartTheme from './../chartTheme.json'
+import { ref, toRaw, computed, onMounted, watch, nextTick } from 'vue';
+import * as echarts from 'echarts'
+const chartId = 'chart-' + util.newGUID(); //chartId
+const chartIns = ref(null)  //chart 实例
+const props = defineProps({
+	xAxis: {
+		type: Object,
+		required: true,
+		default: () => ({})
+	},
+	yAxis: {
+		type: Array,
+		required: false
+	},
+	series: {
+		type: Array,
+		required: true
+	},
+	dataset: {
+		type: Array,
+		required: false,
+		default: () => ([])
+	},
+	height: {
+		type: String,
+		required: false,
+		default: '500px'
+	},
+	width: {
+		type: String,
+		required: false,
+		default: '500px'
+	},
+	title: {
+		type: String,
+		required: false
+	},
+	subtext: {
+		type: String,
+		required: false
+	},
+})
+
+/**定义option */
+const option = computed({
+	get() {
+		return {
+			color:[
+				"#FF8700",
+				"#0098d980",
+				"#626c91",
+				"#a0a7e6",
+				"#c4ebad",
+				"#96dee8"
+			],
+			title: {
+				text: props.title || '',
+				subtext: props.subtext || '',
+				top: 10,
+				left: 30,
+			},
+			xAxis: props.xAxis || {},
+			yAxis: props.yAxis || {},
+			tooltip: {
+				confine: true,
+				axisPointer: {
+            type: "cross",
+          },
+			},
+			dataset: props.dataset || [],
+			series: props.series || [],
+			legend: {
+				right: "120",
+				top: "5",
+				itemWidth: 6,
+			},
+			grid: {
+				top: 42,
+				left: 40,
+				right: 40,
+				bottom: 40,
+			},
+			dataZoom: [
+          {
+            type: "inside", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+          {
+            type: "slider", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+        ],
+		}
+	},
+	set(val) { }
+})
+watch(() => option, (newVal, oldVal) => {
+	if (chartIns.value) {
+		console.log(newVal)
+		const echartIns = toRaw(chartIns.value)
+		echartIns.setOption(toRaw(newVal.value))
+	}
+}, { deep: true })
+
+onMounted(() => {
+	echarts.registerTheme('chartTheme', chartTheme)
+	const echartIns =	echarts.init(document.getElementById(chartId),'chartTheme') 
+	chartIns.value = echartIns
+	echartIns.setOption(option.value)
+	window.addEventListener('resize', () => {
+		echartIns.resize()
+	})
+})
+</script>
+<template>
+	<div :id="chartId" :style="{ height: props.height, width: props.width }"></div>
+</template>

+ 117 - 0
src/views/curveDeviation/rateAnalysis/components/scatterSingleChart.vue

@@ -0,0 +1,117 @@
+<script setup name="scatterSingleChart">
+import util from "@tools/util";
+import chartTheme from './../chartTheme.json'
+import { ref, toRaw, computed, onMounted, watch, nextTick } from 'vue';
+import * as echarts from 'echarts'
+const chartId = 'chart-' + util.newGUID(); //chartId
+const chartIns = ref(null)  //chart 实例
+const props = defineProps({
+	xAxis: {
+		type: Array,
+		required: true,
+		default: () => ([])
+	},
+	yAxis: {
+		type: Array,
+		required: true,
+		default: () => ([])
+	},
+	series: {
+		type: Array,
+		required: false,
+		default: () => ([])
+	},
+	height: {
+		type: String,
+		required: false,
+		default: '500px'
+	},
+	width: {
+		type: String,
+		required: false,
+		default: '500px'
+	},
+})
+
+/**定义option */
+const option = computed({
+	get() {
+		return {
+			tooltip: {
+				position: 'top',
+				formatter: function (params) {
+					return (
+						params.value[2] +
+						' commits in ' +
+						params.value[0] +
+						' of ' +
+						params.value[1]
+					);
+				}
+			},
+			grid: {
+				top: 20,
+				left: 2,
+				bottom: 10,
+				right: 20,
+				containLabel: true
+			},
+			xAxis: props.xAxis || [],
+			//  {
+			// 	type: 'category',
+			// 	data: props.xAxis || [],
+			// 	boundaryGap: false,
+			// 	splitLine: {
+			// 		show: true
+			// 	},
+			// 	axisLine: {
+			// 		show: false
+			// 	}
+			// },
+			yAxis: props.yAxis || [],
+			// {
+			// 	type: 'category',
+			// 	data: props.yAxis,
+			// 	axisLine: {
+			// 		show: false
+			// 	}
+			// },
+			series: props.series || [] 
+			// [
+			// 	{
+			// 		name: 'Punch Card',
+			// 		type: 'scatter',
+			// 		symbolSize: function (val) {
+			// 			return val[2] * 2;
+			// 		},
+			// 		data: props.data,
+			// 		animationDelay: function (idx) {
+			// 			return idx * 5;
+			// 		}
+			// 	}
+			// ]
+		}
+	},
+	set(val) { }
+})
+watch(() => option, (newVal, oldVal) => {
+	if (chartIns.value) {
+		console.log(newVal)
+		const echartIns = toRaw(chartIns.value)
+		echartIns.setOption(toRaw(newVal.value))
+	}
+}, { deep: true })
+
+onMounted(() => {
+	echarts.registerTheme('chartTheme', chartTheme)
+	const echartIns = echarts.init(document.getElementById(chartId), 'chartTheme')
+	chartIns.value = echartIns
+	echartIns.setOption(option.value)
+	window.addEventListener('resize', () => {
+		echartIns.resize()
+	})
+})
+</script>
+<template>
+	<div :id="chartId" :style="{ height: props.height, width: props.width }"></div>
+</template>

+ 29 - 0
src/views/curveDeviation/rateAnalysis/components/search.vue

@@ -0,0 +1,29 @@
+<script setup name="search">
+import submitBtn from '@com/submitBtn'
+import { onMounted, reactive, ref } from 'vue'
+
+const queryForm = reactive({
+	mode: 0
+})
+/**执行 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	emits('submit', queryForm)
+}
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#B3B3B3] text-[14px]">操作面板</div>
+		<el-form class="whitespace-nowrap" :inline="true" :model="queryForm">
+			<el-form-item label="合并方式" class="!mb-0">
+				<el-select v-model="queryForm.mode">
+					<el-option :value="0" label="多表单台"></el-option>
+					<!-- <el-option :value="1" label="单表多台"></el-option> -->
+				</el-select>
+			</el-form-item>
+			<el-form-item class="!mb-0">
+				<submit-btn v-prevdbclick:5000="funSubmit" desc="执行"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

文件差異過大導致無法顯示
+ 449 - 0
src/views/curveDeviation/rateAnalysis/index.vue


+ 398 - 0
src/views/dataFilter/chartTheme.json

@@ -0,0 +1,398 @@
+
+{
+	"color": [
+			"#1C99FF",
+			"#FF8700",
+			"#e6b600d9",
+			"#0098d9",
+			"#3D54BE",
+			"#005eaa",
+			"#cda819",
+			"#32a487"
+	],
+	"textStyle": {},
+	"title": {
+			"textStyle": {
+					"color": "#333333"
+			},
+			"subtextStyle": {
+					"color": "#aaaaaa"
+			}
+	},
+	"line": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"radar": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"bar": {
+			"itemStyle": {
+					"barBorderWidth": 0,
+					"barBorderColor": "#ccc"
+			}
+	},
+	"pie": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"scatter": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"boxplot": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"parallel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"sankey": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"funnel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"gauge": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"candlestick": {
+			"itemStyle": {
+					"color": "#c12e34",
+					"color0": "#2b821d",
+					"borderColor": "#c12e34",
+					"borderColor0": "#2b821d",
+					"borderWidth": 1
+			}
+	},
+	"graph": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			},
+			"lineStyle": {
+					"width": 1,
+					"color": "#aaaaaa"
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false,
+			"color": [
+					"#c12e34",
+					"#e6b600",
+					"#0098d9",
+					"#50ec39",
+					"#005eaa",
+					"#339ca8",
+					"#cda819",
+					"#32a487"
+			],
+			"label": {
+					"color": "#eeeeee"
+			}
+	},
+	"map": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"geo": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"categoryAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": false,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"valueAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#B3B3B3"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#B3B3B3"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#B3B3B3"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"logAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"timeAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"toolbox": {
+			"iconStyle": {
+					"borderColor": "#06467c"
+			},
+			"emphasis": {
+					"iconStyle": {
+							"borderColor": "#4187c2"
+					}
+			},
+			"textStyle": {
+				"color": "#B3B3B3"
+			}
+	},
+	"legend": {
+			"textStyle": {
+					"color": "#B3B3B3"
+			}
+	},
+	"tooltip": {
+			"axisPointer": {
+					"lineStyle": {
+							"color": "#cccccc",
+							"width": 1
+					},
+					"crossStyle": {
+							"color": "#cccccc",
+							"width": 1
+					}
+			}
+	},
+	"timeline": {
+			"lineStyle": {
+					"color": "#005eaa",
+					"width": 1
+			},
+			"itemStyle": {
+					"color": "#005eaa",
+					"borderWidth": 1
+			},
+			"controlStyle": {
+					"color": "#005eaa",
+					"borderColor": "#005eaa",
+					"borderWidth": 0.5
+			},
+			"checkpointStyle": {
+					"color": "#005eaa",
+					"borderColor": "#316bc2"
+			},
+			"label": {
+					"color": "#005eaa"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"color": "#005eaa"
+					},
+					"controlStyle": {
+							"color": "#005eaa",
+							"borderColor": "#005eaa",
+							"borderWidth": 0.5
+					},
+					"label": {
+							"color": "#005eaa"
+					}
+			}
+	},
+	"visualMap": {
+			"color": [
+					"#1790cf",
+					"#a2d4e6"
+			]
+	},
+	"dataZoom": {
+			"backgroundColor": "rgba(47,69,84,0)",
+			"dataBackgroundColor": "rgba(47,69,84,0.3)",
+			"fillerColor": "rgba(167,183,204,0.4)",
+			"handleColor": "#a7b7cc",
+			"handleSize": "100%",
+			"textStyle": {
+					"color": "#333333"
+			}
+	},
+	"markPoint": {
+			"label": {
+					"color": "#eeeeee"
+			},
+			"emphasis": {
+					"label": {
+							"color": "#eeeeee"
+					}
+			}
+	}
+}

+ 321 - 0
src/views/dataFilter/combine/components/current-scatter-chart.vue

@@ -0,0 +1,321 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@tools/util";
+import partten from "@tools/partten";
+import * as echarts from "echarts";
+import chartTheme from './../../chartTheme.json'
+
+export default {
+  name: 'currentScatterChart',
+  props: {
+    // 图表宽度
+    width: {
+      type: String,
+      default: "100%",
+    },
+    // 图表高度
+    height: {
+      type: String,
+      default: "350px",
+    },
+    // 图表主标题
+    chartTitle: {
+      type: String,
+      default: "自定义图表组件",
+    },
+    // X 轴配置项
+    xAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // Y 轴配置项
+    yAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    dataSet: {
+      type: String,
+      default: ''
+    },
+    // 图表核心数据
+    seriesData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // 是否显示图表图例
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否默认采用笔刷模式
+    brushSelected: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      color: [
+        "#05bb4c",
+        "#4b55ae",
+        "#fa8c16",
+        "#f8de5b",
+        "#1a93cf",
+        "#c531c7",
+        "#bd3338",
+      ],
+      theme: 'dark'
+    };
+  },
+  methods: {
+    resize() {},
+    initChart() {
+      const that = this;
+      echarts.registerTheme('chartTheme', chartTheme)
+      let myChart = echarts.init(document.getElementById(this.id), 'chartTheme');
+      //指定图表的配置项和数据
+      const option = {
+        //标题
+        title: {
+          text: that.chartTitle,
+          right: 440,
+          top: 4,
+          textStyle: {
+            fontSize: 14,
+            color: that.theme === "dark" ? partten.getColor("grayl") : "#000",
+          },
+        },
+        // backgroundColor:
+        //   that.theme === "dark"
+        //     ? "rgba(0,0,0,0.4)"
+        //     : "rgba(255,255,255,0.5)",
+        //工具箱
+        toolbox: {
+          show: true,
+          x: "right",
+          position: [10, 10],
+          // backgroundColor:'rgba(0,0,0,0.4)',
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: "#fff",
+          },
+          iconStyle: {
+            borderColor:"#fff",
+          },
+          emphasis: {
+            iconStyle: {
+              borderColor: "#fff",
+            },
+          },
+        },
+        tooltip: {
+          trigger: "item",
+          axisPointer: {
+            type: "cross",
+          },
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: "#fff",
+          },
+          formatter(params) {
+            return params.value?.x
+              ? `${params.seriesName}<br />风速:${params.value.x}m/s<br />功率:${params.value.y}kW`
+              : `${params.name}`;
+          },
+        },
+        brush: {
+          seriesIndex: [2,3],
+          yAxisIndex: 0,
+          transformable: true,
+          throttleType: "debounce",
+          throttleDelay: 1000,
+          removeOnClick: true,
+          brushType: "polygon",
+          brushMode: "multiple",
+          brushStyle: {
+            borderWidth: 1,
+            borderColor: "#ff2424",
+          },
+        },
+        dataZoom: [
+          {
+            type: "inside", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+          {
+            type: "slider", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+        ],
+        textStyle: {
+          fontSize: util.vh(16),
+          color: that.theme === "dark" ? "#fff" : "#000",
+        },
+        //图例-每一条数据的名字
+        legend: {
+          show: that.showLegend,
+          data: [ "拟合功率", "保证功率","无用点", "有用点", "Cp值"],
+          right: "120",
+          top: "5",
+          // icon: "circle",
+          itemWidth: 6,
+          inactiveColor:
+            that.theme === "dark"
+              ? partten.getColor("gray")
+              : "#000",
+          textStyle: {
+            color:
+              that.theme === "dark"
+                ? partten.getColor("grayl")
+                : "#000",
+            fontSize: 12,
+          },
+          
+        },
+        grid: {
+          top: 48,
+          left: 40,
+          right: 40,
+          bottom: 24,
+        },
+        //x轴
+        xAxis: [
+          {
+            type: "value",
+            boundaryGap: false,
+            data: that.xAxisData || [],
+            min: 0,
+            max: 25,
+            interval: 1,
+            axisLabel: {
+              formatter: "{value}",
+            },
+            splitLine: {
+              show: false,
+            },
+            textStyle: {
+              color:
+                that.theme === "dark"
+                  ? partten.getColor("gray")
+                  : "#000",
+            },
+          },
+        ],
+        //y轴没有显式设置,根据值自动生成y轴
+        yAxis: [{
+          splitLine: { show: false },
+          position: 'left',
+          min: 0,
+        }, {
+          splitLine: { show: false },
+          position: 'right',
+          min: 0,
+        }],
+        animation: true,
+        dataset: that.dataSet.length? JSON.parse(that.dataSet) : [],
+        //数据-data是最终要显示的数据
+        series: that.seriesData,
+      };
+
+      that.resize = function () {
+        myChart.resize();
+      };
+
+      window.addEventListener("resize", that.resize);
+
+      myChart.setOption(option);
+      if (that.brushSelected) {
+        myChart.dispatchAction({
+          type: "takeGlobalCursor",
+          // 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
+          key: "brush",
+          brushOption: {
+            seriesIndex: [2,3],
+            yAxisIndex: 0,
+            transformable: true,
+            throttleType: "debounce",
+            throttleDelay: 1000,
+            removeOnClick: true,
+            brushType: "polygon",
+            brushMode: "multiple",
+            brushStyle: {
+              borderWidth: 1,
+              color: "rgba(255,36,36,0.2)",
+              borderColor: "#ff2424",
+            },
+          },
+        });
+      }
+      myChart.off("brushSelected");
+      myChart.on("brushSelected", (params) => {
+        that.$emit("getSelected", params.batch || []);
+      });
+      myChart.off('click')
+      myChart.on('click', params => {
+          console.log(params)
+          if(params.componentType === 'markArea'){
+            myChart.dispatchAction({
+              type: 'brush',
+              areas: [
+                {
+                  xAxisIndex: 0,
+                  brushType: 'lineX',
+                  coordRange: [params.data.coord[0][0], params.data.coord[1][0]]
+                },
+              ]
+            });
+          }
+        })
+    },
+  },
+  created() {
+    this.id = "chart-" + util.newGUID();
+  },
+  mounted() {
+    // this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    // });
+  },
+  updated() {
+    console.log('update')
+    let myChart = echarts.init(document.getElementById(this.id));
+    myChart.dispose();
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 53 - 0
src/views/dataFilter/combine/components/search.vue

@@ -0,0 +1,53 @@
+<script setup name="search">
+import { reactive, ref } from 'vue'
+import submitBtn from '@com/submitBtn'
+
+const queryForm = reactive({
+	maxs: 25,
+	mins: 0,
+	maxp: 2500,
+	minp: 0,
+	dimension: 10,  //拟合维度
+	mode: 0   //拟合方式
+})
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	emits('submit', queryForm)
+}
+/**created */
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#B3B3B3] text-[14px]">操作面板</div>
+		<el-form class="" :inline="true" :model="queryForm">
+			<el-form-item label="最大风速" class="!mb-0">
+				<el-input-number v-model="queryForm.maxs" size="small" :max="30"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最小风速" class="!mb-0">
+				<el-input-number v-model="queryForm.mins" size="small" :min="0"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最大功率" class="!mb-0">
+				<el-input-number v-model="queryForm.maxp" size="small"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最小功率" class="!mb-0">
+				<el-input-number v-model="queryForm.minp" size="small" :min="0"></el-input-number>
+			</el-form-item>
+			<el-form-item label="多项式" class="!mb-0">
+				<el-select v-model="queryForm.dimension" class="w-[80px]">
+					<el-option v-for="item in 30" :key="item" :value="item" :label="item"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="拟合方式" class="!mb-0">
+				<el-select v-model="queryForm.mode" class="w-[120px]">
+					<el-option :value="0" label="单台拟合"></el-option>
+					<el-option :value="1" label="合并拟合"></el-option>
+					<el-option :value="2" label="同名拟合"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item class="!mb-0">
+				<submit-btn @click="funSubmit" desc="曲线拟合"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

+ 52 - 0
src/views/dataFilter/combine/components/table.vue

@@ -0,0 +1,52 @@
+<script setup name="table">
+import { computed, ref } from 'vue';
+
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 46 : 739
+})
+</script>
+<template>
+  <div ref="tableRef" class=""
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <div class="flex justify-between items-center pb-[10px]">
+      <h3>{{ props.tableName }}</h3>
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    </div>
+    <el-table stripe :data="props.data" size="small" v-loading="props.loading" :max-height="tableHeight"
+      :style="{ width: '100%' }">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop"
+        :label="item.label" sortable resizable :min-width="item.width ? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 537 - 0
src/views/dataFilter/combine/index.vue

@@ -0,0 +1,537 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import submitBtn from '@/components/submitBtn'
+import { ref, nextTick, onActivated, onMounted, reactive } from 'vue'
+import request from '@/utils/request'
+import { ElMessage } from 'element-plus'
+import util from "@tools/util";
+import CurrentScatterChart from './components/current-scatter-chart.vue'
+// import dotRes from '@/data/dot.json'
+// import tableRes from '@/data/table.json'
+// import areaDataRes from '@/data/areaData.json'
+/**配置参数 */
+const treeHeight = ref((window.innerHeight - 210) / 2 + 'px') //tree高度
+const excelHeight = ref((window.innerHeight - 210) / 2 + 'px') //excel高度
+const tableHeight = ref(window.innerHeight - 254 + 'px')
+/**excel 开始 */
+const excelCheckboxShow = ref(false)
+const excelType = ref('')
+const excelCheckIds = ref([])
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	activeTab.value = '1'
+	isChartArea.value = false
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	excelType.value = obj.type // 接收excel的type 用于控制右侧tab展示
+
+	let res = null
+	let chartRes = {
+		scatterhs: [[]],
+		scatterls: [[]],
+		sjgl: [[]],
+		llgl: [[]],
+		cpz: [[]]
+	}
+	let poiRes = null
+	let chartResponse = null
+	tableLoading.value = true
+	if (obj.type === 'process') {
+		res = await request.get('/power/process/show', { params: { id: obj.id } })
+	} else if (obj.type === 'fitting') {
+		activeTab.value = '2'
+		res = await request.get('/power/fitting/show', { params: { id: obj.id } })
+		// res = tableRes
+		// chartResponse = dotRes
+		chartResponse = await request.get('/power/fitting/curve', { params: { id: obj.id, p: 1 } })
+		poiRes = await request.get('/power/fitting/curve/ratio', {params: {id: obj.id}})
+		// poiRes = areaDataRes
+	}
+	tableColumn.value = res.data.title.map(o => {
+		return {
+			prop: o.key,
+			width: o.des==='时间'? 100: 80,
+			label: o.des,
+		}
+	})
+	tableData.value = res.data.data
+	tableLoading.value = false
+
+	// markDot 
+	if(poiRes && poiRes.code=== 200){
+		markDot.pcl5 = poiRes.data.pcl5
+		markDot.pcl10 = poiRes.data.pcl10
+		markDot.pcl12 = poiRes.data.pcl12
+		markDot.pcl25 = poiRes.data.pcl25
+	}
+
+	if (chartResponse && chartResponse.code === 200) {
+		chartRes = chartResponse.data
+		avgObj.cpavg = chartRes.obj.cpavg?.toFixed(2)
+		avgObj.frequency = chartRes.obj.frequency?.toFixed(2)
+		avgObj.pcratio = chartRes.obj.pcratio?.toFixed(2)
+		dataSet.value = JSON.stringify([
+			{
+				source: chartRes.wyd
+			},
+			{
+				source: chartRes.yyd
+			}
+		])
+		const color = ["#1C99FF", "#FF8700", "#3D54BE", "#fa8c16", "#1DA0D7", "#DD5044"]
+		seriesData.value = [
+			{
+				name: "拟合功率",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: chartRes.sjgl,
+				xAxisIndex: 0,
+			},
+			{
+				name: "保证功率",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: chartRes.llgl,
+				xAxisIndex: 0,
+			},
+			{
+				type: 'effectScatter',
+				showEffectOn: "emphasis",
+				rippleEffect: {
+					scale: 1
+				},
+				name: '无用点',
+				symbolSize: (data) => {
+					return data.s ? data.s > 10 ? 10 : data.s : 4
+				},
+				datasetIndex: 0,
+				encode: {
+					x: 'x',
+					y: 'y'
+				},
+				xAxisIndex: 0,
+				yAxisIndex: 0,
+			},
+			{
+				type: 'effectScatter',
+				showEffectOn: "emphasis",
+				rippleEffect: {
+					scale: 1
+				},
+				name: '有用点',
+				symbolSize: (data) => {
+					return data.s ? data.s > 10 ? 10 : data.s : 4
+				},
+				datasetIndex: 1,
+				encode: {
+					x: 'x',
+					y: 'y'
+				},
+				xAxisIndex: 0,
+				yAxisIndex: 0,
+			},
+			{
+				name: "Cp值",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: chartRes.cpz,
+				xAxisIndex: 0,
+				yAxisIndex: 1,
+			},
+		]
+	}
+}
+const funExcelCheckChange = ({ checkArr, data }) => {   //bug 
+	excelCheckIds.value = checkArr
+}
+/**excel fitData */
+const excelFitList = ref([])
+/**prepare tree 开始 */
+const treeData = ref([])
+const funRepeatMap = (arr) => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+			}
+		}
+		return {
+			...o,
+			children: o.children ? funRepeatMap(o.children) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	const res = await request.get("/power/process/tree")
+	treeData.value = funRepeatMap(res.data)
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	excelCheckboxShow.value = true
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+const funTreeCheckChange = ({ current, checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys }) => {  //tree change  -> excel change
+	funCurrentChange({ current, currentNode: '' })
+	const checkIds = []
+	if (checkedNodes.length) {
+		for (const node of checkedNodes) {
+			if (node.childs && node.childs.length) {
+				for (const child of node.childs) {
+					checkIds.push(child.id)
+				}
+			}
+		}
+	}
+	excelCheckIds.value = checkIds
+}
+
+/**process tree 开始 */
+const processTreeData = ref([])
+const funGetProcessTree = async () => {
+	const res = await request.get("/power/fitting/tree")
+	processTreeData.value = funRepeatMap(res.data)
+}
+const funProcessCurrentChange = ({ current, currentNode }) => {
+	if (current.childs) {
+		excelFitList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelFitList.value = []
+	}
+}
+
+/**table 开始 */
+const tableShowId = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableName = ref('')
+const tableData = ref([])
+/**table 结束 */
+/**search 开始 */
+const funSubmit = async (query) => {
+	if (!excelCheckIds.value.length) {
+		ElMessage.error('请勾选要预处理的项')
+		return false
+	}
+	const params = {
+		...query,
+		ids: excelCheckIds.value.join(',')
+	}
+	const res = await request.get('/power/fitting/data', { params: params })
+	if (res.code === 200) {
+		ElMessage.success(res.msg)
+		funGetProcessTree()
+		const excelInfo = res.data
+
+		/**拟合完成后 显示右侧图表及数据 */
+		funExcelChange({
+			id: excelInfo.id,
+			name: excelInfo.path.substring(excelInfo.path.indexOf(excelInfo.station + '_') + (excelInfo.station + '_').length),
+			type: 'fitting'
+		})
+	}
+}
+/**chart Data */
+const avgObj = reactive({ //平均cpz等
+	cpavg: '',
+	frequency: '',
+	pcratio: ''
+})
+const markDot = reactive({ //3-5 point点等
+	pcl5: null,
+	pcl10: null,
+	pcl12: null,
+	pcl25: null
+})
+const xAxisData = ref([])
+const chartRef = ref() //chart 的ref
+const seriesData = ref([])
+const isChartArea = ref(false) // 用来控制图表是否区域划分
+const dataSet = ref('')
+const funChartSelect = async (batch) => {
+	const wDataArr = []
+	const yDataArr = []
+	let scatterls = []
+	let scatterhs = []
+	let dataSetObj = []
+	wtData.value = []
+	if (batch?.length && dataSet.value) {
+		scatterls = batch[0].selected[2].dataIndex
+		scatterhs = batch[0].selected[3].dataIndex
+		if (scatterls?.length || scatterhs?.length) {
+			dataSetObj = JSON.parse(dataSet.value)
+			if (scatterls?.length) {
+				for (const scatterIndex of scatterls) {
+					wDataArr.push(dataSetObj[0].source[scatterIndex].k)
+				}
+			}
+			if (scatterhs?.length) {
+				for (const scatterIndex of scatterhs) {
+					yDataArr.push(dataSetObj[1].source[scatterIndex].k)
+				}
+			}
+			const wtRes = await request.get('/power/fitting/filter', { params: { yk: yDataArr.join(','), wk: wDataArr.join(',') } })
+			if (wtRes.code === 200) {
+				let id = 1
+				const tempArr = [] //用于以风机id 聚合dataArr
+				if (wtRes.data?.length) {
+					for (const data of wtRes.data) {
+						if (tempArr.length) {
+							const findIndex = tempArr.findIndex(o => o.wtId === data.wtId)
+							if (findIndex !== -1) {
+								if (!tempArr[findIndex].children) {
+									tempArr[findIndex].children = []
+								}
+								tempArr[findIndex].children.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+								id++
+							} else {
+								tempArr.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+								id++
+							}
+						} else {
+							tempArr.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+							id++
+						}
+					}
+					wtDialog.value = true
+					nextTick(() => {
+						wtTab.value = 'table'
+						wtData.value = tempArr
+					})
+				}
+			}
+		}
+	}
+}
+const funChartArea = () => {
+	if (seriesData.value?.length) {
+		if (!isChartArea.value) {
+			// 请求一下
+			seriesData.value[0] = {
+					...seriesData.value[0],
+					markLine: {
+						symbol: 'none',
+						label: {
+							show: false
+						},
+						lineStyle: {
+							color: 'rgba(96,174,255, 1)'
+						},
+						data: [
+							{
+								xAxis: 3,
+								valueIndex: 0,
+							},
+							{
+								xAxis: 5,
+								valueIndex: 0
+							},
+							{
+								xAxis: 10,
+								valueIndex: 0
+							},
+							{
+								xAxis: 12,
+								valueIndex: 0
+							},
+							{
+								xAxis: 25,
+								valueIndex: 0
+							},
+						]
+					},
+					markArea: {
+						label: {
+							fontSize: util.vh(12),
+						},
+						itemStyle: {
+							color: 'rgba(236,245,255, 0)'
+						},
+						emphasis: {
+							itemStyle: {
+								color: 'rgba(96,174,255, 0.5)'
+							}
+						},
+						data: [
+							[
+								{
+									name: `3~5m 偏差率: ${markDot.pcl5}`,
+									xAxis: 3,
+								},
+								{
+									xAxis: 5,
+								}
+							],
+							[
+								{
+									name: `5~10m 偏差率: ${markDot.pcl10}`,
+									xAxis: 5,
+								},
+								{
+									xAxis: 10,
+								}
+							],
+							[
+								{
+									name: `10~12m 偏差率: ${markDot.pcl12}`,
+									xAxis: 10,
+								},
+								{
+									xAxis: 12,
+								}
+							],
+							[
+								{
+									name: `12~25m 偏差率: ${markDot.pcl25}`,
+									xAxis: 12,
+								},
+								{
+									xAxis: 25,
+								}
+							],
+						]
+					},
+				}
+			isChartArea.value = true
+		} else {
+			seriesData.value[0] = {
+					...seriesData.value[0],
+					markLine: null,
+					markArea: null,
+				}
+			isChartArea.value = false
+		}
+	}
+}
+/**dialog 数据 */
+const wtDialog = ref(false)
+const wtData = ref([])
+const wtTab = ref('table')
+/**tab  */
+const activeTab = ref('1')
+/**created */
+funGetTree()
+funGetProcessTree()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 254 + 'px'
+	excelHeight.value =(window.innerHeight - 210) / 2 + 'px'
+	treeHeight.value = (window.innerHeight - 210) / 2 + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 254 + 'px'
+		excelHeight.value = (window.innerHeight - 210) / 2 + 'px'
+		treeHeight.value = (window.innerHeight - 210) / 2  + 'px'
+	})
+	/**test */
+	// funExcelChange({
+	// 	id: 1,
+	// 	name: 'excel',
+	// 	type: 'fitting',
+	// })
+})
+/**activated */
+onActivated(() => {
+	funGetTree()
+	funGetProcessTree()
+})
+</script>
+<template>
+	<div class="py-[10px] px-[10px]">
+		<search-cop class="mb-[20px] bg-[rgba(0,0,0,0.3)] shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop>
+		<el-dialog v-model="wtDialog" title="风机功率点位">
+			<el-tabs v-model="wtTab">
+				<el-tab-pane label="数据" name="table">
+					<el-table :data="wtData" row-key="id" :max-height="550">
+						<el-table-column property="wtId" align="center" label="风机" />
+						<el-table-column property="time" sortable :width="160" align="center" label="时间" />
+						<el-table-column property="speed" sortable align="center" label="风速(m/s)" />
+						<el-table-column property="power" sortable align="center" label="功率(kw)" />
+						<el-table-column property="rr" sortable align="center" label="转速" />
+						<el-table-column property="filter" sortable align="center" label="是否有用点" />
+					</el-table>
+				</el-tab-pane>
+				<el-tab-pane label="故障" name="problem" disabled>
+
+				</el-tab-pane>
+				<el-tab-pane label="预警" name="warning" disabled>
+
+				</el-tab-pane>
+			</el-tabs>
+		</el-dialog>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#B3B3B3] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<el-col :span="5">
+					<tree-cop :data="treeData" @checkChange="funTreeCheckChange" :show-checkbox="true" :height="treeHeight"
+						@currentChange="funCurrentChange" @refresh="funGetTree"></tree-cop>
+					<tree-cop class="mt-[10px]" :data="processTreeData" :height="treeHeight"
+						@currentChange="funProcessCurrentChange" @refresh="funGetProcessTree"></tree-cop>
+				</el-col>
+				<el-col :span="3">
+					<excel-cop :checkIds="excelCheckIds" :showCheckbox="excelCheckboxShow" :data="excelList" :height="excelHeight"
+						@excelChange="funExcelChange" @checkChange="funExcelCheckChange"></excel-cop>
+					<excel-cop class="mt-[10px]" :data="excelFitList" :height="excelHeight" @excelChange="funExcelChange">
+					</excel-cop>
+				</el-col>
+				<el-col :span="16">
+					<div class="px-[10px] shadow rounded-[6px] shadow-blue-500 bg-[rgba(0,0,0,0.3)]">
+						<submitBtn class="absolute right-[16px] top-[6px] z-10" desc="区域划分" v-if="activeTab === '2' && excelType === 'fitting'" @click="funChartArea"></submitBtn>
+						<el-tabs v-model="activeTab">
+							<el-tab-pane label="表格数据" name="1">
+							</el-tab-pane>
+							<el-tab-pane label="图表展示" name="2" v-if="excelType === 'fitting'">
+							</el-tab-pane>
+							<table-cop v-show="activeTab === '1'" :data="tableData" :loading="tableLoading" :column="tableColumn"
+								:height="tableHeight" :tableId="tableShowId" :tableName="tableName"></table-cop>
+							<div v-show="activeTab === '2'"
+								:style="{ height: typeof tableHeight === 'string' ? tableHeight : tableHeight + 'px' }"
+								class="p-[10px]">
+								<CurrentScatterChart ref="chartRef" width="100%" height="calc( 100% - 20px )" :chartTitle="'平均Cp:'+avgObj.cpavg+'; 静风频率:'+avgObj.frequency+'; 曲线偏差率:'+avgObj.pcratio+'%'"
+									:xAxisData="xAxisData" :yAxisData="{ splitLine: { show: false } }" :seriesData="seriesData"
+									:showLegend="true" :brushSelected="!isChartArea" :dataSet="dataSet" @getSelected="funChartSelect" />
+							</div>
+						</el-tabs>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+	</div>
+</template>

+ 321 - 0
src/views/dataFilter/lineAnalysis/components/current-scatter-chart.vue

@@ -0,0 +1,321 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@tools/util";
+import partten from "@tools/partten";
+import * as echarts from "echarts";
+import chartTheme from './../../chartTheme.json'
+
+export default {
+  name: 'currentScatterChart',
+  props: {
+    // 图表宽度
+    width: {
+      type: String,
+      default: "100%",
+    },
+    // 图表高度
+    height: {
+      type: String,
+      default: "350px",
+    },
+    // 图表主标题
+    chartTitle: {
+      type: String,
+      default: "自定义图表组件",
+    },
+    // X 轴配置项
+    xAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // Y 轴配置项
+    yAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    dataSet: {
+      type: String,
+      default: ''
+    },
+    // 图表核心数据
+    seriesData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // 是否显示图表图例
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否默认采用笔刷模式
+    brushSelected: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      color: [
+        "#05bb4c",
+        "#4b55ae",
+        "#fa8c16",
+        "#f8de5b",
+        "#1a93cf",
+        "#c531c7",
+        "#bd3338",
+      ],
+      theme: 'dark'
+    };
+  },
+  methods: {
+    resize() {},
+    initChart() {
+      const that = this;
+      echarts.registerTheme('chartTheme', chartTheme)
+      let myChart = echarts.init(document.getElementById(this.id), 'chartTheme');
+      //指定图表的配置项和数据
+      const option = {
+        //标题
+        title: {
+          text: that.chartTitle,
+          right: 440,
+          top: 4,
+          textStyle: {
+            fontSize: 14,
+            color: that.theme === "dark" ? partten.getColor("grayl") : "#000",
+          },
+        },
+        // backgroundColor:
+        //   that.theme === "dark"
+        //     ? "rgba(0,0,0,0.4)"
+        //     : "rgba(255,255,255,0.5)",
+        //工具箱
+        toolbox: {
+          show: true,
+          x: "right",
+          position: [10, 10],
+          // backgroundColor:'rgba(0,0,0,0.4)',
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: "#fff",
+          },
+          iconStyle: {
+            borderColor:"#fff",
+          },
+          emphasis: {
+            iconStyle: {
+              borderColor: "#fff",
+            },
+          },
+        },
+        tooltip: {
+          trigger: "item",
+          axisPointer: {
+            type: "cross",
+          },
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: "#fff",
+          },
+          formatter(params) {
+            return params.value?.x
+              ? `${params.seriesName}<br />风速:${params.value.x}m/s<br />功率:${params.value.y}kW`
+              : `${params.name}`;
+          },
+        },
+        brush: {
+          seriesIndex: [2,3],
+          yAxisIndex: 0,
+          transformable: true,
+          throttleType: "debounce",
+          throttleDelay: 1000,
+          removeOnClick: true,
+          brushType: "polygon",
+          brushMode: "multiple",
+          brushStyle: {
+            borderWidth: 1,
+            borderColor: "#ff2424",
+          },
+        },
+        dataZoom: [
+          {
+            type: "inside", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+          {
+            type: "slider", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+        ],
+        textStyle: {
+          fontSize: util.vh(16),
+          color: that.theme === "dark" ? "#fff" : "#000",
+        },
+        //图例-每一条数据的名字
+        legend: {
+          show: that.showLegend,
+          data: [ "拟合功率", "保证功率","无用点", "有用点", "Cp值"],
+          right: "120",
+          top: "5",
+          // icon: "circle",
+          itemWidth: 6,
+          inactiveColor:
+            that.theme === "dark"
+              ? partten.getColor("gray")
+              : "#000",
+          textStyle: {
+            color:
+              that.theme === "dark"
+                ? partten.getColor("grayl")
+                : "#000",
+            fontSize: 12,
+          },
+          
+        },
+        grid: {
+          top: 48,
+          left: 40,
+          right: 40,
+          bottom: 24,
+        },
+        //x轴
+        xAxis: [
+          {
+            type: "value",
+            boundaryGap: false,
+            data: that.xAxisData || [],
+            min: 0,
+            max: 25,
+            interval: 1,
+            axisLabel: {
+              formatter: "{value}",
+            },
+            splitLine: {
+              show: false,
+            },
+            textStyle: {
+              color:
+                that.theme === "dark"
+                  ? partten.getColor("gray")
+                  : "#000",
+            },
+          },
+        ],
+        //y轴没有显式设置,根据值自动生成y轴
+        yAxis: [{
+          splitLine: { show: false },
+          position: 'left',
+          min: 0,
+        }, {
+          splitLine: { show: false },
+          position: 'right',
+          min: 0,
+        }],
+        animation: true,
+        dataset: that.dataSet.length? JSON.parse(that.dataSet) : [],
+        //数据-data是最终要显示的数据
+        series: that.seriesData,
+      };
+
+      that.resize = function () {
+        myChart.resize();
+      };
+
+      window.addEventListener("resize", that.resize);
+
+      myChart.setOption(option);
+      if (that.brushSelected) {
+        myChart.dispatchAction({
+          type: "takeGlobalCursor",
+          // 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
+          key: "brush",
+          brushOption: {
+            seriesIndex: [2,3],
+            yAxisIndex: 0,
+            transformable: true,
+            throttleType: "debounce",
+            throttleDelay: 1000,
+            removeOnClick: true,
+            brushType: "polygon",
+            brushMode: "multiple",
+            brushStyle: {
+              borderWidth: 1,
+              color: "rgba(255,36,36,0.2)",
+              borderColor: "#ff2424",
+            },
+          },
+        });
+      }
+      myChart.off("brushSelected");
+      myChart.on("brushSelected", (params) => {
+        that.$emit("getSelected", params.batch || []);
+      });
+      myChart.off('click')
+      myChart.on('click', params => {
+          console.log(params)
+          if(params.componentType === 'markArea'){
+            myChart.dispatchAction({
+              type: 'brush',
+              areas: [
+                {
+                  xAxisIndex: 0,
+                  brushType: 'lineX',
+                  coordRange: [params.data.coord[0][0], params.data.coord[1][0]]
+                },
+              ]
+            });
+          }
+        })
+    },
+  },
+  created() {
+    this.id = "chart-" + util.newGUID();
+  },
+  mounted() {
+    // this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    // });
+  },
+  updated() {
+    console.log('update')
+    let myChart = echarts.init(document.getElementById(this.id));
+    myChart.dispose();
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 53 - 0
src/views/dataFilter/lineAnalysis/components/search.vue

@@ -0,0 +1,53 @@
+<script setup name="search">
+import { reactive, ref } from 'vue'
+import submitBtn from '@com/submitBtn'
+
+const queryForm = reactive({
+	maxs: 25,
+	mins: 0,
+	maxp: 2500,
+	minp: 0,
+	dimension: 10,  //拟合维度
+	mode: 0   //拟合方式
+})
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	emits('submit', queryForm)
+}
+/**created */
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#B3B3B3] text-[14px]">操作面板</div>
+		<el-form class="" :inline="true" :model="queryForm">
+			<el-form-item label="最大风速" class="!mb-0">
+				<el-input-number v-model="queryForm.maxs" size="small" :max="30"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最小风速" class="!mb-0">
+				<el-input-number v-model="queryForm.mins" size="small" :min="0"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最大功率" class="!mb-0">
+				<el-input-number v-model="queryForm.maxp" size="small"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最小功率" class="!mb-0">
+				<el-input-number v-model="queryForm.minp" size="small" :min="0"></el-input-number>
+			</el-form-item>
+			<el-form-item label="多项式" class="!mb-0">
+				<el-select v-model="queryForm.dimension" class="w-[80px]">
+					<el-option v-for="item in 30" :key="item" :value="item" :label="item"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="拟合方式" class="!mb-0">
+				<el-select v-model="queryForm.mode" class="w-[120px]">
+					<el-option :value="0" label="单台拟合"></el-option>
+					<el-option :value="1" label="合并拟合"></el-option>
+					<el-option :value="2" label="同名拟合"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item class="!mb-0">
+				<submit-btn @click="funSubmit" desc="曲线拟合"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

+ 52 - 0
src/views/dataFilter/lineAnalysis/components/table.vue

@@ -0,0 +1,52 @@
+<script setup name="table">
+import { computed, ref } from 'vue';
+
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 46 : 739
+})
+</script>
+<template>
+  <div ref="tableRef" class=""
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <div class="flex justify-between items-center pb-[10px]">
+      <h3>{{ props.tableName }}</h3>
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    </div>
+    <el-table stripe :data="props.data" size="small" v-loading="props.loading" :max-height="tableHeight"
+      :style="{ width: '100%' }">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop"
+        :label="item.label" sortable resizable :min-width="item.width ? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 537 - 0
src/views/dataFilter/lineAnalysis/index.vue

@@ -0,0 +1,537 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import submitBtn from '@/components/submitBtn'
+import { ref, nextTick, onActivated, onMounted, reactive } from 'vue'
+import request from '@/utils/request'
+import { ElMessage } from 'element-plus'
+import util from "@tools/util";
+import CurrentScatterChart from './components/current-scatter-chart.vue'
+// import dotRes from '@/data/dot.json'
+// import tableRes from '@/data/table.json'
+// import areaDataRes from '@/data/areaData.json'
+/**配置参数 */
+const treeHeight = ref((window.innerHeight - 210) / 2 + 'px') //tree高度
+const excelHeight = ref((window.innerHeight - 210) / 2 + 'px') //excel高度
+const tableHeight = ref(window.innerHeight - 254 + 'px')
+/**excel 开始 */
+const excelCheckboxShow = ref(false)
+const excelType = ref('')
+const excelCheckIds = ref([])
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	activeTab.value = '1'
+	isChartArea.value = false
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	excelType.value = obj.type // 接收excel的type 用于控制右侧tab展示
+
+	let res = null
+	let chartRes = {
+		scatterhs: [[]],
+		scatterls: [[]],
+		sjgl: [[]],
+		llgl: [[]],
+		cpz: [[]]
+	}
+	let poiRes = null
+	let chartResponse = null
+	tableLoading.value = true
+	if (obj.type === 'process') {
+		res = await request.get('/power/process/show', { params: { id: obj.id } })
+	} else if (obj.type === 'fitting') {
+		activeTab.value = '2'
+		res = await request.get('/power/fitting/show', { params: { id: obj.id } })
+		// res = tableRes
+		// chartResponse = dotRes
+		chartResponse = await request.get('/power/fitting/curve', { params: { id: obj.id, p: 1 } })
+		poiRes = await request.get('/power/fitting/curve/ratio', {params: {id: obj.id}})
+		// poiRes = areaDataRes
+	}
+	tableColumn.value = res.data.title.map(o => {
+		return {
+			prop: o.key,
+			width: o.des==='时间'? 100: 80,
+			label: o.des,
+		}
+	})
+	tableData.value = res.data.data
+	tableLoading.value = false
+
+	// markDot 
+	if(poiRes && poiRes.code=== 200){
+		markDot.pcl5 = poiRes.data.pcl5
+		markDot.pcl10 = poiRes.data.pcl10
+		markDot.pcl12 = poiRes.data.pcl12
+		markDot.pcl25 = poiRes.data.pcl25
+	}
+
+	if (chartResponse && chartResponse.code === 200) {
+		chartRes = chartResponse.data
+		avgObj.cpavg = chartRes.obj.cpavg?.toFixed(2)
+		avgObj.frequency = chartRes.obj.frequency?.toFixed(2)
+		avgObj.pcratio = chartRes.obj.pcratio?.toFixed(2)
+		dataSet.value = JSON.stringify([
+			{
+				source: chartRes.wyd
+			},
+			{
+				source: chartRes.yyd
+			}
+		])
+		const color = ["#1C99FF", "#FF8700", "#3D54BE", "#fa8c16", "#1DA0D7", "#DD5044"]
+		seriesData.value = [
+			{
+				name: "拟合功率",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: chartRes.sjgl,
+				xAxisIndex: 0,
+			},
+			{
+				name: "保证功率",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: chartRes.llgl,
+				xAxisIndex: 0,
+			},
+			{
+				type: 'effectScatter',
+				showEffectOn: "emphasis",
+				rippleEffect: {
+					scale: 1
+				},
+				name: '无用点',
+				symbolSize: (data) => {
+					return data.s ? data.s > 10 ? 10 : data.s : 4
+				},
+				datasetIndex: 0,
+				encode: {
+					x: 'x',
+					y: 'y'
+				},
+				xAxisIndex: 0,
+				yAxisIndex: 0,
+			},
+			{
+				type: 'effectScatter',
+				showEffectOn: "emphasis",
+				rippleEffect: {
+					scale: 1
+				},
+				name: '有用点',
+				symbolSize: (data) => {
+					return data.s ? data.s > 10 ? 10 : data.s : 4
+				},
+				datasetIndex: 1,
+				encode: {
+					x: 'x',
+					y: 'y'
+				},
+				xAxisIndex: 0,
+				yAxisIndex: 0,
+			},
+			{
+				name: "Cp值",
+				type: "line",
+				symbol: "line", //设定为实心点
+				symbolSize: 0, //设定实心点的大小
+				smooth: true, //这个是把线变成曲线
+				data: chartRes.cpz,
+				xAxisIndex: 0,
+				yAxisIndex: 1,
+			},
+		]
+	}
+}
+const funExcelCheckChange = ({ checkArr, data }) => {   //bug 
+	excelCheckIds.value = checkArr
+}
+/**excel fitData */
+const excelFitList = ref([])
+/**prepare tree 开始 */
+const treeData = ref([])
+const funRepeatMap = (arr) => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+			}
+		}
+		return {
+			...o,
+			children: o.children ? funRepeatMap(o.children) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	const res = await request.get("/power/process/tree")
+	treeData.value = funRepeatMap(res.data)
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	excelCheckboxShow.value = true
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+const funTreeCheckChange = ({ current, checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys }) => {  //tree change  -> excel change
+	funCurrentChange({ current, currentNode: '' })
+	const checkIds = []
+	if (checkedNodes.length) {
+		for (const node of checkedNodes) {
+			if (node.childs && node.childs.length) {
+				for (const child of node.childs) {
+					checkIds.push(child.id)
+				}
+			}
+		}
+	}
+	excelCheckIds.value = checkIds
+}
+
+/**process tree 开始 */
+const processTreeData = ref([])
+const funGetProcessTree = async () => {
+	const res = await request.get("/power/fitting/tree")
+	processTreeData.value = funRepeatMap(res.data)
+}
+const funProcessCurrentChange = ({ current, currentNode }) => {
+	if (current.childs) {
+		excelFitList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelFitList.value = []
+	}
+}
+
+/**table 开始 */
+const tableShowId = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableName = ref('')
+const tableData = ref([])
+/**table 结束 */
+/**search 开始 */
+const funSubmit = async (query) => {
+	if (!excelCheckIds.value.length) {
+		ElMessage.error('请勾选要预处理的项')
+		return false
+	}
+	const params = {
+		...query,
+		ids: excelCheckIds.value.join(',')
+	}
+	const res = await request.get('/power/fitting/data', { params: params })
+	if (res.code === 200) {
+		ElMessage.success(res.msg)
+		funGetProcessTree()
+		const excelInfo = res.data
+
+		/**拟合完成后 显示右侧图表及数据 */
+		funExcelChange({
+			id: excelInfo.id,
+			name: excelInfo.path.substring(excelInfo.path.indexOf(excelInfo.station + '_') + (excelInfo.station + '_').length),
+			type: 'fitting'
+		})
+	}
+}
+/**chart Data */
+const avgObj = reactive({ //平均cpz等
+	cpavg: '',
+	frequency: '',
+	pcratio: ''
+})
+const markDot = reactive({ //3-5 point点等
+	pcl5: null,
+	pcl10: null,
+	pcl12: null,
+	pcl25: null
+})
+const xAxisData = ref([])
+const chartRef = ref() //chart 的ref
+const seriesData = ref([])
+const isChartArea = ref(false) // 用来控制图表是否区域划分
+const dataSet = ref('')
+const funChartSelect = async (batch) => {
+	const wDataArr = []
+	const yDataArr = []
+	let scatterls = []
+	let scatterhs = []
+	let dataSetObj = []
+	wtData.value = []
+	if (batch?.length && dataSet.value) {
+		scatterls = batch[0].selected[2].dataIndex
+		scatterhs = batch[0].selected[3].dataIndex
+		if (scatterls?.length || scatterhs?.length) {
+			dataSetObj = JSON.parse(dataSet.value)
+			if (scatterls?.length) {
+				for (const scatterIndex of scatterls) {
+					wDataArr.push(dataSetObj[0].source[scatterIndex].k)
+				}
+			}
+			if (scatterhs?.length) {
+				for (const scatterIndex of scatterhs) {
+					yDataArr.push(dataSetObj[1].source[scatterIndex].k)
+				}
+			}
+			const wtRes = await request.get('/power/fitting/filter', { params: { yk: yDataArr.join(','), wk: wDataArr.join(',') } })
+			if (wtRes.code === 200) {
+				let id = 1
+				const tempArr = [] //用于以风机id 聚合dataArr
+				if (wtRes.data?.length) {
+					for (const data of wtRes.data) {
+						if (tempArr.length) {
+							const findIndex = tempArr.findIndex(o => o.wtId === data.wtId)
+							if (findIndex !== -1) {
+								if (!tempArr[findIndex].children) {
+									tempArr[findIndex].children = []
+								}
+								tempArr[findIndex].children.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+								id++
+							} else {
+								tempArr.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+								id++
+							}
+						} else {
+							tempArr.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
+							id++
+						}
+					}
+					wtDialog.value = true
+					nextTick(() => {
+						wtTab.value = 'table'
+						wtData.value = tempArr
+					})
+				}
+			}
+		}
+	}
+}
+const funChartArea = () => {
+	if (seriesData.value?.length) {
+		if (!isChartArea.value) {
+			// 请求一下
+			seriesData.value[0] = {
+					...seriesData.value[0],
+					markLine: {
+						symbol: 'none',
+						label: {
+							show: false
+						},
+						lineStyle: {
+							color: 'rgba(96,174,255, 1)'
+						},
+						data: [
+							{
+								xAxis: 3,
+								valueIndex: 0,
+							},
+							{
+								xAxis: 5,
+								valueIndex: 0
+							},
+							{
+								xAxis: 10,
+								valueIndex: 0
+							},
+							{
+								xAxis: 12,
+								valueIndex: 0
+							},
+							{
+								xAxis: 25,
+								valueIndex: 0
+							},
+						]
+					},
+					markArea: {
+						label: {
+							fontSize: util.vh(12),
+						},
+						itemStyle: {
+							color: 'rgba(236,245,255, 0)'
+						},
+						emphasis: {
+							itemStyle: {
+								color: 'rgba(96,174,255, 0.5)'
+							}
+						},
+						data: [
+							[
+								{
+									name: `3~5m 偏差率: ${markDot.pcl5}`,
+									xAxis: 3,
+								},
+								{
+									xAxis: 5,
+								}
+							],
+							[
+								{
+									name: `5~10m 偏差率: ${markDot.pcl10}`,
+									xAxis: 5,
+								},
+								{
+									xAxis: 10,
+								}
+							],
+							[
+								{
+									name: `10~12m 偏差率: ${markDot.pcl12}`,
+									xAxis: 10,
+								},
+								{
+									xAxis: 12,
+								}
+							],
+							[
+								{
+									name: `12~25m 偏差率: ${markDot.pcl25}`,
+									xAxis: 12,
+								},
+								{
+									xAxis: 25,
+								}
+							],
+						]
+					},
+				}
+			isChartArea.value = true
+		} else {
+			seriesData.value[0] = {
+					...seriesData.value[0],
+					markLine: null,
+					markArea: null,
+				}
+			isChartArea.value = false
+		}
+	}
+}
+/**dialog 数据 */
+const wtDialog = ref(false)
+const wtData = ref([])
+const wtTab = ref('table')
+/**tab  */
+const activeTab = ref('1')
+/**created */
+funGetTree()
+funGetProcessTree()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 254 + 'px'
+	excelHeight.value =(window.innerHeight - 210) / 2 + 'px'
+	treeHeight.value = (window.innerHeight - 210) / 2 + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 254 + 'px'
+		excelHeight.value = (window.innerHeight - 210) / 2 + 'px'
+		treeHeight.value = (window.innerHeight - 210) / 2  + 'px'
+	})
+	// /**test */
+	// funExcelChange({
+	// 	id: 1,
+	// 	name: 'excel',
+	// 	type: 'fitting',
+	// })
+})
+/**activated */
+onActivated(() => {
+	funGetTree()
+	funGetProcessTree()
+})
+</script>
+<template>
+	<div class="py-[10px] px-[10px]">
+		<search-cop class="mb-[20px] bg-[rgba(0,0,0,0.3)] shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop>
+		<el-dialog v-model="wtDialog" title="风机功率点位">
+			<el-tabs v-model="wtTab">
+				<el-tab-pane label="数据" name="table">
+					<el-table :data="wtData" row-key="id" :max-height="550">
+						<el-table-column property="wtId" align="center" label="风机" />
+						<el-table-column property="time" sortable :width="160" align="center" label="时间" />
+						<el-table-column property="speed" sortable align="center" label="风速(m/s)" />
+						<el-table-column property="power" sortable align="center" label="功率(kw)" />
+						<el-table-column property="rr" sortable align="center" label="转速" />
+						<el-table-column property="filter" sortable align="center" label="是否有用点" />
+					</el-table>
+				</el-tab-pane>
+				<el-tab-pane label="故障" name="problem" disabled>
+
+				</el-tab-pane>
+				<el-tab-pane label="预警" name="warning" disabled>
+
+				</el-tab-pane>
+			</el-tabs>
+		</el-dialog>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#B3B3B3] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<el-col :span="5">
+					<tree-cop :data="treeData" @checkChange="funTreeCheckChange" :show-checkbox="true" :height="treeHeight"
+						@currentChange="funCurrentChange" @refresh="funGetTree"></tree-cop>
+					<tree-cop class="mt-[10px]" :data="processTreeData" :height="treeHeight"
+						@currentChange="funProcessCurrentChange" @refresh="funGetProcessTree"></tree-cop>
+				</el-col>
+				<el-col :span="3">
+					<excel-cop :checkIds="excelCheckIds" :showCheckbox="excelCheckboxShow" :data="excelList" :height="excelHeight"
+						@excelChange="funExcelChange" @checkChange="funExcelCheckChange"></excel-cop>
+					<excel-cop class="mt-[10px]" :data="excelFitList" :height="excelHeight" @excelChange="funExcelChange">
+					</excel-cop>
+				</el-col>
+				<el-col :span="16">
+					<div class="px-[10px] shadow rounded-[6px] shadow-blue-500 bg-[rgba(0,0,0,0.3)]">
+						<submitBtn class="absolute right-[16px] top-[6px] z-10" desc="区域划分" v-if="activeTab === '2' && excelType === 'fitting'" @click="funChartArea"></submitBtn>
+						<el-tabs v-model="activeTab">
+							<el-tab-pane label="表格数据" name="1">
+							</el-tab-pane>
+							<el-tab-pane label="图表展示" name="2" v-if="excelType === 'fitting'">
+							</el-tab-pane>
+							<table-cop v-show="activeTab === '1'" :data="tableData" :loading="tableLoading" :column="tableColumn"
+								:height="tableHeight" :tableId="tableShowId" :tableName="tableName"></table-cop>
+							<div v-show="activeTab === '2'"
+								:style="{ height: typeof tableHeight === 'string' ? tableHeight : tableHeight + 'px' }"
+								class="p-[10px]">
+								<CurrentScatterChart ref="chartRef" width="100%" height="calc( 100% - 20px )" :chartTitle="'平均Cp:'+avgObj.cpavg+'; 静风频率:'+avgObj.frequency+'; 曲线偏差率:'+avgObj.pcratio+'%'"
+									:xAxisData="xAxisData" :yAxisData="{ splitLine: { show: false } }" :seriesData="seriesData"
+									:showLegend="true" :brushSelected="!isChartArea" :dataSet="dataSet" @getSelected="funChartSelect" />
+							</div>
+						</el-tabs>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+	</div>
+</template>

+ 102 - 0
src/views/dataFilter/prepare/components/search.vue

@@ -0,0 +1,102 @@
+<script setup name="search">
+import { onMounted, reactive, ref } from 'vue'
+import request from '@/utils/request'
+import submitBtn from '@com/submitBtn'
+import { outerURL } from '@/utils/request'
+import {useRoute} from 'vue-router'
+const route = useRoute()
+const companyId = route.query?.companyId || 'SD_LYDL_ZGS'
+const queryForm = reactive({
+	station: '',
+	wtIds: [],
+	st: Date.now() - 30 * 24 * 60 * 60 * 1000,
+	et: Date.now(),
+	interval: 3
+})
+/**场站 */
+const stationList = ref([])
+const funGetStation = async () => {
+	// const res = await request.get("/base/station")
+	const res = await request.get(`${outerURL}/benchmarking/wpByCplist?companyids=${companyId}&type=0`)
+	console.log(res)
+	stationList.value = res.data
+	if (stationList.value.length) {
+		queryForm.station = stationList.value[0].id
+		funGetWind(queryForm.station)
+	}
+}
+const funStationChange = (stationId) => {
+	if (stationId) {
+		funGetWind(stationId)
+	} else {
+		windList.value = []
+	}
+}
+/**风机 */
+const windList = ref([])
+const funGetWind = async (stationId) => {
+	// const res = await request.get("/base/windturbine", {params: { stationId }})
+	const res = await request.get(`${outerURL}/pro-basic-equipment/equipment-list?companyId=${companyId}&windpowerstationIds=${stationId}`)
+	windList.value = res.data
+	queryForm.wtIds = res.data.map(o => o.id)
+}
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	const query = {
+		station: queryForm.station,
+		wtIds: queryForm.wtIds.join(),
+		st: new Date(queryForm.st).getTime(),
+		et: new Date(queryForm.et).getTime(),
+		interval: queryForm.interval
+	}
+	switch (queryForm.interval) {
+		case 2:
+			query.interval = 60
+			break;
+		case 3:
+			query.interval = 600
+			break;
+		case 4:
+			query.interval = 900
+			break;
+	}
+	emits('submit', query)
+}
+/**created */
+funGetStation()
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#B3B3B3] text-[14px]">操作面板</div>
+		<el-form class="whitespace-nowrap" :inline="true" :model="queryForm">
+			<el-form-item label="场站" class="!mb-0">
+				<el-select v-model="queryForm.station" class="w-[150px]" @change="funStationChange">
+					<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">
+				<el-select multiple clearable class="w-[150px]" v-model="queryForm.wtIds" collapse-tags>
+					<el-option v-for="item in windList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="开始时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.st"></el-date-picker>
+			</el-form-item>
+			<el-form-item label="结束时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.et"></el-date-picker>
+			</el-form-item>
+			<el-form-item label="等间隔" class="!mb-0 h-[40px]">
+				<el-radio-group v-model="queryForm.interval">
+					<el-radio :label="1">一秒钟</el-radio>
+					<el-radio :label="2">一分钟</el-radio>
+					<el-radio :label="3">十分钟</el-radio>
+					<el-radio :label="4">十五分钟</el-radio>
+				</el-radio-group>
+			</el-form-item>
+			<el-form-item class="!mb-0">
+				<submit-btn v-prevdbclick:5000="funSubmit" desc="执行"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

+ 53 - 0
src/views/dataFilter/prepare/components/table.vue

@@ -0,0 +1,53 @@
+<script setup name="table">
+import {ref, computed} from 'vue'
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 46 : 739
+})
+</script>
+<template>
+  <div ref="tableRef" class="p-[10px] shadow rounded-[6px] shadow-blue-500"
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <div class="flex justify-between items-center pb-[10px]">
+      <h3>{{props.tableName}}</h3>
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    </div>
+    <el-table :data="props.data"
+      stripe
+      size="small" v-loading="props.loading"
+      :max-height="tableHeight"
+      :style="{ width: '100%'}">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop" :label="item.label" sortable resizable :min-width="item.width? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 153 - 0
src/views/dataFilter/prepare/index.vue

@@ -0,0 +1,153 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import { ElMessage } from 'element-plus';
+import { onMounted, ref, onActivated } from 'vue'
+import request from '@/utils/request'
+import {baseURL, socketURL} from '@/utils/request'
+/**配置参数 */
+const treeHeight = ref(window.innerHeight - 200 + 'px') //tree高度
+const excelHeight = ref(window.innerHeight - 200 + 'px') //excel高度
+const tableHeight = ref(window.innerHeight - 200 + 'px')
+/**excel 开始 */
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	tableLoading.value = true
+	const res = await request.get('/power/prepare/show', { params: { id: obj.id } })
+	tableColumn.value = res.data.title.map(o => {
+		return {
+			prop: o.key,
+			label: o.des,
+			width: o.des==='时间'? 100: 80,
+		}
+	})
+	tableData.value = res.data.data
+	tableLoading.value = false
+}
+/**tree 开始 */
+const treeData = ref([])
+const funRepeatMap = (arr) => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+			}
+		}
+		return {
+			...o,
+			children: o.children?.length ? funRepeatMap(o.children) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	const res = await request.get("/power/prepare/tree")
+	treeData.value = funRepeatMap(res.data)
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+/**table 开始 */
+const tableShowId = ref('')
+const tableName = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableData = ref([])
+const funExport = async () => {
+	const a = document.createElement('a')
+	a.href = baseURL + '/power/prepare/download?id=' + tableShowId.value
+	a.download = ''
+	a.click()
+}
+/**submit */
+const progress = ref(0)
+const funWebSocket = () => {
+	const webSocket = new WebSocket(`${socketURL}/ws/powerfitting/admin`)
+	webSocket.onerror = () => setTimeout(() => { funWebSocket() }, 2000)
+
+	webSocket.onmessage = (event) => {
+		const message = JSON.parse(event.data)
+		if (message.code === 200) {
+			progress.value = Number(message.data) * 100
+			if (progress.value === 100) {
+				ElMessage.success('数据加载完成')
+				funGetTree()
+				progress.value = 0
+			}
+		}
+	}
+}
+const funSubmit = async (params) => {
+	const res = await request.get('/power/prepare/data', { params: params })
+	if (res.code === 200) {
+		ElMessage.success(res.msg)
+
+	}
+}
+/**created */
+funGetTree()
+funWebSocket()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 200 + 'px'
+	excelHeight.value = window.innerHeight - 200 + 'px'
+	treeHeight.value = window.innerHeight - 200 + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 200 + 'px'
+		excelHeight.value = window.innerHeight - 200 + 'px'
+		treeHeight.value = window.innerHeight - 200 + 'px'
+	})
+})
+/**activated */
+onActivated(() => {
+	funGetTree()
+})
+</script>
+<template>
+	<div class="bg-transparent py-[10px] px-[10px] relative">
+		<search-cop class="mb-[20px] bg-[rgba(0,0,0,0.3)] shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#B3B3B3] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<el-col :span="5">
+					<tree-cop :data="treeData" :height="treeHeight" @currentChange="funCurrentChange" @refresh="funGetTree">
+					</tree-cop>
+				</el-col>
+				<el-col :span="3">
+					<excel-cop :data="excelList" :height="excelHeight" @excelChange="funExcelChange"></excel-cop>
+				</el-col>
+				<el-col :span="16">
+					<div>
+						<table-cop class="bg-[rgba(0,0,0,0.3)]" :data="tableData" :column="tableColumn" :loading="tableLoading"
+							:height="tableHeight" :tableId="tableShowId" :tableName="tableName" @export="funExport"></table-cop>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+
+		<el-progress :percentage="progress" v-if="progress" class="!absolute top-0 right-0 left-0" :indeterminate="false"
+			color="rgb(19,206,102)" :stroke-width="4" :show-text="false" />
+	</div>
+</template>

+ 61 - 0
src/views/dataFilter/process/components/search.vue

@@ -0,0 +1,61 @@
+<script setup name="search">
+import { reactive, ref } from 'vue'
+import submitBtn from '@com/submitBtn'
+
+const queryForm = reactive({
+	maxs: 25,
+	mins: 0,
+	maxp: 2500,
+	minp: 0,
+	isfbw: true,
+	isfhl: true,
+	isbw: true,
+	istj: true,
+	isglpc: true,
+	// isqfh: false,
+	// qfhdj: 2
+})
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	emits('submit', queryForm)
+}
+/**created */
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#B3B3B3] text-[14px]">操作面板</div>
+		<el-form class="" :inline="true" :model="queryForm">
+			<el-form-item label="最大风速" class="!mb-0">
+				<el-input-number v-model="queryForm.maxs" class="!w-[130px]" :max="30"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最小风速" class="!mb-0">
+				<el-input-number v-model="queryForm.mins" class="!w-[130px]" :min="0"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最大功率" class="!mb-0">
+				<el-input-number v-model="queryForm.maxp" class="!w-[130px]"></el-input-number>
+			</el-form-item>
+			<el-form-item label="最小功率" class="!mb-0">
+				<el-input-number v-model="queryForm.minp" class="!w-[130px]" :min="0"></el-input-number>
+			</el-form-item>
+				<el-form-item label="筛选条件:" class="!mb-0">
+					<el-checkbox v-model="queryForm.isfbw">非并网</el-checkbox>
+					<el-checkbox v-model="queryForm.isfhl">非合理值</el-checkbox>
+					<el-checkbox v-model="queryForm.isbw">并网后10分钟</el-checkbox>
+					<el-checkbox v-model="queryForm.istj">停机前10分钟</el-checkbox>
+					<el-checkbox v-model="queryForm.isglpc">功率曲线偏差</el-checkbox>
+					<!-- <el-checkbox v-model="queryForm.isqfh">欠符合等级</el-checkbox> -->
+					<!-- <el-select class="ml-10px w-[80px]" v-model="queryForm.qfhdj">
+						<el-option :value="1" label="1"></el-option>
+						<el-option :value="2" label="2"></el-option>
+						<el-option :value="3" label="3"></el-option>
+						<el-option :value="4" label="4"></el-option>
+						<el-option :value="5" label="5"></el-option>
+					</el-select> -->
+				</el-form-item>
+				<el-form-item class="!mb-0">
+				<submit-btn @click="funSubmit" desc="预处理"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

+ 53 - 0
src/views/dataFilter/process/components/table.vue

@@ -0,0 +1,53 @@
+<script setup name="table">
+import {ref, computed} from 'vue'
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 46 : 700
+})
+</script>
+<template>
+  <div ref="tableRef" class="p-[10px] shadow rounded-[6px] shadow-blue-500"
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <div class="flex justify-between items-center pb-[10px]">
+      <h3>{{props.tableName}}</h3>
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    </div>
+    <el-table :data="props.data"
+      stripe
+      size="small" v-loading="props.loading"
+      :max-height="tableHeight"
+      :style="{ width: '100%'}">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop" :label="item.label" sortable resizable :min-width="item.width? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 199 - 0
src/views/dataFilter/process/index.vue

@@ -0,0 +1,199 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import { ref,onActivated, onMounted } from 'vue'
+import request from '@/utils/request'
+import {baseURL} from '@/utils/request'
+import { ElMessage } from 'element-plus'
+/**配置参数 */
+const treeHeight = ref((window.innerHeight - 210) / 2  + 'px') //tree高度
+const excelHeight = ref(window.innerHeight - 200 + 'px') //excel高度
+const tableHeight = ref(window.innerHeight - 200 + 'px')
+/**excel 开始 */
+const excelCheckboxShow = ref(false)
+const excelCheckIds = ref([])
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	let res = null
+	tableLoading.value = true
+	if (obj.type === 'prepare') {
+		res = await request.get('/power/prepare/show', { params: { id: obj.id } })
+	} else if (obj.type === 'process') {
+		res = await request.get('/power/process/show', { params: { id: obj.id } })
+	}
+	tableColumn.value = res.data.title.map(o => {
+		return {
+			prop: o.key,
+			label: o.des,
+			width: o.des==='时间'? 100: 80,
+		}
+	})
+	tableData.value = res.data.data
+	tableLoading.value = false
+}
+const funExcelCheckChange = ({ checkArr, data }) => {   //bug 
+	excelCheckIds.value = checkArr
+}
+/**prepare tree 开始 */
+const treeData = ref([])
+const funRepeatMap = (arr) => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+			}
+		}
+		return {
+			...o,
+			children: o.children ? funRepeatMap(o.children) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	const res = await request.get("/power/prepare/tree")
+	treeData.value = funRepeatMap(res.data)
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	excelCheckboxShow.value = true
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+const funTreeCheckChange = ({ current, checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys }) => {  //tree change  -> excel change
+	funCurrentChange({ current, currentNode: '' })
+	const checkIds = []
+	if (checkedNodes.length) {
+		for (const node of checkedNodes) {
+			if (node.childs && node.childs.length) {
+				for (const child of node.childs) {
+					checkIds.push(child.id)
+				}
+			}
+		}
+	}
+	excelCheckIds.value = checkIds
+}
+
+/**process tree 开始 */
+const processTreeData = ref([])
+const funGetProcessTree = async () => {
+	const res = await request.get("/power/process/tree")
+	processTreeData.value = funRepeatMap(res.data)
+}
+const funProcessCurrentChange = ({ current, currentNode }) => {
+	excelCheckboxShow.value = false
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+
+/**table 开始 */
+const tableShowId = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableName = ref('')
+const tableData = ref([])
+const funExport = async () => {
+	const a = document.createElement('a')
+	a.href = baseURL + '/power/process/download?id=' + tableShowId.value
+	a.download = ''
+	a.click()
+}
+/**table 结束 */
+/**search 开始 */
+const funSubmit = async (query) => {
+	if (!excelCheckIds.value.length) {
+		ElMessage.error('请勾选要预处理的项')
+		return false
+	}
+	const params = {
+		...query,
+		ids: excelCheckIds.value.join(',')
+	}
+	const res = await request.get('/power/process/data', { params: params })
+	if (res.code === 200) {
+		ElMessage.success(res.msg)
+		funGetProcessTree()
+	}
+}
+/**created */
+funGetTree()
+funGetProcessTree()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 200 + 'px'
+	excelHeight.value = window.innerHeight - 200 + 'px'
+	treeHeight.value = (window.innerHeight - 210) / 2 + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 200 + 'px'
+		excelHeight.value = window.innerHeight - 200 + 'px'
+		treeHeight.value = (window.innerHeight - 210) / 2  + 'px'
+	})
+})
+/**activated */
+onActivated(() => {
+	funGetTree()
+	funGetProcessTree()
+})
+</script>
+<template>
+	<div class="py-[10px] px-[10px]">
+		<search-cop class="mb-[20px] bg-[rgba(0,0,0,0.3)] shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#B3B3B3] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<el-col :span="5">
+					<tree-cop :data="treeData" @checkChange="funTreeCheckChange" :show-checkbox="true" :height="treeHeight"
+						@currentChange="funCurrentChange" @refresh="funGetTree"></tree-cop>
+					<tree-cop class="mt-[10px]" :data="processTreeData" :height="treeHeight"
+						@currentChange="funProcessCurrentChange" @refresh="funGetProcessTree"></tree-cop>
+				</el-col>
+				<el-col :span="3">
+					<excel-cop :checkIds="excelCheckIds" :showCheckbox="excelCheckboxShow" :data="excelList" :height="excelHeight"
+						@excelChange="funExcelChange" @checkChange="funExcelCheckChange"></excel-cop>
+				</el-col>
+				<el-col :span="16">
+					<div>
+						<table-cop class="bg-[rgba(0,0,0,0.3)]" :data="tableData" :loading="tableLoading" :column="tableColumn"
+							:height="tableHeight" :tableId="tableShowId" :tableName="tableName" @export="funExport"></table-cop>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+	</div>
+</template>

+ 13 - 0
src/views/economicsOperation/benchmarkingManagement/companyBenchmarking/index.vue

@@ -0,0 +1,13 @@
+<template>
+  <div>公司对标</div>
+</template>
+
+<script>
+export default {
+  name:'companyBenchmarking',//公司对标
+}
+</script>
+
+<style>
+
+</style>

+ 291 - 0
src/views/economicsOperation/benchmarkingManagement/compontent/bar-line-chart.vue

@@ -0,0 +1,291 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@/helper/util.js";
+import partten from "@/helper/partten.js";
+import * as echarts from "echarts";
+
+export default {
+  name: "multiple-bar-chart",
+  componentName: "multiple-bar-chart",
+  props: {
+    width: {
+      type: String,
+      default: "100%",
+    },
+    height: {
+      type: String,
+      default: "800px",
+    },
+    // 传入数据
+    bardata: {
+      type: Object,
+      default: () => {
+        return {
+          area: [
+            "风场1",
+            "风场2",
+            "风场3",
+            "风场4",
+            "风场5",
+            "风场6",
+            "风场7",
+            "风场8",
+            "风场9",
+          ],
+          legend: [
+            "实际电量",
+            "计划检修损失",
+            "非计划检修损失",
+            "限电损失",
+            "受累损失",
+            "性能损失",
+          ],
+          data: [
+            [1320, 1302, 901, 634, 1390, 1330, 1320, 1000, 500],
+            [320, 302, 301, 334, 390, 330, 320, 100, 50],
+            [320, 302, 301, 334, 390, 330, 320, 100, 50],
+            [1320, 1302, 901, 634, 1390, 1330, 1320, 1000, 500],
+            [320, 302, 301, 334, 390, 330, 320, 100, 50],
+            [320, 302, 301, 334, 390, 330, 320, 100, 50],
+            [1320, 1302, 901, 634, 1390, 1330, 1320, 1000, 500],
+            [320, 302, 301, 334, 390, 330, 320, 100, 50],
+          ],
+        };
+      },
+    },
+    lineData: {
+      type: Array,
+      default: () => [200, 350, 400, 500, 600, 700, 800, 900, 1200],
+    },
+    lineName: {
+      type: String,
+      default: "损失电量",
+    },
+    // 单位
+    units: {
+      type: Array,
+      default: () => ["(万KWh)", "(风速)"],
+    },
+    // 显示 legend
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 颜色
+    color: {
+      type: Array,
+      default: () => ["#323E6F", "#e17e23", "#ba3237", "#c531c7", "#ffffff", "#EDEB2F"],
+    },
+    // 每页显示个数
+    pageSize: {
+      type: Number,
+      default: 20,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      areaData: [],
+    };
+  },
+  computed: {
+    legend() {
+      return this.bardata.legend;
+    },
+    end() {
+      var result = 20;
+      if (this.areaData) {
+        result = parseInt((this.pageSize / this.areaData.length) * 100);
+      }
+      return result;
+    },
+  },
+  methods: {
+    initChart() {
+      let chart = echarts.init(this.$el);
+
+      let option = {
+        color: this.color,
+        grid: {
+          left: 40,
+          right: 16,
+          bottom: 16,
+          top: 40,
+          containLabel: true,
+        },
+        legend: {
+          show: this.showLegend,
+          data: this.bardata.legend,
+          right: 0,
+          icon: "ract",
+          itemWidth: 8,
+          itemHeight: 8,
+          inactiveColor:'#999999',
+          textStyle: {
+            color: '#999999',
+            fontSize: 12,
+          },
+        },
+        tooltip: {
+          trigger: "axis",
+          backgroundColor: "rgba(0,0,0,0.4)",
+          borderColor: '#999999',
+          textStyle: {
+            color: "#fff",
+            fontSize: util.vh(16),
+          },
+        },
+        yAxis: [
+          {
+            type: "category",
+            axisLabel: {
+              color: '#999999',
+            },
+            inverse: true,
+            // minInterval: 10,
+            // maxInterval: 10,
+            axisLine: {
+              show: false,
+            },
+            axisTick: {
+              show: false,
+            },
+            data: this.bardata.area,
+          },
+        ],
+        xAxis: [
+          {
+            type: "value",
+            axisLabel: {
+              show: false,
+              color: '#999999',
+            },
+            axisLine: {
+              type: "",
+              lineStyle: {
+                color: '#999999',
+              },
+              width: 15,
+            },
+            axisTick: {
+              show: true,
+            },
+            splitLine: {
+              lineStyle: {
+                type: "dashed",
+                dashOffset: 100,
+                color: "#5a6162",
+              },
+            },
+          },
+          {
+            type: "value",
+            name: "",
+            axisLabel: {
+              show: false,
+              // formatter: "{value}",
+              // color: partten.getColor("gray"),
+            },
+            axisLine: {
+              show: false,
+            },
+            axisTick: {
+              show: false,
+            },
+            splitLine: {
+              show: false,
+            },
+          },
+        ],
+        series: [],
+      };
+      if (this.bardata && this.bardata.legend)
+        // bar data
+        for (var i = 0; i < this.bardata.legend.length; i++) {
+          option.series.push({
+            name: this.bardata.legend[i],
+            type: "bar",
+            stack: "总量",
+            barWidth: 16,
+            label: {
+              show: false,
+              position: "insideRight",
+            },
+            data: this.bardata.data[i],
+          });
+        }
+
+      // line data
+      if (this.lineData.length > 0) {
+        option.series.push({
+          name: this.lineName,
+          type: "line",
+          data: this.lineData,
+          smooth: false, //平滑展示
+          xAxisIndex: 0,
+          lineStyle: {
+            color: 'green',
+          },
+          itemStyle: {
+            color: 'green',
+          },
+        });
+      }
+      chart.setOption(option);//重新绘制图标
+    },
+  },
+  created() {
+    this.id = "pie-chart-" + util.newGUID();
+    if (this.bardata.area && this.bardata.area.length < this.pageSize) {
+      this.areaData = this.bardata.area;
+      for (let i = this.bardata.area.length; i <= this.pageSize; i++) {
+        this.areaData.push("");
+      }
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    });
+  },
+  updated() {
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  beforeUpdate(){
+	  this.areaData = this.bardata.area;
+  },
+  beforeUpdate(){
+  	  this.areaData = this.bardata.area;
+  },
+  watch: {
+    bardata(val) {
+      if (val.area && val.area.length < this.pageSize) {
+        this.areaData = val.area;
+        for (let i = val.area.length; i <= this.pageSize; i++) {
+          this.areaData.push("");
+        }
+      }
+    },
+	"height"() {
+    this.areaData = this.bardata.area;
+	  this.initChart();
+	},
+  },
+};
+</script>
+
+<style lang="less">
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 255 - 0
src/views/economicsOperation/benchmarkingManagement/compontent/dayinfo.vue

@@ -0,0 +1,255 @@
+<template>
+	<div class="health-day-info">
+		<div class="body">
+			<div class="left">
+				<div class="header">
+					<div class="point left top"></div>
+            		<div class="point right top"></div>
+					<span class="herder-info">
+						对标排名分析
+					</span>
+				</div>
+				<div class="chart-body">
+					<normal-radar-chart :height="'420px'" :value="radarValue" :title="[windNum, windNum2]" />
+				</div>
+			</div>
+			<div class="left">
+				<div class="header">
+					<div class="point left top"></div>
+            		<div class="point right top"></div>
+					<span class="herder-info">
+						基础指标
+					</span>
+				</div>
+				<!-- <table class="table-form">
+					<tr>
+						<td class="white">指标</td>
+						<td class="white">{{windNum}}</td>
+						<td class="white">{{windNum2}}</td>
+					</tr>
+					<tr v-for="(item, index) in tabs" :key="index" >
+						<td class="white">{{item.name}}</td>
+						<td class="white">{{item.windData1}}</td>
+						<td class="white">{{item.windData2}}</td>
+					</tr>
+				</table> -->
+				<el-table :data="tabs" style="width:34vw" :cell-style="{ padding: '6px' }" :row-style="{ height: '4' }"
+					stripe @selection-change="handleCurrentChange">
+					<el-table-column align="center" prop="name" label="场站" width="200">
+					</el-table-column>
+					<el-table-column align="center" prop="windData1" :label="windNum">
+					</el-table-column>
+					<el-table-column align="center" prop="windData2" :label="windNum2">
+					</el-table-column>
+				</el-table>
+			</div>
+
+		</div>
+		<div class="body">
+			<div style="width: 100%;">
+				<div class="header">
+					<div class="point left top"></div>
+            		<div class="point right top"></div>
+					<span class="herder-info">
+						损失电量分析
+					</span>
+				</div>
+				<div class="chart-body">
+					<multiple-bar-chart height="240px" :list="analyisDialog" :customerTooltip="true" @tooltip="tooltip"
+						:units='["(万KWh)"]' />
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+import NormalRadarChart from "../../homePage/components/normal-radar-chart.vue";
+import MultipleBarChart from "../../homePage/components/multiple-bar-chart.vue";
+export default {
+	components: {
+		NormalRadarChart,
+		MultipleBarChart
+	},
+	props: {
+		windNum: {
+			type: String,
+			default: '',
+		},
+		windNum2: {
+			type: String,
+			default: '',
+		},
+		radarValue: {
+			type: Array,
+			default: () => [{
+				indicator: ["风能利用率", "故障损失率", "检修损失率", "弃风率", "性能损失率", "受累损失率", "复位及时率", "消缺及时率", "状态转换率"],
+				data: [{
+					value: [44200, 14200, 20000, 35000, 50000, 38000, 44200, 14200, 20000]
+				}],
+			}],
+		},
+		tabs: {
+			type: Array,
+			default: () => [{
+				name: "发电量",
+				windData1: 1,
+				windData2: 14
+			}, {
+				name: "故障损失电量",
+				windData1: 2,
+				windData2: 13
+			}, {
+				name: "检修损失电量",
+				windData1: 3,
+				windData2: 12
+			}, {
+				name: "性能未达标损失电量",
+				windData1: 4,
+				windData2: 11
+			}, {
+				name: "受累损失电量",
+				windData1: 5,
+				windData2: 10
+			}, {
+				name: "风能利用率",
+				windData1: 6,
+				windData2: 9
+			}, {
+				name: "故障损失率",
+				windData1: 7,
+				windData2: 8
+			}, {
+				name: "检修损失率",
+				windData1: 8,
+				windData2: 7
+			}, {
+				name: "弃风率",
+				windData1: 9,
+				windData2: 6
+			}, {
+				name: "性能损失率",
+				windData1: 10,
+				windData2: 5
+			}, {
+				name: "受累损失率",
+				windData1: 11,
+				windData2: 4
+			}, {
+				name: "复位及时率",
+				windData1: 12,
+				windData2: 3
+			}, {
+				name: "消缺及时率",
+				windData1: 13,
+				windData2: 2
+			}, {
+				name: "状态转换率",
+				windData1: 14,
+				windData2: 1
+			}],
+		},
+		analyisDialog: {
+			type: Array,
+			default: () => [{
+				title: "故障损失电量",
+				yAxisIndex: 0,
+				value: [11, 22]
+			}, {
+				title: "检修损失电量",
+				yAxisIndex: 0,
+				value: [11, 22]
+			}, {
+				title: "性能损失电量",
+				yAxisIndex: 0,
+				value: [11, 22]
+			}, {
+				title: "限电损失电量",
+				yAxisIndex: 0,
+				value: [11, 22]
+			}, {
+				title: "受累损失电量",
+				yAxisIndex: 0,
+				value: [11, 22]
+			}]
+		},
+	},
+	methods: {
+		tooltip(param, callback) {
+			var color = ["#05bb4c", "#4b55ae", "#fa8c16", "#f8de5b"];
+
+			var result = param[0].axisValue;
+			param.forEach((value, index) => {
+				result += "<br />" +
+					`<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:${color[index]};"></span>` +
+					value.seriesName + ":" + value.value;
+			});
+			callback(result);
+			return true;
+		},
+	}
+};
+</script>
+
+<style lang="less">
+.health-day-info {
+	.header {
+		display: flex;
+		width: 98%;
+		height: 40px;
+		line-height: 40px;
+		border-top: 1px solid rgba(153, 153, 153, 0.5);
+		color: #ffffff;
+		position: relative;
+
+		.herder-info {
+			margin-left: 10px;
+		}
+	}
+
+	.body {
+		display: flex;
+
+		.left {
+			flex: 0 0 50%;
+
+			display: flex;
+			flex-direction: column;
+
+			.chart-body {
+				flex-grow: 1;
+				display: flex;
+				align-items: center;
+				height: 43vh;
+			}
+		}
+
+		.right {
+			flex: 0 0 50%;
+		}
+	}
+}
+
+.point {
+	width: 6px;
+	height: 1px;
+	background-color: #ffffff;
+	position: absolute;
+
+	&.left {
+		left: 0;
+	}
+
+	&.right {
+		right: 0;
+	}
+
+	&.top {
+		top: -1px;
+	}
+
+	&.bottom {
+		bottom: -1px;
+	}
+}
+</style>

+ 15 - 0
src/views/economicsOperation/benchmarkingManagement/index.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    <router-view />
+  </div>
+</template>
+
+<script>
+export default {
+  name:'benchmarkingManagement',//对标管理
+}
+</script>
+
+<style>
+
+</style>

+ 746 - 0
src/views/economicsOperation/benchmarkingManagement/intervalBenchmarking/index.vue

@@ -0,0 +1,746 @@
+<template>
+  <div class="parcel-box">
+    <div class="title">
+      <el-select size="mini" v-model="company" placeholder="请选择" @change="handleCompanyChange(company)">
+        <el-option v-for="item in companyOptions" :key="item.id" :label="item.aname" :value="item.id">
+        </el-option>
+      </el-select>
+      <div class="tabCut">
+        <div @click="tabClick(val.id)" :class="tabIndex === val.id ? 'active' : ''" v-for="val in tabOptions"
+          :key="val.id"><span>{{ val.name }}</span></div>
+      </div>
+      <div class="station">
+        场站:
+        <el-select size="mini" v-model="stationObj" multiple collapse-tags placeholder="请选择"
+          @change="handleStationChange(stationObj)" clearable>
+          <el-option v-for="item in stationList" :key="item.id" :label="item.aname" :value="item.id">
+          </el-option>
+        </el-select>
+      </div>
+      <div class="station">
+        开始日期
+        <div class="search-input">
+          <el-date-picker v-model="starTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+            popper-class="date-select">
+          </el-date-picker>
+        </div>
+      </div>
+      <div class="station">
+        结束日期
+        <div class="search-input">
+          <el-date-picker v-model="endTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+            popper-class="date-select">
+          </el-date-picker>
+        </div>
+      </div>
+      <div class="but">
+        <el-button round size="mini" class="buttons" @click="gerCjdb">查询</el-button>
+        <el-button round size="mini" class="buttons" @click="dbfx"  :disabled="chooseList.length === 2?false:true">对标分析</el-button>
+        <el-button round size="mini" class="buttons" @click="goBack" v-if="displayDetail">返回</el-button>
+        <!-- <el-button round size="mini" class="buttons">导出</el-button> -->
+      </div>
+
+    </div>
+    <div v-if="!displayDetail">
+      <div class="line">
+        <div class="leftContent"><span>场际对标</span></div>
+        <div class="rightContent"></div>
+      </div>
+      <div class="table">
+        <el-table :data="tableData" ref="multipleTable" size="mini" height="58vh" :cell-style="{ padding: '0px' }"
+          :row-style="{ height: '0' }" stripe @selection-change="handleCurrentChange">
+          <el-table-column type="selection" width="55" align="center">
+          </el-table-column>
+          <el-table-column align="center" prop="name" label="名称" width="150" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="zhpm" label="综合排名" width="80" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="fdlpm" label="发电量排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="fdl" label="发电量" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdlpm" label="故障损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdl" label="故障损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdlpm" label="检修损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdl" label="检修损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdlpm" label="性能损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdl" label="性能损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdlpm" label="限电损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdl" label="限电损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="slssdlpm" label="受累损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="slssdl" label="受累损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="fnlylpm" label="风能利用率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="fnlyl" label="风能利用率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="gzsslpm" label="故障损失率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssl" label="故障损失率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="jxsslpm" label="检修损失率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssl" label="检修损失率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="qflpm" label="弃风率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="qfl" label="弃风率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xnsslpm" label="性能损失率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssl" label="性能损失率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="slsslpm" label="受累损失率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="slssl" label="受累损失率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="" label="操作">
+            <template v-slot="scope">
+              <span @click="goDetail(scope.row)" style="cursor: pointer;color: #1C99FF;">详情</span>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <div class="echarts">
+        <div class="pie-echarts">
+          <div class="chart-name">
+            <div class="point left bottom"></div>
+            <div class="point right bottom"></div>
+            损失电量分析
+          </div>
+          <PieChart :lossPower="lossPower" width="100%" height="20vh"></PieChart>
+        </div>
+        <div class="bar-echarts">
+          <div class="chart-name">
+            <div class="point left bottom"></div>
+            <div class="point right bottom"></div>
+            五项损失
+          </div>
+          <BarCharts :list="barList" width="100%" height="30vh" :showLegend="true" :xdate="false"></BarCharts>
+        </div>
+      </div>
+    </div>
+
+    <div v-if="displayDetail">
+      <el-table :data="detailTable" ref="multipleTable" size="mini" height="88vh" :cell-style="{ padding: '0px' }"
+          :row-style="{ height: '0' }" stripe @selection-change="handleCurrentChange">
+          <el-table-column type="selection" width="55" align="center">
+          </el-table-column>
+          <el-table-column align="center" prop="name" label="风机名称" width="150" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="zhpm" label="综合排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdl" label="故障损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdlpm" label="检修损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdl" label="检修损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdlpm" label="性能损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdl" label="性能损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdlpm" label="限电损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdl" label="限电损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssdlpm" label="受累损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssdl" label="受累损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzsslpm" label="故障损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzssl" label="故障损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxsslpm" label="检修损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssl" label="检修损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="qflpm" label="弃风率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="qfl" label="弃风率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnsslpm" label="性能损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssl" label="性能损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slsslpm" label="受累损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssl" label="受累损失率(%)" sortable>
+          </el-table-column>
+        </el-table>
+    </div>
+
+    <el-dialog
+      title="对标排名分析"
+      v-model="dialogVisible"
+      width="70%"
+      top="10vh"
+      custom-class="modal"
+      :close-on-click-modal="false"
+    >
+      <dayinfo
+        :radarValue="radarValue"
+        :title="[windNum, windNum2]"
+        :windNum="windNum"
+        :windNum2="windNum2"
+        :tabs="tabs"
+        :analyisDialog="analyisDialog"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import dayjs from "dayjs";
+import { companys } from '@/api/curveAnalyse'
+import { getStation, cjdb, details } from '@/api/performance'
+import PieChart from '../../homePage/components/pieChart.vue'
+import BarCharts from '../../homePage/components/barCharts.vue'
+import dayinfo from '../compontent/dayinfo.vue'
+export default {
+  name: 'intervalBenchmarking',//场际对标
+  components: {
+    PieChart,
+    BarCharts,
+    dayinfo,
+  },
+  data() {
+    return {
+      company: '',
+      companyOptions: [],
+      stationObj: [],
+      stationList: [],
+      starTime: '',
+      endTime: '',
+      tabIndex: -1,
+      tabOptions: [
+        { id: -1, name: "风电" },
+        { id: -2, name: "光伏" },
+      ],
+      tableData: [],
+      detailTable: [],
+      chooseList: [],
+      lossPower: [],
+      barList: [],
+      displayDetail: false,
+      dialogVisible: false,
+      radarValue: [],
+      windNum: "dd",
+      windNum2: "dd",
+      tabs: [],
+      analyisDialog: [],
+    }
+  },
+  created() {
+    let date = new Date();
+    date.setDate(1);
+    let month = parseInt(date.getMonth() + 1);
+    let day = date.getDate();
+    if (month < 10) {
+      month = '0' + month;
+    }
+    if (day < 10) {
+      day = '0' + day;
+    }
+    this.starTime = date.getFullYear() + '-' + month + '-' + day;
+    this.endTime = dayjs(new Date().getTime()).format("YYYY-MM-DD");
+    this.initialization()
+  },
+  methods: {
+    initialization() {
+      companys().then(res => {
+        if (res.data) {
+          this.company = res.data[4].id
+          this.companyOptions = res.data
+          this.getStation(res.data[4].id)
+        }
+      })
+    },
+    getStation(companyids) {
+      getStation({
+        companyids: companyids
+      }).then(res => {
+        if (res.data.length) {
+          this.stationList = res.data
+          this.gerCjdb()
+        }
+      })
+    },
+    gerCjdb() {
+      cjdb({
+        companys: this.company,
+        type: this.tabIndex,
+        beginDate: this.starTime,
+        endDate: this.endTime,
+        wpids: this.stationObj.join(','),
+        target: '',
+        sort: '',
+      }).then(res => {
+        if (res.data) {
+          let barList = [
+            {
+              name: '故障损失电量',
+              children: [],
+              date: [],
+            },
+            {
+              name: '检修损失电量',
+              children: [],
+            },
+            {
+              name: '性能损失电量',
+              children: [],
+            },
+            {
+              name: '限电损失电量',
+              children: [],
+            },
+            {
+              name: '受累损失电量',
+              children: [],
+            },
+          ]
+          this.tableData = res.data
+          let lossPower = []
+          res.data.forEach(item => {
+            let obj = {
+              name: item.name,
+              value: item.zssdl,
+            }
+            lossPower.push(obj)
+            barList[0].date.push(item.name)
+            barList[0].children.push(item.gzssdl)
+            barList[1].children.push(item.jxssdl)
+            barList[2].children.push(item.xnssdl)
+            barList[3].children.push(item.xdssdl)
+            barList[4].children.push(item.slssdl)
+          })
+          this.lossPower = lossPower
+          this.barList = barList
+        }
+      })
+    },
+    handleStationChange(val) {
+      this.stationObj = val
+    },
+    handleCurrentChange(val) {
+      if (val.length > 2) {
+        let del_row = val.shift();
+        this.$refs.multipleTable.toggleRowSelection(del_row, false);
+      }
+      let arr = []
+      val.forEach((item, index) => {
+        if (index < 2) {
+          arr.push(item)
+        }
+      })
+      this.chooseList = arr
+    },
+    goDetail(row) {
+      this.displayDetail = true
+      details({
+        id: row.id,
+        beginDate: this.starTime,
+        endDate: this.endTime,
+        target: '',
+        sort: '',
+      }).then(res =>{
+        if(res.data){
+          this.detailTable = res.data
+        }
+      })
+    },
+    goBack(){
+      this.displayDetail = false
+    },
+    dbfx() {
+      if(this.chooseList.length === 2){
+        this.dialogVisible = true;
+        this.AjaxDbfx();
+      }
+    },
+    AjaxDbfx(){
+      var data = this.chooseList;
+      this.windNum = data[0].name;
+      this.windNum2 = data[1].name;
+      this.tabs = [
+        {
+          name: "发电量",
+          windData1: data[0].fdl,
+          windData2: data[1].fdl,
+        },
+        {
+          name: "故障损失电量",
+          windData1: data[0].gzssdl,
+          windData2: data[1].gzssdl,
+        },
+        {
+          name: "检修损失电量",
+          windData1: data[0].jxssdl,
+          windData2: data[1].jxssdl,
+        },
+        {
+          name: "性能未达标损失电量",
+          windData1: data[0].xnssdl,
+          windData2: data[1].xnssdl,
+        },
+        {
+          name: "受累损失电量",
+          windData1: data[0].slssdl,
+          windData2: data[1].slssdl,
+        },
+        {
+          name: "风能利用率",
+          windData1: data[0].fnlyl,
+          windData2: data[1].fnlyl,
+        },
+        {
+          name: "故障损失率",
+          windData1: data[0].gzssl,
+          windData2: data[1].gzssl,
+        },
+        {
+          name: "检修损失率",
+          windData1: data[0].jxssl,
+          windData2: data[1].jxssl,
+        },
+        {
+          name: "弃风率",
+          windData1: data[0].qfl,
+          windData2: data[1].qfl,
+        },
+        {
+          name: "性能损失率",
+          windData1: data[0].xnssl,
+          windData2: data[1].xnssl,
+        },
+        {
+          name: "受累损失率",
+          windData1: data[0].slssl,
+          windData2: data[1].slssl,
+        },
+      ];
+
+      this.radarValue = [
+        {
+          indicator: [
+          "风能利用率排名",
+            "故障损失率排名",
+            "检修损失率排名",
+            "弃风率排名",
+            "性能损失率排名",
+            "受累损失率排名",
+          ],
+          data: [
+            {
+              value: [
+                data[0].fnlylpm,
+                data[0].gzsslpm,
+                data[0].jxsslpm,
+                data[0].qflpm,
+                data[0].xnsslpm,
+                data[0].slsslpm,
+              ],
+              name: data[0].name
+            },
+          ],
+        },
+        {
+          indicator: [
+          "风能利用率排名",
+            "故障损失率排名",
+            "检修损失率排名",
+            "弃风率排名",
+            "性能损失率排名",
+            "受累损失率排名",
+          ],
+          data: [
+          {
+              value: [
+                data[1].fnlylpm,
+                data[1].gzsslpm,
+                data[1].jxsslpm,
+                data[1].qflpm,
+                data[1].xnsslpm,
+                data[1].slsslpm,
+              ],
+              name: data[1].name
+            },
+          ],
+        },
+      ];
+      var analyis = [],
+        gzssdl = [],
+        jxssdl = [],
+        xnssdl = [],
+        xdssdl = [],
+        slssdl = [];
+      data.forEach((item, index) => {
+        gzssdl.push({
+          text: item.name,
+          value: item.gzssdl,
+        });
+        jxssdl.push({
+          text: item.name,
+          value: item.jxssdl,
+        });
+        xnssdl.push({
+          text: item.name,
+          value: item.xnssdl,
+        });
+        xdssdl.push({
+          text: item.name,
+          value: item.xdssdl,
+        });
+        slssdl.push({
+          text: item.name,
+          value: item.slssdl,
+        });
+      });
+      analyis.push(
+        {
+          title: "故障损失电量",
+          yAxisIndex: 0,
+          value: gzssdl,
+        },
+        {
+          title: "检修损失电量",
+          yAxisIndex: 0,
+          value: jxssdl,
+        },
+        {
+          title: "性能损失电量",
+          yAxisIndex: 0,
+          value: xnssdl,
+        },
+        {
+          title: "限电损失电量",
+          yAxisIndex: 0,
+          value: xdssdl,
+        },
+        {
+          title: "受累损失电量",
+          yAxisIndex: 0,
+          value: slssdl,
+        }
+      );
+      this.analyisDialog = analyis;
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.parcel-box {
+  padding: 0 15px;
+}
+
+.title {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-top: 10px;
+  margin-bottom: 10px;
+
+  .tabCut {
+    display: inline-block;
+    margin: 0 10px;
+
+    div {
+      display: inline-block;
+      width: 60px;
+      height: 27px;
+      border: 1px solid #354460;
+      text-align: center;
+      line-height: 25px;
+      cursor: pointer;
+    }
+
+    div:nth-child(1) {
+      border-radius: 13px 0px 0px 13px;
+    }
+
+    div:nth-child(2) {
+      border-radius: 0px 13px 13px 0px;
+    }
+
+    .active {
+      background-color: #0C3378;
+      color: #fff;
+    }
+  }
+
+  .tabCut1 {
+    display: inline-block;
+    margin: 0 10px;
+
+    div {
+      display: inline-block;
+      width: 60px;
+      height: 27px;
+      border: 1px solid #354460;
+      text-align: center;
+      line-height: 25px;
+      cursor: pointer;
+    }
+
+    div:nth-child(1) {
+      border-radius: 13px 0px 0px 13px;
+    }
+
+    div:nth-child(3) {
+      border-radius: 0px 13px 13px 0px;
+    }
+
+    .active {
+      background-color: #0C3378;
+      color: #fff;
+    }
+  }
+
+  .station {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    font-size: 14px;
+    font-family: Microsoft YaHei;
+    font-weight: 400;
+    color: #B3B3B3;
+    margin-right: 10px;
+  }
+
+  .search-input {
+    margin-left: 10px;
+  }
+
+  .but {
+    display: flex;
+    flex-direction: row;
+    align-content: center;
+    margin-left: 20px;
+  }
+
+  .buttons {
+    background-color: rgba(67, 81, 107, .3);
+    border: 1px solid #3B4C6C;
+    color: #B3B3B3;
+    font-size: 14px;
+
+    &:hover {
+      background-color: rgba(0, 70, 199, .5);
+      color: #ffffff;
+    }
+  }
+}
+
+.line {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+
+  .leftContent {
+    width: 242px;
+    height: 41px;
+    display: flex;
+    align-items: center;
+    background: url("../../../../assets/img/title_left_bg.png");
+
+    span {
+      font-size: 16px;
+      font-family: Microsoft YaHei;
+      font-weight: 400;
+      color: #FFFFFF;
+      margin-left: 25px;
+    }
+  }
+
+  .rightContent {
+    width: 212px;
+    height: 28px;
+    margin-top: 13px;
+    background: url("../../../../assets/img/title_right_bg.png");
+  }
+}
+
+.table {
+  width: 100%;
+}
+
+.echarts {
+  width: 100%;
+  height: 26vh;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+
+  .chart-name {
+    display: flex;
+    align-items: center;
+    padding-left: 20px;
+    position: relative;
+    height: 39px;
+    width: 98%;
+    margin-left: 1%;
+    border-bottom: 1px solid rgba(153, 153, 153, 0.5);
+    font-size: 16px;
+    font-family: Microsoft YaHei;
+    font-weight: 400;
+    color: #FFFFFF;
+  }
+
+  .pie-echarts {
+    width: 30%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.45);
+    border-radius: 5px;
+  }
+
+  .bar-echarts {
+    width: 69%;
+    margin-left: 1%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.45);
+    border-radius: 5px;
+  }
+}
+
+.point {
+  width: 6px;
+  height: 1px;
+  background-color: #ffffff;
+  position: absolute;
+
+  &.left {
+    left: 0;
+  }
+
+  &.right {
+    right: 0;
+  }
+
+  &.top {
+    top: -1px;
+  }
+
+  &.bottom {
+    bottom: -1px;
+  }
+}
+
+/*去除表头全选框*/
+::v-deep .el-table__header-wrapper .el-checkbox {
+  display: none;
+}
+</style>

+ 13 - 0
src/views/economicsOperation/benchmarkingManagement/loseRate/index.vue

@@ -0,0 +1,13 @@
+<template>
+  <div>五项损失率</div>
+</template>
+
+<script>
+export default {
+  name:'loseRate',//五项损失率
+}
+</script>
+
+<style>
+
+</style>

+ 490 - 0
src/views/economicsOperation/benchmarkingManagement/performanceRankingList/decision1Mx.vue

@@ -0,0 +1,490 @@
+<template>
+    <div class="home-body" style="height: 93vh">
+      <div class="title">
+        <el-select size="mini" v-model="company" placeholder="请选择" @change="handleCompanyChange(company)">
+          <el-option v-for="item in companyOptions" :key="item.id" :label="item.aname" :value="item.id">
+          </el-option>
+        </el-select>
+        <div class="tabCut">
+          <div @click="tabClick(val.id)" :class="tabIndex === val.id ? 'active' : ''" v-for="val in tabOptions"
+            :key="val.id"><span>{{ val.name }}</span></div>
+        </div>
+        <div class="tabCut1">
+          <div @click="typeClick(val.id)" :class="typeIndex === val.id ? 'active' : ''" v-for="val in typeOptions"
+            :key="val.id"><span>{{ val.name }}</span></div>
+        </div>
+        <div class="station">
+          场站:
+          <el-select size="mini" v-model="stationObj" placeholder="请选择" @change="handleStationChange(stationObj)" clearable>
+            <el-option v-for="item in stationList" :key="item.id" :label="item.aname" :value="item.id">
+            </el-option>
+          </el-select>
+        </div>
+        <div class="station">
+          项目:
+          <el-select size="mini" v-model="projectObj" placeholder="请选择" @change="handleProjectChange(projectObj)" clearable>
+            <el-option v-for="item in projectList" :key="item.id" :label="item.aname" :value="item.id">
+            </el-option>
+          </el-select>
+        </div>
+        <div class="station">
+          期次:
+          <el-select size="mini" v-model="lineObj" placeholder="请选择" clearable>
+            <el-option v-for="item in lineList" :key="item.id" :label="item.aname" :value="item.id">
+            </el-option>
+          </el-select>
+        </div>
+  
+        <div class="station">
+          开始日期
+          <div class="search-input">
+            <el-date-picker v-model="starTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+              popper-class="date-select">
+            </el-date-picker>
+          </div>
+        </div>
+        <div class="station">
+          结束日期
+          <div class="search-input">
+            <el-date-picker v-model="endTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+              popper-class="date-select">
+            </el-date-picker>
+          </div>
+        </div>
+        <div class="but">
+          <el-button round size="mini" class="buttons" @click="mxClick">查询</el-button>
+          <el-button round size="mini" class="buttons" >明细</el-button>
+          <!-- <el-button round size="mini" class="buttons">导出</el-button> -->
+        </div>
+  
+      </div>
+      <div class="performance" style="height: 90vh">
+        <div class="left">
+          <bar-line-chart :height="'86vh'" :bardata="bardata" :lineData="lineData" :color="barColor" lineName="理论发电量" />
+        </div>
+        <div class="center">
+          <div class="using">
+  
+          </div>
+        </div>
+        <div class="dashed" style="height: 80vh"></div>
+        <div class="dashed1" style="height: 80vh"></div>
+        <div class="table" style="height: 86vh">
+          <el-table :data="tableData" size="mini"  stripe>
+            <el-table-column align="center" prop="name" label="名称" width="150">
+            </el-table-column>
+            <el-table-column align="center" prop="llfdl" label="理论发电量">
+            </el-table-column>
+            <el-table-column align="center" prop="sjfdl" label="SCADA发电量">
+            </el-table-column>
+            <el-table-column align="center" prop="speed" label="风速">
+            </el-table-column>
+            <el-table-column align="center" prop="fjhjx1" label="故障损失">
+            </el-table-column>
+            <el-table-column align="center" prop="fjhjx2" label="故障受累">
+            </el-table-column>
+            <el-table-column align="center" prop="jhjx1" label="检修损失">
+            </el-table-column>
+            <el-table-column align="center" prop="jhjx2" label="检修受累">
+            </el-table-column>
+            <el-table-column align="center" prop="sl1" label="电网受累">
+            </el-table-column>
+            <el-table-column align="center" prop="sl2" label="天气受累">
+            </el-table-column>
+            <el-table-column align="center" prop="xd1" label="限电降出">
+            </el-table-column>
+            <el-table-column align="center" prop="xd2" label="限电停机">
+            </el-table-column>
+            <el-table-column align="center" prop="xn1" label="待风损失">
+            </el-table-column>
+            <el-table-column align="center" prop="xn2" label="手动停机">
+            </el-table-column>
+            <el-table-column align="center" prop="xn3" label="正常发电">
+            </el-table-column>
+            <el-table-column align="center" prop="xn4" label="缺陷降出">
+            </el-table-column>
+            <el-table-column align="center" prop="fnlly" label="风能利用率%">
+            </el-table-column>
+          </el-table>
+        </div>
+      </div>
+    </div>
+  </template>
+  
+  <script>
+  import BarLineChart from "../compontent/bar-line-chart.vue";
+  import { companys } from '@/api/curveAnalyse'
+  import dayjs from "dayjs";
+  import { getStation, getProject, getLine, performanceMX } from '@/api/performance'
+  export default {
+    name: 'performanceRankingList',//风机绩效榜
+    components: {
+      BarLineChart,
+    },
+    data() {
+      return {
+        barColor: [
+          "#4b55ae",
+          "#e17e23",
+          "#ba3237",
+          "#c531c7",
+          "#ffffff",
+          "#05bb4c",
+        ],
+        company: "",
+        companyOptions: [],
+        stationObj: "",
+        stationList: [],
+        projectObj: "",
+        projectList: [],
+        lineObj: "",
+        lineList: [],
+        starTime: '',
+        endTime: '',
+        tabIndex: -1,
+        bardata: [],
+        lineData: [],
+        tabOptions: [
+          { id: -1, name: "风电" },
+          { id: -2, name: "光伏" },
+        ],
+        typeIndex: '1',
+        typeOptions: [
+          { id: '1', name: "风场" },
+          { id: '2', name: "项目" },
+          { id: '3', name: "线路" },
+        ],
+        tableData: [],
+      }
+    },
+    created() {
+        var date = new Date();
+        date.setDate(1);
+        var month = parseInt(date.getMonth() + 1);
+        var day = date.getDate();
+        if (month < 10) {
+          month = '0' + month;
+        }
+        if (day < 10) {
+          day = '0' + day;
+        }
+        this.starTime = date.getFullYear() + '-' + month + '-' + day;
+        console.log(11111);
+        this.endTime = dayjs(new Date().getTime()).format("YYYY-MM-DD"); 
+      this.initialization();
+    },
+    methods: {
+      initialization() {
+        companys().then(res => {
+          this.companyOptions = res.data
+          if (res.data.length) {
+            this.company = res.data[4].id
+            this.getStation(res.data[4].id)
+          } else {
+            this.company = '',
+              this.stationObj = '',
+              this.stationList = [],
+              this.projectObj = '',
+              this.projectList = [],
+              this.lineObj = '',
+              this.lineList = []
+          }
+        })
+      },
+      getStation(companyids) {
+        getStation({
+          companyids: companyids
+        }).then(res => {
+          if (res.data.length) {
+            this.stationList = res.data
+            this.getProject(res.data[0].id)
+          } else {
+            this.stationObj = '',
+              this.stationList = [],
+              this.projectObj = '',
+              this.projectList = [],
+              this.lineObj = '',
+              this.lineList = []
+          }
+        })
+      },
+      getProject(wpids) {
+        getProject({
+          wpids: wpids
+        }).then(res => {
+          if (res.data.length) {
+            this.projectList = res.data
+            this.getLine(res.data[0].id)
+          } else {
+            this.projectObj = '',
+              this.projectList = [],
+              this.lineObj = '',
+              this.lineList = []
+          }
+        })
+      },
+      getLine(pjids) {
+        getLine({
+          pjids: pjids
+        }).then(res => {
+          if (res.data.length) {
+            this.lineList = res.data
+          } else {
+            this.lineObj = '',
+              this.lineList = []
+          }
+          this.getPerformance()
+        })
+      },
+      handleCompanyChange(val) {
+        this.getStation(val)
+      },
+      handleStationChange(val) {
+        this.getProject(val)
+      },
+      handleProjectChange(val) {
+        this.getLine(val)
+      },
+      tabClick(data) {
+        this.tabIndex = data
+        this.getPerformance()
+      },
+      typeClick(data) {
+        this.typeIndex = data
+        this.getPerformance()
+      },
+      getPerformance() {
+        performanceMX({
+          companyid: this.company,
+          getype: this.tabIndex,
+          sttype: this.typeIndex,
+          beginDate: this.starTime,
+          endDate: this.endTime,
+          wpids: this.stationObj,
+          projectids: this.projectObj,
+          lineids: this.lineObj,
+        }).then(res => {
+          if (res.data) {
+            var name = [],
+            data = [],
+            llfdl = [],
+            legend = [
+              "实际电量",
+              "故障损失",
+              "故障受累",
+              "检修受累",
+              "电网受累",
+              "天气受累",
+              "限电降出",
+              "限电停机",
+              "待风损失",
+              "手动停机",
+              "正常发电",
+              "缺陷降出",
+            ]; 
+            res.data.forEach((item, index) => {
+            name.push(item.name);
+            llfdl.push(item.llfdl);
+            data.push([
+              item.sjfdl,
+              item.fjhjx1,
+              item.fjhjx2,
+              item.jhjx1,
+              item.jhjx2,
+              item.sl1,
+              item.sl2,
+              item.xd1,
+              item.xd2,
+              item.xn1,
+              item.xn2,
+              item.xn3,
+              item.xn4,
+            ]);
+          });
+          name.pop();
+          data.pop();
+          llfdl.pop();
+          if (data.length > 0) {
+            let arr1 = [];
+            const length = data[0].length;
+            for (var i = 0; i < length; i++) {
+              let arr2 = [];
+              data.forEach((ele) => {
+                arr2.push(ele[i]);
+              });
+              arr1.push(arr2);
+            }
+            this.lineData = llfdl;
+            this.bardata = {
+              area: name,
+              legend: legend,
+              data: arr1,
+            };
+          }
+            this.tableData = res.data
+          }
+        })
+      },
+      mxClick() {
+        this.$router.push("/economicsOperation/benchmarkingManagement/performanceRankingList");
+      },
+    },
+  }
+  </script>
+  
+  <style lang="less" scoped>
+  .home-body {
+    display: flex;
+    flex-direction: column;
+  }
+  
+  .title {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    margin-top: 10px;
+  
+    .tabCut {
+      display: inline-block;
+      margin: 0 10px;
+  
+      div {
+        display: inline-block;
+        width: 60px;
+        height: 27px;
+        border: 1px solid #354460;
+        text-align: center;
+        line-height: 25px;
+        cursor: pointer;
+      }
+  
+      div:nth-child(1) {
+        border-radius: 13px 0px 0px 13px;
+      }
+  
+      div:nth-child(2) {
+        border-radius: 0px 13px 13px 0px;
+      }
+  
+      .active {
+        background-color: #0C3378;
+        color: #fff;
+      }
+    }
+  
+    .tabCut1 {
+      display: inline-block;
+      margin: 0 10px;
+  
+      div {
+        display: inline-block;
+        width: 60px;
+        height: 27px;
+        border: 1px solid #354460;
+        text-align: center;
+        line-height: 25px;
+        cursor: pointer;
+      }
+  
+      div:nth-child(1) {
+        border-radius: 13px 0px 0px 13px;
+      }
+  
+      div:nth-child(3) {
+        border-radius: 0px 13px 13px 0px;
+      }
+  
+      .active {
+        background-color: #0C3378;
+        color: #fff;
+      }
+    }
+  
+    .station {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      font-size: 14px;
+      font-family: Microsoft YaHei;
+      font-weight: 400;
+      color: #B3B3B3;
+      margin-right: 10px;
+    }
+  
+    .search-input {
+      margin-left: 10px;
+    }
+  
+    .but {
+      display: flex;
+      flex-direction: row;
+      align-content: center;
+      margin-left: 20px;
+    }
+  
+    .buttons {
+      background-color: rgba(67, 81, 107, .3);
+      border: 1px solid #3B4C6C;
+      color: #B3B3B3;
+      font-size: 14px;
+  
+      &:hover {
+        background-color: rgba(0, 70, 199, .5);
+        color: #ffffff;
+      }
+    }
+  }
+  
+  .performance {
+    display: flex;
+    flex-direction: row;
+    width: 98%;
+    background-color: rgba(0, 0, 0, .4);
+    margin-top: 10px;
+    margin-left: 1%;
+    border-radius: 5px;
+    overflow-y: auto;
+  
+    .left {
+      width: 47%;
+      height: 100%;
+  
+    }
+  
+    .center {
+      width: 3%;
+      height: 90%;
+      position: relative;
+      margin-top: 50px;
+  
+      .using {
+        width: 100%;
+        height: 100%;
+        z-index: 99;
+        position: absolute;
+        right: 0px;
+        top: 0px;
+      }
+    }
+  
+    .dashed {
+      width: 1px;
+      background-image: linear-gradient(#3A4043 0%, #3A4043 40%, transparent 50%);
+      background-size: 1px 9px;
+      margin-top: 45px;
+    }
+  
+    .dashed1 {
+      width: 1px;
+      background-image: linear-gradient(#3A4043 0%, #3A4043 40%, transparent 50%);
+      background-size: 1px 9px;
+      margin-top: 45px;
+      margin-left: 20px;
+    }
+  
+    .table {
+      width: 48%;
+      // background-color: yellowgreen;
+    }
+  }
+  </style>

+ 477 - 0
src/views/economicsOperation/benchmarkingManagement/performanceRankingList/index.vue

@@ -0,0 +1,477 @@
+<template>
+  <div class="home-body" style="height: 93vh">
+    <div class="title">
+      <el-select size="mini" v-model="company" placeholder="请选择" @change="handleCompanyChange(company)">
+        <el-option v-for="item in companyOptions" :key="item.id" :label="item.aname" :value="item.id">
+        </el-option>
+      </el-select>
+      <div class="tabCut">
+        <div @click="tabClick(val.id)" :class="tabIndex === val.id ? 'active' : ''" v-for="val in tabOptions"
+          :key="val.id"><span>{{ val.name }}</span></div>
+      </div>
+      <div class="tabCut1">
+        <div @click="typeClick(val.id)" :class="typeIndex === val.id ? 'active' : ''" v-for="val in typeOptions"
+          :key="val.id"><span>{{ val.name }}</span></div>
+      </div>
+      <div class="station">
+        场站:
+        <el-select size="mini" v-model="stationObj" placeholder="请选择" @change="handleStationChange(stationObj)"
+          clearable>
+          <el-option v-for="item in stationList" :key="item.id" :label="item.aname" :value="item.id">
+          </el-option>
+        </el-select>
+      </div>
+      <div class="station">
+        项目:
+        <el-select size="mini" v-model="projectObj" placeholder="请选择" @change="handleProjectChange(projectObj)"
+          clearable>
+          <el-option v-for="item in projectList" :key="item.id" :label="item.aname" :value="item.id">
+          </el-option>
+        </el-select>
+      </div>
+      <div class="station">
+        期次:
+        <el-select size="mini" v-model="lineObj" placeholder="请选择" clearable>
+          <el-option v-for="item in lineList" :key="item.id" :label="item.aname" :value="item.id">
+          </el-option>
+        </el-select>
+      </div>
+
+      <div class="station">
+        开始日期
+        <div class="search-input">
+          <el-date-picker v-model="starTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+            popper-class="date-select">
+          </el-date-picker>
+        </div>
+      </div>
+      <div class="station">
+        结束日期
+        <div class="search-input">
+          <el-date-picker v-model="endTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+            popper-class="date-select">
+          </el-date-picker>
+        </div>
+      </div>
+      <div class="but">
+        <el-button round size="mini" class="buttons" @click="getPerformance">查询</el-button>
+        <el-button round size="mini" class="buttons" @click="mxClick">明细</el-button>
+        <!-- <el-button round size="mini" class="buttons">导出</el-button> -->
+      </div>
+
+    </div>
+    <div class="performance" style="height: 90vh">
+      <div class="left">
+        <bar-line-chart v-if="showDisplay" :height="height" :bardata="bardata" :lineData="lineData" :color="barColor"
+          lineName="理论发电量" />
+      </div>
+      <div class="center">
+        <div class="using">
+
+        </div>
+      </div>
+      <div class="dashed" style="height: 80vh"></div>
+      <div class="dashed1" style="height: 80vh"></div>
+      <div class="table" style="height: 86vh">
+        <el-table :data="tableData" size="mini" stripe>
+          <el-table-column align="center" prop="name" label="名称" width="200">
+          </el-table-column>
+          <el-table-column align="center" prop="llfdl" label="理论发电量">
+          </el-table-column>
+          <el-table-column align="center" prop="speed" label="风速">
+          </el-table-column>
+          <el-table-column align="center" prop="fjhjx" label="非计划检修">
+          </el-table-column>
+          <el-table-column align="center" prop="jhjx" label="计划检修">
+          </el-table-column>
+          <el-table-column align="center" prop="sl" label="受累">
+          </el-table-column>
+          <el-table-column align="center" prop="xd" label="限电">
+          </el-table-column>
+          <el-table-column align="center" prop="xn" label="性能">
+          </el-table-column>
+          <el-table-column align="center" prop="fnlly" label="风能利用率%" width="120">
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import BarLineChart from "../compontent/bar-line-chart.vue";
+import { companys } from '@/api/curveAnalyse'
+import dayjs from "dayjs";
+import { getStation, getProject, getLine, performance } from '@/api/performance'
+export default {
+  name: 'performanceRankingList',//风机绩效榜
+  components: {
+    BarLineChart,
+  },
+  data() {
+    return {
+      barColor: [
+        "#4b55ae",
+        "#e17e23",
+        "#ba3237",
+        "#c531c7",
+        "#ffffff",
+        "#05bb4c",
+      ],
+      company: "",
+      companyOptions: [],
+      stationObj: "",
+      stationList: [],
+      projectObj: "",
+      projectList: [],
+      lineObj: "",
+      lineList: [],
+      starTime: '',
+      endTime: '',
+      tabIndex: -1,
+      bardata: [],
+      lineData: [],
+      tabOptions: [
+        { id: -1, name: "风电" },
+        { id: -2, name: "光伏" },
+      ],
+      typeIndex: '1',
+      typeOptions: [
+        { id: '1', name: "风场" },
+        { id: '2', name: "项目" },
+        { id: '3', name: "线路" },
+      ],
+      tableData: [],
+      showDisplay: true,
+      height: '86vh'
+    }
+  },
+  computed: {
+  },
+  created() {
+    let date = new Date();
+    date.setDate(1);
+    let month = parseInt(date.getMonth() + 1);
+    let day = date.getDate();
+    if (month < 10) {
+      month = '0' + month;
+    }
+    if (day < 10) {
+      day = '0' + day;
+    }
+    this.starTime = date.getFullYear() + '-' + month + '-' + day;
+    this.endTime = dayjs(new Date().getTime()).format("YYYY-MM-DD");
+    this.initialization();
+  },
+  methods: {
+    initialization() {
+      companys().then(res => {
+        this.companyOptions = res.data
+        if (res.data.length) {
+          this.company = res.data[4].id
+          this.getStation(res.data[4].id)
+        } else {
+          this.company = '',
+            this.stationObj = '',
+            this.stationList = [],
+            this.projectObj = '',
+            this.projectList = [],
+            this.lineObj = '',
+            this.lineList = []
+        }
+      })
+    },
+    getStation(companyids) {
+      getStation({
+        companyids: companyids
+      }).then(res => {
+        if (res.data.length) {
+          this.stationList = res.data
+          this.getProject(res.data[0].id)
+        } else {
+          this.stationObj = '',
+            this.stationList = [],
+            this.projectObj = '',
+            this.projectList = [],
+            this.lineObj = '',
+            this.lineList = []
+        }
+      })
+    },
+    getProject(wpids) {
+      getProject({
+        wpids: wpids
+      }).then(res => {
+        if (res.data.length) {
+          this.projectList = res.data
+          this.getLine(res.data[0].id)
+        } else {
+          this.projectObj = '',
+            this.projectList = [],
+            this.lineObj = '',
+            this.lineList = []
+        }
+      })
+    },
+    getLine(pjids) {
+      getLine({
+        pjids: pjids
+      }).then(res => {
+        if (res.data.length) {
+          this.lineList = res.data
+        } else {
+          this.lineObj = '',
+            this.lineList = []
+        }
+        this.getPerformance()
+      })
+    },
+    handleCompanyChange(val) {
+      this.getStation(val)
+    },
+    handleStationChange(val) {
+      this.getProject(val)
+    },
+    handleProjectChange(val) {
+      this.getLine(val)
+    },
+    tabClick(data) {
+      this.tabIndex = data
+      this.getPerformance()
+    },
+    typeClick(data) {
+      this.typeIndex = data
+      this.getPerformance()
+    },
+    getPerformance() {
+      performance({
+        companyid: this.company,
+        getype: this.tabIndex,
+        sttype: this.stationObj ? '' : this.typeIndex,
+        beginDate: this.starTime,
+        endDate: this.endTime,
+        wpids: this.stationObj,
+        projectids: this.projectObj,
+        lineids: this.lineObj,
+      }).then(res => {
+        if (res.data) {
+          let name = [],
+            data = [],
+            llfdl = [],
+            legend = [
+              "实际电量",
+              "计划检修损失",
+              "非计划检修损失",
+              "限电损失",
+              "受累损失",
+              "性能损失",
+            ]; //项目列表
+          res.data.forEach((item, index) => {
+            name.push(item.name);
+            data.push([
+              item.sjfdl,
+              item.jhjx,
+              item.fjhjx,
+              item.xd,
+              item.sl,
+              item.xn,
+            ]);
+            llfdl.push(item.llfdl);
+          });
+          name.pop();
+          data.pop();
+          llfdl.pop();
+          if (data.length > 0) {
+            let arr1 = [];
+            const length = data[0].length;
+            for (let i = 0; i < length; i++) {
+              let arr2 = [];
+              data.forEach((ele) => {
+                arr2.push(ele[i]);
+              });
+              arr1.push(arr2);
+            }
+            this.lineData = llfdl;
+            this.bardata = {
+              area: name,
+              legend: legend,
+              data: arr1,
+            };
+          }
+          console.log(11);
+          if (this.lineData.length > 22) {
+            this.height = this.lineData.length *35+53+ 'px'
+          } else {
+            this.height = '84vh'
+          }
+          this.showDisplay = false
+          setTimeout(() => {
+            this.showDisplay = true
+          }, 10);
+          this.tableData = res.data
+        }
+      })
+    },
+    mxClick() {
+      this.$router.push("/benchmarkingManagement/decision1Mx");
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.home-body {
+  display: flex;
+  flex-direction: column;
+}
+
+.title {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-top: 10px;
+
+  .tabCut {
+    display: inline-block;
+    margin: 0 10px;
+
+    div {
+      display: inline-block;
+      width: 60px;
+      height: 27px;
+      border: 1px solid #354460;
+      text-align: center;
+      line-height: 25px;
+      cursor: pointer;
+    }
+
+    div:nth-child(1) {
+      border-radius: 13px 0px 0px 13px;
+    }
+
+    div:nth-child(2) {
+      border-radius: 0px 13px 13px 0px;
+    }
+
+    .active {
+      background-color: #0C3378;
+      color: #fff;
+    }
+  }
+
+  .tabCut1 {
+    display: inline-block;
+    margin: 0 10px;
+
+    div {
+      display: inline-block;
+      width: 60px;
+      height: 27px;
+      border: 1px solid #354460;
+      text-align: center;
+      line-height: 25px;
+      cursor: pointer;
+    }
+
+    div:nth-child(1) {
+      border-radius: 13px 0px 0px 13px;
+    }
+
+    div:nth-child(3) {
+      border-radius: 0px 13px 13px 0px;
+    }
+
+    .active {
+      background-color: #0C3378;
+      color: #fff;
+    }
+  }
+
+  .station {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    font-size: 14px;
+    font-family: Microsoft YaHei;
+    font-weight: 400;
+    color: #B3B3B3;
+    margin-right: 10px;
+  }
+
+  .search-input {
+    margin-left: 10px;
+  }
+
+  .but {
+    display: flex;
+    flex-direction: row;
+    align-content: center;
+    margin-left: 20px;
+  }
+
+  .buttons {
+    background-color: rgba(67, 81, 107, .3);
+    border: 1px solid #3B4C6C;
+    color: #B3B3B3;
+    font-size: 14px;
+
+    &:hover {
+      background-color: rgba(0, 70, 199, .5);
+      color: #ffffff;
+    }
+  }
+}
+
+.performance {
+  display: flex;
+  flex-direction: row;
+  width: 98%;
+  background-color: rgba(0, 0, 0, .4);
+  margin-top: 10px;
+  margin-left: 1%;
+  border-radius: 5px;
+  overflow-y: auto;
+
+  .left {
+    width: 47%;
+    height: 100%;
+
+  }
+
+  .center {
+    width: 3%;
+    height: 90%;
+    position: relative;
+    margin-top: 50px;
+
+    .using {
+      width: 100%;
+      height: 100%;
+      z-index: 99;
+      position: absolute;
+      right: 0px;
+      top: 0px;
+    }
+  }
+
+  .dashed {
+    width: 1px;
+    background-image: linear-gradient(#3A4043 0%, #3A4043 40%, transparent 50%);
+    background-size: 1px 9px;
+    margin-top: 45px;
+  }
+
+  .dashed1 {
+    width: 1px;
+    background-image: linear-gradient(#3A4043 0%, #3A4043 40%, transparent 50%);
+    background-size: 1px 9px;
+    margin-top: 45px;
+    margin-left: 20px;
+  }
+
+  .table {
+    width: 48%;
+    // background-color: yellowgreen;
+  }
+}
+</style>

+ 767 - 0
src/views/economicsOperation/benchmarkingManagement/projectBenchmarking/index.vue

@@ -0,0 +1,767 @@
+<template>
+  <div class="parcel-box">
+    <div class="title">
+      <el-select size="mini" v-model="company" placeholder="请选择" @change="handleCompanyChange(company)">
+        <el-option v-for="item in companyOptions" :key="item.id" :label="item.aname" :value="item.id">
+        </el-option>
+      </el-select>
+      <div class="tabCut">
+        <div @click="tabClick(val.id)" :class="tabIndex === val.id ? 'active' : ''" v-for="val in tabOptions"
+          :key="val.id"><span>{{ val.name }}</span></div>
+      </div>
+      <div class="station">
+        场站:
+        <el-select size="mini" v-model="stationObj" placeholder="请选择"
+          @change="handleStationChange(stationObj)" clearable>
+          <el-option v-for="item in stationList" :key="item.id" :label="item.aname" :value="item.id">
+          </el-option>
+        </el-select>
+      </div>
+      <div class="station">
+        项目:
+        <el-select size="mini" v-model="projectObj" placeholder="请选择" multiple collapse-tags @change="handleProjectChange(projectObj)" clearable>
+          <el-option v-for="item in projectList" :key="item.id" :label="item.aname" :value="item.id">
+          </el-option>
+        </el-select>
+      </div>
+      <div class="station">
+        开始日期
+        <div class="search-input">
+          <el-date-picker v-model="starTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+            popper-class="date-select">
+          </el-date-picker>
+        </div>
+      </div>
+      <div class="station">
+        结束日期
+        <div class="search-input">
+          <el-date-picker v-model="endTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+            popper-class="date-select">
+          </el-date-picker>
+        </div>
+      </div>
+      <div class="but">
+        <el-button round size="mini" class="buttons" @click="gerCmdb">查询</el-button>
+        <el-button round size="mini" class="buttons" @click="dbfx"  :disabled="chooseList.length === 2?false:true">对标分析</el-button>
+        <el-button round size="mini" class="buttons" @click="goBack" v-if="displayDetail">返回</el-button>
+        <!-- <el-button round size="mini" class="buttons">导出</el-button> -->
+      </div>
+
+    </div>
+    <div v-if="!displayDetail">
+      <div class="line">
+        <div class="leftContent"><span>项目对标</span></div>
+        <div class="rightContent"></div>
+      </div>
+      <div class="table">
+        <el-table :data="tableData" ref="multipleTable" size="mini" height="58vh" :cell-style="{ padding: '0px' }"
+          :row-style="{ height: '0' }" stripe @selection-change="handleCurrentChange">
+          <el-table-column type="selection" width="55" align="center">
+          </el-table-column>
+          <el-table-column align="center" prop="name" label="名称" width="150" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="zhpm" label="综合排名" width="80" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="fdlpm" label="发电量排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="fdl" label="发电量" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdlpm" label="故障损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdl" label="故障损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdlpm" label="检修损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdl" label="检修损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdlpm" label="性能损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdl" label="性能损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdlpm" label="限电损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdl" label="限电损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="slssdlpm" label="受累损失排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="slssdl" label="受累损失" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="fnlylpm" label="风能利用率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="fnlyl" label="风能利用率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="gzsslpm" label="故障损失率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssl" label="故障损失率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="jxsslpm" label="检修损失率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssl" label="检修损失率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="qflpm" label="弃风率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="qfl" label="弃风率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xnsslpm" label="性能损失率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssl" label="性能损失率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="slsslpm" label="受累损失率排名" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="slssl" label="受累损失率(%)" sortable width="64">
+          </el-table-column>
+          <el-table-column align="center" prop="" label="操作">
+            <template v-slot="scope">
+              <span @click="goDetail(scope.row)" style="cursor: pointer;color: #1C99FF;">详情</span>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <div class="echarts">
+        <div class="pie-echarts">
+          <div class="chart-name">
+            <div class="point left bottom"></div>
+            <div class="point right bottom"></div>
+            损失电量分析
+          </div>
+          <PieChart :lossPower="lossPower" width="100%" height="20vh"></PieChart>
+        </div>
+        <div class="bar-echarts">
+          <div class="chart-name">
+            <div class="point left bottom"></div>
+            <div class="point right bottom"></div>
+            五项损失
+          </div>
+          <BarCharts :list="barList" width="100%" height="30vh" :showLegend="true" :xdate="false"></BarCharts>
+        </div>
+      </div>
+    </div>
+
+    <div v-if="displayDetail">
+      <el-table :data="detailTable" ref="multipleTable" size="mini" height="88vh" :cell-style="{ padding: '0px' }"
+          :row-style="{ height: '0' }" stripe @selection-change="handleCurrentChange">
+          <el-table-column type="selection" width="55" align="center">
+          </el-table-column>
+          <el-table-column align="center" prop="name" label="风机名称" width="150" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="zhpm" label="综合排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdl" label="故障损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdlpm" label="检修损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdl" label="检修损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdlpm" label="性能损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdl" label="性能损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdlpm" label="限电损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdl" label="限电损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssdlpm" label="受累损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssdl" label="受累损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzsslpm" label="故障损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzssl" label="故障损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxsslpm" label="检修损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssl" label="检修损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="qflpm" label="弃风率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="qfl" label="弃风率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnsslpm" label="性能损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssl" label="性能损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slsslpm" label="受累损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssl" label="受累损失率(%)" sortable>
+          </el-table-column>
+        </el-table>
+    </div>
+
+    <el-dialog
+      title="对标排名分析"
+      v-model="dialogVisible"
+      width="70%"
+      top="10vh"
+      custom-class="modal"
+      :close-on-click-modal="false"
+    >
+      <dayinfo
+        :radarValue="radarValue"
+        :title="[windNum, windNum2]"
+        :windNum="windNum"
+        :windNum2="windNum2"
+        :tabs="tabs"
+        :analyisDialog="analyisDialog"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import dayjs from "dayjs";
+import { companys } from '@/api/curveAnalyse'
+import { getStation, getProject, xmdb, details } from '@/api/performance'
+import PieChart from '../../homePage/components/pieChart.vue'
+import BarCharts from '../../homePage/components/barCharts.vue'
+import dayinfo from '../compontent/dayinfo.vue'
+export default {
+  name: 'intervalBenchmarking',//场际对标
+  components: {
+    PieChart,
+    BarCharts,
+    dayinfo,
+  },
+  data() {
+    return {
+      company: '',
+      companyOptions: [],
+      stationObj: '',
+      stationList: [],
+      projectObj: [],
+      projectList: [],
+      starTime: '',
+      endTime: '',
+      tabIndex: -1,
+      tabOptions: [
+        { id: -1, name: "风电" },
+        { id: -2, name: "光伏" },
+      ],
+      tableData: [],
+      detailTable: [],
+      chooseList: [],
+      lossPower: [],
+      barList: [],
+      displayDetail: false,
+      dialogVisible: false,
+      radarValue: [],
+      windNum: "dd",
+      windNum2: "dd",
+      tabs: [],
+      analyisDialog: [],
+    }
+  },
+  created() {
+    let date = new Date();
+    date.setDate(1);
+    let month = parseInt(date.getMonth() + 1);
+    let day = date.getDate();
+    if (month < 10) {
+      month = '0' + month;
+    }
+    if (day < 10) {
+      day = '0' + day;
+    }
+    this.starTime = date.getFullYear() + '-' + month + '-' + day;
+    this.endTime = dayjs(new Date().getTime()).format("YYYY-MM-DD");
+    this.initialization()
+  },
+  methods: {
+    initialization() {
+      companys().then(res => {
+        if (res.data) {
+          this.company = res.data[4].id
+          this.companyOptions = res.data
+          this.getStation(res.data[4].id)
+        }
+      })
+    },
+    getStation(companyids) {
+      getStation({
+        companyids: companyids
+      }).then(res => {
+        if (res.data.length) {
+          this.stationList = res.data
+          this.stationObj = res.data[0].id
+          this.getProject(res.data[0].id)
+        }
+      })
+    },
+    getProject(wpids) {
+      getProject({
+        wpids: wpids
+      }).then(res => {
+        if (res.data.length) {
+          this.projectList = res.data
+          this.gerCmdb()
+        }
+      })
+    },
+    gerCmdb() {
+      xmdb({
+        companys: this.company,
+        type: this.tabIndex,
+        beginDate: this.starTime,
+        endDate: this.endTime,
+        wpids: this.stationObj,
+        projectids: this.projectObj.join(','),
+        target: '',
+        sort: '',
+      }).then(res => {
+        if (res.data) {
+          let barList = [
+            {
+              name: '故障损失电量',
+              children: [],
+              date: [],
+            },
+            {
+              name: '检修损失电量',
+              children: [],
+            },
+            {
+              name: '性能损失电量',
+              children: [],
+            },
+            {
+              name: '限电损失电量',
+              children: [],
+            },
+            {
+              name: '受累损失电量',
+              children: [],
+            },
+          ]
+          this.tableData = res.data
+          let lossPower = []
+          res.data.forEach(item => {
+            let obj = {
+              name: item.name,
+              value: item.zssdl,
+            }
+            lossPower.push(obj)
+            barList[0].date.push(item.name)
+            barList[0].children.push(item.gzssdl)
+            barList[1].children.push(item.jxssdl)
+            barList[2].children.push(item.xnssdl)
+            barList[3].children.push(item.xdssdl)
+            barList[4].children.push(item.slssdl)
+          })
+          this.lossPower = lossPower
+          this.barList = barList
+        }
+      })
+    },
+    handleStationChange(val) {
+      this.stationObj = val
+    },
+    handleCurrentChange(val) {
+      if (val.length > 2) {
+        let del_row = val.shift();
+        this.$refs.multipleTable.toggleRowSelection(del_row, false);
+      }
+      let arr = []
+      val.forEach((item, index) => {
+        if (index < 2) {
+          arr.push(item)
+        }
+      })
+      this.chooseList = arr
+    },
+    goDetail(row) {
+      this.displayDetail = true
+      details({
+        id: row.id,
+        beginDate: this.starTime,
+        endDate: this.endTime,
+        target: '',
+        sort: '',
+      }).then(res =>{
+        if(res.data){
+          this.detailTable = res.data
+        }
+      })
+    },
+    goBack(){
+      this.displayDetail = false
+    },
+    dbfx() {
+      if(this.chooseList.length === 2){
+        this.dialogVisible = true;
+        this.AjaxDbfx();
+      }
+    },
+    AjaxDbfx(){
+      var data = this.chooseList;
+      this.windNum = data[0].name;
+      this.windNum2 = data[1].name;
+      this.tabs = [
+        {
+          name: "发电量",
+          windData1: data[0].fdl,
+          windData2: data[1].fdl,
+        },
+        {
+          name: "故障损失电量",
+          windData1: data[0].gzssdl,
+          windData2: data[1].gzssdl,
+        },
+        {
+          name: "检修损失电量",
+          windData1: data[0].jxssdl,
+          windData2: data[1].jxssdl,
+        },
+        {
+          name: "性能未达标损失电量",
+          windData1: data[0].xnssdl,
+          windData2: data[1].xnssdl,
+        },
+        {
+          name: "受累损失电量",
+          windData1: data[0].slssdl,
+          windData2: data[1].slssdl,
+        },
+        {
+          name: "风能利用率",
+          windData1: data[0].fnlyl,
+          windData2: data[1].fnlyl,
+        },
+        {
+          name: "故障损失率",
+          windData1: data[0].gzssl,
+          windData2: data[1].gzssl,
+        },
+        {
+          name: "检修损失率",
+          windData1: data[0].jxssl,
+          windData2: data[1].jxssl,
+        },
+        {
+          name: "弃风率",
+          windData1: data[0].qfl,
+          windData2: data[1].qfl,
+        },
+        {
+          name: "性能损失率",
+          windData1: data[0].xnssl,
+          windData2: data[1].xnssl,
+        },
+        {
+          name: "受累损失率",
+          windData1: data[0].slssl,
+          windData2: data[1].slssl,
+        },
+      ];
+
+      this.radarValue = [
+        {
+          indicator: [
+          "风能利用率排名",
+            "故障损失率排名",
+            "检修损失率排名",
+            "弃风率排名",
+            "性能损失率排名",
+            "受累损失率排名",
+          ],
+          data: [
+            {
+              value: [
+                data[0].fnlylpm,
+                data[0].gzsslpm,
+                data[0].jxsslpm,
+                data[0].qflpm,
+                data[0].xnsslpm,
+                data[0].slsslpm,
+              ],
+              name: data[0].name
+            },
+          ],
+        },
+        {
+          indicator: [
+          "风能利用率排名",
+            "故障损失率排名",
+            "检修损失率排名",
+            "弃风率排名",
+            "性能损失率排名",
+            "受累损失率排名",
+          ],
+          data: [
+          {
+              value: [
+                data[1].fnlylpm,
+                data[1].gzsslpm,
+                data[1].jxsslpm,
+                data[1].qflpm,
+                data[1].xnsslpm,
+                data[1].slsslpm,
+              ],
+              name: data[1].name
+            },
+          ],
+        },
+      ];
+      var analyis = [],
+        gzssdl = [],
+        jxssdl = [],
+        xnssdl = [],
+        xdssdl = [],
+        slssdl = [];
+      data.forEach((item, index) => {
+        gzssdl.push({
+          text: item.name,
+          value: item.gzssdl,
+        });
+        jxssdl.push({
+          text: item.name,
+          value: item.jxssdl,
+        });
+        xnssdl.push({
+          text: item.name,
+          value: item.xnssdl,
+        });
+        xdssdl.push({
+          text: item.name,
+          value: item.xdssdl,
+        });
+        slssdl.push({
+          text: item.name,
+          value: item.slssdl,
+        });
+      });
+      analyis.push(
+        {
+          title: "故障损失电量",
+          yAxisIndex: 0,
+          value: gzssdl,
+        },
+        {
+          title: "检修损失电量",
+          yAxisIndex: 0,
+          value: jxssdl,
+        },
+        {
+          title: "性能损失电量",
+          yAxisIndex: 0,
+          value: xnssdl,
+        },
+        {
+          title: "限电损失电量",
+          yAxisIndex: 0,
+          value: xdssdl,
+        },
+        {
+          title: "受累损失电量",
+          yAxisIndex: 0,
+          value: slssdl,
+        }
+      );
+      this.analyisDialog = analyis;
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.parcel-box {
+  padding: 0 15px;
+}
+
+.title {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-top: 10px;
+  margin-bottom: 10px;
+
+  .tabCut {
+    display: inline-block;
+    margin: 0 10px;
+
+    div {
+      display: inline-block;
+      width: 60px;
+      height: 27px;
+      border: 1px solid #354460;
+      text-align: center;
+      line-height: 25px;
+      cursor: pointer;
+    }
+
+    div:nth-child(1) {
+      border-radius: 13px 0px 0px 13px;
+    }
+
+    div:nth-child(2) {
+      border-radius: 0px 13px 13px 0px;
+    }
+
+    .active {
+      background-color: #0C3378;
+      color: #fff;
+    }
+  }
+
+  .tabCut1 {
+    display: inline-block;
+    margin: 0 10px;
+
+    div {
+      display: inline-block;
+      width: 60px;
+      height: 27px;
+      border: 1px solid #354460;
+      text-align: center;
+      line-height: 25px;
+      cursor: pointer;
+    }
+
+    div:nth-child(1) {
+      border-radius: 13px 0px 0px 13px;
+    }
+
+    div:nth-child(3) {
+      border-radius: 0px 13px 13px 0px;
+    }
+
+    .active {
+      background-color: #0C3378;
+      color: #fff;
+    }
+  }
+
+  .station {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    font-size: 14px;
+    font-family: Microsoft YaHei;
+    font-weight: 400;
+    color: #B3B3B3;
+    margin-right: 10px;
+  }
+
+  .search-input {
+    margin-left: 10px;
+  }
+
+  .but {
+    display: flex;
+    flex-direction: row;
+    align-content: center;
+    margin-left: 20px;
+  }
+
+  .buttons {
+    background-color: rgba(67, 81, 107, .3);
+    border: 1px solid #3B4C6C;
+    color: #B3B3B3;
+    font-size: 14px;
+
+    &:hover {
+      background-color: rgba(0, 70, 199, .5);
+      color: #ffffff;
+    }
+  }
+}
+
+.line {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+
+  .leftContent {
+    width: 242px;
+    height: 41px;
+    display: flex;
+    align-items: center;
+    background: url("../../../../assets/img/title_left_bg.png");
+
+    span {
+      font-size: 16px;
+      font-family: Microsoft YaHei;
+      font-weight: 400;
+      color: #FFFFFF;
+      margin-left: 25px;
+    }
+  }
+
+  .rightContent {
+    width: 212px;
+    height: 28px;
+    margin-top: 13px;
+    background: url("../../../../assets/img/title_right_bg.png");
+  }
+}
+
+.table {
+  width: 100%;
+}
+
+.echarts {
+  width: 100%;
+  height: 26vh;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+
+  .chart-name {
+    display: flex;
+    align-items: center;
+    padding-left: 20px;
+    position: relative;
+    height: 39px;
+    width: 98%;
+    margin-left: 1%;
+    border-bottom: 1px solid rgba(153, 153, 153, 0.5);
+    font-size: 16px;
+    font-family: Microsoft YaHei;
+    font-weight: 400;
+    color: #FFFFFF;
+  }
+
+  .pie-echarts {
+    width: 30%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.45);
+    border-radius: 5px;
+  }
+
+  .bar-echarts {
+    width: 69%;
+    margin-left: 1%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.45);
+    border-radius: 5px;
+  }
+}
+
+.point {
+  width: 6px;
+  height: 1px;
+  background-color: #ffffff;
+  position: absolute;
+
+  &.left {
+    left: 0;
+  }
+
+  &.right {
+    right: 0;
+  }
+
+  &.top {
+    top: -1px;
+  }
+
+  &.bottom {
+    bottom: -1px;
+  }
+}
+
+/*去除表头全选框*/
+::v-deep .el-table__header-wrapper .el-checkbox {
+  display: none;
+}
+</style>

+ 747 - 0
src/views/economicsOperation/benchmarkingManagement/siteBenchmarking/index.vue

@@ -0,0 +1,747 @@
+<template>
+  <div class="parcel-box">
+    <div class="title">
+      <el-select size="mini" v-model="company" placeholder="请选择" @change="handleCompanyChange(company)">
+        <el-option v-for="item in companyOptions" :key="item.id" :label="item.aname" :value="item.id">
+        </el-option>
+      </el-select>
+      <div class="tabCut">
+        <div @click="tabClick(val.id)" :class="tabIndex === val.id ? 'active' : ''" v-for="val in tabOptions"
+          :key="val.id"><span>{{ val.name }}</span></div>
+      </div>
+      <div class="station">
+        场站:
+        <el-select size="mini" v-model="stationObj" placeholder="请选择"
+          @change="handleStationChange(stationObj)" clearable>
+          <el-option v-for="item in stationList" :key="item.id" :label="item.aname" :value="item.id">
+          </el-option>
+        </el-select>
+      </div>
+      <div class="station">
+        开始日期
+        <div class="search-input">
+          <el-date-picker v-model="starTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+            popper-class="date-select">
+          </el-date-picker>
+        </div>
+      </div>
+      <div class="station">
+        结束日期
+        <div class="search-input">
+          <el-date-picker v-model="endTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
+            popper-class="date-select">
+          </el-date-picker>
+        </div>
+      </div>
+      <div class="but">
+        <el-button round size="mini" class="buttons" @click="gerCndb">查询</el-button>
+        <el-button round size="mini" class="buttons" @click="dbfx"  :disabled="chooseList.length === 2?false:true">对标分析</el-button>
+        <el-button round size="mini" class="buttons" @click="goBack" v-if="displayDetail">返回</el-button>
+        <!-- <el-button round size="mini" class="buttons">导出</el-button> -->
+      </div>
+
+    </div>
+    <div v-if="!displayDetail">
+      <div class="line">
+        <div class="leftContent"><span>场内对标</span></div>
+        <div class="rightContent"></div>
+      </div>
+      <div class="table">
+        <el-table :data="tableData" ref="multipleTable" size="mini" height="58vh" :cell-style="{ padding: '0px' }"
+          :row-style="{ height: '0' }" stripe @selection-change="handleCurrentChange">
+          <el-table-column type="selection" width="55" align="center">
+          </el-table-column>
+          <el-table-column align="center" prop="zhpm" label="综合排名" width="80" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="date" label="日期" sortable width="100">
+          </el-table-column>
+          <el-table-column align="center" prop="fdlpm" label="发电量排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="fdl" label="发电量" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdlpm" label="故障损失排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdl" label="故障损失" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdlpm" label="检修损失排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdl" label="检修损失" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdlpm" label="性能损失排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdl" label="性能损失" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdlpm" label="限电损失排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdl" label="限电损失" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="slssdlpm" label="受累损失排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="slssdl" label="受累损失" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="fnlylpm" label="风能利用率排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="fnlyl" label="风能利用率(%)" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="gzsslpm" label="故障损失率排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="gzssl" label="故障损失率(%)" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="jxsslpm" label="检修损失率排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="jxssl" label="检修损失率(%)" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="qflpm" label="弃风率排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="qfl" label="弃风率(%)" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="xnsslpm" label="性能损失率排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="xnssl" label="性能损失率(%)" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="slsslpm" label="受累损失率排名" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="slssl" label="受累损失率(%)" sortable width="66">
+          </el-table-column>
+          <el-table-column align="center" prop="" label="操作">
+            <template v-slot="scope">
+              <span @click="goDetail(scope.row)" style="cursor: pointer;color: #1C99FF;">详情</span>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <div class="echarts">
+        <div class="pie-echarts">
+          <div class="chart-name">
+            <div class="point left bottom"></div>
+            <div class="point right bottom"></div>
+            损失电量分析
+          </div>
+          <PieChart :lossPower="lossPower" width="100%" height="20vh"></PieChart>
+        </div>
+        <div class="bar-echarts">
+          <div class="chart-name">
+            <div class="point left bottom"></div>
+            <div class="point right bottom"></div>
+            五项损失
+          </div>
+          <BarCharts :list="barList" width="100%" height="30vh" :showLegend="true" :xdate="false"></BarCharts>
+        </div>
+      </div>
+    </div>
+
+    <div v-if="displayDetail">
+      <el-table :data="detailTable" ref="multipleTable" size="mini" height="88vh" :cell-style="{ padding: '0px' }"
+          :row-style="{ height: '0' }" stripe @selection-change="handleCurrentChange">
+          <el-table-column type="selection" width="55" align="center">
+          </el-table-column>
+          <el-table-column align="center" prop="name" label="风机名称" width="150" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="zhpm" label="综合排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzssdl" label="故障损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdlpm" label="检修损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssdl" label="检修损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdlpm" label="性能损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssdl" label="性能损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdlpm" label="限电损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xdssdl" label="限电损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssdlpm" label="受累损失排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssdl" label="受累损失" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzsslpm" label="故障损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="gzssl" label="故障损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxsslpm" label="检修损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="jxssl" label="检修损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="qflpm" label="弃风率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="qfl" label="弃风率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnsslpm" label="性能损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="xnssl" label="性能损失率(%)" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slsslpm" label="受累损失率排名" sortable>
+          </el-table-column>
+          <el-table-column align="center" prop="slssl" label="受累损失率(%)" sortable>
+          </el-table-column>
+        </el-table>
+    </div>
+
+    <el-dialog
+      title="对标排名分析"
+      v-model="dialogVisible"
+      width="70%"
+      top="10vh"
+      custom-class="modal"
+      :close-on-click-modal="false"
+    >
+      <dayinfo
+        :radarValue="radarValue"
+        :title="[windNum, windNum2]"
+        :windNum="windNum"
+        :windNum2="windNum2"
+        :tabs="tabs"
+        :analyisDialog="analyisDialog"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import dayjs from "dayjs";
+import { companys } from '@/api/curveAnalyse'
+import { getStation, cndb, details } from '@/api/performance'
+import PieChart from '../../homePage/components/pieChart.vue'
+import BarCharts from '../../homePage/components/barCharts.vue'
+import dayinfo from '../compontent/dayinfo.vue'
+export default {
+  name: 'intervalBenchmarking',//场际对标
+  components: {
+    PieChart,
+    BarCharts,
+    dayinfo,
+  },
+  data() {
+    return {
+      company: '',
+      companyOptions: [],
+      stationObj: '',
+      stationList: [],
+      starTime: '',
+      endTime: '',
+      tabIndex: -1,
+      tabOptions: [
+        { id: -1, name: "风电" },
+        { id: -2, name: "光伏" },
+      ],
+      tableData: [],
+      detailTable: [],
+      chooseList: [],
+      lossPower: [],
+      barList: [],
+      displayDetail: false,
+      dialogVisible: false,
+      radarValue: [],
+      windNum: "dd",
+      windNum2: "dd",
+      tabs: [],
+      analyisDialog: [],
+    }
+  },
+  created() {
+    let date = new Date();
+    date.setDate(1);
+    let month = parseInt(date.getMonth() + 1);
+    let day = date.getDate();
+    if (month < 10) {
+      month = '0' + month;
+    }
+    if (day < 10) {
+      day = '0' + day;
+    }
+    this.starTime = date.getFullYear() + '-' + month + '-' + day;
+    this.endTime = dayjs(new Date().getTime()).format("YYYY-MM-DD");
+    this.initialization()
+  },
+  methods: {
+    initialization() {
+      companys().then(res => {
+        if (res.data) {
+          this.company = res.data[4].id
+          this.companyOptions = res.data
+          this.getStation(res.data[4].id)
+        }
+      })
+    },
+    getStation(companyids) {
+      getStation({
+        companyids: companyids
+      }).then(res => {
+        if (res.data.length) {
+          this.stationList = res.data
+          this.stationObj = res.data[0].id
+          this.gerCndb()
+        }
+      })
+    },
+    gerCndb() {
+      cndb({
+        companys: this.company,
+        type: this.tabIndex,
+        beginDate: this.starTime,
+        endDate: this.endTime,
+        wpids: this.stationObj,
+        target: '',
+        sort: '',
+      }).then(res => {
+        if (res.data) {
+          let barList = [
+            {
+              name: '故障损失电量',
+              children: [],
+              date: [],
+            },
+            {
+              name: '检修损失电量',
+              children: [],
+            },
+            {
+              name: '性能损失电量',
+              children: [],
+            },
+            {
+              name: '限电损失电量',
+              children: [],
+            },
+            {
+              name: '受累损失电量',
+              children: [],
+            },
+          ]
+          this.tableData = res.data
+          let lossPower = []
+          res.data.forEach(item => {
+            let obj = {
+              name: item.date,
+              value: item.zssdl,
+            }
+            lossPower.push(obj)
+            barList[0].date.push(item.date)
+            barList[0].children.push(item.gzssdl)
+            barList[1].children.push(item.jxssdl)
+            barList[2].children.push(item.xnssdl)
+            barList[3].children.push(item.xdssdl)
+            barList[4].children.push(item.slssdl)
+          })
+          this.lossPower = lossPower
+          this.barList = barList
+        }
+      })
+    },
+    handleStationChange(val) {
+      this.stationObj = val
+    },
+    handleCurrentChange(val) {
+      if (val.length > 2) {
+        let del_row = val.shift();
+        this.$refs.multipleTable.toggleRowSelection(del_row, false);
+      }
+      let arr = []
+      val.forEach((item, index) => {
+        if (index < 2) {
+          arr.push(item)
+        }
+      })
+      this.chooseList = arr
+    },
+    goDetail(row) {
+      this.displayDetail = true
+      details({
+        id: row.id,
+        beginDate: this.starTime,
+        endDate: this.endTime,
+        target: '',
+        sort: '',
+      }).then(res =>{
+        if(res.data){
+          this.detailTable = res.data
+        }
+      })
+    },
+    goBack(){
+      this.displayDetail = false
+    },
+    dbfx() {
+      if(this.chooseList.length === 2){
+        this.dialogVisible = true;
+        this.AjaxDbfx();
+      }
+    },
+    AjaxDbfx(){
+      var data = this.chooseList;
+      this.windNum = data[0].date || data[0].name;
+      this.windNum2 = data[1].date || data[1].name;
+      this.tabs = [
+        {
+          name: "发电量",
+          windData1: data[0].fdl,
+          windData2: data[1].fdl,
+        },
+        {
+          name: "故障损失电量",
+          windData1: data[0].gzssdl,
+          windData2: data[1].gzssdl,
+        },
+        {
+          name: "检修损失电量",
+          windData1: data[0].jxssdl,
+          windData2: data[1].jxssdl,
+        },
+        {
+          name: "性能未达标损失电量",
+          windData1: data[0].xnssdl,
+          windData2: data[1].xnssdl,
+        },
+        {
+          name: "受累损失电量",
+          windData1: data[0].slssdl,
+          windData2: data[1].slssdl,
+        },
+        {
+          name: "风能利用率",
+          windData1: data[0].fnlyl,
+          windData2: data[1].fnlyl,
+        },
+        {
+          name: "故障损失率",
+          windData1: data[0].gzssl,
+          windData2: data[1].gzssl,
+        },
+        {
+          name: "检修损失率",
+          windData1: data[0].jxssl,
+          windData2: data[1].jxssl,
+        },
+        {
+          name: "弃风率",
+          windData1: data[0].qfl,
+          windData2: data[1].qfl,
+        },
+        {
+          name: "性能损失率",
+          windData1: data[0].xnssl,
+          windData2: data[1].xnssl,
+        },
+        {
+          name: "受累损失率",
+          windData1: data[0].slssl,
+          windData2: data[1].slssl,
+        },
+      ];
+
+      this.radarValue = [
+        {
+          indicator: [
+            "风能利用率排名",
+            "故障损失率排名",
+            "检修损失率排名",
+            "弃风率排名",
+            "性能损失率排名",
+            "受累损失率排名",
+          ],
+          data: [
+            {
+              value: [
+                data[0].fnlylpm,
+                data[0].gzsslpm,
+                data[0].jxsslpm,
+                data[0].qflpm,
+                data[0].xnsslpm,
+                data[0].slsslpm,
+              ],
+              name: data[0].name
+            },
+          ],
+        },
+        {
+          indicator: [
+          "风能利用率排名",
+            "故障损失率排名",
+            "检修损失率排名",
+            "弃风率排名",
+            "性能损失率排名",
+            "受累损失率排名",
+          ],
+          data: [
+          {
+              value: [
+                data[1].fnlylpm,
+                data[1].gzsslpm,
+                data[1].jxsslpm,
+                data[1].qflpm,
+                data[1].xnsslpm,
+                data[1].slsslpm,
+              ],
+              name: data[1].name
+            },
+          ],
+        },
+      ];
+      var analyis = [],
+        gzssdl = [],
+        jxssdl = [],
+        xnssdl = [],
+        xdssdl = [],
+        slssdl = [];
+      data.forEach((item, index) => {
+        gzssdl.push({
+          text: item.date || item.name,
+          value: item.gzssdl,
+        });
+        jxssdl.push({
+          text: item.date || item.name,
+          value: item.jxssdl,
+        });
+        xnssdl.push({
+          text: item.date || item.name,
+          value: item.xnssdl,
+        });
+        xdssdl.push({
+          text: item.date || item.name,
+          value: item.xdssdl,
+        });
+        slssdl.push({
+          text: item.date || item.name,
+          value: item.slssdl,
+        });
+      });
+      analyis.push(
+        {
+          title: "故障损失电量",
+          yAxisIndex: 0,
+          value: gzssdl,
+        },
+        {
+          title: "检修损失电量",
+          yAxisIndex: 0,
+          value: jxssdl,
+        },
+        {
+          title: "性能损失电量",
+          yAxisIndex: 0,
+          value: xnssdl,
+        },
+        {
+          title: "限电损失电量",
+          yAxisIndex: 0,
+          value: xdssdl,
+        },
+        {
+          title: "受累损失电量",
+          yAxisIndex: 0,
+          value: slssdl,
+        }
+      );
+      this.analyisDialog = analyis;
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.parcel-box {
+  padding: 0 15px;
+}
+
+.title {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-top: 10px;
+  margin-bottom: 10px;
+
+  .tabCut {
+    display: inline-block;
+    margin: 0 10px;
+
+    div {
+      display: inline-block;
+      width: 60px;
+      height: 27px;
+      border: 1px solid #354460;
+      text-align: center;
+      line-height: 25px;
+      cursor: pointer;
+    }
+
+    div:nth-child(1) {
+      border-radius: 13px 0px 0px 13px;
+    }
+
+    div:nth-child(2) {
+      border-radius: 0px 13px 13px 0px;
+    }
+
+    .active {
+      background-color: #0C3378;
+      color: #fff;
+    }
+  }
+
+  .tabCut1 {
+    display: inline-block;
+    margin: 0 10px;
+
+    div {
+      display: inline-block;
+      width: 60px;
+      height: 27px;
+      border: 1px solid #354460;
+      text-align: center;
+      line-height: 25px;
+      cursor: pointer;
+    }
+
+    div:nth-child(1) {
+      border-radius: 13px 0px 0px 13px;
+    }
+
+    div:nth-child(3) {
+      border-radius: 0px 13px 13px 0px;
+    }
+
+    .active {
+      background-color: #0C3378;
+      color: #fff;
+    }
+  }
+
+  .station {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    font-size: 14px;
+    font-family: Microsoft YaHei;
+    font-weight: 400;
+    color: #B3B3B3;
+    margin-right: 10px;
+  }
+
+  .search-input {
+    margin-left: 10px;
+  }
+
+  .but {
+    display: flex;
+    flex-direction: row;
+    align-content: center;
+    margin-left: 20px;
+  }
+
+  .buttons {
+    background-color: rgba(67, 81, 107, .3);
+    border: 1px solid #3B4C6C;
+    color: #B3B3B3;
+    font-size: 14px;
+
+    &:hover {
+      background-color: rgba(0, 70, 199, .5);
+      color: #ffffff;
+    }
+  }
+}
+
+.line {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+
+  .leftContent {
+    width: 242px;
+    height: 41px;
+    display: flex;
+    align-items: center;
+    background: url("../../../../assets/img/title_left_bg.png");
+
+    span {
+      font-size: 16px;
+      font-family: Microsoft YaHei;
+      font-weight: 400;
+      color: #FFFFFF;
+      margin-left: 25px;
+    }
+  }
+
+  .rightContent {
+    width: 212px;
+    height: 28px;
+    margin-top: 13px;
+    background: url("../../../../assets/img/title_right_bg.png");
+  }
+}
+
+.table {
+  width: 100%;
+}
+
+.echarts {
+  width: 100%;
+  height: 26vh;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+
+  .chart-name {
+    display: flex;
+    align-items: center;
+    padding-left: 20px;
+    position: relative;
+    height: 39px;
+    width: 98%;
+    margin-left: 1%;
+    border-bottom: 1px solid rgba(153, 153, 153, 0.5);
+    font-size: 16px;
+    font-family: Microsoft YaHei;
+    font-weight: 400;
+    color: #FFFFFF;
+  }
+
+  .pie-echarts {
+    width: 30%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.45);
+    border-radius: 5px;
+  }
+
+  .bar-echarts {
+    width: 69%;
+    margin-left: 1%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.45);
+    border-radius: 5px;
+  }
+}
+
+.point {
+  width: 6px;
+  height: 1px;
+  background-color: #ffffff;
+  position: absolute;
+
+  &.left {
+    left: 0;
+  }
+
+  &.right {
+    right: 0;
+  }
+
+  &.top {
+    top: -1px;
+  }
+
+  &.bottom {
+    bottom: -1px;
+  }
+}
+
+/*去除表头全选框*/
+::v-deep .el-table__header-wrapper .el-checkbox {
+  display: none;
+}
+</style>

+ 0 - 0
src/views/economicsOperation/benchmarkingManagement/standAloneBenchmarking/index.vue


部分文件因文件數量過多而無法顯示