Kaynağa Gözat

feat: 增加光伏功率图标

Jerry Liang 1 yıl önce
ebeveyn
işleme
49653dfa48

+ 1 - 1
.env

@@ -2,7 +2,7 @@
 VITE_GLOB_APP_TITLE = Bee Admin
 
 # 本地运行端口号
-VITE_PORT = 8848
+VITE_PORT = 8362
 
 # 启动时自动打开浏览器
 VITE_OPEN = false

+ 4 - 3
.env.development

@@ -2,7 +2,7 @@
 VITE_USER_NODE_ENV = development
 
 # 公共基础路径
-VITE_PUBLIC_PATH = /
+VITE_PUBLIC_PATH = /bee-admin/
 
 # 路由模式
 # Optional: hash | history
@@ -15,10 +15,11 @@ VITE_DROP_CONSOLE = true
 VITE_PWA = false
 
 # 开发环境接口地址
-VITE_API_URL = /api
+VITE_API_URL = /bee-admin/api
 
 # 开发环境跨域代理,支持配置多个
-VITE_PROXY = [["/api","http://jerry-remote:9999"]]
+VITE_PROXY = [["/bee-admin/api","http://jerry-remote:8201"]]
+# VITE_PROXY = [["/api","http://jerry-remote:9999"]]
 # VITE_PROXY = [["/api","https://mock.mengxuegu.com/mock/629d727e6163854a32e8307e"]]
 # VITE_PROXY = [["/api","https://www.fastmock.site/mock/f81e8333c1a9276214bcdbc170d9e0a0"]]
 # VITE_PROXY = [["/api-easymock","https://mock.mengxuegu.com"],["/api-fastmock","https://www.fastmock.site"]]

+ 9 - 5
src/components/ECharts/index.vue

@@ -31,14 +31,14 @@ const echartsStyle = computed(() => {
   if (typeof props.width === "number") {
     width = props.width + "px";
   } else {
-    width = props.width;
+    width = props.width ?? "auto";
   }
   if (typeof props.height === "number") {
     height = props.height + "px";
   } else {
-    height = props.height;
+    height = props.height ?? "auto";
   }
-  console.log(height, width);
+  console.log({ height, width });
   return {
     height,
     width
@@ -70,11 +70,15 @@ const init = () => {
   chartInstance.value = echarts.getInstanceByDom(chartRef.value);
 
   if (!chartInstance.value) {
+    console.log({ props });
+    console.log({ chartRef: chartRef.value });
     chartInstance.value = markRaw(
       echarts.init(chartRef.value, props.theme, {
         renderer: props.renderer,
-        height: props.height,
-        width: props.width
+        // height: props.height ?? "auto",
+        // width: props.width ?? "auto"
+        height: "auto",
+        width: "auto"
       })
     );
     console.log(echarts);

+ 1 - 1
src/views/cloudData/cloudLog/index.vue

@@ -116,7 +116,7 @@ const columns = reactive<ColumnProps<CloudLog.CloudLogListItem>[]>([
       const indeterminate: boolean = scope.row.status === 0;
       const showText: boolean = false;
       return (
-        <el-progress percentage={percentage} status={status} indeterminate={indeterminate} duration="5" show-text={showText} />
+        <el-progress percentage={percentage} status={status} indeterminate={indeterminate} duration={5} show-text={showText} />
       );
     }
   },

+ 1 - 1
src/views/cloudData/cloudLog/siteView/chart/powerFlow.chart.vue

@@ -1,5 +1,5 @@
 <template>
-  <ECharts ref="chartRef" :option="optionPowerFlow" />
+  <ECharts ref="chartRef" :option="optionPowerFlow" width="100%" height="100%" />
 </template>
 
 <script setup lang="ts" name="PowerFlowChart">

+ 144 - 0
src/views/cloudData/cloudLog/siteView/chart/pvPowerFlow.chart.vue

@@ -0,0 +1,144 @@
+<template>
+  <ECharts ref="chartRef" :option="optionPowerFlow" width="100%" height="100%" />
+</template>
+
+<script setup lang="ts" name="PvPowerFlowChart">
+import { ref } from "vue";
+import ECharts from "@/components/ECharts/index.vue";
+import { ECOption } from "@/components/ECharts/config";
+import { PowerFlowData } from "./pvPowerFlow.class";
+
+// 使用 ref 获取 DOM 元素引用
+const chartRef = ref();
+
+interface Props {
+  pf: PowerFlowData;
+}
+
+const props = defineProps<Props>();
+
+// 图表配置
+let optionPowerFlow: ECOption = {
+  title: { text: "PV功率流图" },
+  legend: {
+    data: ["DC-PV", "AC-PV"]
+  },
+  toolbox: {
+    feature: {
+      dataView: {},
+      saveAsImage: {
+        pixelRatio: 2
+      }
+    }
+  },
+  tooltip: {
+    trigger: "axis",
+    axisPointer: {
+      type: "cross",
+      label: {
+        backgroundColor: "#6a7985"
+      }
+    },
+    backgroundColor: "rgba(255, 255, 255, 0.8)",
+    position: function (pos, params, el, elRect, size) {
+      let obj = { top: 10 };
+      obj[["left", "right"][+(pos[0] < size.viewSize[0] / 2)]] = 30;
+      return obj;
+    },
+    extraCssText: "width: 170px"
+  },
+  xAxis: {
+    type: "time",
+    axisLabel: {
+      formatter: function (value) {
+        const date = new Date(value);
+        // 自定义时间格式
+        return `${date.getHours()}:${date.getMinutes()}\n${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
+      }
+    },
+    splitLine: {
+      show: false
+    }
+  },
+  yAxis: [
+    {
+      id: "watt",
+      type: "value",
+      position: "left",
+      axisLabel: {
+        formatter: "{value}kw"
+      }
+    }
+  ],
+  dataZoom: [
+    {
+      type: "inside"
+    },
+    {
+      type: "slider",
+      show: true,
+      handleSize: "100%"
+    }
+  ],
+  series: [
+    {
+      name: "DC-PV",
+      type: "line",
+      smooth: true,
+      showSymbol: false,
+      data: props.pf.axisData.dcPvData,
+      emphasis: {
+        focus: "series"
+      },
+      yAxisId: "watt"
+    },
+    {
+      name: "AC-PV",
+      type: "line",
+      smooth: true,
+      showSymbol: false,
+      data: props.pf.axisData.acPvData,
+      emphasis: {
+        focus: "series"
+      },
+      yAxisId: "watt",
+      markArea: {
+        itemStyle: {
+          color: "lightgray"
+        },
+        data: [
+          ...props.pf.axisData.acPvRelay.map<[{ name?: string; xAxis: Date }, { xAxis: Date }]>(item => {
+            return [{ name: item[0].name, xAxis: item[0].xAxis }, { xAxis: item[1].xAxis }];
+          })
+        ]
+        // data: [
+        //   [
+        //     {
+        //       name: "realy open",
+        //       xAxis: new Date()
+        //     },
+        //     {
+        //       xAxis: new Date()
+        //     }
+        //   ]
+        // ]
+      }
+    }
+  ],
+  animationEasing: "elasticOut"
+  // animationDelayUpdate: function (idx) {
+  //   return idx * 5;
+  // }
+};
+
+const refresh = () => {
+  if (chartRef.value) {
+    chartRef.value.draw();
+    console.log("draw");
+  }
+};
+
+defineExpose({
+  refresh
+});
+</script>

+ 98 - 0
src/views/cloudData/cloudLog/siteView/chart/pvPowerFlow.class.ts

@@ -0,0 +1,98 @@
+import { CloudLog } from "@/api/interface/cloudData/cloudLog";
+
+interface AxisValue {
+  value: number[];
+}
+
+interface AxisMarkArea {
+  name?: string;
+  xAxis: Date;
+}
+
+// 需要的数据类型
+export const PowerFlowLogTypes: string[] = ["201"];
+
+export class PowerFlowData {
+  constructor(refresh: () => void) {
+    this.refresh = refresh;
+  }
+
+  // 刷新接口
+  refresh: () => void;
+
+  // 数据
+  axisData: {
+    dcPvData: AxisValue[];
+    acPvData: AxisValue[];
+    acPvRelay: AxisMarkArea[][];
+  } = { dcPvData: [], acPvData: [], acPvRelay: [] };
+
+  // 解析数据
+  parser(type: string, data: CloudLog.ResCloudLogData[]) {
+    if (type === "201") {
+      let acPvRelayStTemp: number = -1;
+      let acPvRelayStOpenTime: Date | undefined = undefined;
+      let acPvRelayStEndTime: Date | undefined = undefined;
+      for (const row of data) {
+        const dataString = row.data;
+
+        if (!dataString.dataArea["mpptAllPower"] || !dataString.dataArea["aggAcPvPower"]) {
+          console.log({ mpptAllPower: dataString.dataArea["mpptAllPower"], aggAcPvPower: dataString.dataArea["aggAcPvPower"] });
+          continue;
+        }
+
+        try {
+          const time = new Date(row.time);
+          acPvRelayStEndTime = time;
+          const dcPvData = Number(dataString.dataArea.mpptAllPower);
+          const acPvData = Number(dataString.dataArea.aggAcPvPower);
+          const acPvRelaySt = Number(dataString.dataArea.main_sw[2]);
+
+          this.axisData.dcPvData.push({ value: [time.getTime(), dcPvData] });
+          this.axisData.acPvData.push({ value: [time.getTime(), acPvData] });
+
+          if (acPvRelaySt !== acPvRelayStTemp) {
+            acPvRelayStTemp = acPvRelaySt;
+            if (acPvRelaySt === 0) {
+              acPvRelayStOpenTime = time;
+            } else if (acPvRelaySt === 1) {
+              if (acPvRelayStOpenTime !== undefined) {
+                this.axisData.acPvRelay.push([
+                  {
+                    name: "relay open",
+                    xAxis: acPvRelayStOpenTime
+                  },
+                  {
+                    xAxis: time
+                  }
+                ]);
+                acPvRelayStOpenTime = undefined;
+              }
+            }
+          }
+        } catch (error) {
+          console.error("[siteView] Invalid JSON string:", error);
+          return;
+        }
+      }
+      // 判断继电器断开区域是否延续到结束
+      if (acPvRelayStOpenTime !== undefined && acPvRelayStEndTime !== undefined) {
+        this.axisData.acPvRelay.push([
+          {
+            name: "relay open",
+            xAxis: acPvRelayStOpenTime
+          },
+          {
+            xAxis: acPvRelayStEndTime
+          }
+        ]);
+      }
+    }
+  }
+
+  // 清空数据
+  clearData() {
+    this.axisData.dcPvData.length = 0;
+    this.axisData.acPvData.length = 0;
+  }
+}

+ 47 - 12
src/views/cloudData/cloudLog/siteView/index.vue

@@ -44,6 +44,9 @@
     <div class="card chart-box" v-if="enablePowerFlow">
       <PowerFlow ref="refPowerFlow" :pf="chartPowerFlow" />
     </div>
+    <div class="card chart-box" v-if="enablePvPowerFlow">
+      <PvPowerFlow ref="refPvPowerFlow" :pf="chartPvPowerFlow" />
+    </div>
     <!-- <div class="card chart-box" v-if="enableAlarmTimeLine">
       <PowerFlow ref="refPowerFlow" :pf="chartPowerFlow" />
     </div> -->
@@ -60,6 +63,8 @@ import { getCloudLogData } from "@/api/modules/cloudLog";
 import { showFullScreenLoading, tryHideFullScreenLoading } from "@/components/Loading/fullScreen";
 import PowerFlow from "./chart/powerFlow.chart.vue";
 import { PowerFlowData, PowerFlowLogTypes } from "./chart/powerFlow.class";
+import PvPowerFlow from "./chart/pvPowerFlow.chart.vue";
+import { PowerFlowData as PvPowerFlowData, PowerFlowLogTypes as PvPowerFlowLogTypes } from "./chart/pvPowerFlow.class";
 
 const route = useRoute();
 const tabStore = useTabsStore();
@@ -105,8 +110,12 @@ interface FromModelType {
 const isNoData = ref(true);
 // 与chartType表单选择一致
 const enablePowerFlow = ref(false);
+const enablePvPowerFlow = ref(false);
 
-const chartTypes = [{ label: "功率流图", value: "power-flow" }];
+const chartTypes: { label: string; value: string }[] = [
+  { label: "功率流图", value: "power-flow" },
+  { label: "PV功率流图", value: "pv-power-flow" }
+];
 
 // 图表
 const refPowerFlow = ref();
@@ -116,6 +125,13 @@ const refreshPowerFlow = () => {
   }
 };
 const chartPowerFlow = new PowerFlowData(refreshPowerFlow);
+const refPvPowerFlow = ref();
+const refreshPvPowerFlow = () => {
+  if (refPvPowerFlow.value) {
+    refPvPowerFlow.value?.refresh();
+  }
+};
+const chartPvPowerFlow = new PvPowerFlowData(refreshPvPowerFlow);
 
 // 表单参数
 const fromModel = ref<FromModelType>({
@@ -164,12 +180,19 @@ const handleSubmit = () => {
     let logData = {};
     let logTypeList: string[] = [];
     // 图表选择 - 判断图表是否显示或更新
-    if (fromModel.value.chartType.includes("power-flow")) {
-      logTypeList.push(...PowerFlowLogTypes);
-      enablePowerFlow.value = true;
+    if (fromModel.value.chartType.length > 0) {
+      if (fromModel.value.chartType.includes("power-flow")) {
+        logTypeList.push(...PowerFlowLogTypes);
+        enablePowerFlow.value = true;
+      }
+      if (fromModel.value.chartType.includes("pv-power-flow")) {
+        logTypeList.push(...PvPowerFlowLogTypes);
+        enablePvPowerFlow.value = true;
+      }
       isNoData.value = false;
     } else {
       enablePowerFlow.value = false;
+      enablePvPowerFlow.value = false;
     }
 
     // 判断选择数据是否改变
@@ -192,14 +215,26 @@ const handleSubmit = () => {
       }
 
       // 将数据插入chart中
-      // 插入PowerFlow
-      chartPowerFlow.clearData();
-      PowerFlowLogTypes.map(item => {
-        const resData: CloudLog.ResCloudLogData[] = logData[item] as CloudLog.ResCloudLogData[];
-        chartPowerFlow.parser(item, resData);
-      });
-      // 刷新图表
-      chartPowerFlow.refresh();
+      if (enablePowerFlow.value) {
+        // 插入PowerFlow
+        chartPowerFlow.clearData();
+        PowerFlowLogTypes.map(item => {
+          const resData: CloudLog.ResCloudLogData[] = logData[item] as CloudLog.ResCloudLogData[];
+          chartPowerFlow.parser(item, resData);
+        });
+        // 刷新图表
+        chartPowerFlow.refresh();
+      }
+      if (enablePvPowerFlow.value) {
+        // 插入PowerFlow
+        chartPvPowerFlow.clearData();
+        PvPowerFlowLogTypes.map(item => {
+          const resData: CloudLog.ResCloudLogData[] = logData[item] as CloudLog.ResCloudLogData[];
+          chartPvPowerFlow.parser(item, resData);
+        });
+        // 刷新图表
+        chartPvPowerFlow.refresh();
+      }
 
       // 记录获取到的数据
       currDataStatus.logTypes.length = 0;