From 3c3576d5792bfabcef84979757ee344712e71cd3 Mon Sep 17 00:00:00 2001
From: he wei <858544502@qq.com>
Date: 星期六, 21 六月 2025 09:19:29 +0800
Subject: [PATCH] UA 整理提交

---
 src/components/echarts/BaseChart.vue     |   30 
 src/components/echarts/line2.vue         |   16 
 src/styles/blue.css                      |    3 
 src/styles/blue.less                     |    4 
 src/components/hrParams.vue              |  239 +
 src/views/statistics/battGood.vue        |  501 ++
 src/api/control.js                       |  101 
 src/views/statistics/battCompare0.vue    |    4 
 src/views/statistics/nodisYear.vue       |  511 ++
 src/components/echarts/water.vue         |  149 
 src/components/echarts/bar4.vue          |  209 
 src/components/echarts/line1.vue         |  111 
 src/components/pwrAlarmParams.vue        |  214 
 src/views/statistics/battDamage.vue      |  501 ++
 src/icons/svg/arrow-right.svg            |    1 
 src/views/alarm/earlyWarningAnalysis.vue |  644 ++
 src/views/statistics/battBad.vue         |  526 ++
 src/views/statistics/battCompare1.vue    |    4 
 src/components/ycTag.vue                 |   47 
 src/views/realtime/tabs/system.vue       |  730 ++
 src/components/echarts/bar3.vue          |  193 
 src/api/alarm.js                         |  100 
 src/components/echarts/pie3d0.vue        |  356 +
 src/views/statistics/battCompare2.vue    |  579 ++
 src/api/statistic.js                     |   80 
 src/components/echarts/bar2.vue          |  190 
 src/router/index.js                      |    1 
 src/router/modules/alarm.js              |   18 
 src/components/echarts/bar1.vue          |   19 
 src/views/realtime/devAlarmParams.vue    |  312 +
 src/components/alarmParams.vue           |  166 
 src/components/echarts/gauge1.vue        |  323 +
 src/views/alarm/battSetting.vue          |  636 ++
 src/views/history/hisTest.vue            |  723 +++
 src/views/statistics/powerGood.vue       |  595 ++
 src/components/echarts/line4.vue         |  180 
 src/components/echarts/pie1.vue          |  153 
 src/views/realtime/tabs/manage.vue       |  222 
 src/hooks/useStationList.js              |   85 
 package-lock.json                        |   35 
 src/views/alarm/pwrAlarm.vue             |   35 
 src/components/echarts/line-scroll.vue   |  312 +
 src/views/datas/device.vue               |    6 
 src/views/realtime/tabs/temp.vue         |  137 
 src/utils/const/const_digit.js           |    4 
 src/utils/eventBus.js                    |   20 
 src/views/alarm/powerSetting.vue         |  642 ++
 src/utils/hexToRgba.js                   |   17 
 src/components/scrollerField0.vue        |  359 +
 src/views/history/index.vue              |   69 
 src/views/statistics/disYear.vue         |  524 ++
 src/api/station.js                       |   33 
 src/components/siteList/index.vue        |    3 
 src/views/statistics/chartView.vue       |   82 
 src/views/realtime/index.vue             |  121 
 src/router/modules/statistics.js         |   42 
 src/views/statistics/battCell.vue        |    4 
 src/api/history.js                       |   37 
 src/components/svgDiagram.vue            |   39 
 src/components/info.vue                  |    5 
 src/views/alarm/battAlarmParams.vue      |   56 
 src/api/realtime.js                      |   33 
 src/components/echarts/bar7.vue          |  193 
 src/utils/getBinaryDigits.js             |   23 
 src/views/realtime/tabs/res.vue          |  137 
 src/views/realtime/tabs/vol.vue          |  137 
 src/components/echarts/bar6.vue          |  256 +
 /dev/null                                |  170 
 package.json                             |    3 
 src/views/realtime/tabs/power.vue        |  208 
 src/components/echarts/bar5.vue          |  238 +
 src/views/datas/addEdit.vue              |   56 
 72 files changed, 13,091 insertions(+), 421 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index c2c8579..9be3195 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,11 +11,14 @@
         "@element-plus/icons-vue": "^2.3.1",
         "axios": "^1.7.2",
         "echarts": "^5.5.0",
+        "echarts-gl": "^2.0.9",
+        "echarts-liquidfill": "^3.1.0",
         "element-plus": "^2.8.1",
         "file-saver": "^2.0.5",
         "js-cookie": "^3.0.5",
         "js-md5": "^0.8.3",
         "jsencrypt": "^3.3.2",
+        "mitt": "^3.0.1",
         "moment": "^2.30.1",
         "nprogress": "^0.2.0",
         "path-browserify": "^1.0.1",
@@ -1925,6 +1928,11 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/claygl": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/claygl/-/claygl-1.3.0.tgz",
+      "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
+    },
     "node_modules/clone": {
       "version": "2.1.2",
       "resolved": "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz",
@@ -2325,6 +2333,27 @@
       "dependencies": {
         "tslib": "2.3.0",
         "zrender": "5.6.1"
+      }
+    },
+    "node_modules/echarts-gl": {
+      "version": "2.0.9",
+      "resolved": "https://registry.npmmirror.com/echarts-gl/-/echarts-gl-2.0.9.tgz",
+      "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
+      "dependencies": {
+        "claygl": "^1.2.1",
+        "zrender": "^5.1.1"
+      },
+      "peerDependencies": {
+        "echarts": "^5.1.2"
+      }
+    },
+    "node_modules/echarts-liquidfill": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmmirror.com/echarts-liquidfill/-/echarts-liquidfill-3.1.0.tgz",
+      "integrity": "sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "echarts": "^5.0.1"
       }
     },
     "node_modules/element-plus": {
@@ -4053,6 +4082,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/mitt": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
+      "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
+      "license": "MIT"
+    },
     "node_modules/mixin-deep": {
       "version": "1.3.2",
       "resolved": "https://registry.npmmirror.com/mixin-deep/-/mixin-deep-1.3.2.tgz",
diff --git a/package.json b/package.json
index d4aaf1f..6874f79 100644
--- a/package.json
+++ b/package.json
@@ -12,11 +12,14 @@
     "@element-plus/icons-vue": "^2.3.1",
     "axios": "^1.7.2",
     "echarts": "^5.5.0",
+    "echarts-gl": "^2.0.9",
+    "echarts-liquidfill": "^3.1.0",
     "element-plus": "^2.8.1",
     "file-saver": "^2.0.5",
     "js-cookie": "^3.0.5",
     "js-md5": "^0.8.3",
     "jsencrypt": "^3.3.2",
+    "mitt": "^3.0.1",
     "moment": "^2.30.1",
     "nprogress": "^0.2.0",
     "path-browserify": "^1.0.1",
diff --git a/src/api/alarm.js b/src/api/alarm.js
index ed78d09..0a90cfa 100644
--- a/src/api/alarm.js
+++ b/src/api/alarm.js
@@ -42,6 +42,18 @@
   });
 }
 
+
+/**
+ * 鑾峰彇鐢垫睜鍛婅鍙傛暟
+ */
+export function getBattAlmParam(data) {
+  return request({
+    url: "almParam/getBattAlmParam",
+    method: "POST",
+    data,
+  });
+}
+
 /**
  * 鐢垫睜鍘嗗彶鍛婅
  */
@@ -51,4 +63,92 @@
     method: "POST",
     data
   });
+}
+
+/**
+ * 璁剧疆鐢垫睜鍛婅鍙傛暟
+ */
+export function setBattAlmParam(data) {
+  return request({
+    url: "almParam/setBattAlmParam",
+    method: "POST",
+    data
+  });
+}
+
+/**
+ * 璁剧疆鐢垫簮鍛婅鍙傛暟
+ */
+export function setPwrAlmParam(data) {
+  return request({
+    url: "almParam/setPwrAlmParam",
+    method: "POST",
+    data
+  });
+}
+
+/**
+ * 鑾峰彇鐢垫簮鍛婅鍙傛暟(鏃犲弬鐢ㄤ簬瀵煎嚭)
+ */
+export function getPwrAllAlmParam() {
+  return request({
+    url: "almParam/getPwrAlmParamToExport",
+    method: "GET"
+  });
+}
+
+/**
+ * 鑾峰彇鐢垫睜鍛婅鍙傛暟(鏃犲弬鐢ㄤ簬瀵煎嚭)
+ */
+export function getBattAlmParamToExport() {
+  return request({
+    url: "almParam/getBattAlmParamToExport",
+    method: "GET"
+  });
+}
+
+/**
+ * 鑾峰彇璁惧鍛婅鍙傛暟
+ */
+export function getAlarmFromDevice(devId) {
+  return request({
+    url: "almparamFromDevice/getAlarmFromDevice",
+    method: "GET",
+    params: {
+      devId
+    }
+  });
+}
+
+/**
+ * 璁剧疆璁惧鍛婅鍙傛暟
+ */
+export function setAlarmFromDevice(data) {
+  return request({
+    url: "almparamFromDevice/setAlarmFromDevice",
+    method: "POST",
+    data
+  });
+}
+
+/**
+ * 棰勮鍒嗘瀽绠$悊 鐢垫睜鍛婅
+ */
+export function getBattAlmAnalyse(data) {
+  return request({
+    url: "almParam/getBattAlmAnalyse",
+    method: "POST",
+    data
+  });
+}
+
+/**
+ * 棰勮鍒嗘瀽绠$悊 鐢垫簮鍛婅
+ */
+export function getPwrAlmParam(data) {
+  return request({
+    url: "almParam/getPwrAlmParam",
+    method: "POST",
+    data
+  });
 }
\ No newline at end of file
diff --git a/src/api/control.js b/src/api/control.js
new file mode 100644
index 0000000..59fc6e3
--- /dev/null
+++ b/src/api/control.js
@@ -0,0 +1,101 @@
+import request from "@/utils/request";
+
+/**
+ * 璇诲彇鏀剧數鍙傛暟
+ * devId battGroupNum  
+ */
+export function getHrParam(devId, battGroupNum) {
+  return request({
+    url: "devSetparam/getParam",
+    method: "GET",
+    params: {
+      devId,
+      battGroupNum
+    }
+  });
+}
+
+/**
+ * 璁剧疆鏀剧數鍙傛暟
+ */
+export function setHrParam(data) {
+  return request({
+    url: "devSetparam/updateParam",
+    method: "POST",
+    data
+  });
+}
+
+/**
+ * 杩滅▼閲嶅惎
+ * devId
+ */
+export function restart(devId, battGroupNum) {
+  return request({
+    url: "devSetparam/restart",
+    method: "GET",
+    params: {
+      devId,
+      battGroupNum
+    }
+  });
+}
+
+/**
+ * 杩滅▼鏍稿
+ */
+export function startDis(devId, battGroupNum) {
+  return request({
+    url: "devSetparam/startDis",
+    method: "GET",
+    params: {
+      devId,
+      battGroupNum
+    }
+  });
+}
+
+/**
+ * 鍐呴樆娴嬭瘯
+ */
+export function startRes(devId, battGroupNum) {
+  return request({
+    url: "devSetparam/startRes",
+    method: "GET",
+    params: {
+      devId,
+      battGroupNum
+    }
+  });
+}
+
+/**
+ * 鍋滄鍐呴樆娴嬭瘯
+ */
+export function stopRes(devId, battGroupNum) {
+  return request({
+    url: "devSetparam/stopRes",
+    method: "GET",
+    params: {
+      devId,
+      battGroupNum
+    }
+  });
+}
+
+
+/**
+ * devSetparam/stopDis
+ * 鍋滄鏍稿
+ */
+export function stopDis(devId, battGroupNum) {
+  return request({
+    url: "devSetparam/stopDis",
+    method: "GET",
+    params: {
+      devId,
+      battGroupNum
+    }
+  });
+}
+
diff --git a/src/api/history.js b/src/api/history.js
new file mode 100644
index 0000000..00ad462
--- /dev/null
+++ b/src/api/history.js
@@ -0,0 +1,37 @@
+import request from '@/utils/request';
+
+/**
+ * 鍘嗗彶娴嬭瘯璁板綍
+ * battgroupId
+ */
+export function getBattTinf(battgroupId) {
+  return request({
+    url: 'real/getBattTinf',
+    method: 'GET',
+    params: { battgroupId }
+  });
+}
+
+/**
+ * 鍘嗗彶瀹炴椂鏌ヨ
+ * battgroupId, startTime, endTime, granularity
+ */
+export function getBattRealDataHis(battgroupId, startTime, endTime, granularity) {
+  return request({
+    url: 'real/getBattRealDataHis',
+    method: 'GET',
+    params: { battgroupId, startTime, endTime, granularity }
+  });
+}
+
+/**
+ * 鍘嗗彶娴嬭瘯璁板綍鍏蜂綋鏌愪竴娆℃斁鐢垫暟鎹鎯�
+ * battgroupId, granularity, recordNum, testRecordCount
+ */
+export function getTinfDataWithTestRecordCount(battgroupId, granularity, recordNum, testRecordCount) {
+  return request({
+    url: 'real/getTinfDataWithTestRecordCount',
+    method: 'GET',
+    params: { battgroupId, granularity, recordNum, testRecordCount }
+  });
+}
\ No newline at end of file
diff --git a/src/api/realtime.js b/src/api/realtime.js
index 7ad2866..a6db238 100644
--- a/src/api/realtime.js
+++ b/src/api/realtime.js
@@ -36,4 +36,37 @@
     method: 'GET',
     params: { powerId, granularity }
   });
+}
+
+/**
+ * 鑾峰彇鐢垫睜缁勬渶杩戜竴瀛e害鐨勫唴闃绘暟鎹�
+ */
+export function getBattQuarterRes(battgroupId) {
+  return request({
+    url: 'hisId/getBattQuarterRes',
+    method: 'GET',
+    params: { battgroupId }
+  });
+}
+
+/**
+ * 鑾峰彇鐢垫睜缁勬渶杩戜竴瀛e害鐨勬俯搴︽暟鎹�
+ */
+export function getBattQuarterTmp(battgroupId) {
+  return request({
+    url: 'hisId/getBattQuarterTmp',
+    method: 'GET',
+    params: { battgroupId }
+  });
+}
+
+/**
+ * 鑾峰彇鐢垫睜缁勬渶杩戜竴瀛e害鐨勭數鍘嬫暟鎹�
+ */
+export function getBattQuarterVol(battgroupId) {
+  return request({
+    url: 'hisId/getBattQuarterVol',
+    method: 'GET',
+    params: { battgroupId }
+  });
 }
\ No newline at end of file
diff --git a/src/api/station.js b/src/api/station.js
index b5f8cfc..361971b 100644
--- a/src/api/station.js
+++ b/src/api/station.js
@@ -334,4 +334,37 @@
     url: 'condition/getCapperformance',
     method: 'GET',
   });
+}
+
+
+/**
+ * 鑾峰彇绔欑偣涓嬬殑鐢垫睜缁�(涓嬫媺)
+ */
+export function getBattByUid(params) {
+  return request({
+    url: 'condition/getBattByUid',
+    method: 'GET',
+    params
+  });
+}
+
+/**
+ * 鑾峰彇鎵�鏈夌殑鐝粍(涓嬫媺)
+ */
+export function getBattGroupBZ() {
+  return request({
+    url: 'condition/getBattGroupBZ',
+    method: 'GET',
+  });
+}
+
+/**
+ * 鑾峰彇鐢垫簮鎬ц兘(涓嬫媺)
+ * condition/getPwrCapperformance
+ */
+export function getPwrCapperformance() {
+  return request({
+    url: 'condition/getPwrCapperformance',
+    method: 'GET',
+  });
 }
\ No newline at end of file
diff --git a/src/api/statistic.js b/src/api/statistic.js
index 24698d4..3ffbb18 100644
--- a/src/api/statistic.js
+++ b/src/api/statistic.js
@@ -100,6 +100,17 @@
 }
 
 /**
+ * 钃勭數姹犵粍瀵规瘮鍒嗘瀽鐣岄潰锛堜笉鍚屽搧鐗屽悓涓�鏃堕棿锛�(1.2.17)
+ */
+export function getBattCompare17(data) {
+  return request({
+    url: "statistic/getBattCompare17Statistic",
+    method: "POST",
+    data
+  });
+}
+
+/**
  * 鍗曡妭鏁版渶缁熻瀵煎嚭
  */
 export function battMonExport(data) {
@@ -110,4 +121,73 @@
     responseType: "blob",
     data
   });
+}
+
+
+// ===================2025-06-12=====================
+
+/**
+ * 鏈勾搴﹀凡鏀剧數鏁伴噺缁熻
+ */
+export function getDischr5Statistic(data) {
+  return request({
+    url: 'statistic/getDischr5Statistic',
+    method: 'POST',
+    data
+  });
+}
+
+/**
+ * 鏈勾搴︽湭鏀剧數鏁伴噺缁熻
+ */
+export function getDischr6Statistic(data) {
+  return request({
+    url: 'statistic/getDischr6Statistic',
+    method: 'POST',
+    data
+  });
+}
+
+
+/**
+ * 鏈勾搴︽斁鐢垫暟閲� 鎬ц兘 鍥捐〃鏁版嵁
+ */
+export function getDischr5Chart() {
+  return request({
+    url: 'statistic/getDischr5Chart',
+    method: 'POST',
+  });
+}
+
+/**
+ * 鐢垫睜缁勬�ц兘缁熻 1.2.8/ 1.2.9/ 1.2.10
+ */
+export function getPerformanceStatistic(data) {
+  return request({
+    url: 'statistic/getPerformanceStatistic',
+    method: 'POST',
+    data
+  });
+}
+
+/**
+ * 鐢垫睜缁勭數姹犳�ц兘缁熻 鍔e寲 鎸夌収鍗曚綋鐢靛帇 鍐呴樆缁熻
+ */
+export function getPerVolAndRes9Statistic(data) {
+  return request({
+    url: 'statistic/getPerVolAndRes9Statistic',
+    method: 'POST',
+    data
+  });
+}
+
+/**
+ * 浼樿壇鐢垫簮鏁伴噺缁熻(1.2.7)
+ */
+export function getPwr7Statistic(data) {
+  return request({
+    url: 'statistic/getPwr7Statistic',
+    method: 'POST',
+    data
+  });
 }
\ No newline at end of file
diff --git a/src/components/alarmParams.vue b/src/components/alarmParams.vue
new file mode 100644
index 0000000..787bcf2
--- /dev/null
+++ b/src/components/alarmParams.vue
@@ -0,0 +1,166 @@
+<script setup name="alarmParams">
+import { ref, reactive, computed, watch, onMounted } from 'vue';
+
+import useElement from "@/hooks/useElement.js";
+	const { $loading, $message, $confirm } = useElement();
+
+import {
+  setBattAlmParam,
+} from '@/api/alarm.js';
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
+  },
+  info: {
+    type: Object,
+    default: () => ({})
+  }
+});
+
+const emit = defineEmits(['update:visible', 'change']);
+
+const initFlag = ref(false);
+
+const layout = {
+  gutter: 16,
+  span: 8,
+}
+const option = {
+  // almId: '鍛婅ID',
+  // almName: '鐢垫睜鍛婅鍚嶇О',
+  almHighCoeUpper: '涓婁笂闄愬憡璀﹂槇鍊�',
+  almHighLevelUpper: '涓婁笂闄愬憡璀︾瓑绾�',
+  almHighCoeUpperEn: '涓婁笂闄愬埗鍛婅浣胯兘',
+  almHighCoe: '涓婇檺鍛婅闃堝��',
+  almHighLevel: '涓婇檺鍛婅绛夌骇',
+  almHighEn: '涓婇檺鍛婅绛夌骇浣胯兘',
+  almLowCoe: '涓嬮檺鍛婅闃堝��',
+  almLowLevel: '涓嬮檺鍛婅绛夌骇',
+  almLowEn: '涓嬮檺鍛婅浣胯兘',
+  almLowCoeLower: '涓嬩笅闄愬憡璀﹂槇鍊�',
+  almLowLevelLower: '涓嬩笅闄愬憡璀︾瓑绾�',
+  almLowCoeLowerEn: '涓嬩笅闄愬憡璀︿娇鑳�',
+  almDelayTime: '鍛婅寤舵椂鏃堕暱',
+};
+const form1 = reactive({});
+
+const almId = ref('');
+
+Object.keys(option).forEach(key => {
+  form1[key] = '';
+});
+
+
+const alarmLevels = [
+  {
+    label: '涓�绾у憡璀�',
+    value: 1,
+  },
+  {
+    label: '浜岀骇鍛婅',
+    value: 2,
+  },
+  {
+    label: '涓夌骇鍛婅',
+    value: 3,
+  },
+  {
+    label: '鍥涚骇鍛婅',
+    value: 4,
+  },
+];
+
+async function submit() {
+  // console.log(obj, '=============');
+  let loading = $loading();
+  let res = await setBattAlmParam([form1]);
+  let { code, data } = res;
+  if (code && data) {
+    $message.success('鎿嶄綔鎴愬姛');
+    emit('update:visible', false);
+    emit('change');
+  } else {
+    $message.error('鎿嶄綔澶辫触');
+  }
+  loading.close();
+}
+
+function close() {
+  emit('update:visible', false);
+}
+
+onMounted(() => {
+  Object.keys(option).forEach(key => {
+    form1[key] = props.info[key];
+  });
+  form1.almId = props.info.almId;
+  form1.battgroupId = props.info.battgroupId;
+  initFlag.value = true;
+});
+</script>
+
+<template>
+  <div class="alarm-form">
+    <!-- 琛ㄥ崟鍖哄煙 -->
+    <div class="content">
+      <el-form ref="formRef" :model="form1" label-width="10em" :key="initFlag">
+        <el-row :gutter="layout.gutter">
+          <el-col
+            :span="layout.span"
+            v-for="(item, idx) in Object.keys(option)"
+            :key="'list1_' + idx"
+          >
+            <el-form-item :label="option[item]" :prop="item">
+              <el-checkbox
+                :checked="form1[item] == 1"
+                @change="(v) => form1[item] = v ? 1 : 0"
+                v-if="/En$/.test(item)"
+              ></el-checkbox>
+              <el-select
+                v-else-if="/Level/.test(item)"
+                v-model="form1[item]"
+                placeholder="璇烽�夋嫨"
+              >
+                <el-option
+                  v-for="(item, key) in alarmLevels"
+                  :key="'list3_' + idx + '_' + key"
+                  :label="item.label"
+                  :value="item.value"
+                ></el-option>
+              </el-select>
+              <el-input v-else v-model="form1[item]"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </div>
+    <div class="footer">
+      <el-button  @click="close">鍏抽棴</el-button>
+      <el-button type="primary" @click="submit">鎻愪氦</el-button>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.search-container {
+  margin-bottom: 10px;
+  padding-left: 20px;
+  display: flex;
+  align-items: center;
+  .label {
+    margin-right: 10px;
+    font-size: 20px;
+    font-family: 'YouSheBiaoTiHei';
+  }
+  .el-select {
+    width: 200px;
+  }
+}
+.footer {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 8px;
+}
+</style>
diff --git a/src/components/echarts/BaseChart.vue b/src/components/echarts/BaseChart.vue
index f0a5e3e..07a9919 100644
--- a/src/components/echarts/BaseChart.vue
+++ b/src/components/echarts/BaseChart.vue
@@ -2,14 +2,24 @@
 import * as echarts from "echarts";
 import "./transparent";
 import { onMounted, onBeforeUnmount, ref, nextTick } from "vue";
+import eventBus from "@/utils/eventBus";
 
 let chart_instance = null;
 let exportChart_instance = null;
 
 const chart = ref(null);
 const exportChart = ref(null);
-const fullScreenFlag = ref(false);
-const emit = defineEmits(["click"]);
+const emit = defineEmits(["click", "update:fullFlag"]);
+
+const props = defineProps({
+  fullFlag: {
+    type: Boolean,
+    default: false,
+  }
+});
+
+const fullScreenFlag = ref(props.fullFlag);
+
 
 
   onMounted(() => {
@@ -24,10 +34,20 @@
     });
     window.addEventListener("resize", resize);
 
+    eventBus.on("toggleSiteList", () => {
+      console.log('toggleSiteList', '=============');
+      setTimeout(() => {
+        resize();
+        // 鍥犱负杩囨浮璁剧疆浜�0.5s,鎵�浠ラ渶瑕佺瓑寰�0.5s鍚庡啀resize
+      }, 500);
+      
+    });
+
   });
 
   onBeforeUnmount(() => {
     window.removeEventListener("resize", resize);
+    eventBus.off("toggleSiteList");
     dispose();
   });
 
@@ -43,6 +63,7 @@
 
   function fullScreen() {
     fullScreenFlag.value = !fullScreenFlag.value;
+    emit("update:fullFlag", fullScreenFlag.value);
     nextTick(() => {
       resize();
     });
@@ -55,12 +76,17 @@
       option.xAxis[0].axisLine.lineStyle = {
         color: "#000",
       };
+      option.xAxis[0].axisLabel.textStyle = option.xAxis[0].axisLabel.textStyle || {};
       option.xAxis[0].axisLabel.textStyle.color = "#000";
 
       option.yAxis[0].axisLine.lineStyle = {
         color: "#000",
       };
+      option.yAxis[0].axisLabel.textStyle = option.yAxis[0].axisLabel.textStyle || {};
       option.yAxis[0].axisLabel.textStyle.color = "#000";
+      
+      option.animation = false;
+
       exportChart_instance.setOption(option);
       base64 = exportChart_instance.getDataURL({
         pixelRatio: 1,
diff --git a/src/components/echarts/bar1.vue b/src/components/echarts/bar1.vue
index 960ab16..9307ade 100644
--- a/src/components/echarts/bar1.vue
+++ b/src/components/echarts/bar1.vue
@@ -2,6 +2,7 @@
 	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
 	import * as echarts from 'echarts';
   import baseChart from "./BaseChart.vue";
+  import { toFixed } from '@/utils/toFixed.js';
 
   const chart = ref(null);
   const props = defineProps({
@@ -16,10 +17,12 @@
     unit: {
       type: String,
       default: ''
-    }
+    },
+    barW: {
+      type: [Number, String],
+      default: 60,
+    },
   });
-
-  const barWidth = 60;
 
   function createLinearColor(color) {
     return new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
@@ -39,13 +42,14 @@
 
   function getMax(data) {
     let max = Math.max.apply(null, data) * 1.2;
-    return max || 1;
+    return toFixed(max, 1) || 1;
   }
 
 
  function getOptions(xLabels, datas) {
     xLabels = xLabels || [];
     datas = datas || [];
+    let barWidth = props.barW;
 		const option = {
 			// title: {
 			// 	text: props.title,
@@ -67,7 +71,7 @@
 			grid: {
 				left: '3%',
 				right: '4%',
-				bottom: '3%',
+				bottom: '8%',
         top: 30,
 				containLabel: true
 			},
@@ -188,8 +192,13 @@
     return chart_instance;
   }
 
+  function getDataURL() {
+    return chart.value.getDataURL();
+  }
+
   defineExpose({
     getChart,
+    getDataURL,
     updateChart
   });
 
diff --git a/src/components/echarts/bar2.vue b/src/components/echarts/bar2.vue
new file mode 100644
index 0000000..09c6bff
--- /dev/null
+++ b/src/components/echarts/bar2.vue
@@ -0,0 +1,190 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+  import baseChart from "./BaseChart.vue";
+  import { toFixed } from '@/utils/toFixed.js';
+
+  const chart = ref(null);
+  const props = defineProps({
+    // type: {
+    //   type: String,
+    //   default: '鐢靛帇'
+    // },
+    title: {
+      type: String,
+      default: '鐢靛帇'
+    },
+    unit: {
+      type: String,
+      default: 'V'
+    }
+  });
+
+  const barWidth = 60;
+
+
+  const colors = ['#196EB1', '#12D2AD', '#C75C86'];
+
+  function getMax(data) {
+    let max = Math.max.apply(null, data) * 1.2;
+    return toFixed(max, 1) || 1;
+  }
+
+
+ function getOptions(xLabels, datas) {
+    xLabels = xLabels || [];
+    datas = datas || [];
+		const option = {
+			title: {
+				text: props.title,
+				textStyle: {
+					fontWeight: 'normal',
+					fontSize: 14,
+					color: '#fff'
+				},
+				left: 'center',
+        top: 6
+			},
+			tooltip: {
+				trigger: 'axis',
+				axisPointer: {
+					lineStyle: {
+						color: '#fff'
+					}
+				}
+			},
+			grid: {
+				left: '3%',
+				right: '4%',
+				bottom: '8%',
+        top: 30,
+				containLabel: true
+			},
+			xAxis: [{
+				type: 'category',
+				// boundaryGap: false,
+				axisLine: {
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+        // offset: 16,
+				data: xLabels
+			}],
+			yAxis: [{
+				type: 'value',
+				name: props.unit,
+				axisTick: {
+					show: true,
+				},
+				axisLine: {
+          show: true,
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+				axisLabel: {
+					margin: 10,
+					fontSize: 12,
+          color: '#fff'
+				},
+				splitLine: {
+					lineStyle: {
+						color: 'rgba(255,255,255,0.2)'
+					}
+				},
+        max: getMax(datas),
+			}],
+			series: [
+        {
+				type: 'bar',
+        barGap: "-100%",
+        barWidth,
+        tooltip: {
+          show: false
+        },
+        itemStyle: {
+          color: 'rgba(255,255,255,0.1)',
+        },
+				data: datas.map(v => getMax(datas)),
+        z: 0
+			},
+       {
+				type: 'pictorialBar',
+				smooth: true,
+        barWidth,
+        label: {
+          show: true,
+          position: "top",
+          offset: [0, -4],
+          fontSize: 20,
+          fontWeight: "bolder",
+          color: "#ebf006",
+        },
+        itemStyle: {
+          color: function (params) {
+              return colors[params.dataIndex % 3];
+          },
+        },
+        symbolSize: ['100%',  '100%'],
+        symbol: 'path://M0,10 L10,10 C9,10 7,2 5,0 C3,2 1,10 0,10 z',
+				data: datas
+			}]
+		};
+
+		return option;
+	}
+
+  let myChart = null;
+  let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+      chart.value.setOption(option);
+      chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(xLabels, datas) {
+    if (chart.value) {
+			let option = getOptions(xLabels, datas);
+      chart.value.setOption(option);
+		}
+	}
+
+  function getChart() {
+    return chart_instance;
+  }
+
+  function getDataURL() {
+    return chart.value.getDataURL();
+  }
+
+  defineExpose({
+    getChart,
+    getDataURL,
+    updateChart
+  });
+
+	onMounted(() => {
+    // console.log('line mounted', '=============');
+    
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/bar3.vue b/src/components/echarts/bar3.vue
new file mode 100644
index 0000000..4299d0b
--- /dev/null
+++ b/src/components/echarts/bar3.vue
@@ -0,0 +1,193 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+  import baseChart from "./BaseChart.vue";
+  import { toFixed } from '@/utils/toFixed.js';
+
+  const chart = ref(null);
+  const props = defineProps({
+    // type: {
+    //   type: String,
+    //   default: '鐢靛帇'
+    // },
+    title: {
+      type: String,
+      default: '鐢垫祦'
+    },
+    unit: {
+      type: String,
+      default: 'V'
+    },
+    barW: {
+      type: [Number, String],
+      default: 60,
+    },
+
+  });
+
+
+
+  const colors = ['#196EB1', '#12D2AD', '#C75C86'];
+
+  function getMax(data) {
+    let max = Math.max.apply(null, data) * 1.2;
+    return toFixed(max, 1) || 1;
+  }
+
+
+ function getOptions(xLabels, datas) {
+    xLabels = xLabels || [];
+    datas = datas || [];
+    let barWidth = props.barW;
+		const option = {
+			title: {
+				text: props.title,
+				textStyle: {
+					fontWeight: 'normal',
+					fontSize: 14,
+					color: '#fff'
+				},
+				left: 'center',
+        top: 6
+			},
+			tooltip: {
+				trigger: 'axis',
+				axisPointer: {
+					lineStyle: {
+						color: '#fff'
+					}
+				}
+			},
+			grid: {
+				left: '3%',
+				right: '4%',
+				bottom: '8%',
+        top: 30,
+				containLabel: true
+			},
+			xAxis: [{
+				type: 'category',
+				// boundaryGap: false,
+				axisLine: {
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+        // offset: 16,
+				data: xLabels
+			}],
+			yAxis: [{
+				type: 'value',
+				name: props.unit,
+				axisTick: {
+					show: true,
+				},
+				axisLine: {
+          show: true,
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+				axisLabel: {
+					margin: 10,
+					fontSize: 12,
+          color: '#fff'
+				},
+				splitLine: {
+					lineStyle: {
+						color: 'rgba(255,255,255,0.2)'
+					}
+				},
+        max: getMax(datas),
+			}],
+			series: [
+        {
+				type: 'bar',
+        barGap: "-100%",
+        barWidth,
+        tooltip: {
+          show: false
+        },
+        itemStyle: {
+          color: 'rgba(255,255,255,0.1)',
+        },
+				data: datas.map(v => getMax(datas)),
+        z: 0
+			},
+       {
+				type: 'bar',
+				smooth: true,
+        barWidth,
+        label: {
+          show: true,
+          position: "top",
+          offset: [0, -4],
+          fontSize: 20,
+          fontWeight: "bolder",
+          color: "#ebf006",
+        },
+        itemStyle: {
+          color: function (params) {
+              return colors[params.dataIndex % 3];
+          },
+        },
+				data: datas
+			}]
+		};
+
+		return option;
+	}
+
+  let myChart = null;
+  let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+      chart.value.setOption(option);
+      chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(xLabels, datas) {
+    if (chart.value) {
+			let option = getOptions(xLabels, datas);
+      chart.value.setOption(option);
+		}
+	}
+
+  function getChart() {
+    return chart_instance;
+  }
+
+  function getDataURL() {
+    return chart.value.getDataURL();
+  }
+
+  defineExpose({
+    getChart,
+    getDataURL,
+    updateChart
+  });
+
+	onMounted(() => {
+    // console.log('line mounted', '=============');
+    
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/bar4.vue b/src/components/echarts/bar4.vue
new file mode 100644
index 0000000..bf88bf4
--- /dev/null
+++ b/src/components/echarts/bar4.vue
@@ -0,0 +1,209 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+  import baseChart from "./BaseChart.vue";
+  import { toFixed } from '@/utils/toFixed.js';
+
+  const chart = ref(null);
+  const props = defineProps({
+    title: {
+      type: String,
+      default: ''
+    },
+    unit: {
+      type: String,
+      default: ''
+    },
+    // barW: {
+    //   type: [Number, String],
+    //   default: 60,
+    // },
+  });
+
+  function createLinearColor(color) {
+    return new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
+        offset: 0,
+        color,
+      }, {
+        offset: 0.5,
+        color: 'transparent'
+      }, {
+        offset: 1,
+        color
+      }
+    ], false)
+  }
+
+  const colors = ['#12E876', '#E87615', '#0AE3E5'];
+  const minColor = '#f00';
+  const maxColor = '#0f0';
+
+  function getMax(data) {
+    let max = Math.max.apply(null, data) * 1.2;
+    return toFixed(max, 1) || 1;
+  }
+
+
+ function getOptions(xLabels, datas) {
+    xLabels = xLabels || [];
+    datas = datas || [];
+    // let barWidth = props.barW;
+
+    let max = Math.max.apply(null, datas);
+    let min = Math.min.apply(null, datas);
+
+		const option = {
+			// title: {
+			// 	text: props.title,
+			// 	textStyle: {
+			// 		fontWeight: 'normal',
+			// 		fontSize: 14,
+			// 		color: '#fff'
+			// 	},
+			// 	left: '6%'
+			// },
+			tooltip: {
+				trigger: 'axis',
+				axisPointer: {
+					lineStyle: {
+						color: '#fff'
+					}
+				}
+			},
+			grid: {
+				left: '3%',
+				right: '4%',
+				bottom: '8%',
+        top: 30,
+				containLabel: true
+			},
+			xAxis: [{
+				type: 'category',
+				// boundaryGap: false,
+				axisLine: {
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+        offset: 16,
+				data: xLabels
+			}],
+			yAxis: [{
+				type: 'value',
+				name: props.unit,
+				axisTick: {
+					show: true,
+				},
+				axisLine: {
+          show: true,
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+				axisLabel: {
+					margin: 10,
+					fontSize: 12,
+          color: '#fff'
+				},
+				splitLine: {
+					lineStyle: {
+						color: 'rgba(255,255,255,0.2)'
+					}
+				},
+        max: getMax(datas),
+			}],
+			series: [
+        {
+				type: 'bar',
+        barGap: "-100%",
+        // barWidth,
+        tooltip: {
+          show: false
+        },
+        itemStyle: {
+          color: 'rgba(255,255,255,0.1)',
+        },
+				data: datas.map(v => getMax(datas)),
+        z: 0
+			},
+       {
+				type: 'bar',
+				smooth: true,
+        // barWidth,
+        label: {
+          show: true,
+          position: "top",
+          offset: [0, -18],
+          fontSize: 20,
+          fontWeight: "bolder",
+          color: "#ebf006",
+        },
+        itemStyle: {
+          color: function (params) {
+              return params.value == max
+                  ? maxColor
+                  : params.value == min
+                  ? minColor
+                  : colors[0];
+          },
+        },
+				data: datas
+			}]
+		};
+
+		return option;
+	}
+
+  let myChart = null;
+  let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+      chart.value.setOption(option);
+      chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(xLabels, datas) {
+    if (chart.value) {
+			let option = getOptions(xLabels, datas);
+      chart.value.setOption(option);
+		}
+	}
+
+  function getChart() {
+    return chart_instance;
+  }
+
+  function getDataURL() {
+    return chart.value.getDataURL();
+  }
+
+  defineExpose({
+    getChart,
+    getDataURL,
+    updateChart
+  });
+
+	onMounted(() => {
+    // console.log('line mounted', '=============');
+    
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/bar5.vue b/src/components/echarts/bar5.vue
new file mode 100644
index 0000000..3beb0e2
--- /dev/null
+++ b/src/components/echarts/bar5.vue
@@ -0,0 +1,238 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+  import baseChart from "./BaseChart.vue";
+  import { toFixed } from '@/utils/toFixed.js';
+  import hexToRgba from '@/utils/hexToRgba.js';
+
+  const chart = ref(null);
+  const props = defineProps({
+    title: {
+      type: String,
+      default: ''
+    },
+    unit: {
+      type: String,
+      default: ''
+    },
+    // barW: {
+    //   type: [Number, String],
+    //   default: 60,
+    // },
+  });
+
+
+
+  function createLinearColor(color) {
+    return new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+        offset: 0,
+        color,
+      }, {
+        offset: 0.6,
+        color: hexToRgba(color, 0.2)
+      }, {
+        offset: 1,
+        color: 'transparent'
+      }
+    ], false)
+  }
+
+  const color = '#13ACBE';
+  const topColor = '#07FBFF';
+  const minColor = '#f00';
+  const maxColor = '#0f0';
+
+  function getMax(data) {
+    let max = Math.max.apply(null, data) * 1.2;
+    return toFixed(max, 1) || 1;
+  }
+
+
+ function getOptions(xLabels, datas) {
+    xLabels = xLabels || [];
+    datas = datas || [];
+    // let barWidth = props.barW;
+
+    let max = Math.max.apply(null, datas);
+    let min = Math.min.apply(null, datas);
+
+    let markPoint = datas.map((item, index) => {
+      return {
+        coord: [index, item],
+        symbolSize: () => {
+            
+            const seriesModel = chart.value.getChart().getModel().getSeries()[0];
+            // 鑾峰彇鏌卞瓙鐨勫搴�
+            let w = seriesModel.getData().getLayout('size');
+            console.log('w', w, '=============');
+            return [w * 1.2, 10];
+          
+          
+        },
+        symbolOffset: [0, -5],
+        symbol: 'path://M0,10 L10,10 L10,0 L0,0 z',
+        itemStyle: {
+          color: topColor,
+        }
+      };
+    });
+
+		const option = {
+			// title: {
+			// 	text: props.title,
+			// 	textStyle: {
+			// 		fontWeight: 'normal',
+			// 		fontSize: 14,
+			// 		color: '#fff'
+			// 	},
+			// 	left: '6%'
+			// },
+			tooltip: {
+				trigger: 'axis',
+				axisPointer: {
+					lineStyle: {
+						color: '#fff'
+					}
+				}
+			},
+			grid: {
+				left: '3%',
+				right: '4%',
+				bottom: '8%',
+        top: 30,
+				containLabel: true
+			},
+			xAxis: [{
+				type: 'category',
+				// boundaryGap: false,
+				axisLine: {
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+        offset: 16,
+				data: xLabels
+			}],
+			yAxis: [{
+				type: 'value',
+				name: props.unit,
+				axisTick: {
+					show: true,
+				},
+				axisLine: {
+          show: true,
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+				axisLabel: {
+					margin: 10,
+					fontSize: 12,
+          color: '#fff'
+				},
+				splitLine: {
+					lineStyle: {
+						color: 'rgba(255,255,255,0.2)'
+					}
+				},
+        max: getMax(datas),
+			}],
+			series: [
+        {
+				type: 'bar',
+        barGap: "-100%",
+        // barWidth,
+        tooltip: {
+          show: false
+        },
+        itemStyle: {
+          color: 'rgba(255,255,255,0.1)',
+        },
+				data: datas.map(v => getMax(datas)),
+        z: 0
+			},
+       {
+				type: 'bar',
+				smooth: true,
+        // barWidth,
+        // label: {
+        //   show: true,
+        //   position: "top",
+        //   offset: [0, -18],
+        //   fontSize: 20,
+        //   fontWeight: "bolder",
+        //   color: "#ebf006",
+        // },
+        itemStyle: {
+          color: function (params) {
+              return params.value == max
+                  ? createLinearColor(maxColor)
+                  : params.value == min
+                  ? createLinearColor(minColor)
+                  : createLinearColor(color);
+          },
+        },
+				data: datas,
+        markPoint: {
+          data: markPoint
+        },
+        z: 1
+			}]
+		};
+
+		return option;
+	}
+
+  let myChart = null;
+  let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+      chart.value.setOption(option);
+      chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(xLabels, datas) {
+    if (chart.value) {
+			let option = getOptions(xLabels, datas);
+      chart.value.setOption(option);
+		}
+	}
+
+  function getChart() {
+    return chart_instance;
+  }
+
+  function getDataURL() {
+    return chart.value.getDataURL();
+  }
+
+  defineExpose({
+    getChart,
+    getDataURL,
+    updateChart
+  });
+
+	onMounted(() => {
+    // console.log('line mounted', '=============');
+    
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/bar6.vue b/src/components/echarts/bar6.vue
new file mode 100644
index 0000000..a3ac28c
--- /dev/null
+++ b/src/components/echarts/bar6.vue
@@ -0,0 +1,256 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+	import baseChart from "./BaseChart.vue";
+	import { toFixed } from '@/utils/toFixed.js';
+	import hexToRgba from '@/utils/hexToRgba.js';
+
+	const chart = ref(null);
+	const props = defineProps({
+		title: {
+			type: String,
+			default: ''
+		},
+		unit: {
+			type: String,
+			default: ''
+		},
+		// barW: {
+		//   type: [Number, String],
+		//   default: 60,
+		// },
+	});
+
+
+
+	function createLinearColor(color) {
+		return new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+			offset: 0,
+			color,
+		}, {
+			offset: 0.6,
+			color: hexToRgba(color, 0.2)
+		}, {
+			offset: 1,
+			color: 'transparent'
+		}
+		], false)
+	}
+
+	const color = ['#0a58f2', '#ee822f'];
+  const types = ['宸叉斁鐢�', '鏈斁鐢�'];
+
+	function getMax(data) {
+		let max = Math.max.apply(null, data.flat()) * 1.2;
+		return toFixed(max, 1) || 1;
+	}
+
+
+	function getOptions(xLabels, datas) {
+		xLabels = xLabels || [];
+		datas = datas || [[], []];
+		// let barWidth = props.barW;
+    // 淇濊瘉缂╂斁鍒版渶澶氭樉绀�4鏁版嵁 濡傛灉xLabels.length > 4
+
+    let end = xLabels.length > 4 ? toFixed(4 * 100 / xLabels.length, 1)  : 100;
+		let dataZoom = [
+			{
+				show: xLabels.length > 4,
+        type: "slider",
+				height: 12,
+				xAxisIndex: 'all',
+				bottom: "8%",
+				start: 0,
+				end,
+				handleIcon:
+					"path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z",
+				handleSize: "110%",
+				handleStyle: {
+					color: "#d3dee5",
+				},
+				textStyle: {
+					color: "#fff",
+				},
+				borderColor: "#90979c",
+        zoomLock: true,
+        brushSelect: false,
+			},
+		];
+		const option = {
+			// title: {
+			// 	text: props.title,
+			// 	textStyle: {
+			// 		fontWeight: 'normal',
+			// 		fontSize: 14,
+			// 		color: '#fff'
+			// 	},
+			// 	left: '6%'
+			// },
+      dataZoom,
+			tooltip: {
+				trigger: 'axis',
+				axisPointer: {
+					lineStyle: {
+						color: '#fff'
+					}
+				}
+			},
+      legend: {
+        data: types,
+        textStyle: {
+          color: '#fff'
+        }
+      },
+			grid: {
+				left: '3%',
+				right: '4%',
+				bottom: '14%',
+				top: 30,
+				containLabel: true
+			},
+			xAxis: [{
+				type: 'category',
+				// boundaryGap: false,
+				axisLine: {
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+				offset: 6,
+				data: xLabels
+			}, {
+				type: 'category',
+				// boundaryGap: false,
+				axisLine: {
+          show: false,
+				},
+        axisLabel: {
+          show: false
+        },
+        axisTick: {
+          show: false
+        },
+        splitLine: {
+          show: false
+        },
+				data: xLabels
+			}],
+			yAxis: [{
+				type: 'value',
+				name: props.unit,
+				axisTick: {
+					show: true,
+				},
+				axisLine: {
+					show: true,
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+				axisLabel: {
+					margin: 10,
+					fontSize: 12,
+					color: '#fff'
+				},
+				splitLine: {
+					lineStyle: {
+						color: 'rgba(255,255,255,0.2)'
+					}
+				},
+				max: getMax(datas),
+			}],
+			series: [
+				{
+					type: 'bar',
+					name: types[0],
+					smooth: true,
+					barWidth: '35%',
+					itemStyle: {
+						color: createLinearColor(color[0])
+					},
+					data: datas[0],
+					z: 1
+				}, {
+					type: 'bar',
+					name: types[1],
+					smooth: true,
+					barWidth: '35%',
+					itemStyle: {
+						color: createLinearColor(color[1])
+					},
+					data: datas[1],
+					z: 1
+				},
+				{
+					type: 'bar',
+					// barGap: "-150%",
+					barWidth: '88%',
+					tooltip: {
+						show: false
+					},
+          xAxisIndex: 1,
+					itemStyle: {
+						color: 'rgba(255,255,255,0.1)',
+					},
+					data: datas.map(v => getMax(datas)),
+					z: 0
+				},
+			]
+		};
+
+		return option;
+	}
+
+	let myChart = null;
+	let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+			chart.value.setOption(option);
+			chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(xLabels, datas) {
+		if (chart.value) {
+			let option = getOptions(xLabels, datas);
+			chart.value.setOption(option);
+		}
+	}
+
+	function getChart() {
+		return chart_instance;
+	}
+
+	function getDataURL() {
+		return chart.value.getDataURL();
+	}
+
+	defineExpose({
+		getChart,
+		getDataURL,
+		updateChart
+	});
+
+	onMounted(() => {
+		// console.log('line mounted', '=============');
+
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/bar7.vue b/src/components/echarts/bar7.vue
new file mode 100644
index 0000000..1861162
--- /dev/null
+++ b/src/components/echarts/bar7.vue
@@ -0,0 +1,193 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+  import baseChart from "./BaseChart.vue";
+  import { toFixed } from '@/utils/toFixed.js';
+
+  const chart = ref(null);
+  const props = defineProps({
+    title: {
+      type: String,
+      default: ''
+    },
+    unit: {
+      type: String,
+      default: ''
+    },
+  });
+
+  function createLinearColor(color) {
+    return new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
+        offset: 0,
+        color,
+      }, {
+        offset: 0.5,
+        color: 'transparent'
+      }, {
+        offset: 1,
+        color
+      }
+    ], false)
+  }
+
+  // const colors = ['#12E876', '#E87615', '#0AE3E5'];
+  const color = '#0AE3E5';
+
+  function getMax(data) {
+    let max = Math.max.apply(null, data) * 1.2;
+    return toFixed(max, 1) || 1;
+  }
+
+
+ function getOptions(xLabels, datas, datas_bg) {
+    xLabels = xLabels || [];
+    datas = datas || [];
+    datas_bg = datas_bg || [];
+		const option = {
+			// title: {
+			// 	text: props.title,
+			// 	textStyle: {
+			// 		fontWeight: 'normal',
+			// 		fontSize: 14,
+			// 		color: '#fff'
+			// 	},
+			// 	left: '6%'
+			// },
+			tooltip: {
+				trigger: 'axis',
+				axisPointer: {
+					lineStyle: {
+						color: '#fff'
+					}
+				}
+			},
+			grid: {
+				left: '3%',
+				right: '4%',
+				bottom: '8%',
+        top: 30,
+				containLabel: true
+			},
+			xAxis: [{
+				type: 'category',
+				// boundaryGap: false,
+				axisLine: {
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+        offset: 16,
+				data: xLabels
+			}],
+			yAxis: [{
+				type: 'value',
+				name: props.unit,
+				axisTick: {
+					show: true,
+				},
+				axisLine: {
+          show: true,
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+				axisLabel: {
+					margin: 10,
+					fontSize: 12,
+          color: '#fff'
+				},
+				splitLine: {
+					lineStyle: {
+						color: 'rgba(255,255,255,0.2)'
+					}
+				},
+        max: getMax(datas),
+			}],
+			series: [
+        {
+				type: 'bar',
+        barGap: "-100%",
+        tooltip: {
+          show: false
+        },
+        itemStyle: {
+          color: 'rgba(255,255,255,0.2)',
+        },
+				data: datas_bg,
+        z: 0
+			},
+       {
+				type: 'bar',
+				smooth: true,
+        name: datas.name,
+        // label: {
+        //   show: true,
+        //   position: "top",
+        //   offset: [0, -18],
+        //   fontSize: 20,
+        //   fontWeight: "bolder",
+        //   color: "#ebf006",
+        // },
+        itemStyle: {
+          color: createLinearColor(color),
+        },
+				data: datas.data
+			}]
+		};
+
+		return option;
+	}
+
+  let myChart = null;
+  let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+      chart.value.setOption(option);
+      chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(xLabels, datas, datas_bg) {
+    if (chart.value) {
+			let option = getOptions(xLabels, datas, datas_bg);
+      chart.value.setOption(option);
+		}
+	}
+
+  function getChart() {
+    return chart_instance;
+  }
+
+  function getDataURL() {
+    return chart.value.getDataURL();
+  }
+
+  defineExpose({
+    getChart,
+    getDataURL,
+    updateChart
+  });
+
+	onMounted(() => {
+    // console.log('line mounted', '=============');
+    
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/gauge1.vue b/src/components/echarts/gauge1.vue
new file mode 100644
index 0000000..d67a20f
--- /dev/null
+++ b/src/components/echarts/gauge1.vue
@@ -0,0 +1,323 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+	import baseChart from "./BaseChart.vue";
+	import { toFixed } from '@/utils/toFixed.js';
+
+  let colorLeft = '#00FCF7';
+  let colorRight = '#5098ed';
+  let colorLeftAlpha = ['#00FCF788', '#00FCF70c'];
+  let colorRightAlpha = ['#5098ed88', '#5098ed08'];
+
+	const chart = ref(null);
+	const props = defineProps({
+		type: {
+			type: String,
+			default: '鐢垫祦'
+		},
+		title: {
+			type: String,
+			default: '鐩存祦杈撳嚭鐢靛帇'
+		},
+    max: {
+      type: [Number, String],
+      default: 300,
+    },
+		unit: {
+			type: String,
+			default: 'V'
+		}
+	});
+
+	const barWidth = 60;
+
+	function createLinearColor(color) {
+		return new echarts.graphic.LinearGradient(0, 0, 1, 0, [{
+			offset: 0,
+			color,
+		}, {
+			offset: 0.5,
+			color: 'transparent'
+		}, {
+			offset: 1,
+			color
+		}
+		], false)
+	}
+
+	const colors = ['#12E876', '#E87615', '#0AE3E5'];
+
+
+	function getOptions(datas) {
+		datas = datas || 0;
+    let data = {
+      value: datas,
+      percent: toFixed(datas / props.max, 2)
+    };
+		const option = {
+			// backgroundColor: '#040d2e',
+			series: [
+				// 澶栦晶鐏拌壊杞寸嚎
+				{
+					type: "gauge",
+					radius: "98%", // 浣嶇疆
+					center: ["50%", "70%"],
+					min: 0,
+					max: props.max,
+					startAngle: 180,
+					endAngle: 0,
+					axisLine: {
+						show: true,
+						lineStyle: {
+							// 杞寸嚎鏍峰紡
+							width: 4, // 瀹藉害
+							color: [
+								[1, "rgba(229,229,229,0.3)"]
+							] // 棰滆壊
+						}
+					},
+					axisTick: {
+						// 鍒诲害
+						show: false
+					},
+					splitLine: {
+						// 鍒嗗壊绾�
+						show: false
+					},
+					axisLabel: {
+						// 鍒诲害鏍囩
+						show: false
+					},
+					pointer: {
+						// 浠〃鐩樻寚閽�
+						show: false
+					},
+					detail: {
+						// 浠〃鐩樿鎯�
+						show: false
+					}
+				},
+				// 涓棿鐧借壊鍗婂渾
+				{
+					type: "gauge",
+					radius: "40%", // 浣嶇疆
+					center: ["50%", "70%"],
+					min: 0,
+					max: props.max,
+					startAngle: 180,
+					endAngle: 0,
+					axisLine: {
+						show: true,
+						lineStyle: {
+							// 杞寸嚎鏍峰紡
+							width: 120, // 瀹藉害
+							color: [
+								[
+									1,
+									new echarts.graphic.RadialGradient(.5, 1, 1, [{
+										offset: 1,
+										color: "rgba(229, 229, 229,0.15)"
+									},
+									{
+										offset: 0.72,
+										color: "rgba(229, 229, 229,0.05)"
+									},
+									{
+										offset: 0.7,
+										color: "rgba(229, 229, 229,0.4)"
+									},
+									{
+										offset: 0.401,
+										color: "rgba(229, 229, 229,0.05)"
+									},
+									{
+										offset: 0.4,
+										color: "rgba(229, 229, 229,0.8)"
+									},
+									{
+										offset: 0,
+										color: "rgba(229, 229, 229,0.8)"
+									}
+									])
+								]
+							], // 棰滆壊
+						}
+					},
+					axisTick: {
+						// 鍒诲害
+						show: false
+					},
+					splitLine: {
+						// 鍒嗗壊绾�
+						show: false
+					},
+					axisLabel: {
+						// 鍒诲害鏍囩
+						show: false
+					},
+					pointer: {
+						// 浠〃鐩樻寚閽�
+						show: false
+					},
+					detail: {
+						// 浠〃鐩樿鎯�
+						show: false
+					}
+				},
+				// 鍐呬晶杞寸嚎
+				{
+					type: "gauge",
+					radius: "90%", // 浣嶇疆
+					center: ["50%", "70%"],
+					min: 0,
+					max: props.max,
+					startAngle: 180,
+					endAngle: 0,
+					axisLine: {
+						show: true,
+						lineStyle: {
+							// 杞寸嚎鏍峰紡
+							width: 20, // 瀹藉害
+							color: [
+								[data.percent, colorLeft],
+								[1, colorRight]
+							], // 棰滆壊
+
+						}
+					},
+					pointer: {
+						// 浠〃鐩樻寚閽�
+						show: false,
+					},
+					axisTick: {
+						// 鍒诲害
+						show: false
+					},
+					splitLine: {
+						// 鍒嗗壊绾�
+						show: false
+					},
+					axisLabel: {
+						// 鍒诲害鏍囩
+						show: false
+					},
+					detail: {
+						// 浠〃鐩樿鎯�
+						show: false
+					}
+				},
+				// 鎸囬拡
+				{
+					type: "gauge",
+					radius: "80%", // 浣嶇疆
+					center: ["50%", "70%"],
+					min: 0,
+					max: props.max,
+					startAngle: 180,
+					endAngle: 0,
+					axisLine: {
+						show: false,
+					},
+					data: [{
+						value: data.value,
+						name: props.title
+					}],
+					pointer: {
+						// 浠〃鐩樻寚閽�
+						show: true,
+					},
+					itemStyle: {
+						color: "rgba(255,255,255,0)",
+						borderColor: "#f3f5f6",
+						borderWidth: "4",
+						borderType: "solid"
+					},
+					axisTick: {
+						// 鍒诲害
+						show: false
+					},
+					splitLine: {
+						// 鍒嗗壊绾�
+						show: false
+					},
+					axisLabel: {
+						// 鍒诲害鏍囩
+						show: false
+					},
+					detail: {
+						// 浠〃鐩樿鎯�
+						show: true,
+						formatter: function (value) {
+							return value + props.unit;
+						},
+						offsetCenter: ['0%', '30%'],
+						fontSize: '28px',
+						color: '#fff',
+            fontFamily: 'YouSheBiaoTiHei'
+					},
+					title: {
+						show: true,
+						offsetCenter: [0, '56%'],
+						color: '#08b5d6',
+            fontSize: '12px',
+					}
+				},
+			]
+		};
+
+		return option;
+	}
+
+	let myChart = null;
+	let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+			chart.value.setOption(option);
+			chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(xLabels, datas) {
+		if (chart.value) {
+			let option = getOptions(xLabels, datas);
+			chart.value.setOption(option);
+		}
+	}
+
+	function getChart() {
+		return chart_instance;
+	}
+
+	function getDataURL() {
+		return chart.value.getDataURL();
+	}
+
+	defineExpose({
+		getChart,
+		getDataURL,
+		updateChart
+	});
+
+	onMounted(() => {
+		// console.log('line mounted', '=============');
+
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/line-scroll.vue b/src/components/echarts/line-scroll.vue
new file mode 100644
index 0000000..054c8d3
--- /dev/null
+++ b/src/components/echarts/line-scroll.vue
@@ -0,0 +1,312 @@
+<script setup>
+	import { onMounted, ref, reactive, watchEffect, computed, watch, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+  import baseChart from "./BaseChart.vue";
+
+  const chart = ref(null);
+  const props = defineProps({
+    type: {
+      type: String,
+      default: '鐢垫祦'
+    },
+    yLabels: {
+      type: Array,
+      default: () => []
+    },
+    startIdx: {
+      type: [Number, String],
+      default: 0
+    },
+    modeCount: {
+      type: [Number, String],
+      default: 4
+    },
+    title: {
+      type: String,
+      default: ''
+    },
+    unit: {
+      type: String,
+      default: ''
+    }
+  });
+
+  const fullFlag = ref(false);
+
+  // 杩欎袱涓暟鍊兼槸鐧惧垎姣� 
+	const baseTop = 10;
+	let gridHeight = 20;
+
+  let gridCount = computed(() => {
+    return props.yLabels.length || 1;
+  });
+
+  const emit = defineEmits(['scroll']);
+
+
+	function makeXAxis(gridIndex, opt) {
+		let res = echarts.util.merge({
+			type: 'category',
+      boundaryGap: false,
+			gridIndex: gridIndex,
+			axisLine: { onZero: false, lineStyle: { color: '#ddd' } },
+			axisTick: { show: false },
+			axisLabel: { show: false },
+			splitLine: { show: false, lineStyle: { color: '#ddd' } },
+		}, opt || {}, true);
+    return JSON.parse(JSON.stringify(res));
+	}
+
+	function makeYAxis(gridIndex, opt) {
+		let res = echarts.util.merge({
+			type: 'value',
+			gridIndex: gridIndex,
+			nameLocation: 'middle',
+			nameTextStyle: {
+				color: '#fff',
+				lineHeight: 18
+			},
+			nameRotate: 0,
+			boundaryGap: ['30%', '30%'],
+			axisTick: { show: false },
+			axisLine: { lineStyle: { color: '#ccc' } },
+			axisLabel: { show: false },
+			splitLine: { show: false }
+		}, opt || {}, true);
+    return JSON.parse(JSON.stringify(res));
+	}
+
+
+	function makeGrid(top, opt) {
+		let res = echarts.util.merge({
+			top: top + '%',
+			height: gridHeight + '%',
+			left: 60,
+			right: 14,
+		}, opt || {}, true);
+    return JSON.parse(JSON.stringify(res));
+	}
+
+
+	function getSeries(datas) {
+		let res = [];  
+    
+		datas.forEach((item, idx) => {
+			res.push({
+				type: 'line',
+        name: props.yLabels[idx],
+				smooth: true,
+				symbol: 'circle',
+				symbolSize: 5,
+				showSymbol: false,
+        xAxisIndex: idx,
+        yAxisIndex: idx,
+        gridIndex: idx,
+				lineStyle: {
+					width: 1
+				},
+				data: datas[idx],
+			});
+		});
+
+		return JSON.parse(JSON.stringify(res));
+	}
+
+  let lastXLabels = [];
+  let lastDatas = [];
+
+  watch(
+    () => props.yLabels,
+    () => {
+      nextTick(() => {
+        chart.value.setOption(getOptions(lastXLabels, lastDatas));
+      });
+    }
+  )
+
+
+	function getOptions(xLabels, datas) {
+		xLabels = xLabels || [];
+    datas = datas || [];
+
+    lastXLabels = xLabels;
+    lastDatas = datas;
+
+
+    let series = getSeries(datas);
+    
+    let grid = [];
+    let xAxis = [];
+    let yAxis = [];
+    let counter = gridCount.value;
+    gridHeight = (100 - 20) / counter;
+    
+    for (let i = 0; i < counter; i++) {
+      grid.push(makeGrid(baseTop + gridHeight * i));
+      let xAxisOption = i == counter - 1 ? {
+          data: xLabels,
+          axisTick: { show: true },
+          axisLabel: { show: true },
+          axisLine: {
+            lineStyle: {
+              color: '#fff'
+            }
+          },
+      } : { show: false };
+      xAxis.push(makeXAxis(i, xAxisOption));
+      yAxis.push(makeYAxis(i, {
+					name: props.yLabels.length ? props.yLabels[i].replace(/(#)/g, '$1\n').replace(/\n$/, '') : '',
+				}));
+    }
+
+		const option = {
+      color: ['#1186ce', '#e5c619', '#1d1dfd', '#2dbfae'],
+			tooltip: {
+				trigger: 'axis',
+				axisPointer: {
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+        formatter: function (params) {
+					if (params.length) {
+            // params.unshift({ seriesName: 'time', value: params[0].name, color: '#5193f2' })
+            let _label = '';
+						let res =  props.yLabels.map((seriesName, idx) => {
+							for (var i = 0; i < params.length; i++) {
+								var param = params[i];
+								var style = 'color: ' + param.color;
+								if (param.seriesIndex === idx) {
+                  _label = param.name;
+									return '<span style="' + style + '">'
+										+ seriesName + props.type
+										+ '锛�</span><span style="'
+										+ style + '">' + param.value + '</span>';
+								}
+							}
+						});
+            res.push('<span style="color: #000">' + _label + '</span>');
+            res = res.join('<br>');
+            // console.log('res', res, '=============');
+            return res;
+            
+					}
+				}
+			},
+			axisPointer: {
+				link: [{ xAxisIndex: 'all' }],
+        lineStyle: {
+          color: '#fff'
+        },
+				snap: true
+			},
+			grid,
+			xAxis,
+			yAxis,
+			series
+		};
+
+    console.log('option', option, '=============');
+    
+		return option;
+	}
+
+  let myChart = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+      chart.value.setOption(option);
+		}
+	}
+
+	function updateChart(xLabels, datas) {
+    if (chart.value) {
+			let option = getOptions(xLabels, datas);
+      // chart.value.setOption(option, {notMerge: true});
+      chart.value.setOption(option);
+		}
+	}
+
+  function scrollToTop() {
+    if (props.startIdx > 0) {
+      emit('scroll', -1);      
+    }
+    
+  }
+
+  function scrollToBottom() {
+    if (props.startIdx < props.modeCount - 4) {
+      nextTick(() => {
+        emit('scroll', 1);
+      });
+    }
+  }
+
+  defineExpose({
+    updateChart
+  });
+
+	onMounted(() => {
+    // console.log('line mounted', '=============');
+    
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart" v-model:fullFlag="fullFlag" :key="startIdx">
+      <template #tools v-if="modeCount > 4">
+        <div class="t-contain">
+          <div :class="['btn', 'btn-top', {disabled: startIdx == 0}]" @click="scrollToTop">
+            <svg-icon icon-class="arrow-right" ></svg-icon>
+          </div>
+          <div :class="['btn', 'btn-bottom', {disabled: startIdx == modeCount - 4}]" @click="scrollToBottom">
+            <svg-icon icon-class="arrow-right" ></svg-icon>
+          </div>
+        </div>
+      </template>
+    </base-chart>
+  </div>
+</template>
+
+<style scoped lang="less">
+.line-chart {
+  width: 100%;
+  height: 100%;
+
+  .t-contain {
+    position: absolute;
+    right: 4px;
+    top: 0;
+    bottom: 0;
+    padding-top: 40px;
+    padding-bottom: 40px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    
+
+    .btn {
+      cursor: pointer;
+      font-size: 14px;
+      &:hover {
+        color: #0ff;
+      }
+      &.disabled {
+        cursor: not-allowed;
+        color: #666;
+      }
+      &.btn-top {
+        transform: rotate(-90deg);
+      }
+      &.btn-bottom {
+        transform: rotate(90deg);
+      }
+    }
+  }
+}
+</style>
diff --git a/src/components/echarts/line1.vue b/src/components/echarts/line1.vue
index f71efd2..4707598 100644
--- a/src/components/echarts/line1.vue
+++ b/src/components/echarts/line1.vue
@@ -5,10 +5,10 @@
 
   const chart = ref(null);
   const props = defineProps({
-    type: {
-      type: String,
-      default: '鐢垫祦'
-    },
+    // type: {
+    //   type: String,
+    //   default: '鐢垫祦'
+    // },
     title: {
       type: String,
       default: ''
@@ -19,10 +19,45 @@
     }
   });
 
+  function getSeries(_props, datas) {
+		let series = [];
+    let xlabels = [];
+    let _datas = {};
+    _props.forEach((item, idx) => {
+      _datas[item[1]] = [];
+    });
 
- function getOptions(xLabels, datas) {
-    xLabels = xLabels || [];
+    datas.forEach(v => {
+      xlabels.push(v.recordDatetime);
+      _props.forEach((item, idx) => {
+        _datas[item[1]].push(v[item[1]]);
+      });
+    });
+    
+		_props.forEach((item, idx) => {
+			series.push({
+				type: 'line',
+        name: item[0],
+				smooth: true,
+				symbol: 'circle',
+				symbolSize: 5,
+				showSymbol: false,
+				lineStyle: {
+					width: 1
+				},
+				data: _datas[item[1]],
+			});
+		});
+		return [series, xlabels];
+	}
+
+ function getOptions(labels, datas) {
+    labels = labels || [];
     datas = datas || [];
+
+    let [series, xLabels] = getSeries(labels, datas);
+    console.log('labels', labels, 'datas', series, '=============');
+    
 		const option = {
 			// title: {
 			// 	text: props.title,
@@ -41,11 +76,16 @@
 					}
 				}
 			},
+      legend: {
+        textStyle: {
+          color: '#fff'
+        }
+      },
 			grid: {
 				left: '3%',
 				right: '4%',
 				bottom: '3%',
-        top: 30,
+        top: 60,
 				containLabel: true
 			},
 			xAxis: [{
@@ -81,34 +121,35 @@
 					}
 				}
 			}],
-			series: [{
-				name: props.type,
-				type: 'line',
-				smooth: true,
-				symbol: 'circle',
-				symbolSize: 5,
-				showSymbol: false,
-				lineStyle: {
-          width: 1
-				},
-				areaStyle: {
-          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
-            offset: 0,
-            color: 'rgba(0, 136, 212, 0.3)'
-          }, {
-            offset: 0.8,
-            color: 'rgba(0, 136, 212, 0)'
-          }], false),
-          shadowColor: 'rgba(0, 0, 0, 0.1)',
-          shadowBlur: 10
-				},
-				itemStyle: {
-          color: 'rgb(0,136,212)',
-          borderColor: 'rgba(0,136,212,0.2)',
-          borderWidth: 12
-				},
-				data: datas
-			}]
+      series,
+			// series: [{
+			// 	name: props.type,
+			// 	type: 'line',
+			// 	smooth: true,
+			// 	symbol: 'circle',
+			// 	symbolSize: 5,
+			// 	showSymbol: false,
+			// 	lineStyle: {
+      //     width: 1
+			// 	},
+			// 	areaStyle: {
+      //     color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
+      //       offset: 0,
+      //       color: 'rgba(0, 136, 212, 0.3)'
+      //     }, {
+      //       offset: 0.8,
+      //       color: 'rgba(0, 136, 212, 0)'
+      //     }], false),
+      //     shadowColor: 'rgba(0, 0, 0, 0.1)',
+      //     shadowBlur: 10
+			// 	},
+			// 	itemStyle: {
+      //     color: 'rgb(0,136,212)',
+      //     borderColor: 'rgba(0,136,212,0.2)',
+      //     borderWidth: 12
+			// 	},
+			// 	data: datas
+			// }]
 		};
 
 		return option;
diff --git a/src/components/echarts/line2.vue b/src/components/echarts/line2.vue
index 4affcd1..16d4045 100644
--- a/src/components/echarts/line2.vue
+++ b/src/components/echarts/line2.vue
@@ -16,6 +16,7 @@
 	});
 
 	const typeList = ['璁惧娓╁害', '缁勭鐢垫祦', '缁勭鐢靛帇', '璐熻浇鐢垫祦'];
+  const propList = ['groupTmp', 'groupCurr', 'groupVol', 'loadCurr'];
 
 	// 杩欎袱涓暟鍊兼槸鐧惧垎姣� 
 	const baseTop = 10;
@@ -68,7 +69,7 @@
 
 	function getSeries(datas) {
 		let res = [];
-		typeList.forEach((item, index) => {
+		propList.forEach((item, index) => {
 			res.push({
 				type: 'line',
 				smooth: true,
@@ -77,10 +78,11 @@
 				showSymbol: false,
 				xAxisIndex: index,
 				yAxisIndex: index,
+        gridIndex: index,
 				lineStyle: {
 					width: 1
 				},
-				data: datas[item] || [],
+				data: datas.map(v => v[item])
 			});
 		});
 		return res;
@@ -90,7 +92,7 @@
 
 	function getOptions(xLabels, datas) {
 		xLabels = xLabels || [];
-		datas = datas || {};
+		datas = datas || [];
 		let series = getSeries(datas);
 		const option = {
 			// title: {
@@ -113,19 +115,23 @@
 				formatter: function (params) {
 					if (params.length) {
             // params.unshift({ seriesName: 'time', value: Math.floor(params[0].value), color: '#5193f2' })
+            let _label = '';
 						let res = typeList.map((seriesName, idx) => {
 							for (var i = 0; i < params.length; i++) {
 								var param = params[i];
 								var style = 'color: ' + param.color;
 								if (param.seriesIndex === idx) {
+                  _label = param.name;
 									return '<span style="' + style + '">'
 										+ seriesName
 										+ '锛�</span><span style="'
 										+ style + '">' + param.value + '</span>';
 								}
 							}
-						}).join('<br>');
-            console.log('res', res, '=============');
+						});
+            res.push('<span style="color: #000">' + _label + '</span>');
+            res = res.join('<br>');
+            // console.log('res', res, '=============');
             return res;
             
 					}
diff --git a/src/components/echarts/line4.vue b/src/components/echarts/line4.vue
new file mode 100644
index 0000000..19ea1fb
--- /dev/null
+++ b/src/components/echarts/line4.vue
@@ -0,0 +1,180 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+  import baseChart from "./BaseChart.vue";
+
+  const chart = ref(null);
+  const props = defineProps({
+    title: {
+      type: String,
+      default: ''
+    },
+    unit: {
+      type: String,
+      default: ''
+    }
+  });
+
+  function getSeries(_props, datas) {
+		let series = [];
+    let xlabels = [];
+    let _datas = {};
+    _props.forEach((item, idx) => {
+      _datas[item[1]] = [];
+    });
+
+    datas.forEach(v => {
+      xlabels.push(v.recordDatetime);
+      _props.forEach((item, idx) => {
+        _datas[item[1]].push(v[item[1]]);
+      });
+    });
+    
+		_props.forEach((item, idx) => {
+			series.push({
+				type: 'line',
+        name: item[0],
+				smooth: true,
+				symbol: 'circle',
+				symbolSize: 5,
+				showSymbol: false,
+				lineStyle: {
+					width: 1
+				},
+				data: _datas[item[1]],
+			});
+		});
+		return [series, xlabels];
+	}
+
+ function getOptions(opt) {
+    opt = opt || {series: []};
+    let series = opt.series.map(item => {
+      item.type = 'line';
+      item.smooth = item.smooth == undefined ? true : item.smooth;
+      item.symbolSize = item.symbolSize == undefined ? 0 : item.symbolSize;
+      item.sampling = 'average';
+      return item;
+    });
+
+    
+    
+		const option = {
+			// title: {
+			// 	text: props.title,
+			// 	textStyle: {
+			// 		fontWeight: 'normal',
+			// 		fontSize: 14,
+			// 		color: '#fff'
+			// 	},
+			// 	left: '6%'
+			// },
+			tooltip: {
+				trigger: 'axis',
+				axisPointer: {
+					lineStyle: {
+						color: '#fff'
+					}
+				}
+			},
+      legend: {
+        textStyle: {
+          color: '#fff'
+        }
+      },
+			grid: {
+				left: '3%',
+				right: '4%',
+				bottom: '3%',
+        top: 60,
+				containLabel: true
+			},
+			xAxis: [{
+				type: 'category',
+				boundaryGap: false,
+				axisLine: {
+          onZero: false,
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+			}],
+			yAxis: [{
+				type: 'value',
+				name: props.unit,
+				axisTick: {
+					show: true,
+				},
+				axisLine: {
+          show: true,
+					lineStyle: {
+						color: '#fff'
+					}
+				},
+				axisLabel: {
+					margin: 10,
+					fontSize: 12,
+          color: '#fff'
+				},
+				splitLine: {
+					lineStyle: {
+						color: 'rgba(255,255,255,0.2)'
+					}
+				}
+			}],
+      ...opt,
+      series
+		};
+    
+
+		return option;
+	}
+
+  let myChart = null;
+  let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+      chart.value.setOption(option);
+      chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(opt) {
+    if (chart.value) {
+			let option = getOptions(opt);
+      chart.value.setOption(option);
+		}
+	}
+
+  function getChart() {
+    return chart_instance;
+  }
+
+  defineExpose({
+    updateChart,
+    getChart,
+  });
+
+	onMounted(() => {
+    // console.log('line mounted', '=============');
+    
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/pie1.vue b/src/components/echarts/pie1.vue
new file mode 100644
index 0000000..e6c6ec4
--- /dev/null
+++ b/src/components/echarts/pie1.vue
@@ -0,0 +1,153 @@
+<script setup>
+import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+import * as echarts from 'echarts';
+import baseChart from "./BaseChart.vue";
+import { toFixed } from '@/utils/toFixed.js';
+import hexToRgba from '@/utils/hexToRgba.js';
+
+const chart = ref(null);
+const props = defineProps({
+	title: {
+		type: String,
+		default: ''
+	},
+	unit: {
+		type: String,
+		default: ''
+	},
+	// barW: {
+	//   type: [Number, String],
+	//   default: 60,
+	// },
+});
+
+
+
+
+const color = '#13ACBE';
+const topColor = '#07FBFF';
+const minColor = '#f00';
+const maxColor = '#0f0';
+
+function getMax(data) {
+	let max = Math.max.apply(null, data) * 1.2;
+	return toFixed(max, 1) || 1;
+}
+
+
+function getOptions(datas) {
+  // {value, name}
+	datas = datas || [];
+
+
+	const option = {
+		tooltip: {
+			trigger: 'item',
+			formatter: "{a} <br/>{b} : {c} ({d}%)"
+		},
+		series: [{
+			name: '鎬ц兘鍗犳瘮',
+			type: 'pie',
+			radius: '48%',
+			center: ['50%', '50%'],
+			clockwise: false,
+			data: datas,
+      label: {
+        textStyle: {
+          color: '#0ff',
+          fontSize: 14,
+        },
+        // 鑷姩璋冩暣閲嶅彔鏍囩
+        // autoAdjustOverlap: true,
+        // 鏍囩浣嶇疆
+        position: 'outside',
+        // 鏍囩鏂囨湰鏍峰紡
+        formatter: '{b}:\n {d}% \n {c}'
+      },
+			labelLine: {
+        length: 20,
+        length2: 8,
+        minTurnAngle: 40, // 鏈�灏忚搴�,闃叉鏍囩閲嶅彔 
+        maxSurfaceAngle: 110, // 闄愬埗寮曞绾夸笌鎵囧尯娉曠嚎鐨勬渶澶уす瑙�
+				show: true
+			},
+			itemStyle: {
+					borderWidth: 2,
+					borderColor: '#ffffff',
+				emphasis: {
+					borderWidth: 0,
+					shadowBlur: 10,
+					shadowOffsetX: 0,
+					shadowColor: 'rgba(0, 0, 0, 0.5)'
+				}
+			},
+      emptyCircleStyle: {
+        color: '#73c0de',
+        borderWidth: 0
+      }
+		}],
+		color: [
+			'#00acee',
+			'#52cdd5',
+			'#79d9f1',
+			'#a7e7ff',
+			'#c8efff'
+		],
+	};
+
+	return option;
+}
+
+let myChart = null;
+let chart_instance = null;
+
+function initChart() {
+	if (chart.value) {
+		// myChart = chart.value.getChart();
+
+		let option = getOptions();
+		chart.value.setOption(option);
+		chart_instance = chart.value.getChart();
+	}
+}
+
+function updateChart(datas) {
+	if (chart.value) {
+		let option = getOptions(datas);
+		chart.value.setOption(option);
+	}
+}
+
+function getChart() {
+	return chart_instance;
+}
+
+function getDataURL() {
+	return chart.value.getDataURL();
+}
+
+defineExpose({
+	getChart,
+	getDataURL,
+	updateChart
+});
+
+onMounted(() => {
+	// console.log('line mounted', '=============');
+
+	initChart();
+});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/pie3d0.vue b/src/components/echarts/pie3d0.vue
new file mode 100644
index 0000000..444d804
--- /dev/null
+++ b/src/components/echarts/pie3d0.vue
@@ -0,0 +1,356 @@
+<script setup>
+import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+import * as echarts from 'echarts';
+import baseChart from "./BaseChart.vue";
+import { toFixed } from '@/utils/toFixed.js';
+import hexToRgba from '@/utils/hexToRgba.js';
+
+import 'echarts-gl';
+
+const chart = ref(null);
+const props = defineProps({
+	title: {
+		type: String,
+		default: ''
+	},
+	unit: {
+		type: String,
+		default: ''
+	},
+	// barW: {
+	//   type: [Number, String],
+	//   default: 60,
+	// },
+});
+
+
+// 鐢熸垚鎵囧舰鐨勬洸闈㈠弬鏁版柟绋嬶紝鐢ㄤ簬 series-surface.parametricEquation
+function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
+	// 璁$畻
+	const midRatio = (startRatio + endRatio) / 2;
+	const startRadian = startRatio * Math.PI * 2;
+	const endRadian = endRatio * Math.PI * 2;
+	const midRadian = midRatio * Math.PI * 2;
+	// 濡傛灉鍙湁涓�涓墖褰紝鍒欎笉瀹炵幇閫変腑鏁堟灉銆�
+	if (startRatio === 0 && endRatio === 1) {
+		isSelected = false;
+	}
+	// 閫氳繃鎵囧舰鍐呭緞/澶栧緞鐨勫�硷紝鎹㈢畻鍑鸿緟鍔╁弬鏁� k锛堥粯璁ゅ�� 1/3锛�
+	k = 1;
+	// 璁$畻閫変腑鏁堟灉鍒嗗埆鍦� x 杞淬�亂 杞存柟鍚戜笂鐨勪綅绉伙紙鏈�変腑锛屽垯浣嶇Щ鍧囦负 0锛�
+	const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
+	const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
+	// 璁$畻楂樹寒鏁堟灉鐨勬斁澶ф瘮渚嬶紙鏈珮浜紝鍒欐瘮渚嬩负 1锛�
+	const hoverRate = isHovered ? 1.05 : 1;
+	// 杩斿洖鏇查潰鍙傛暟鏂圭▼
+	return {
+		u: {
+			min: -Math.PI,
+			max: Math.PI * 3,
+			step: Math.PI / 32,
+		},
+		v: {
+			min: 0,
+			max: Math.PI * 2,
+			step: Math.PI / 20,
+		},
+		x: function (u, v) {
+			if (u < startRadian) {
+				return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
+			}
+			if (u > endRadian) {
+				return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
+			}
+			return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
+		},
+		y: function (u, v) {
+			if (u < startRadian) {
+				return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
+			}
+			if (u > endRadian) {
+				return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
+			}
+			return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
+		},
+		z: function (u, v) {
+			if (u < -Math.PI * 0.5) {
+				return Math.sin(u);
+			}
+			if (u > Math.PI * 2.5) {
+				return Math.sin(u) * h * 0.1;
+			}
+			return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
+		},
+	};
+}
+
+/**
+ * 缁樺埗3d鍥�
+ * @param pieData 鎬绘暟鎹�
+ * @param internalDiameterRatio:閫忔槑鐨勭┖蹇冨崰姣�
+ * @param distance 瑙嗚鍒颁富浣撶殑璺濈
+ * @param alpha 鏃嬭浆瑙掑害
+ * @param pieHeight 绔嬩綋鐨勯珮搴�
+ * @param opacity 楗兼垨鑰呯幆鐨勯�忔槑搴�
+ */
+function getPie3D(pieData, internalDiameterRatio, distance, alpha, pieHeight, opacity = 1) {
+	const series = [];
+	let sumValue = 0;
+	let startValue = 0;
+	let endValue = 0;
+	const legendData = [];
+	const k =
+		typeof internalDiameterRatio !== 'undefined'
+			? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
+			: 1 / 3;
+	// 涓烘瘡涓�涓ゼ鍥炬暟鎹紝鐢熸垚涓�涓� series-surface 閰嶇疆
+	for (let i = 0; i < pieData.length; i += 1) {
+		sumValue += pieData[i].value;
+		const seriesItem = {
+			name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
+			type: 'surface',
+			parametric: true,
+			wireframe: {
+				show: false,
+			},
+			pieData: pieData[i],
+			pieStatus: {
+				selected: false,
+				hovered: false,
+				k: k,
+			},
+		};
+		if (typeof pieData[i].itemStyle !== 'undefined') {
+			const itemStyle = {};
+			if (typeof pieData[i].itemStyle.color !== 'undefined') {
+				itemStyle.color = pieData[i].itemStyle.color;
+			}
+			if (typeof pieData[i].itemStyle.opacity !== 'undefined') {
+				itemStyle.opacity = pieData[i].itemStyle.opacity;
+			}
+			seriesItem.itemStyle = itemStyle;
+		}
+		series.push(seriesItem);
+	}
+	// 浣跨敤涓婁竴娆¢亶鍘嗘椂锛岃绠楀嚭鐨勬暟鎹拰 sumValue锛岃皟鐢� getParametricEquation 鍑芥暟锛�
+	// 鍚戞瘡涓� series-surface 浼犲叆涓嶅悓鐨勫弬鏁版柟绋� series-surface.parametricEquation锛屼篃灏辨槸瀹炵幇姣忎竴涓墖褰€��
+	for (let i = 0; i < series.length; i += 1) {
+		endValue = startValue + series[i].pieData.value;
+		series[i].pieData.startRatio = startValue / sumValue;
+		series[i].pieData.endRatio = endValue / sumValue;
+		console.log(series[i].pieData.startRatio,
+			series[i].pieData.endRatio,
+			false,
+			false,
+			k,
+			series[i].pieData.value)
+		series[i].parametricEquation = getParametricEquation(
+			series[i].pieData.startRatio,
+			series[i].pieData.endRatio,
+			false,
+			false,
+			k,
+			// series[i].pieData.value
+			10
+		);
+		startValue = endValue;
+		legendData.push(series[i].name);
+	}
+	return series;
+}
+
+const optionsData = [
+	{
+		name: 'aa',
+		value: 11,
+		itemStyle: {
+			color: '#41adf8',
+			// opacity: 1,
+		},
+	},
+	{
+		name: 'cc',
+		value: 330,
+		itemStyle: {
+			color: '#ffa100',
+			// opacity: 1,
+		},
+	},
+	{
+		name: 'bb',
+		value: 22,
+		itemStyle: {
+			color: '#2acf81',
+			// opacity: 1,
+		},
+	},
+];
+
+function getOptions(datas) {
+  
+  datas = datas || [];
+
+  const series = getPie3D(datas, 0.8, 240, 28, 26, 0.5);
+  
+  series.unshift({
+    name: 'pie2d',
+    type: 'pie',
+    label: {
+      opacity: 1,
+      fontSize: 12,
+      // textStyle: {
+      //   color: '#fff',
+      // }
+      // lineHeight: 20,
+    },
+    labelLine: {
+      length: 20,
+      length2: 20,
+    },
+    startAngle: -30, //璧峰瑙掑害锛屾敮鎸佽寖鍥碵0, 360]銆�
+    clockwise: false, //楗煎浘鐨勬墖鍖烘槸鍚︽槸椤烘椂閽堟帓甯冦�備笂杩拌繖涓ら」閰嶇疆涓昏鏄负浜嗗榻�3d鐨勬牱寮�
+    radius: ['20%', '46%'],
+    center: ['50%', '50%'],
+    data: datas,
+    itemStyle: {
+      opacity: 0,
+    },
+  });
+
+	let option = {
+		legend: {
+			tooltip: {
+				show: true,
+			},
+			data: datas.map((item) => item.name),
+			bottom: '6%',
+			textStyle: {
+				color: '#fff',
+				fontSize: 12,
+			},
+		},
+		tooltip: {
+			formatter: (params) => {
+				if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
+          let end = option.series[params.seriesIndex].pieData?.endRatio || 0;
+          let start = option.series[params.seriesIndex].pieData?.startRatio || 0;
+					let bfb = (
+						(end - start) *
+						100
+					).toFixed(2);
+					return (
+						`${params.seriesName}<br/>` +
+						`<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
+						`${bfb}%`
+					);
+				}
+			},
+		},
+		// title: {
+		// 	text: '3D 楗煎浘',
+		// 	x: 'center',
+		// 	top: '20',
+		// 	textStyle: {
+		// 		color: '#fff',
+		// 		fontSize: 22,
+		// 	},
+		// },
+		labelLine: {
+			show: true,
+			lineStyle: {
+				color: '#7BC0CB',
+			},
+		},
+		label: {
+			show: true,
+			position: 'outside',
+			formatter: '{b} \n{c} \n {d}%',
+      textStyle: {
+        color: '#fff',
+        fontSize: 12,
+      }
+		},
+		xAxis3D: {
+			min: -1,
+			max: 1,
+		},
+		yAxis3D: {
+			min: -1,
+			max: 1,
+		},
+		zAxis3D: {
+			min: -1,
+			max: 1,
+		},
+		grid3D: {
+			show: false,
+			boxHeight: 30, // 涓夌淮绗涘崱灏斿潗鏍囩郴鍦ㄤ笁缁村満鏅腑鐨勯珮搴�
+			viewControl: {
+				alpha: 40,
+				beta: 40,
+				distance: 500, //璋冩暣瑙嗚鍒颁富浣撶殑璺濈锛岀被浼艰皟鏁磟oom
+				rotateSensitivity: 0, // 璁剧疆涓�0鏃犳硶鏃嬭浆
+				zoomSensitivity: 0, // 璁剧疆涓�0鏃犳硶缂╂斁
+				panSensitivity: 0, // 璁剧疆涓�0鏃犳硶骞崇Щ
+				autoRotate: false, // 鑷姩鏃嬭浆
+			},
+		},
+		series: series,
+	};
+
+	return option;
+}
+
+let myChart = null;
+let chart_instance = null;
+
+function initChart() {
+	if (chart.value) {
+		// myChart = chart.value.getChart();
+
+		let option = getOptions();
+		chart.value.setOption(option);
+		chart_instance = chart.value.getChart();
+	}
+}
+
+function updateChart(datas) {
+	if (chart.value) {
+		let option = getOptions(datas);
+		chart.value.setOption(option);
+	}
+}
+
+function getChart() {
+	return chart_instance;
+}
+
+function getDataURL() {
+	return chart.value.getDataURL();
+}
+
+defineExpose({
+	getChart,
+	getDataURL,
+	updateChart
+});
+
+onMounted(() => {
+	// console.log('line mounted', '=============');
+
+	initChart();
+});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/echarts/water.vue b/src/components/echarts/water.vue
new file mode 100644
index 0000000..800fb09
--- /dev/null
+++ b/src/components/echarts/water.vue
@@ -0,0 +1,149 @@
+<script setup>
+	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
+	import * as echarts from 'echarts';
+	import baseChart from "./BaseChart.vue";
+	import { toFixed } from '@/utils/toFixed.js';
+	import 'echarts-liquidfill';
+
+	const chart = ref(null);
+	const props = defineProps({
+		// type: {
+		//   type: String,
+		//   default: '鐢靛帇'
+		// },
+		title: {
+			type: String,
+			default: '鐩存祦杈撳嚭鐢垫祦'
+		},
+		unit: {
+			type: String,
+			default: 'A'
+		}
+	});
+
+	const barWidth = 60;
+
+
+	const colors = ['#196EB1', '#12D2AD', '#C75C86'];
+
+	function getMax(data) {
+		let max = Math.max.apply(null, data) * 1.2;
+		return toFixed(max, 1) || 1;
+	}
+
+
+	function getOptions(datas) {
+		datas = datas || 0;
+		const option = {
+      title: {
+        text: props.title,
+        left: 'center',
+        top: 'bottom',
+        textStyle: {
+          color: '#08b5d6',
+          fontWeight: 'normal',
+          fontSize: 14
+        }
+      },
+			series: [
+				{
+					type: 'liquidFill', //姘翠綅鍥�
+					radius: '76%', //鏄剧ず姣斾緥
+					center: ['50%', '50%'], //涓績鐐�
+					amplitude: 20, //姘存尝鎸箙
+					// data: [0.5, 0.5, 0.5], // data涓暟浠h〃娉㈡氮鏁�
+					data: [0.5, {
+						value: 0.5,
+						phase: Math.PI,
+						itemStyle: {
+							color: '#1A9840'
+						}
+					}, 0.5],
+					phase: 0,
+					period: 4000,
+					waveLength: '100%',
+					color: '#c72',
+					animationDurationUpdate: 2000,
+					color: ['#23cc72'], //娉㈡氮棰滆壊
+					backgroundStyle: {
+						borderWidth: 6, //澶栬竟妗�
+						borderColor: '#23cc72', //杈规棰滆壊
+						color: 'transparent', //杈规鍐呴儴濉厖閮ㄥ垎棰滆壊
+					},
+					label: {
+						//鏍囩璁剧疆
+						normal: {
+							position: ['50%', '50%'],
+							formatter: datas + props.unit, //鏄剧ず鏂囨湰,
+							color: '#23cc72',
+							textStyle: {
+								fontSize: '36px', //鏂囨湰瀛楀彿,
+								fontFamily: 'YouSheBiaoTiHei',
+								// backgroundColor: '#23cc72',
+								// color: '#fff',
+							},
+						},
+					},
+					outline: {
+						show: false,//鏈�澶栧眰杈规鏄剧ず鎺у埗
+					},
+				},
+			],
+		};
+
+		return option;
+	}
+
+	let myChart = null;
+	let chart_instance = null;
+
+	function initChart() {
+		if (chart.value) {
+			// myChart = chart.value.getChart();
+
+			let option = getOptions();
+			chart.value.setOption(option);
+			chart_instance = chart.value.getChart();
+		}
+	}
+
+	function updateChart(datas) {
+		if (chart.value) {
+			let option = getOptions(datas);
+			chart.value.setOption(option);
+		}
+	}
+
+	function getChart() {
+		return chart_instance;
+	}
+
+	function getDataURL() {
+		return chart.value.getDataURL();
+	}
+
+	defineExpose({
+		getChart,
+		getDataURL,
+		updateChart
+	});
+
+	onMounted(() => {
+		// console.log('line mounted', '=============');
+
+		initChart();
+	});
+</script>
+
+<template>
+  <div class="line-chart">
+    <base-chart ref="chart"></base-chart>
+  </div>
+</template>
+
+<style scoped>
+.line-chart {
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/hrParams.vue b/src/components/hrParams.vue
new file mode 100644
index 0000000..0504e8b
--- /dev/null
+++ b/src/components/hrParams.vue
@@ -0,0 +1,239 @@
+<script setup>
+import { ref, onMounted, reactive, watch, nextTick, computed } from "vue";
+
+
+import useElement from "@/hooks/useElement.js";
+	const { $loading, $message, $confirm } = useElement();
+
+import {
+  getHrParam,
+  setHrParam,
+  startDis,
+} from "@/api/control.js";
+
+const emit = defineEmits(['update:visible']);
+
+const props = defineProps({
+  battgroupId: {
+    type: [String, Number],
+  },
+  devId: {
+    type: [String, Number],
+  },
+  visible: {
+    type: Boolean,
+    default: false
+  },
+});
+
+const layout = {
+  gutter: 16,
+  span: 8,
+}
+
+const startFlag = ref(false);
+const setFlag = ref(false);
+
+// TODO 鍙傛暟鑼冨洿
+
+const form1 = reactive({
+  devId: '',
+  opCmd: '',
+  testCmd: '',
+  hourrate: '',
+  discurr: '',
+  discap: '',
+  distime: '',
+  groupvolLow: '',
+  monomervolLow: '',
+  monomerlowcount: '',
+  battgroupnum: '',
+  onlinevollowaction: '',
+  dcvolhighlimit: '',
+  chargecurrset: '',
+  monomertmpHigh: '',
+  monvolstd: '',
+  diswaittime: '',
+  moncapstd: '',
+});
+
+async function getParam() {
+  let loading = $loading();
+  let res = await getHrParam(props.devId, props.battgroupId);
+  let { code, data, data2 } = res;
+  loading.close();
+  if (code && data) {
+    $message.success('鎿嶄綔鎴愬姛');
+    setFlag.value = true;
+  } else {
+    $message.error('鎿嶄綔澶辫触');
+    // setFlag.value = false;
+    setFlag.value = true;
+  }
+  if (data2) {
+    for(let key in form1) {
+      form1[key] = data2[key];
+    }
+  }
+}
+
+
+async function setParam() {
+  let loading = $loading();
+  let res = await setHrParam(form1);
+  let { code, data } = res;
+  loading.close();
+  if (code && data) {
+    $message.success('鎿嶄綔鎴愬姛');
+    startFlag.value = true;
+  } else {
+    $message.error('鎿嶄綔澶辫触');
+    // startFlag.value = false;
+    startFlag.value = true;
+  }
+}
+
+function close () {
+  emit('update:visible', false);
+}
+
+async function startTest() {
+  let loading = $loading();
+  let res = await startDis(props.devId, props.battgroupId);
+  let { code, data } = res;
+  loading.close();
+  if (code && data) {
+    $message.success('鎿嶄綔鎴愬姛');
+    close();
+  } else {
+    $message.error('鎿嶄綔澶辫触');
+  }
+}
+
+
+
+onMounted(() => {
+  getParam();
+});
+</script>
+
+<template>
+  <div class="param-contain">
+    <el-form ref="formRef" :model="form1" label-width="10em">
+        <el-row :gutter="layout.gutter">
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鏀剧數灏忔椂鐜�" prop="hourrate">
+              <el-input v-model="form1.hourrate"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鏀剧數鐢垫祦" prop="discurr">
+              <el-input v-model="form1.discurr"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鏀剧數瀹归噺" prop="discap">
+              <el-input v-model="form1.discap"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鏀剧數鏃堕暱" prop="distime">
+              <el-input v-model="form1.distime"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="缁勭鐢靛帇涓嬮檺" prop="groupvolLow">
+              <el-input v-model="form1.groupvolLow"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋鐢靛帇涓嬮檺" prop="monomervolLow">
+              <el-input v-model="form1.monomervolLow"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋涓嬮檺鏁伴噺" prop="monomerlowcount">
+              <el-input v-model="form1.monomerlowcount"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鐢垫睜缁勭粍鍙�" prop="battgroupnum">
+              <el-input v-model="form1.battgroupnum" disabled></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍦ㄧ嚎鐢靛帇浣庡鐞�" prop="onlinevollowaction">
+              <el-input v-model="form1.onlinevollowaction"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗囧帇涓婇檺" prop="dcvolhighlimit">
+              <el-input v-model="form1.dcvolhighlimit"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍏呯數鐢垫祦" prop="chargecurrset">
+              <el-input v-model="form1.chargecurrset"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋娓╁害涓婇檺" prop="monomertmpHigh">
+              <el-input v-model="form1.monomertmpHigh"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋鐢靛帇" prop="monvolstd">
+              <el-input v-model="form1.monvolstd"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="闈欑疆鏃堕棿" prop="diswaittime">
+              <el-input v-model="form1.diswaittime"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div class="footer">
+        <el-button @click="close">鍏抽棴</el-button>
+        <el-button type="primary" :disabled="!startFlag" @click="startTest">鍚姩娴嬭瘯</el-button>
+        <el-button type="primary" :disabled="!setFlag" @click="setParam">璁剧疆</el-button>
+        <el-button type="primary" @click="getParam">璇诲彇</el-button>
+      </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.footer {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 8px;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/info.vue b/src/components/info.vue
index 14f102b..1c41d2c 100644
--- a/src/components/info.vue
+++ b/src/components/info.vue
@@ -15,7 +15,10 @@
 <template>
   <div class="info">
     <div class="label">{{ label }}</div>
-    <div class="value">{{ value }}</div>
+    <div class="value">
+      <slot v-if="$slots.value" name="value" />
+      <template v-else>{{ value }}</template>
+    </div>
   </div>
 </template>
 
diff --git a/src/components/pwrAlarmParams.vue b/src/components/pwrAlarmParams.vue
new file mode 100644
index 0000000..d9a0fdb
--- /dev/null
+++ b/src/components/pwrAlarmParams.vue
@@ -0,0 +1,214 @@
+<script setup name="pwrAlarmParams">
+import { ref, reactive, computed, watch, onMounted } from 'vue';
+
+import useElement from "@/hooks/useElement.js";
+const { $loading, $message, $confirm } = useElement();
+
+import {
+	setPwrAlmParam,
+} from '@/api/alarm.js';
+
+const props = defineProps({
+	visible: {
+		type: Boolean,
+		default: false
+	},
+	type: {
+		type: [String, Number],
+		validate: (val) => [0, 1, 2, '0', '1', '2'].includes(val),
+		default: 0
+	},
+	info: {
+		type: Object,
+		default: () => ({})
+	}
+});
+
+const emit = defineEmits(['update:visible', 'change']);
+
+const initFlag = ref(false);
+
+const layout = {
+	gutter: 16,
+	span: 8,
+}
+
+const opt0 = {
+	alarmLimithUpper: '涓婁笂闄愬憡璀﹂槇鍊�',
+	alarmLimithUpperLevel: '涓婁笂闄愬憡璀︾瓑绾�',
+	alarmLimithUpperEn: '涓婁笂闄愬埗鍛婅浣胯兘',
+	alarmLimith: '涓婇檺鍛婅闃堝��',
+	alarmLimithLevel: '涓婇檺鍛婅绛夌骇',
+	alarmLimithEn: '涓婇檺鍛婅绛夌骇浣胯兘',
+};
+
+const opt1 = {
+	alarmLimitl: '涓嬮檺鍛婅闃堝��',
+	alarmLimitlLevel: '涓嬮檺鍛婅绛夌骇',
+	alarmLimitlEn: '涓嬮檺鍛婅浣胯兘',
+	alarmLimitlLower: '涓嬩笅闄愬憡璀﹂槇鍊�',
+	alarmLimitlLowerLevel: '涓嬩笅闄愬憡璀︾瓑绾�',
+	alarmLimitlLowerEn: '涓嬩笅闄愬憡璀︿娇鑳�',
+};
+
+
+
+let option = {};
+switch (props.type) {
+  case 0:
+  case '0':
+    option = {
+      ...opt0,
+      ...opt1,
+      almDelayTime: '鍛婅寤舵椂鏃堕暱',
+    };
+    break;
+  case 1:
+  case '1':
+    option = {
+      ...opt0,
+      almDelayTime: '鍛婅寤舵椂鏃堕暱',
+    };
+    break;
+  case 2:
+  case '2':
+    option = {
+      ...opt1,
+      almDelayTime: '鍛婅寤舵椂鏃堕暱',
+    };
+    break;
+}
+
+let option1 = {
+  ...opt0,
+  ...opt1,
+  almDelayTime: '鍛婅寤舵椂鏃堕暱',
+};
+
+
+const form1 = reactive({});
+
+const almId = ref('');
+
+Object.keys(option).forEach(key => {
+	form1[key] = '';
+});
+
+
+const alarmLevels = [
+	{
+		label: '涓�绾у憡璀�',
+		value: 1,
+	},
+	{
+		label: '浜岀骇鍛婅',
+		value: 2,
+	},
+	{
+		label: '涓夌骇鍛婅',
+		value: 3,
+	},
+	{
+		label: '鍥涚骇鍛婅',
+		value: 4,
+	},
+];
+
+async function submit() {
+	// console.log(obj, '=============');
+	let loading = $loading();
+	let res = await setPwrAlmParam([form1]);
+	let { code, data } = res;
+	if (code && data) {
+		$message.success('鎿嶄綔鎴愬姛');
+		emit('update:visible', false);
+		emit('change');
+	} else {
+		$message.error('鎿嶄綔澶辫触');
+	}
+	loading.close();
+}
+
+function close() {
+	emit('update:visible', false);
+}
+
+onMounted(() => {
+	Object.keys(option1).forEach(key => {
+		form1[key] = props.info[key];
+	});
+	form1.almId = props.info.almId;
+	form1.powerId = props.info.powerId;
+	form1.alarmType = props.info.alarmType;
+	form1.alarmSource = props.info.alarmSource;
+	form1.alarmEnNode = props.info.alarmEnNode;
+	initFlag.value = true;
+});
+</script>
+
+<template>
+  <div class="alarm-form">
+    <!-- 琛ㄥ崟鍖哄煙 -->
+    <div class="content">
+      <el-form ref="formRef" :model="form1" label-width="10em" :key="initFlag">
+        <el-row :gutter="layout.gutter">
+          <el-col
+            :span="layout.span"
+            v-for="(item, idx) in Object.keys(option)"
+            :key="'list1_' + idx"
+          >
+            <el-form-item :label="option[item]" :prop="item">
+              <el-checkbox
+                :checked="form1[item] == 1"
+                @change="(v) => form1[item] = v ? 1 : 0"
+                v-if="/En$/.test(item)"
+              ></el-checkbox>
+              <el-select
+                v-else-if="/Level/.test(item)"
+                v-model="form1[item]"
+                placeholder="璇烽�夋嫨"
+              >
+                <el-option
+                  v-for="(item, key) in alarmLevels"
+                  :key="'list3_' + idx + '_' + key"
+                  :label="item.label"
+                  :value="item.value"
+                ></el-option>
+              </el-select>
+              <el-input v-else v-model="form1[item]"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </div>
+    <div class="footer">
+      <el-button @click="close">鍏抽棴</el-button>
+      <el-button type="primary" @click="submit">鎻愪氦</el-button>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.search-container {
+  margin-bottom: 10px;
+  padding-left: 20px;
+  display: flex;
+  align-items: center;
+
+  .label {
+    margin-right: 10px;
+    font-size: 20px;
+    font-family: 'YouSheBiaoTiHei';
+  }
+
+  .el-select {
+    width: 200px;
+  }
+}
+
+.footer {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 8px;
+}
+</style>
diff --git a/src/components/scrollerField0.vue b/src/components/scrollerField0.vue
new file mode 100644
index 0000000..3ef470e
--- /dev/null
+++ b/src/components/scrollerField0.vue
@@ -0,0 +1,359 @@
+<script setup>
+import { ref, reactive, computed, watch } from 'vue';
+
+const props = defineProps({
+  list: {
+    type: Array,
+    default: () => []
+  },
+  
+});
+
+
+// 鎼滅储鐩稿叧鐘舵��
+const searchQuery = ref('');
+const matches = ref([]);
+const currentMatchIndex = ref(-1);
+const recentlyEdited = ref([]);
+
+// 鑾峰彇鎵�鏈夊垎绫�
+const categories = computed(() => {
+  return props.list.map((v) => v.almName);
+});
+
+const allFields = computed(() => {
+  return props.list || [];
+});
+
+// 鏍规嵁鍛婅ID 鍒涘缓鍛婅琛ㄥ崟
+function getFieldsByCategory(category) {
+  // TODO
+  return allFields.value.filter(field => field.category === category);
+}
+
+// 澶勭悊鎼滅储
+function handleSearch() {
+  if (!searchQuery.value.trim()) {
+    matches.value = [];
+    currentMatchIndex.value = -1;
+    return;
+  }
+  
+  const query = searchQuery.value.toLowerCase();
+  matches.value = allFields.value.filter(field => 
+    field.label.toLowerCase().includes(query) || 
+    (field.description && field.description.toLowerCase().includes(query))
+  );
+  
+  // 濡傛灉鏈夊尮閰嶉」锛岄珮浜涓�涓�
+  if (matches.value.length > 0) {
+    currentMatchIndex.value = 0;
+    scrollToCurrentMatch();
+  }
+}
+
+// 娓呴櫎鎼滅储
+function clearSearch() {
+  searchQuery.value = '';
+  matches.value = [];
+  currentMatchIndex.value = -1;
+}
+
+// 妫�鏌ュ瓧娈垫槸鍚﹀尮閰嶆悳绱�
+function isMatch(field) {
+  return matches.value.includes(field);
+}
+
+// 妫�鏌ュ瓧娈垫槸鍚︿负褰撳墠鍖归厤椤�
+function isCurrentMatch(field) {
+  return currentMatchIndex.value >= 0 && 
+         matches.value[currentMatchIndex.value] === field;
+}
+
+// 璺宠浆鍒颁笅涓�涓尮閰嶉」
+function goToNextMatch() {
+  if (matches.value.length === 0) return;
+  currentMatchIndex.value = (currentMatchIndex.value + 1) % matches.value.length;
+  scrollToCurrentMatch();
+}
+
+// 璺宠浆鍒颁笂涓�涓尮閰嶉」
+function goToPrevMatch() {
+  if (matches.value.length === 0) return;
+  currentMatchIndex.value = (currentMatchIndex.value - 1 + matches.value.length) % matches.value.length;
+  scrollToCurrentMatch();
+}
+
+// 婊氬姩鍒板綋鍓嶅尮閰嶉」
+function scrollToCurrentMatch() {
+  if (currentMatchIndex.value < 0) return;
+  
+  const currentField = matches.value[currentMatchIndex.value];
+  if (!currentField) return;
+  
+  // 鎵惧埌瀵瑰簲鐨凞OM鍏冪礌骞舵粴鍔ㄥ埌瑙嗗浘
+  const fieldElement = document.querySelector(`[data-field-key="${currentField.key}"]`);
+  if (fieldElement) {
+    fieldElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
+    
+    // 鑷姩鑱氱劍鍒拌緭鍏ユ
+    const input = fieldElement.querySelector('input');
+    if (input) input.focus();
+  }
+}
+
+// 鑱氱劍鍒版寚瀹氬瓧娈�
+function focusOnField(field) {
+  // 鏇存柊褰撳墠鍖归厤椤�
+  const matchIndex = matches.value.indexOf(field);
+  if (matchIndex >= 0) {
+    currentMatchIndex.value = matchIndex;
+  }
+  
+  // 鎵惧埌瀵瑰簲鐨凞OM鍏冪礌骞惰仛鐒�
+  const fieldElement = document.querySelector(`[data-field-key="${field.key}"]`);
+  if (fieldElement) {
+    const input = fieldElement.querySelector('input');
+    if (input) input.focus();
+  }
+}
+
+// 妫�鏌ュ瓧娈垫槸鍚︽渶杩戣缂栬緫
+function isRecentlyEdited(key) {
+  return recentlyEdited.value.includes(key);
+}
+
+// 澶勭悊瀛楁鍙樻洿
+function handleFieldChange(field) {
+  // 璁板綍瀛楁鍙樻洿鏃堕棿
+  const now = new Date().getTime();
+  
+  // 妫�鏌ュ瓧娈垫槸鍚﹀凡鍦ㄦ渶杩戠紪杈戝垪琛ㄤ腑
+  const existingIndex = recentlyEdited.value.findIndex(key => key === field.key);
+  
+  if (existingIndex > -1) {
+    // 灏嗗瓧娈电Щ鍒版渶杩戠紪杈戝垪琛ㄧ殑椤堕儴
+    recentlyEdited.value.splice(existingIndex, 1);
+    recentlyEdited.value.unshift(field.key);
+  } else {
+    // 娣诲姞鍒版渶杩戠紪杈戝垪琛ㄧ殑椤堕儴
+    recentlyEdited.value.unshift(field.key);
+    
+    // 闄愬埗鍒楄〃闀垮害
+    if (recentlyEdited.value.length > 5) {
+      recentlyEdited.value.pop();
+    }
+  }
+}
+
+
+// 鐩戝惉鎼滅储鍙樺寲
+watch(searchQuery, (newValue, oldValue) => {
+  if (newValue !== oldValue) {
+    handleSearch();
+  }
+});
+
+</script>
+
+<template>
+<div class="highlight-form">
+    <!-- 椤堕儴宸ュ叿鏍� -->
+    <div class="toolbar">
+      <div class="search-container">
+        <input 
+          v-model="searchQuery" 
+          placeholder="鎼滅储瀛楁鍚嶇О鎴栨弿杩�..." 
+          @keyup="handleSearch"
+        >
+        <button @click="clearSearch">
+          <i class="fa fa-times"></i>
+        </button>
+      </div>
+      
+      <div class="quick-actions">
+        <button @click="goToNextMatch">
+          <i class="fa fa-arrow-down"></i> 涓嬩竴涓�
+        </button>
+        <button @click="goToPrevMatch">
+          <i class="fa fa-arrow-up"></i> 涓婁竴涓�
+        </button>
+        <span v-if="searchQuery">
+          鎵惧埌 {{ matches.length }} 涓尮閰嶉」 (褰撳墠 {{ currentMatchIndex + 1 }})
+        </span>
+      </div>
+    </div>
+    
+    <!-- 瀹屾暣琛ㄥ崟鍖哄煙 -->
+    <div class="form-content">
+      <!-- 绫诲埆鍒嗛殧 -->
+      <div v-for="category in categories" :key="category" class="category-section">
+        <h3 class="category-title">{{ category }}</h3>
+        
+        <div class="fields-grid">
+          <div 
+            v-for="field in getFieldsByCategory(category)" 
+            :key="field.key"
+            class="form-field"
+            :class="{ 
+              'search-match': isMatch(field),
+              'current-match': isCurrentMatch(field),
+              'recently-edited': isRecentlyEdited(field.key)
+            }"
+            @click="focusOnField(field)"
+          >
+            <div class="field-header">
+              <span class="field-label">{{ field.label }}</span>
+              <span v-if="isRecentlyEdited(field.key)" class="recent-tag">鏈�杩戠紪杈�</span>
+            </div>
+            
+            <div class="field-value">
+              <input 
+                v-model="formData[field.key]" 
+                :type="field.type"
+                @change="handleFieldChange(field)"
+              >
+            </div>
+            
+            <div class="field-description" v-if="field.description">
+              {{ field.description }}
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    
+  </div>
+</template>
+
+<style scoped lang="less">
+.highlight-form {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 20px;
+}
+
+.toolbar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+
+.search-container {
+  display: flex;
+  align-items: center;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.search-container input {
+  padding: 8px;
+  border: none;
+  width: 300px;
+}
+
+.search-container button {
+  padding: 8px 12px;
+  border: none;
+  background-color: #f0f0f0;
+  cursor: pointer;
+}
+
+.quick-actions {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.quick-actions button {
+  padding: 6px 10px;
+  border: 1px solid #ddd;
+  background-color: white;
+  cursor: pointer;
+  border-radius: 4px;
+}
+
+.category-section {
+  margin-bottom: 30px;
+}
+
+.category-title {
+  font-size: 1.2em;
+  font-weight: bold;
+  margin-bottom: 15px;
+  padding-bottom: 10px;
+  border-bottom: 1px solid #eee;
+}
+
+.fields-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+  gap: 15px;
+}
+
+.form-field {
+  padding: 15px;
+  border: 1px solid #eee;
+  border-radius: 4px;
+  transition: all 0.2s;
+  position: relative;
+}
+
+.search-match {
+  border-color: #42b983;
+  background-color: #f9f9f9;
+}
+
+.current-match {
+  border-color: #ff7a45;
+  box-shadow: 0 0 0 2px rgba(255, 122, 69, 0.2);
+  z-index: 1;
+}
+
+.recently-edited {
+  background-color: #fffbe6;
+}
+
+.field-header {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 8px;
+}
+
+.field-label {
+  font-weight: bold;
+}
+
+.recent-tag {
+  padding: 2px 6px;
+  border-radius: 4px;
+  font-size: 0.8em;
+  background-color: #fff7e6;
+  color: #fa8c16;
+}
+
+.field-value input {
+  width: 100%;
+  padding: 8px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+}
+
+.field-description {
+  margin-top: 8px;
+  color: #666;
+  font-size: 0.9em;
+}
+
+.form-footer {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.form-footer button {
+  margin-left: 10px;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/siteList/index.vue b/src/components/siteList/index.vue
index 5f06e3a..536fc45 100644
--- a/src/components/siteList/index.vue
+++ b/src/components/siteList/index.vue
@@ -3,6 +3,7 @@
 import YcTree from "./ycTree.vue";
 import getQueryString from "@/utils/getQueryString";
 import pinyinMatch from 'pinyin-match';
+import eventBus from "@/utils/eventBus";
 
 import {
   getStationTree,
@@ -58,6 +59,7 @@
 
 function toggleChange() {
   // emit("toggleChange");
+  eventBus.emit('toggleSiteList');
   hideFlag.value = !hideFlag.value;
 }
 
@@ -280,6 +282,7 @@
   width: 320px;
   position: relative;
   transition: all 0.5s ease;
+  z-index: 1;
   .btn {
     display: flex;
     position: absolute;
diff --git a/src/components/svgDiagram.vue b/src/components/svgDiagram.vue
index 5a53bda..385f6cb 100644
--- a/src/components/svgDiagram.vue
+++ b/src/components/svgDiagram.vue
@@ -133,7 +133,7 @@
 ];
 
 const state_k1 = ref(true);
-const state_k2 = ref(true);
+const state_k2 = ref(false);
 const state_k3 = ref(true);
 const currentCabinetIdx = ref(-1);
 const currentLockIdx = ref(-1);
@@ -144,31 +144,47 @@
 const viewInfo = ref({});
 
 const props = defineProps({
-  state: {
-    type: [Number, String],
-    default: 3,
+  data: {
+    type: Object,
+    default() { return {}},
   },
+  battRt: {
+    type: Object,
+    default() { return {}},
+  },
+});
+
+const state = computed(() => {
+  return props.data.devWorkstate;
 });
 
 const flowList = computed(() => {
   let res = [];
+  // 0	鐩磋繛鍏呯數
+  // 1	鍏呯數娴嬭瘯
+  // 2	鏀剧數娴嬭瘯
+  // 3	鍋滅數鏀剧數
+  // 4	鍐呴樆娴嬭瘯
 
-  switch(props.state) {
-    // 鏍稿鏀剧數
+  switch(state.value) {
+    // 鐩磋繛鍏呯數
     case 0:
-      res = line0;
+      res = line2;
       break;
     // 鏍稿鍏呯數
     case 1:
       res = line1;
       break;
-    // 鐩磋繛鍏呯數
+    // 鏍稿鏀剧數
     case 2:
-      res = line2;
+      res = line0;
       break;
     // 鍋滅數鏀剧數
     case 3:
       res = line3;
+      break;
+    default:
+      console.log('state', state.value, '=============');
       break;
   }
 
@@ -238,7 +254,6 @@
       ]"
       :color='lineColor'
     ></svg-line>
-    <!-- 124 194 -->
     <svg-dot-rect
       :offset="[252, 124]"
       width="124"
@@ -454,12 +469,12 @@
     ></svg-text>
     <svg-text
       :offset="[1100, 150]"
-      text="娓╁害:12掳C"
+      :text="`娓╁害:${data.devTemp}掳C`"
       textAnchor="middle"
     ></svg-text>
     <svg-text
       :offset="[918, 240]"
-      text="0.2A"
+      :text="`${battRt.groupCurr}A`"
       textAnchor="end"
     ></svg-text>
     <svg-line
diff --git a/src/components/ycTag.vue b/src/components/ycTag.vue
new file mode 100644
index 0000000..bf0f2d3
--- /dev/null
+++ b/src/components/ycTag.vue
@@ -0,0 +1,47 @@
+<script setup>
+import { ref } from "vue";
+
+
+</script>
+
+<template>
+  <div class="yc-tag">
+    <!-- <div class="content"> -->
+      <slot></slot>
+    <!-- </div> -->
+  </div>
+</template>
+
+<style scoped lang="less">
+.yc-tag {
+  // width: 200px;
+  // height: 60px;
+  height: 100%;
+  position: relative;
+  padding: 10px;
+  z-index: 0;
+  background: linear-gradient(#5cddf7) 12px 4px / calc(100% - 24px) 2px no-repeat,
+        linear-gradient(#5cddf7) 12px calc(100% - 4px) / calc(100% - 24px) 2px no-repeat,
+        linear-gradient(#5cddf7) 4px 12px / 2px calc(100% - 24px) no-repeat,
+        linear-gradient(#5cddf7) calc(100% - 4px) 12px / 2px calc(100% - 24px) no-repeat,
+        radial-gradient(circle, #5cddf7 0%, #5cddf7 60%, rgba(92,221,247, .4) 68%, transparent 68%) 0 0 / 10px 10px no-repeat,
+        radial-gradient(circle, #5cddf7 0%, #5cddf7 60%, rgba(92,221,247, .4) 68%, transparent 68%) 100% 100% / 10px 10px no-repeat,
+        radial-gradient(circle, transparent 20%, rgba(92,221,247, .4) 20%, #5cddf7 30%, #5cddf7 60%, rgba(92,221,247, .4) 68%, transparent 68%) 100% 0 / 10px 10px no-repeat,
+        radial-gradient(circle,  transparent 20%, rgba(92,221,247, .4) 20%, #5cddf7 30%,  #5cddf7 60%, rgba(92,221,247, .4) 68%, transparent 68%) 0 100% / 10px 10px no-repeat;
+  &::before {
+    position: absolute;
+    z-index: -1;
+    content: '';
+    left: 8px;
+    right: 8px;
+    top: 8px;
+    bottom: 8px;
+    background: #27658A;
+    border: 1px solid #5cddf7;
+    border-radius: 6px;
+  }
+  // .content {
+  //   height: 100%;
+  // }
+}
+</style>
\ No newline at end of file
diff --git a/src/hooks/useStationList.js b/src/hooks/useStationList.js
index edeeff8..e2fb23c 100644
--- a/src/hooks/useStationList.js
+++ b/src/hooks/useStationList.js
@@ -6,6 +6,7 @@
   getCountryByUid,
   getStationByUid,
   getPowerByUid,
+  getBattByUid,
 } from '@/api/station.js';
 
 
@@ -14,18 +15,29 @@
   const city = ref("");
   const country = ref("");
   const stationName = ref("");
+  const stationId = ref("");
   const powerId = ref("");
-  const lockName = ref("");
+  const battId = ref("");
   const proviceList = ref([]);
   const cityList = ref([]);
   const countryList = ref([]);
   const stationList = ref([]);
   const powerList = ref([]);
+  const battList = ref([]);
 
-  onMounted(() => {
-    getProviceList();
-    getStationList();
-    getPowerList();
+  const isManual = ref(false);
+
+  let loadPromise = null;
+
+  onMounted(async () => {
+    loadPromise = new Promise(async (resolve, reject) => {
+      await getProviceList();
+      await getStationList();
+      await getPowerList();
+      await getBattList();
+
+      resolve();
+    });
   });
 
   watch(
@@ -39,8 +51,9 @@
         city.value = "";
       }
       powerId.value = "";
-      lockName.value = "";
+      battId.value = "";
       getPowerList();
+      getBattList();
     }
   );
 
@@ -55,8 +68,9 @@
         country.value = "";
       }
       powerId.value = "";
-      lockName.value = "";
+      battId.value = "";
       getPowerList();
+      getBattList();
     }
   );
 
@@ -71,24 +85,31 @@
         stationName.value = "";
       }
       powerId.value = "";
-      lockName.value = "";
+      battId.value = "";
       getPowerList();
+      getBattList();
     }
   );
 
   watch(
     () => stationName.value,
-    (val) => {
-      if (val) {
-        powerId.value = "";
-        getPowerList();
-      } else {
-        powerList.value = [];
-        powerId.value = "";
+    async (val) => {
+      // if (val) {
+      //   powerId.value = "";
+      // } else {
+      //   powerList.value = [];
+      //   powerId.value = "";
+      // }
+      let station = stationList.value.find(v => v.stationName == val);
+      if (station) {
+        stationId.value = station.stationId;
       }
-      powerId.value = "";
-      lockName.value = "";
-      getPowerList();
+      if (!isManual.value) {
+        powerId.value = "";
+        battId.value = "";
+        await getPowerList();
+        await getBattList();
+      }
     }
   );
 
@@ -113,6 +134,7 @@
       }
       cityList.value = _list;
       // city.value = "";
+      return _list;
     });
   }
 
@@ -125,6 +147,7 @@
       }
       countryList.value = _list;
       // country.value = "";
+      return _list;
     });
   }
 
@@ -142,6 +165,7 @@
       }
       stationList.value = _list;
       // stationName.value = "";
+      return _list;
     });
   }
 
@@ -160,8 +184,31 @@
       }
       powerList.value = _list;
       // powerId.value = "";
+      return _list;
     });
   }
 
-  return { provice, city, country, stationName, powerId, proviceList, cityList, countryList, stationList, powerList, getProviceList, getCityList, getCountryList, getStationList, getPowerList };
+  function getBattList() {
+    let params = {
+      provice: provice.value || undefined,
+      city: city.value || undefined,
+      country: country.value || undefined,
+      stationName: stationName.value || undefined,
+    };
+    return getBattByUid(params).then((res) => {
+      let { code, data, data2 } = res;
+      let _list = [];
+      if (code && data) {
+        _list = data2;
+      }
+      battList.value = _list;
+      // powerId.value = "";
+      isManual.value = false;
+      return _list;
+    });
+  }
+
+  return { provice, city, country, stationName, stationId, powerId, battId, proviceList, cityList, countryList, stationList, powerList, battList, getProviceList, getCityList, getCountryList, getStationList, getPowerList, getBattList, isManual,
+    whenLoaded: () => loadPromise,
+  };
 };
diff --git a/src/icons/svg/arrow-right.svg b/src/icons/svg/arrow-right.svg
new file mode 100644
index 0000000..6ee936e
--- /dev/null
+++ b/src/icons/svg/arrow-right.svg
@@ -0,0 +1 @@
+<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M110.82799867-387.1474074l-251.73183788 249.77518224L513.70357252 511.95117175-140.90034903 1161.29898281l251.73183785 249.84842804 906.47876054-899.19623911L110.82799867-387.1474074 110.82799867-387.1474074zM110.82799867-387.1474074"></path></svg>
\ No newline at end of file
diff --git a/src/router/index.js b/src/router/index.js
index 7c785ff..332f8f2 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -1,7 +1,6 @@
 import { createRouter, createWebHashHistory } from 'vue-router'; // createWebHashHistory, createWebHistory
 // import type { Router, RouteRecordRaw, RouteComponent } from 'vue-router';
 
-// import devicesRouter from './modules/devices';
 // import generalRouter from './modules/general';
 import systemRouter from './modules/system';
 import datasRouter from './modules/datas';
diff --git a/src/router/modules/alarm.js b/src/router/modules/alarm.js
index e2163d1..c16fb66 100644
--- a/src/router/modules/alarm.js
+++ b/src/router/modules/alarm.js
@@ -34,6 +34,24 @@
       name: 'pwrAlarm',
       meta: { title: '鐢垫簮瀹炴椂鍛婅', icon: 'alarm', noCache: false }
     },
+    {
+      path: 'batt-setting',
+      component: () => import('@/views/alarm/battSetting.vue'),
+      name: 'battSetting',
+      meta: { title: '鐢垫睜鍛婅鍙傛暟璁剧疆', icon: 'alarm', noCache: false }
+    },
+    {
+      path: 'power-setting',
+      component: () => import('@/views/alarm/powerSetting.vue'),
+      name: 'powerSetting',
+      meta: { title: '鐢垫簮鍛婅鍙傛暟璁剧疆', icon: 'alarm', noCache: false }
+    },
+    {
+      path: 'early-Warning-analysis',
+      component: () => import('@/views/alarm/earlyWarningAnalysis.vue'),
+      name: 'earlyWarningAnalysis',
+      meta: { title: '棰勮鍒嗘瀽绠$悊鐣岄潰', icon: 'alarm', noCache: false }
+    },
   ]
 };
 
diff --git a/src/router/modules/devices.js b/src/router/modules/devices.js
deleted file mode 100644
index b782fef..0000000
--- a/src/router/modules/devices.js
+++ /dev/null
@@ -1,60 +0,0 @@
-const Layout = () => import('@/layout/index.vue');
-
-const devicesRouter = {
-  path: '/device',
-  component: Layout,
-  redirect: 'noRedirect',
-  name: 'Device',
-  meta: {
-    title: '璁惧绠$悊',
-    icon: 'device-hdw'
-  },
-  children: [
-    {
-      path: 'realtime',
-      component: () => import('@/views/device/realtime/index.vue'),
-      name: 'Realtime',
-      meta: { title: '瀹炴椂鐩戞祴', icon: 'lock-hdw', noCache: false }
-    },
-    {
-      path: 'history',
-      component: () => import('@/views/device/history/index.vue'),
-      name: 'History',
-      meta: { title: '鍘嗗彶鏁版嵁', icon: 'lock-hdw', noCache: false }
-    },
-    {
-      path: 'lock',
-      component: () => import('@/views/device/locks/index.vue'),
-      name: 'LockManage',
-      meta: { title: '閿佸叿绠$悊', icon: 'lock-hdw', noCache: false }
-    },
-    // {
-    //   path: 'station',
-    //   component: () => import('@/views/device/station/index.vue'),
-    //   name: 'stationManage',
-    //   meta: { title: '鏈烘埧绠$悊', icon: 'lock-hdw', noCache: false }
-    // },
-    {
-      path: 'task',
-      component: () => import('@/views/device/locks/task.vue'),
-      name: 'LockTask',
-      meta: { title: '钃濈墮寮�鍚鍒�', icon: 'lock-hdw', noCache: false }
-    },
-    {
-      path: 'key',
-      component: () => import('@/views/device/keys/index.vue'),
-      // component: () => import('@/views/test/index2.vue'),
-      name: 'KeyManage',
-      meta: { title: '鐢靛瓙鍗$鐞�', icon: 'key-hdw', noCache: false }
-    },
-    {
-      path: 'thread',
-      component: () => import('@/views/device/threadManage.vue'),
-      // component: () => import('@/views/test/index2.vue'),
-      name: 'threadManage',
-      meta: { title: '鍚庡彴绾跨▼绠$悊', icon: 'key-hdw', noCache: false }
-    }
-  ]
-};
-
-export default devicesRouter;
diff --git a/src/router/modules/statistics.js b/src/router/modules/statistics.js
index a317d65..f125058 100644
--- a/src/router/modules/statistics.js
+++ b/src/router/modules/statistics.js
@@ -65,6 +65,48 @@
       name: 'battCompare1',
       meta: { title: '钃勭數姹犵粍瀵规瘮鍒嗘瀽2', icon: 'component', noCache: false, hidden: true }
     },
+    {
+      path: 'batt-compare2',
+      component: () => import('@/views/statistics/battCompare2.vue'),
+      name: 'battCompare2',
+      meta: { title: '钃勭數姹犵粍瀵规瘮鍒嗘瀽3', icon: 'component', noCache: false, hidden: true }
+    },
+    {
+      path: 'dis-year',
+      component: () => import('@/views/statistics/disYear.vue'),
+      name: 'disYear',
+      meta: { title: '鏈勾搴﹀凡鏀剧數', icon: 'component', noCache: false, }
+    },
+    {
+      path: 'nodis-year',
+      component: () => import('@/views/statistics/nodisYear.vue'),
+      name: 'nodisYear',
+      meta: { title: '鏈勾搴︽湭鏀剧數', icon: 'component', noCache: false, }
+    },
+    {
+      path: 'power-good',
+      component: () => import('@/views/statistics/powerGood.vue'),
+      name: 'powerGood',
+      meta: { title: '浼樿壇鐢垫簮鏁伴噺缁熻', icon: 'component', noCache: false, }
+    },
+    {
+      path: 'batt-good',
+      component: () => import('@/views/statistics/battGood.vue'),
+      name: 'battGood',
+      meta: { title: '浼樿壇鐢垫睜缁勬暟缁熻', icon: 'component', noCache: false, }
+    },
+    {
+      path: 'batt-bad',
+      component: () => import('@/views/statistics/battBad.vue'),
+      name: 'battBad',
+      meta: { title: '鍔e寲鐢垫睜缁勬暟缁熻', icon: 'component', noCache: false, }
+    },
+    {
+      path: 'batt-damage',
+      component: () => import('@/views/statistics/battDamage.vue'),
+      name: 'battDamage',
+      meta: { title: '鎹熷潖鐢垫睜缁勬暟缁熻', icon: 'component', noCache: false, }
+    },
   ]
 };
 
diff --git a/src/styles/blue.css b/src/styles/blue.css
index fdfadf7..889e9d4 100644
--- a/src/styles/blue.css
+++ b/src/styles/blue.css
@@ -215,6 +215,9 @@
 .el-transfer .el-checkbox__input.is-checked .el-checkbox__inner::after {
   border-color: #333;
 }
+.opacity1.opacity1.opacity1 {
+  opacity: 1;
+}
 .page-filter {
   display: table;
   background: #071426;
diff --git a/src/styles/blue.less b/src/styles/blue.less
index 0beb255..aad9de1 100644
--- a/src/styles/blue.less
+++ b/src/styles/blue.less
@@ -271,6 +271,10 @@
   }
 }
 
+.opacity1.opacity1.opacity1 {
+  opacity: 1;
+}
+
 // 鎼滅储鏉′欢鏍峰紡
 .page-filter {
   display: table;
diff --git a/src/utils/const/const_digit.js b/src/utils/const/const_digit.js
index 195535c..28b7849 100644
--- a/src/utils/const/const_digit.js
+++ b/src/utils/const/const_digit.js
@@ -6,4 +6,8 @@
   VOL: 3,
   // 鐢垫祦
   CURR: 3,
+  // 娓╁害
+  TEMP: 1,
+  // 瀹归噺
+  CAP: 2,
 }
\ No newline at end of file
diff --git a/src/utils/eventBus.js b/src/utils/eventBus.js
new file mode 100644
index 0000000..48f5f8b
--- /dev/null
+++ b/src/utils/eventBus.js
@@ -0,0 +1,20 @@
+import mitt from 'mitt';
+
+const emitter = mitt();
+
+const eventBus = {
+  // 鍙戦�佷簨浠�
+  emit(name, data) {
+    emitter.emit(name, data);
+  },
+  // 璁㈤槄浜嬩欢
+  on(name, callback) {
+    emitter.on(name, callback);
+  },
+  // 鍙栨秷璁㈤槄浜嬩欢
+  off(name, callback) {
+    emitter.off(name, callback);
+  }
+}
+
+export default eventBus;
\ No newline at end of file
diff --git a/src/utils/getBinaryDigits.js b/src/utils/getBinaryDigits.js
new file mode 100644
index 0000000..7e728d1
--- /dev/null
+++ b/src/utils/getBinaryDigits.js
@@ -0,0 +1,23 @@
+/**
+ *  灏嗘暣鏁拌浆涓轰簩杩涘埗鏁� 骞惰緭鍑烘瘡涓�浣嶇殑鍊煎埌鏁扮粍涓� 浠庝綆浣嶅埌楂樹綅 浜岃繘鍒朵綅鏁板彲鎸囧畾 锛堝鐨勮鍒� 涓嶅鐨勮ˉ0锛�
+ */
+export default function getBinaryDigits(num = 0, bits = 16) {
+  // 灏嗘暟鍊艰浆鎹负浜岃繘鍒跺瓧绗︿覆
+  let binaryStr = num.toString(2);
+  let len = binaryStr.length;
+  // 浣嶆暟杩囧鐨勮鍒� 涓嶅鐨勮ˉ0
+  if (len > bits) {
+    let start = len - bits;
+    binaryStr = binaryStr.slice(start);
+  } else if (len < bits) {
+    let len0 = bits - len;
+    let preStr = new Array(len0 + 1).join("0");
+    binaryStr = preStr + binaryStr;
+  }
+  // 灏嗕簩杩涘埗瀛楃涓茶浆鎹负鏁扮粍
+  let binaryArray = binaryStr
+    .split("")
+    .map((v) => v * 1)
+    .reverse();
+  return binaryArray;
+}
diff --git a/src/utils/hexToRgba.js b/src/utils/hexToRgba.js
new file mode 100644
index 0000000..dfbf72f
--- /dev/null
+++ b/src/utils/hexToRgba.js
@@ -0,0 +1,17 @@
+export default function hexToRgba(hex, alpha = 1) {
+  // 鍘婚櫎 # 绗﹀彿
+  hex = hex.replace('#', '');
+
+  // 澶勭悊 3 浣嶅拰 6 浣嶅崄鍏繘鍒堕鑹茬爜
+  if (hex.length === 3) {
+    hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
+  }
+
+  // 瑙f瀽绾€�佺豢銆佽摑閫氶亾鐨勫��
+  const r = parseInt(hex.slice(0, 2), 16);
+  const g = parseInt(hex.slice(2, 4), 16);
+  const b = parseInt(hex.slice(4, 6), 16);
+
+  // 鐢熸垚 rgba 瀛楃涓�
+  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
+}
\ No newline at end of file
diff --git a/src/views/alarm/battAlarmParams.vue b/src/views/alarm/battAlarmParams.vue
new file mode 100644
index 0000000..0719667
--- /dev/null
+++ b/src/views/alarm/battAlarmParams.vue
@@ -0,0 +1,56 @@
+<script setup>
+import { ref, onMounted } from "vue";
+import alarmParams from '@/components/alarmParams.vue';
+
+import useElement from "@/hooks/useElement.js";
+	const { $loading, $message, $confirm } = useElement();
+
+const emit = defineEmits(['close']);
+
+import {
+  // getBattAlmParam,
+} from '@/api/control.js';
+
+const props = defineProps({
+  id: {
+    type: [String, Number],
+    default: '',
+  },
+  visible: {
+    type: Boolean,
+    default: false
+  },
+});
+
+const alarmTypeList = ref([]);
+
+async function getParams() {
+  // if (!props.id) return;
+  // let loading = $loading();
+  // let res = await getBattAlmParam(props.id);
+  // // console.log('res', res, '=============');
+  // let { code, data, data2 } = res;
+  // let list = [];
+  // if (code && data) {
+  //   list = data2;
+  // }
+  // loading.close();
+  // alarmTypeList.value = list;
+}
+
+function close () {
+  emit('close');
+}
+
+onMounted(() => {
+  getParams();
+});
+</script>
+
+<template>
+  <alarm-params :list="alarmTypeList" @update:visible="close" @change="getParams"></alarm-params>
+</template>
+
+<style scoped lang="less">
+
+</style>
\ No newline at end of file
diff --git a/src/views/alarm/battSetting.vue b/src/views/alarm/battSetting.vue
new file mode 100644
index 0000000..034ecf0
--- /dev/null
+++ b/src/views/alarm/battSetting.vue
@@ -0,0 +1,636 @@
+<script setup name="battSetting">
+import { ref, reactive, onMounted, computed, nextTick, watch, onActivated } from "vue";
+import { storeToRefs } from "pinia";
+import { Search, Plus } from "@element-plus/icons-vue";
+import ycCard from "@/components/ycCard/index.vue";
+// import addEdit from "./addEdit.vue";
+import { ElMessage } from "element-plus";
+import useElement from "@/hooks/useElement.js";
+import { useUserStore } from '@/store/user';
+import getQueryString from "@/utils/getQueryString";
+
+import alarmParams from '@/components/alarmParams.vue';
+
+import useStation from "@/hooks/useStationList.js";
+const { provice, city, country, stationName, stationId, battId,
+	proviceList, cityList, countryList, stationList, battList, isManual,
+  getBattList,
+  whenLoaded,
+} = useStation();
+
+import powerTypes from '@/utils/const/const_powerType.js';
+import { ExportFile } from '@/utils/exportFile.js';
+import { useRouter } from "vue-router";
+const router = useRouter();
+
+const userStore = useUserStore();
+const { uid, uname } = storeToRefs(userStore);
+import moment from 'moment';
+
+
+import {
+	confirmBattAlm,
+	getBattAlmHis,
+	getBattAlmParam,
+  getBattAlmParamToExport,
+} from "@/api/alarm.js";
+
+import {
+	getBattAlarmIdType,
+} from "@/api/station.js";
+
+
+const { $loading, $message, $confirm } = useElement();
+const flag = ref(Math.random());
+
+
+const headers = [
+	{
+		prop: "fullName",
+		label: "鏈烘埧鍚嶇О",
+		width: "220",
+	},
+	{
+		prop: "devName",
+		label: "璁惧鍚嶇О",
+		width: "80",
+	},
+	{
+		prop: "battgroupName",
+		label: "鐢垫睜缁勫悕绉�",
+		width: "120",
+	},
+	{
+		prop: "almName",
+		label: "鍛婅鍚嶇О",
+		width: "120",
+	},
+	{
+		prop: "almHighCoeUpper",
+		label: "涓婁笂闄愰槇鍊�",
+		width: "120",
+	},
+	{
+		prop: "almHighLevelUpperStr",
+		label: "涓婁笂闄愮瓑绾�",
+		width: "120",
+	},
+	{
+		prop: "almHighCoeUpperEnStr",
+		label: "涓婁笂闄愪娇鑳�",
+		width: "120",
+	},
+	{
+		prop: "almHighCoe",
+		label: "涓婇檺闃堝��",
+		width: "120",
+	},
+	{
+		prop: "almHighLevelStr",
+		label: "涓婇檺绛夌骇",
+		width: "120",
+	},
+	{
+		prop: "almHighEnStr",
+		label: "涓婇檺浣胯兘",
+		width: "120",
+	},
+	{
+		prop: "almLowCoe",
+		label: "涓嬮檺闃堝��",
+		width: "120",
+	},
+	{
+		prop: "almLowLevelStr",
+		label: "涓嬮檺绛夌骇",
+		width: "120",
+	},
+	{
+		prop: "almLowEnStr",
+		label: "涓嬮檺浣胯兘",
+		width: "120",
+	},
+	{
+		prop: "almLowCoeLower",
+		label: "涓嬩笅闄愰槇鍊�",
+		width: "120",
+	},
+	{
+		prop: "almLowLevelLowerStr",
+		label: "涓嬩笅闄愮瓑绾�",
+		width: "120",
+	},
+	{
+		prop: "almLowCoeLowerEnStr",
+		label: "涓嬩笅闄愪娇鑳�",
+		width: "120",
+	},
+];
+
+// const pageCurr = ref(1);
+// const pageSize = ref(10);
+// const total = ref(0);
+const addEditVisible = ref(false);
+const dialogTitle = ref("");
+const datas = reactive({
+	tableData: [],
+	rowData: {},
+});
+
+const currentRow = ref({});
+
+const alarmTypeList = ref([]);
+
+const alarmId = ref('');
+
+function getList() {
+	let params = {
+		almIdList: alarmId.value ? [alarmId.value] : undefined,
+		provice: provice.value || undefined,
+		city: city.value || undefined,
+		country: country.value || undefined,
+		stationId: stationId.value || undefined,
+		battgroupId: battId.value || undefined,
+	};
+
+  if (!battId.value) {
+    $message.error('璇烽�夋嫨鐢垫睜缁�');
+    return false;
+  }
+
+  let loading = $loading();
+	getBattAlmParam(params).then((res) => {
+		let { code, data, data2, data3 } = res;
+		let list = [];
+		// let _total = 0;
+    loading.close();
+		if (code && data) {
+			// console.log(data);
+      let bInf = data3;
+			list = data2.map(v => ({
+        ...v,
+        fullName: bInf.fullName,
+        devName: bInf.devName,
+        battgroupName: bInf.battgroupName,
+				almHighLevelUpperStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almHighLevelUpper],
+				almHighCoeUpperEnStr: ['涓嶅惎鐢�', '鍚敤'][v.almHighCoeUpperEn],
+				almHighLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almHighLevel],
+				almHighEnStr: ['涓嶅惎鐢�', '鍚敤'][v.almHighEn],
+				almLowLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almLowLevel],
+				almLowEnStr: ['涓嶅惎鐢�', '鍚敤'][v.almLowEn],
+				almLowLevelLowerStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almLowLevelLower],
+				almLowCoeLowerEnStr: ['涓嶅惎鐢�', '鍚敤'][v.almLowCoeLowerEn],
+			}));
+			// _total = data2.total;
+		}
+		datas.tableData = list;
+		// total.value = _total;
+	})
+		.catch((err) => {
+			console.log(err);
+		});
+}
+
+
+
+// 鏌ヨ鍛婅绫诲瀷
+async function getAlarmType() {
+	let res = await getBattAlarmIdType();
+	let { code, data, data2 } = res;
+	let list = [];
+	if (code && data) {
+		list = Object.keys(data2).map((key) => ({ value: key, label: data2[key] }));
+	}
+	alarmTypeList.value = list;
+}
+
+
+// 灞曠ず鏁版嵁鏁伴噺
+// function handleSizeChange(val) {
+// 	pageSize.value = val;
+// 	getList();
+// }
+// 缈婚〉
+// function handleCurrentChange(val) {
+// 	pageCurr.value = val;
+// 	getList();
+// }
+
+function edit(record) {
+  dialogTitle.value = `缂栬緫鍛婅鍙傛暟--${record.alarmName}`;
+  addEditVisible.value = true;
+  currentRow.value = record;
+  // console.log('record', record, '=============');
+  
+}
+
+function onOk() {
+	addEditVisible.value = false;
+	// handleCurrentChange(1);
+}
+function onCanel() {
+	addEditVisible.value = false;
+}
+
+function exportExcel() {
+	let _headers = headers.map(v => {
+		let prop = v.prop;
+		let label = v.label;
+		if (prop == 'almIsConfirmed') {
+			prop = 'almIsConfirmedStr';
+		}
+		return {
+			prop,
+			label
+		};
+	});
+	ExportFile(_headers, datas.tableData, "鐢垫睜鍛婅鍙傛暟");
+}
+
+async function exportExcelAll() {
+  let res = await getBattAlmParamToExport();
+  let { code, data, data2 } = res;
+  let list = [];
+  if (code && data) {
+			list = data2.map(v => ({
+        ...v,
+				almHighLevelUpperStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almHighLevelUpper],
+				almHighCoeUpperEnStr: ['涓嶅惎鐢�', '鍚敤'][v.almHighCoeUpperEn],
+				almHighLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almHighLevel],
+				almHighEnStr: ['涓嶅惎鐢�', '鍚敤'][v.almHighEn],
+				almLowLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almLowLevel],
+				almLowEnStr: ['涓嶅惎鐢�', '鍚敤'][v.almLowEn],
+				almLowLevelLowerStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almLowLevelLower],
+				almLowCoeLowerEnStr: ['涓嶅惎鐢�', '鍚敤'][v.almLowCoeLowerEn],
+			}));
+  }
+  let _headers = headers.map(v => {
+    let prop = v.prop;
+    let label = v.label;
+    return {
+      prop,
+      label
+    };
+  });
+  ExportFile(_headers, list, "鐢垫睜鍛婅鍙傛暟-鍏ㄩ儴");
+}
+
+onMounted(async () => {
+	await getAlarmType();
+	// getList();
+   console.log('stationList', stationList, '===========1==');
+});
+
+onActivated(async () => {
+  let pageFlag = getQueryString("pageFlag");
+  // console.log('pageFlag', pageFlag, flag.value, '=============');
+  await nextTick();
+  await whenLoaded();
+  // console.log('battList', JSON.stringify(battList.value), battList.value, '=============');
+  
+  if (pageFlag && pageFlag != flag.value) {
+    // let provice, city, country, stationName, battId;
+    
+    if (getQueryString('stationId')) {
+      let statId = getQueryString('stationId');
+      let stat = stationList.value.find(v => v.stationId == statId);
+      if (stat) {
+        isManual.value = true;
+        stationName.value = stat.stationName;
+        await getBattList();
+      }
+    }
+    if (getQueryString('battgroupId')) {
+      battId.value = getQueryString('battgroupId') * 1;
+      // console.log('battId', battId.value, battList.value, '=============');
+    }
+    getList();
+    flag.value = pageFlag;
+  }
+});
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+      </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 8}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鐢垫睜缁勫悕绉�</div>
+                <div class="value">
+                  <el-select
+                    v-model="battId"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨鐢垫睜缁�"
+                  >
+                    <el-option
+                      v-for="item in battList"
+                      :key="'l4_' + item.battgroupId"
+                      :label="`${item.devName}-${item.battgroupName}`"
+                      :value="item.battgroupId"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍛婅鍚嶇О</div>
+                <div class="value">
+                  <el-select
+                    v-model="alarmId"
+                    size="small"
+                    clearable
+                    placeholder="璇烽�夋嫨鍛婅鍚嶇О"
+                  >
+                    <el-option
+                      v-for="item in alarmTypeList"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table
+                  class="yc-table"
+                  stripe
+                  height="100%"
+                  size="small"
+                  :data="datas.tableData"
+                  style="width: 100%"
+                >
+                  <el-table-column
+                    type="index"
+                    fixed="left"
+                    label="搴忓彿"
+                    width="60"
+                  ></el-table-column>
+                  <el-table-column
+                    v-for="header in headers"
+                    :key="header.prop"
+                    :prop="header.prop"
+                    :label="header.label"
+                    :min-width="header.width"
+                    align="center"
+                  >
+                    <template #default="scope">
+                      <template v-if="header.prop == 'almIsConfirmed'">
+                        <el-checkbox
+                          disabled
+                          :checked="scope.row[header.prop] == 1"
+                        ></el-checkbox>
+                      </template>
+                      <template v-else>
+                        {{ scope.row[header.prop] || '--' }}
+                      </template>
+                    </template>
+                  </el-table-column>
+                  <el-table-column
+                    label="鎿嶄綔"
+                    fixed="right"
+                    width="240"
+                    align="center"
+                  >
+                    <template #default="scope">
+                      <el-button
+                        type="primary"
+                        size="small"
+                        @click="edit(scope.row)"
+                        >淇敼</el-button
+                      >
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button
+                type="primary"
+                round
+                size="small"
+                @click="getList"
+                :icon="Search"
+                >鏌ヨ</el-button
+              >
+            </div>
+            <div class="el-page-container">
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel"
+                >瀵煎嚭</el-button
+              >
+              <el-button type="primary" round size="small" @click="exportExcelAll"
+                >瀵煎嚭鍏ㄩ儴</el-button
+              >
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer"></div>
+    <!-- 寮圭獥 -->
+    <el-dialog
+      :title="dialogTitle"
+      v-model="addEditVisible"
+      top="0"
+      :close-on-click-modal="false"
+      class="dialog-center"
+      width="860px"
+      center
+    >
+      <alarm-params
+        v-if="addEditVisible"
+        :info="currentRow"
+        @change="getList"
+        v-model:visible="addEditVisible"
+      ></alarm-params>
+    </el-dialog>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+
+    .flex-row {
+      display: flex;
+      align-items: center;
+
+      :deep(.el-checkbox) {
+        color: #fff;
+      }
+
+      .group {
+        margin-left: 30px;
+      }
+    }
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+</style>
diff --git a/src/views/alarm/earlyWarningAnalysis.vue b/src/views/alarm/earlyWarningAnalysis.vue
new file mode 100644
index 0000000..0f27387
--- /dev/null
+++ b/src/views/alarm/earlyWarningAnalysis.vue
@@ -0,0 +1,644 @@
+<script setup name="earlyWarningAnalysis">
+import { ref, reactive, onMounted, computed, nextTick, watch, onActivated } from "vue";
+import { storeToRefs } from "pinia";
+import { Search, Plus } from "@element-plus/icons-vue";
+import ycCard from "@/components/ycCard/index.vue";
+// import addEdit from "./addEdit.vue";
+import { ElMessage } from "element-plus";
+import useElement from "@/hooks/useElement.js";
+import { useUserStore } from '@/store/user';
+import getQueryString from "@/utils/getQueryString";
+
+import alarmParams from '@/components/pwrAlarmParams.vue';
+
+import useStation from "@/hooks/useStationList.js";
+const { provice, city, country, stationName, stationId, powerId,
+	proviceList, cityList, countryList, stationList, powerList, isManual,
+  getPowerList,
+  whenLoaded,
+} = useStation();
+
+import powerTypes from '@/utils/const/const_powerType.js';
+import { ExportFile } from '@/utils/exportFile.js';
+import { useRouter } from "vue-router";
+const router = useRouter();
+
+const userStore = useUserStore();
+const { uid, uname } = storeToRefs(userStore);
+import moment from 'moment';
+
+
+import {
+	confirmBattAlm,
+	getBattAlmHis,
+	getPwrAlmParam,
+  getPwrAllAlmParam,
+} from "@/api/alarm.js";
+
+import {
+  getPowerAlmIdType,
+} from "@/api/station.js";
+
+
+const { $loading, $message, $confirm } = useElement();
+const flag = ref(Math.random());
+
+
+const headers = [
+	{
+		prop: "fullName",
+		label: "鏈烘埧鍚嶇О",
+		width: "220",
+	},
+	{
+		prop: "powerName",
+		label: "鐢垫簮鍚嶇О",
+		width: "80",
+	},
+	{
+		prop: "alarmName",
+		label: "鍛婅鍚嶇О",
+		width: "160",
+	},
+	{
+		prop: "alarmLimithUpper",
+		label: "涓婁笂闄愰槇鍊�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimithUpperLevelStr",
+		label: "涓婁笂闄愮瓑绾�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimithUpperEnStr",
+		label: "涓婁笂闄愪娇鑳�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimith",
+		label: "涓婇檺闃堝��",
+		width: "120",
+	},
+	{
+		prop: "alarmLimithLevelStr",
+		label: "涓婇檺绛夌骇",
+		width: "120",
+	},
+	{
+		prop: "alarmLimithEnStr",
+		label: "涓婇檺浣胯兘",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitl",
+		label: "涓嬮檺闃堝��",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlLevelStr",
+		label: "涓嬮檺绛夌骇",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlEnStr",
+		label: "涓嬮檺浣胯兘",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlLower",
+		label: "涓嬩笅闄愰槇鍊�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlLowerLevelStr",
+		label: "涓嬩笅闄愮瓑绾�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlLowerEnStr",
+		label: "涓嬩笅闄愪娇鑳�",
+		width: "120",
+	},
+];
+
+// const pageCurr = ref(1);
+// const pageSize = ref(10);
+// const total = ref(0);
+const addEditVisible = ref(false);
+const dialogTitle = ref("");
+const datas = reactive({
+	tableData: [],
+	rowData: {},
+});
+
+const currentRow = ref({});
+
+const alarmTypeList = ref([]);
+
+const alarmId = ref('');
+
+function getList() {
+	let params = {
+		almIdList: alarmId.value ? [alarmId.value] : undefined,
+		provice: provice.value || undefined,
+		city: city.value || undefined,
+		country: country.value || undefined,
+		stationId: stationId.value || undefined,
+		powerId: powerId.value || undefined,
+	};
+
+  if (!powerId.value) {
+    $message.error('璇烽�夋嫨鐢垫簮');
+    return false;
+  }
+
+  let loading = $loading();
+	getPwrAlmParam(params).then((res) => {
+		let { code, data, data2, data3 } = res;
+		let list = [];
+		// let _total = 0;
+    loading.close();
+		if (code && data) {
+			// console.log(data);
+      let bInf = data3;
+			list = data2.map(v => ({
+        ...v,
+        fullName: bInf.fullName,
+        powerName: bInf.powerName,
+				alarmLimithUpperLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimithUpperLevel],
+				alarmLimithUpperEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimithUpperEn],
+				alarmLimithLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimithLevel],
+				alarmLimithEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimithEn],
+				alarmLimitlLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimitlLevel],
+				alarmLimitlEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimitlEn],
+				alarmLimitlLowerLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimitlLowerLevel],
+				alarmLimitlLowerEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimitlLowerEn],
+			}));
+			// _total = data2.total;
+		}
+		datas.tableData = list;
+		// total.value = _total;
+	})
+		.catch((err) => {
+			console.log(err);
+		});
+}
+
+
+
+// 鏌ヨ鍛婅绫诲瀷
+async function getAlarmType() {
+	let res = await getPowerAlmIdType();
+	let { code, data, data2 } = res;
+	let list = [];
+	if (code && data) {
+		Object.keys(data2).map((key) => {
+      Object.keys(data2[key]).map((key2) => {
+        list.push({
+          value: key2,
+          label: data2[key][key2]
+        });
+      })
+    });
+	}
+	alarmTypeList.value = list;
+}
+
+
+// 灞曠ず鏁版嵁鏁伴噺
+// function handleSizeChange(val) {
+// 	pageSize.value = val;
+// 	getList();
+// }
+// 缈婚〉
+// function handleCurrentChange(val) {
+// 	pageCurr.value = val;
+// 	getList();
+// }
+
+const alarmType = ref(0);
+
+function edit(record) {
+  dialogTitle.value = `缂栬緫鍛婅鍙傛暟--${record.alarmName}`;
+  alarmType.value = record.alarmType;
+  addEditVisible.value = true;
+  currentRow.value = record;
+  // console.log('record', record, '=============');
+  
+}
+
+function onOk() {
+	addEditVisible.value = false;
+	// handleCurrentChange(1);
+}
+function onCanel() {
+	addEditVisible.value = false;
+}
+
+function exportExcel() {
+	let _headers = headers.map(v => {
+		let prop = v.prop;
+		let label = v.label;
+		if (prop == 'almIsConfirmed') {
+			prop = 'almIsConfirmedStr';
+		}
+		return {
+			prop,
+			label
+		};
+	});
+	ExportFile(_headers, datas.tableData, "鐢垫簮鍛婅鍙傛暟");
+}
+
+async function exportExcelAll() {
+  let res = await getPwrAllAlmParam();
+  let { code, data, data2 } = res;
+  let list = [];
+  if (code && data) {
+			list = data2.map(v => ({
+        ...v,
+				alarmLimithUpperLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimithUpperLevel],
+				alarmLimithUpperEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimithUpperEn],
+				alarmLimithLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimithLevel],
+				alarmLimithEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimithEn],
+				alarmLimitlLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimitlLevel],
+				alarmLimitlEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimitlEn],
+				alarmLimitlLowerLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimitlLowerLevel],
+				alarmLimitlLowerEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimitlLowerEn],
+			}));
+  }
+  let _headers = headers.map(v => {
+    let prop = v.prop;
+    let label = v.label;
+    return {
+      prop,
+      label
+    };
+  });
+  ExportFile(_headers, list, "鐢垫簮鍛婅鍙傛暟-鍏ㄩ儴");
+}
+
+onMounted(async () => {
+	await getAlarmType();
+	// getList();
+   console.log('stationList', stationList, '===========1==');
+});
+
+onActivated(async () => {
+  let pageFlag = getQueryString("pageFlag");
+  // console.log('pageFlag', pageFlag, flag.value, '=============');
+  await nextTick();
+  await whenLoaded();
+  
+  if (pageFlag && pageFlag != flag.value) {
+    // let provice, city, country, stationName, battId;
+    
+    if (getQueryString('stationId')) {
+      let statId = getQueryString('stationId');
+      let stat = stationList.value.find(v => v.stationId == statId);
+      if (stat) {
+        isManual.value = true;
+        stationName.value = stat.stationName;
+        await getPowerList();
+      }
+    }
+    if (getQueryString('powerId')) {
+      powerId.value = getQueryString('powerId') * 1;
+      // console.log('battId', battId.value, battList.value, '=============');
+    }
+    getList();
+    flag.value = pageFlag;
+  }
+});
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+      </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 8}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鐢垫簮鍚嶇О</div>
+                <div class="value">
+                  <el-select
+                    v-model="powerId"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨鐢垫簮"
+                  >
+                    <el-option
+                      v-for="item in powerList"
+                      :key="'l4_' + item.powerId"
+                      :label="`${item.stationName}-${item.powerName}`"
+                      :value="item.powerId"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍛婅鍚嶇О</div>
+                <div class="value">
+                  <el-select
+                    v-model="alarmId"
+                    size="small"
+                    clearable
+                    filterable
+                    placeholder="璇烽�夋嫨鍛婅鍚嶇О"
+                  >
+                    <el-option
+                      v-for="item in alarmTypeList"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table
+                  class="yc-table"
+                  stripe
+                  height="100%"
+                  size="small"
+                  :data="datas.tableData"
+                  style="width: 100%"
+                >
+                  <el-table-column
+                    type="index"
+                    fixed="left"
+                    label="搴忓彿"
+                    width="60"
+                  ></el-table-column>
+                  <el-table-column
+                    v-for="header in headers"
+                    :key="header.prop"
+                    :prop="header.prop"
+                    :label="header.label"
+                    :min-width="header.width"
+                    align="center"
+                  >
+                    <template #default="scope">
+                      <template v-if="header.prop == 'almIsConfirmed'">
+                        <el-checkbox
+                          disabled
+                          :checked="scope.row[header.prop] == 1"
+                        ></el-checkbox>
+                      </template>
+                      <template v-else>
+                        {{ scope.row[header.prop] || '--' }}
+                      </template>
+                    </template>
+                  </el-table-column>
+                  <el-table-column
+                    label="鎿嶄綔"
+                    fixed="right"
+                    width="240"
+                    align="center"
+                  >
+                    <template #default="scope">
+                      <el-button
+                        type="primary"
+                        size="small"
+                        @click="edit(scope.row)"
+                        >淇敼</el-button
+                      >
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button
+                type="primary"
+                round
+                size="small"
+                @click="getList"
+                :icon="Search"
+                >鏌ヨ</el-button
+              >
+            </div>
+            <div class="el-page-container">
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel"
+                >瀵煎嚭</el-button
+              >
+              <el-button type="primary" round size="small" @click="exportExcelAll"
+                >瀵煎嚭鍏ㄩ儴</el-button
+              >
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer">
+      
+    </div>
+    <!-- 寮圭獥 -->
+    <el-dialog
+      :title="dialogTitle"
+      v-model="addEditVisible"
+      top="0"
+      draggable
+      :close-on-click-modal="false"
+      class="dialog-center"
+      width="860px"
+      center
+    >
+      <alarm-params
+        v-if="addEditVisible"
+        :type="alarmType"
+        :info="currentRow"
+        @change="getList"
+        v-model:visible="addEditVisible"
+      ></alarm-params>
+    </el-dialog>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+
+    .flex-row {
+      display: flex;
+      align-items: center;
+
+      :deep(.el-checkbox) {
+        color: #fff;
+      }
+
+      .group {
+        margin-left: 30px;
+      }
+    }
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+</style>
diff --git a/src/views/alarm/powerSetting.vue b/src/views/alarm/powerSetting.vue
new file mode 100644
index 0000000..d56fa4f
--- /dev/null
+++ b/src/views/alarm/powerSetting.vue
@@ -0,0 +1,642 @@
+<script setup name="powerSetting">
+import { ref, reactive, onMounted, computed, nextTick, watch, onActivated } from "vue";
+import { storeToRefs } from "pinia";
+import { Search, Plus } from "@element-plus/icons-vue";
+import ycCard from "@/components/ycCard/index.vue";
+// import addEdit from "./addEdit.vue";
+import { ElMessage } from "element-plus";
+import useElement from "@/hooks/useElement.js";
+import { useUserStore } from '@/store/user';
+import getQueryString from "@/utils/getQueryString";
+
+import alarmParams from '@/components/pwrAlarmParams.vue';
+
+import useStation from "@/hooks/useStationList.js";
+const { provice, city, country, stationName, stationId, powerId,
+	proviceList, cityList, countryList, stationList, powerList, isManual,
+  getPowerList,
+  whenLoaded,
+} = useStation();
+
+import powerTypes from '@/utils/const/const_powerType.js';
+import { ExportFile } from '@/utils/exportFile.js';
+import { useRouter } from "vue-router";
+const router = useRouter();
+
+const userStore = useUserStore();
+const { uid, uname } = storeToRefs(userStore);
+import moment from 'moment';
+
+
+import {
+	confirmBattAlm,
+	getBattAlmHis,
+	getPwrAlmParam,
+  getPwrAllAlmParam,
+} from "@/api/alarm.js";
+
+import {
+  getPowerAlmIdType,
+} from "@/api/station.js";
+
+
+const { $loading, $message, $confirm } = useElement();
+const flag = ref(Math.random());
+
+
+const headers = [
+	{
+		prop: "fullName",
+		label: "鏈烘埧鍚嶇О",
+		width: "220",
+	},
+	{
+		prop: "powerName",
+		label: "鐢垫簮鍚嶇О",
+		width: "80",
+	},
+	{
+		prop: "alarmName",
+		label: "鍛婅鍚嶇О",
+		width: "160",
+	},
+	{
+		prop: "alarmLimithUpper",
+		label: "涓婁笂闄愰槇鍊�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimithUpperLevelStr",
+		label: "涓婁笂闄愮瓑绾�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimithUpperEnStr",
+		label: "涓婁笂闄愪娇鑳�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimith",
+		label: "涓婇檺闃堝��",
+		width: "120",
+	},
+	{
+		prop: "alarmLimithLevelStr",
+		label: "涓婇檺绛夌骇",
+		width: "120",
+	},
+	{
+		prop: "alarmLimithEnStr",
+		label: "涓婇檺浣胯兘",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitl",
+		label: "涓嬮檺闃堝��",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlLevelStr",
+		label: "涓嬮檺绛夌骇",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlEnStr",
+		label: "涓嬮檺浣胯兘",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlLower",
+		label: "涓嬩笅闄愰槇鍊�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlLowerLevelStr",
+		label: "涓嬩笅闄愮瓑绾�",
+		width: "120",
+	},
+	{
+		prop: "alarmLimitlLowerEnStr",
+		label: "涓嬩笅闄愪娇鑳�",
+		width: "120",
+	},
+];
+
+// const pageCurr = ref(1);
+// const pageSize = ref(10);
+// const total = ref(0);
+const addEditVisible = ref(false);
+const dialogTitle = ref("");
+const datas = reactive({
+	tableData: [],
+	rowData: {},
+});
+
+const currentRow = ref({});
+
+const alarmTypeList = ref([]);
+
+const alarmId = ref('');
+
+function getList() {
+	let params = {
+		almIdList: alarmId.value ? [alarmId.value] : undefined,
+		provice: provice.value || undefined,
+		city: city.value || undefined,
+		country: country.value || undefined,
+		stationId: stationId.value || undefined,
+		powerId: powerId.value || undefined,
+	};
+
+  if (!powerId.value) {
+    $message.error('璇烽�夋嫨鐢垫簮');
+    return false;
+  }
+
+  let loading = $loading();
+	getPwrAlmParam(params).then((res) => {
+		let { code, data, data2, data3 } = res;
+		let list = [];
+		// let _total = 0;
+    loading.close();
+		if (code && data) {
+			// console.log(data);
+      let bInf = data3;
+			list = data2.map(v => ({
+        ...v,
+        fullName: bInf.fullName,
+        powerName: bInf.powerName,
+				alarmLimithUpperLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimithUpperLevel],
+				alarmLimithUpperEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimithUpperEn],
+				alarmLimithLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimithLevel],
+				alarmLimithEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimithEn],
+				alarmLimitlLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimitlLevel],
+				alarmLimitlEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimitlEn],
+				alarmLimitlLowerLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimitlLowerLevel],
+				alarmLimitlLowerEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimitlLowerEn],
+			}));
+			// _total = data2.total;
+		}
+		datas.tableData = list;
+		// total.value = _total;
+	})
+		.catch((err) => {
+			console.log(err);
+		});
+}
+
+
+
+// 鏌ヨ鍛婅绫诲瀷
+async function getAlarmType() {
+	let res = await getPowerAlmIdType();
+	let { code, data, data2 } = res;
+	let list = [];
+	if (code && data) {
+		Object.keys(data2).map((key) => {
+      Object.keys(data2[key]).map((key2) => {
+        list.push({
+          value: key2,
+          label: data2[key][key2]
+        });
+      })
+    });
+	}
+	alarmTypeList.value = list;
+}
+
+
+// 灞曠ず鏁版嵁鏁伴噺
+// function handleSizeChange(val) {
+// 	pageSize.value = val;
+// 	getList();
+// }
+// 缈婚〉
+// function handleCurrentChange(val) {
+// 	pageCurr.value = val;
+// 	getList();
+// }
+
+const alarmType = ref(0);
+
+function edit(record) {
+  dialogTitle.value = `缂栬緫鍛婅鍙傛暟--${record.alarmName}`;
+  alarmType.value = record.alarmType;
+  addEditVisible.value = true;
+  currentRow.value = record;
+  // console.log('record', record, '=============');
+  
+}
+
+function onOk() {
+	addEditVisible.value = false;
+	// handleCurrentChange(1);
+}
+function onCanel() {
+	addEditVisible.value = false;
+}
+
+function exportExcel() {
+	let _headers = headers.map(v => {
+		let prop = v.prop;
+		let label = v.label;
+		if (prop == 'almIsConfirmed') {
+			prop = 'almIsConfirmedStr';
+		}
+		return {
+			prop,
+			label
+		};
+	});
+	ExportFile(_headers, datas.tableData, "鐢垫簮鍛婅鍙傛暟");
+}
+
+async function exportExcelAll() {
+  let res = await getPwrAllAlmParam();
+  let { code, data, data2 } = res;
+  let list = [];
+  if (code && data) {
+			list = data2.map(v => ({
+        ...v,
+				alarmLimithUpperLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimithUpperLevel],
+				alarmLimithUpperEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimithUpperEn],
+				alarmLimithLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimithLevel],
+				alarmLimithEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimithEn],
+				alarmLimitlLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimitlLevel],
+				alarmLimitlEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimitlEn],
+				alarmLimitlLowerLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.alarmLimitlLowerLevel],
+				alarmLimitlLowerEnStr: ['涓嶅惎鐢�', '鍚敤'][v.alarmLimitlLowerEn],
+			}));
+  }
+  let _headers = headers.map(v => {
+    let prop = v.prop;
+    let label = v.label;
+    return {
+      prop,
+      label
+    };
+  });
+  ExportFile(_headers, list, "鐢垫簮鍛婅鍙傛暟-鍏ㄩ儴");
+}
+
+onMounted(async () => {
+	await getAlarmType();
+	// getList();
+   console.log('stationList', stationList, '===========1==');
+});
+
+onActivated(async () => {
+  let pageFlag = getQueryString("pageFlag");
+  // console.log('pageFlag', pageFlag, flag.value, '=============');
+  await nextTick();
+  await whenLoaded();
+  
+  if (pageFlag && pageFlag != flag.value) {
+    // let provice, city, country, stationName, battId;
+    
+    if (getQueryString('stationId')) {
+      let statId = getQueryString('stationId');
+      let stat = stationList.value.find(v => v.stationId == statId);
+      if (stat) {
+        isManual.value = true;
+        stationName.value = stat.stationName;
+        await getPowerList();
+      }
+    }
+    if (getQueryString('powerId')) {
+      powerId.value = getQueryString('powerId') * 1;
+      // console.log('battId', battId.value, battList.value, '=============');
+    }
+    getList();
+    flag.value = pageFlag;
+  }
+});
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+      </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 8}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鐢垫簮鍚嶇О</div>
+                <div class="value">
+                  <el-select
+                    v-model="powerId"
+                    clearable
+                    size="small"
+                    placeholder="璇烽�夋嫨鐢垫簮"
+                  >
+                    <el-option
+                      v-for="item in powerList"
+                      :key="'l4_' + item.powerId"
+                      :label="`${item.stationName}-${item.powerName}`"
+                      :value="item.powerId"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍛婅鍚嶇О</div>
+                <div class="value">
+                  <el-select
+                    v-model="alarmId"
+                    size="small"
+                    clearable
+                    filterable
+                    placeholder="璇烽�夋嫨鍛婅鍚嶇О"
+                  >
+                    <el-option
+                      v-for="item in alarmTypeList"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table
+                  class="yc-table"
+                  stripe
+                  height="100%"
+                  size="small"
+                  :data="datas.tableData"
+                  style="width: 100%"
+                >
+                  <el-table-column
+                    type="index"
+                    fixed="left"
+                    label="搴忓彿"
+                    width="60"
+                  ></el-table-column>
+                  <el-table-column
+                    v-for="header in headers"
+                    :key="header.prop"
+                    :prop="header.prop"
+                    :label="header.label"
+                    :min-width="header.width"
+                    align="center"
+                  >
+                    <template #default="scope">
+                      <template v-if="header.prop == 'almIsConfirmed'">
+                        <el-checkbox
+                          disabled
+                          :checked="scope.row[header.prop] == 1"
+                        ></el-checkbox>
+                      </template>
+                      <template v-else>
+                        {{ scope.row[header.prop] || '--' }}
+                      </template>
+                    </template>
+                  </el-table-column>
+                  <el-table-column
+                    label="鎿嶄綔"
+                    fixed="right"
+                    width="240"
+                    align="center"
+                  >
+                    <template #default="scope">
+                      <el-button
+                        type="primary"
+                        size="small"
+                        @click="edit(scope.row)"
+                        >淇敼</el-button
+                      >
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button
+                type="primary"
+                round
+                size="small"
+                @click="getList"
+                :icon="Search"
+                >鏌ヨ</el-button
+              >
+            </div>
+            <div class="el-page-container">
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel"
+                >瀵煎嚭</el-button
+              >
+              <el-button type="primary" round size="small" @click="exportExcelAll"
+                >瀵煎嚭鍏ㄩ儴</el-button
+              >
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer"></div>
+    <!-- 寮圭獥 -->
+    <el-dialog
+      :title="dialogTitle"
+      v-model="addEditVisible"
+      top="0"
+      draggable
+      :close-on-click-modal="false"
+      class="dialog-center"
+      width="860px"
+      center
+    >
+      <alarm-params
+        v-if="addEditVisible"
+        :type="alarmType"
+        :info="currentRow"
+        @change="getList"
+        v-model:visible="addEditVisible"
+      ></alarm-params>
+    </el-dialog>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+
+    .flex-row {
+      display: flex;
+      align-items: center;
+
+      :deep(.el-checkbox) {
+        color: #fff;
+      }
+
+      .group {
+        margin-left: 30px;
+      }
+    }
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+</style>
diff --git a/src/views/alarm/pwrAlarm.vue b/src/views/alarm/pwrAlarm.vue
index 90f7a05..9128a7f 100644
--- a/src/views/alarm/pwrAlarm.vue
+++ b/src/views/alarm/pwrAlarm.vue
@@ -139,6 +139,8 @@
 		rowData: {},
 	});
 
+  const indeterminate = reactive({});
+
   const almIds = ref([]);
   const alarmTypeList = ref([]);
 
@@ -148,6 +150,9 @@
   function handleCheckAllChange (val) {
     almIds.value = val ? alarmTypeList.value.map(v => v.value) : []
     isIndeterminate.value = false
+    Object.keys(indeterminate).forEach(v => {
+      indeterminate[v] = false
+    });
   }
   function handleCheckedChange (value) {
     const checkedCount = value.length
@@ -171,7 +176,7 @@
   // stationName: "娴嬭瘯鏈烘埧6",
   function sendMessage() {
     let params = {
-      // almIds: [119001],
+      almIds: almIds2.value,
       almLevel: alarmLevel.value || undefined,
       provice: provice.value || undefined,
       city: city.value || undefined,
@@ -189,13 +194,24 @@
     });
   }
 
+  const alarmTypeList2 = reactive({});
+
   // 鏌ヨ鍛婅绫诲瀷
   async function getAlarmType() {
     let res = await getPowerAlmIdType();
     let { code, data, data2 } = res;
     let list = [];
     if (code && data) {
-      list = Object.keys(data2).map((key) => ({value: key, label: data2[key]}));
+      list = Object.keys(data2).map((key, idx) => {
+        alarmTypeList2[idx] = Object.keys(data2[key]);
+        // ({value: key, label: data2[key]})
+        indeterminate[idx] = false;
+        return {
+          value: idx,
+          label: key,
+          children: Object.keys(data2[key]),
+        };
+      });
     }
     alarmTypeList.value = list;
     almIds.value = list.map(v => v.value);
@@ -224,6 +240,19 @@
     }
   );
 
+
+  const almIds2 = computed(() => {
+    return almIds.value.map(v => {
+      return indeterminate[v] ? [] : alarmTypeList2[v];
+    }).flat();
+  });
+
+  watch(
+    () => almIds2.value,
+    () => {
+      sendMessage();
+    }
+  );
 
 	// 灞曠ず鏁版嵁鏁伴噺
 	function handleSizeChange(val) {
@@ -419,7 +448,7 @@
                     v-model="almIds"
                     @change="handleCheckedChange"
                   >
-                    <el-checkbox v-for="(item, idx) in alarmTypeList" :key="'list0_' + idx" :label="item.label" :value="item.value">
+                    <el-checkbox v-for="(item, idx) in alarmTypeList" :indeterminate="indeterminate[idx]" :key="'list0_' + idx" :label="item.label" :value="item.value">
                     </el-checkbox>
                   </el-checkbox-group>
                 </div>
diff --git a/src/views/datas/addEdit.vue b/src/views/datas/addEdit.vue
index 8ad342b..1ae927e 100644
--- a/src/views/datas/addEdit.vue
+++ b/src/views/datas/addEdit.vue
@@ -22,6 +22,8 @@
     getMonCapByUid,
   } from "@/api/station";
 
+  import getBinaryDigits from '@/utils/getBinaryDigits.js';
+
   import powerTypes from '@/utils/const/const_powerType.js';
   import moment from 'moment';
 
@@ -54,6 +56,7 @@
     latitude: 0,
     powerName: "",
     company: "",
+    modelCfg: 0,
     powerModel: "",
     protocol: "",
     powerIp: "",
@@ -62,6 +65,7 @@
     monvolstd: '',
     moncapstd: '',
     monresstd: '',
+    nodeStation: '',
     moncount: '',
     product: "",
     battModel: "",
@@ -207,6 +211,7 @@
     params.longitude = params.longitude || 0;
     params.latitude = params.latitude || 0;
     params.addBinfFlag = addBinfFlag.value;
+    params.modelCfg = form1.modelCfg.reduce((pre, cur) => pre + cur, 0);
 
     // 缂栬緫鐢ㄦ埛鏃�, 鍖哄煙涓笉鍦ㄧ鐞嗗憳绠$悊鍐呯殑鍖哄煙瑕佹寫鍑烘潵 鏈�鍚庢洿鏂版椂鍐嶈拷鍔犺繘鍘�
     console.log("params update", params, "=============");
@@ -246,6 +251,7 @@
     params.longitude = params.longitude || 0;
     params.latitude = params.latitude || 0;
     params.addBinfFlag = addBinfFlag.value;
+    params.modelCfg = form1.modelCfg.reduce((pre, cur) => pre + cur, 0);
     console.log("params", params, "=============");
 
     let loading = $loading();
@@ -293,6 +299,7 @@
     params.longitude = params.longitude || 0;
     params.latitude = params.latitude || 0;
     params.addBinfFlag = addBinfFlag.value;
+    params.modelCfg = form1.modelCfg.reduce((pre, cur) => pre + cur, 0);
     console.log("params", params, "=============");
 
     if (addDevFlag.value == 1) {
@@ -466,6 +473,10 @@
         form1[key] = info[key];
       }
 
+      form1.modelCfg = getBinaryDigits(info.modelCfg).map((v, i) => {
+        return v == 1 ? 1 << i : 0;
+      }).filter(v => !!v);
+
       addBinfFlag.value = info.stationId ? !!info.battgroupId * 1 : 1;
       if (info.addBattFlag) {
         if (!info.devId) {
@@ -601,6 +612,27 @@
           </el-form-item>
         </el-col>
         <el-col :span="layout.span">
+          <el-form-item label="鏄惁鑺傜偣绔�" prop="nodeStation">
+            <el-select
+              v-model="form1.nodeStation"
+              :disabled="info.addBattFlag"
+              filterable
+              allow-create
+              placeholder="璇烽�夋嫨"
+              style="width: 180px"
+            >
+              <el-option
+                label="闈炶妭鐐圭珯"
+                :value="0"
+              />
+              <el-option
+                label="鑺傜偣绔�"
+                :value="1"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="layout.span">
           <el-form-item label="缁忓害" prop="longitude">
             <el-input v-model="form1.longitude" :disabled="info.addBattFlag"></el-input>
           </el-form-item>
@@ -693,6 +725,28 @@
         <el-col :span="layout.span">
           <el-form-item label="鐢垫簮IP" prop="powerIp">
             <el-input v-model="form1.powerIp" :disabled="info.addBattFlag"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="layout.span * 2">
+          <el-form-item label="鏁存祦鍣ㄥ惎鐢�" prop="modelCfg">
+            <el-select
+              v-model="form1.modelCfg"
+              :disabled="info.addBattFlag"
+              filterable
+              multiple
+              clearable
+              collapse-tags
+              collapse-tags-tooltip
+              placeholder="璇烽�夋嫨"
+              style="width: 100%"
+            >
+              <el-option
+                v-for="(item, idx) in 16"
+                :key="'list12_' + idx"
+                :label="'#' + item"
+                :value="1 << idx"
+              />
+            </el-select>
           </el-form-item>
         </el-col>
         <el-col :span="layout.span">
@@ -818,7 +872,7 @@
               >
                 <el-option
                   v-for="(item, idx) in monCapList"
-                  :key="'list11_' + idx"
+                  :key="'list13_' + idx"
                   :label="item"
                   :value="item"
                 />
diff --git a/src/views/datas/device.vue b/src/views/datas/device.vue
index 41cec62..5a45ee2 100644
--- a/src/views/datas/device.vue
+++ b/src/views/datas/device.vue
@@ -58,6 +58,11 @@
 			width: "80",
 		},
     {
+      prop: "nodeStationStr",
+      label: "鏄惁鑺傜偣绔�",
+      width: "200",
+    },
+    {
 			prop: "longitude",
 			label: "缁忓害",
 			width: "80",
@@ -202,6 +207,7 @@
 					list = data2.list.map(v => ({
             ...v,
             powerTypeStr: powerTypes[v.powerType],
+            nodeStationStr: v.nodeStation ? "鏄�" : "鍚�",
             // roleName: roles[v.role],
           }));
 					_total = data2.total;
diff --git a/src/views/history/hisTest.vue b/src/views/history/hisTest.vue
index b158710..03f99a6 100644
--- a/src/views/history/hisTest.vue
+++ b/src/views/history/hisTest.vue
@@ -1,65 +1,700 @@
 <script setup name="hisTest">
-import { ref, reactive } from "vue";
+	import { ref, reactive, onMounted, watch, nextTick, computed } from "vue";
+	import lineChart from '@/components/echarts/line4.vue';
+	import barChart from '@/components/echarts/bar7.vue';
 
-const testTypes = [
-  {
-    prop: 'hrfd',
-    label: '鏍稿鏀剧數'
-  },
-  {
-    prop: 'hrcd',
-    label: '鏍稿鍏呯數'
-  },
-  {
-    prop: 'jkfd',
-    label: '鐩戞帶鏀剧數'
-  },
-  {
-    prop: 'jkcd',
-    label: '鐩戞帶鍏呯數'
-  },
-  {
-    prop: 'tdfd',
-    label: '鍋滅數鏀剧數'
-  }
-];
+	import formatSeconds from '@/utils/formatSeconds';
+	import useElement from "@/hooks/useElement.js";
+	const { $loading, $message, $confirm } = useElement();
 
-const testRecordList = reactive({
-  hrfd: [],
-  hrcd: [],
-  jkfd: [],
-  jkcd: [],
-  tdfd: []
-});
+	import * as echarts from 'echarts';
 
+	import {
+		toFixed,
+		digits,
+	} from '@/utils/toFixed';
+
+	import {
+		getBattTinf,
+		getTinfDataWithTestRecordCount,
+	} from "@/api/history.js";
+	import { format } from "echarts";
+
+	const props = defineProps({
+		battgroupId: {
+			type: [String, Number],
+		},
+		num: {
+			type: [String, Number],
+		}
+	});
+
+	const testTypes = [
+		{
+			prop: 'hrfd',
+			label: '鏍稿鏀剧數'
+		},
+		{
+			prop: 'hrcd',
+			label: '鏍稿鍏呯數'
+		},
+		{
+			prop: 'jkfd',
+			label: '鐩戞祴鏀剧數'
+		},
+		{
+			prop: 'jkcd',
+			label: '鐩戞祴鍏呯數'
+		},
+		{
+			prop: 'tdfd',
+			label: '鍋滅數鏀剧數'
+		}
+	];
+
+	const testRecordList = reactive({
+		hrfd: [],
+		hrcd: [],
+		jkfd: [],
+		jkcd: [],
+		tdfd: [],
+	});
+
+	const selectValues = reactive({
+		hrfd: '',
+		hrcd: '',
+		jkfd: '',
+		jkcd: '',
+		tdfd: '',
+	});
+
+	const slider = ref(100);
+	const chart0 = ref(null);
+	const chart1 = ref(null);
+	const chart2 = ref(null);
+	const chart3 = ref(null);
+
+	const statusList = reactive([
+		{ label: '鐢垫睜鐘舵��', prop: 'battStateName', unit: '' },
+		{ label: '鍦ㄧ嚎鐢靛帇', prop: 'onlineVol', unit: 'V' },
+		{ label: '鐢垫睜鐢垫祦', prop: 'groupCurr', unit: 'A' },
+		{ label: '娴嬭瘯鏃堕暱', prop: 'testTimeLongStr', unit: '' },
+		{ label: '娴嬭瘯鏃堕棿', prop: 'testStarttime', unit: '' },
+		{ label: '娴嬭瘯瀹归噺', prop: 'testCap', unit: 'Ah' },
+		{ label: '棰勪及瀹归噺', prop: 'realCap', unit: 'Ah' },
+		{ label: '棰勪及缁埅', prop: 'restTimeStr', unit: '' },
+	]);
+
+	const infoList = reactive([
+		{ label: '鏍囩О瀹归噺', prop: 'moncapstd', unit: 'Ah' },
+		{ label: '钃勭數姹犳暟閲�', prop: 'monCount', unit: '' },
+		{ label: '鏍囩О鐢靛帇', prop: 'monvolstd', unit: 'V' },
+		{ label: '娴厖鐢靛帇', prop: 'floatchartVol', unit: 'V' },
+	])
+
+	const monBarTitle = ref("鏈�澶у��=0V;鏈�灏忓��=0V;骞冲潎鍊�=0V");
+	const chartType = ref("vol");
+	const chartTypes = [
+		{
+			label: "鍗曚綋鐢靛帇",
+			value: "vol",
+			unit: "V",
+			fixed: digits.VOL,
+		},
+		{
+			label: "鍗曚綋娓╁害",
+			value: "temp",
+			unit: "鈩�",
+			fixed: digits.TEMP,
+		},
+		{
+			label: "鍗曚綋瀹為檯瀹归噺",
+			value: "realCap",
+			unit: "AH",
+			fixed: digits.CAP,
+		},
+		{
+			label: "鍗曚綋鍓╀綑瀹归噺",
+			value: "resCap",
+			unit: "AH",
+			fixed: digits.CAP,
+		},
+		{
+			label: "鍗曚綋瀹归噺鐧惧垎姣�",
+			value: "preCap",
+			unit: "%",
+			fixed: 0,
+		},
+	];
+
+	const chartData = reactive({
+		vol: [],
+		temp: [],
+		realCap: [],
+		resCap: [],
+		preCap: [],
+	});
+
+	const testRecordCount = ref('');
+	const currProp = ref('');
+	function filterChange(prop) {
+		testTypes.forEach(v => {
+			if (v.prop !== prop) {
+				selectValues[v.prop] = '';
+			}
+		});
+
+		testRecordCount.value = selectValues[prop];
+		currProp.value = prop;
+		getTestInfo();
+	}
+
+	const battStatus = computed(() => {
+		return currProp.value ? testTypes.filter(v => v.prop == currProp.value)[0].label : '--';
+	});
+
+	const testInfo = computed(() => {
+		let obj = currProp.value ? testRecordList[currProp.value].filter(v => v.value == testRecordCount.value)[0] : {};
+		obj.battStateName = battStatus.value;
+		console.log('obj', obj, '=============');
+
+		return obj;
+	});
+
+
+	// 鍘嗗彶娴嬭瘯璁板綍
+	async function getLists() {
+		let res = await getBattTinf(props.battgroupId);
+		let { code, data, data2 } = res;
+		if (code && data) {
+			testRecordList.hrfd = data2['鏍稿鏀剧數'].map(v => ({
+				...v,
+				testCap: toFixed(v.testCap, digits.CAP),
+				restTimeStr: formatSeconds(v.restTime),
+				testTimeLongStr: formatSeconds(v.testTimeLong),
+				value: `${v.testRecordCount}-${v.recordNum}`,
+				label: v.testStarttime
+			}));
+			testRecordList.hrfd = data2['鏍稿鏀剧數'].map(v => ({
+				...v,
+				testCap: toFixed(v.testCap, digits.CAP),
+				restTimeStr: formatSeconds(v.restTime),
+				testTimeLongStr: formatSeconds(v.testTimeLong),
+				value: `${v.testRecordCount}-${v.recordNum}`,
+				label: v.testStarttime
+			}));
+			testRecordList.hrfd = data2['鏍稿鏀剧數'].map(v => ({
+				...v,
+				testCap: toFixed(v.testCap, digits.CAP),
+				restTimeStr: formatSeconds(v.restTime),
+				testTimeLongStr: formatSeconds(v.testTimeLong),
+				value: `${v.testRecordCount}-${v.recordNum}`,
+				label: v.testStarttime
+			}));
+			testRecordList.hrfd = data2['鏍稿鏀剧數'].map(v => ({
+				...v,
+				testCap: toFixed(v.testCap, digits.CAP),
+				restTimeStr: formatSeconds(v.restTime),
+				testTimeLongStr: formatSeconds(v.testTimeLong),
+				value: `${v.testRecordCount}-${v.recordNum}`,
+				label: v.testStarttime
+			}));
+			testRecordList.hrfd = data2['鏍稿鏀剧數'].map(v => ({
+				...v,
+				testCap: toFixed(v.testCap, digits.CAP),
+				restTimeStr: formatSeconds(v.restTime),
+				testTimeLongStr: formatSeconds(v.testTimeLong),
+				value: `${v.testRecordCount}-${v.recordNum}`,
+				label: v.testStarttime
+			}));
+		}
+	}
+
+	// 鏌ヨ娴嬭瘯淇℃伅
+	async function getTestInfo() {
+		let [recordCount, recordNum] = testRecordCount.value.split('-');
+		let loading = $loading();
+		let res = await getTinfDataWithTestRecordCount(props.battgroupId, props.num, recordNum, recordCount);
+		loading.close();
+		let { code, data, data2 } = res;
+		if (code && data) {
+			// testInfo.value = data2;
+			formatData(data2);
+		}
+	}
+
+  watch(
+    () => props.num,
+    () => {
+      if (!currProp.value) {
+        return false;
+      }
+      getTestInfo();
+    }
+  );
+
+	const chartOptions = reactive({
+		chart0: {
+			color: ["#0081ff", "#df9d02"],
+			title: {
+				show: false,
+				text: "绔數鍘嬫姌绾垮浘(V)",
+				x: "left",
+				textStyle: {
+					fontSize: "14",
+				},
+			},
+			legend: {
+				show: false,
+				data: ["鍦ㄧ嚎鐢靛帇", "缁勭鐢靛帇"],
+				right: 0,
+				orient: "vertical",
+			},
+			series: [
+				{
+					name: "鍦ㄧ嚎鐢靛帇",
+					data: [],
+				},
+				{
+					name: "缁勭鐢靛帇",
+					data: [],
+				},
+			],
+		},
+		chart1: {
+			name: '',
+			data: [],
+		},
+		chart2: {
+			title: {
+				show: false,
+				text: "鐢垫睜鐢垫祦鎶樼嚎鍥�(A)",
+				x: "center",
+				textStyle: {
+					fontSize: "14",
+				},
+			},
+			legend: {
+				show: false,
+			},
+			series: [
+				{
+					name: "鐢垫睜鐢垫祦",
+					areaStyle: {
+						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+							{
+								offset: 0,
+								color: "#00feff",
+							},
+							{
+								offset: 1,
+								color: "transparent",
+							},
+						]),
+					},
+					data: [],
+				},
+			],
+		},
+		chart3: {
+			title: {
+				show: false,
+				text: "鍗曚綋鐢靛帇(V)",
+				x: "center",
+				textStyle: {
+					fontSize: "14",
+				},
+			},
+			legend: {
+				show: false,
+			},
+			series: [],
+		},
+	});
+
+	const testTLong = ref([]);
+	const barDatas = ref({});
+	const bgDatas = ref({});
+	const monNames = ref([]);
+
+	// 鏍煎紡鍖栨暟鎹�
+	function formatData(data) {
+		let recordNum = -1;
+		let chartData = {
+			groupVol: [],
+			onlineVol: [],
+			testCurr: [],
+			monVolLine: [],
+		};
+		let monBarData = {
+			vol: [],
+			temp: [],
+			realCap: [],
+			resCap: [],
+			preCap: [],
+		};
+		let xLabels = [];
+		let firestData = {
+			vol: [],
+			temp: [],
+			realCap: [],
+			resCap: [],
+			preCap: [],
+		};
+		let firstRecordNum = -1;
+		for (let i = 0, len = data.length; i < len; i++) {
+			let item = data[i];
+			let monNum = item.monNum;
+			let testTimeLong = formatSeconds(item.testTimelong);
+			if (recordNum != item.recordNum) {
+				recordNum = item.recordNum;
+				if (firstRecordNum == -1) {
+					firstRecordNum = item.recordNum;
+				}
+				chartData.groupVol.push([testTimeLong, item.groupVol]);
+				chartData.onlineVol.push([testTimeLong, item.onlineVol]);
+				chartData.testCurr.push([testTimeLong, item.testCurr]);
+				monBarData.vol.push([]);
+				monBarData.temp.push([]);
+				monBarData.realCap.push([]);
+				monBarData.resCap.push([]);
+				monBarData.preCap.push([]);
+				testTLong.value.push(testTimeLong);
+			}
+			let monName;
+			if (firstRecordNum == recordNum) {
+				monName = '#' + monNum;
+				firestData.vol.push(item.monVol);
+				firestData.temp.push(item.monTmp);
+				firestData.realCap.push(item.realCap);
+				firestData.resCap.push(item.restCap);
+				firestData.preCap.push(item.percentCap);
+				xLabels.push(monName);
+			}
+			monBarData.vol[monBarData.vol.length - 1].push(item.monVol);
+			monBarData.temp[monBarData.temp.length - 1].push(item.monTmp);
+			monBarData.realCap[monBarData.realCap.length - 1].push(item.realCap);
+			monBarData.resCap[monBarData.resCap.length - 1].push(item.restCap);
+			monBarData.preCap[monBarData.preCap.length - 1].push(item.percentCap);
+
+			let monIdx = monNum - 1;
+			chartData.monVolLine[monIdx] = chartData.monVolLine[monIdx] || [];
+			chartData.monVolLine[monIdx].push([testTimeLong, item.monVol]);
+		}
+		// return { chartData, monBarData, xLabels };
+
+		chartOptions.chart0.series[0].data = chartData.onlineVol;
+		chartOptions.chart0.series[1].data = chartData.groupVol;
+
+		chartOptions.chart2.series[0].data = chartData.testCurr;
+		chartOptions.chart3.series = chartData.monVolLine.map((item, idx) => ({
+			name: '#' + (idx + 1),
+			data: item
+		}));
+
+		barDatas.value = monBarData;
+		bgDatas.value = firestData;
+		monNames.value = xLabels;
+		updateChart();
+	}
+
+	function updateChart() {
+		chart0.value.updateChart(chartOptions.chart0);
+		updateBarChart();
+		chart2.value.updateChart(chartOptions.chart2);
+		chart3.value.updateChart(chartOptions.chart3);
+		// chart2.value.updateChart(xLabels, monBarData.vol, monBarData.temp, monBarData.realCap, monBarData.resCap, monBarData.preCap);
+	}
+
+	function getBarNum(data) {
+		let sum = 0;
+		data.map(v => v * 1).forEach((item) => {
+			sum += item;
+		});
+		let max = data.length > 0 ? Math.max(...data) : 0;
+		let min = data.length > 0 ? Math.min(...data) : 0;
+		let avg = data.length > 0 ? sum / data.length : 0;
+		return {
+			max,
+			min,
+			avg,
+		};
+	}
+
+	function updateBarChart() {
+		let dataList = barDatas.value[chartType.value];
+		let opt = chartTypes.find((item) => item.value == chartType.value);
+		let fixed = opt.fixed;
+		let unit = opt.unit;
+		let name = opt.label;
+		let index = getDataIndex(dataList.length, slider.value);
+		let data = [];
+		if (index != -1) {
+			data = dataList[index];
+			let batNum = getBarNum(data);
+			monBarTitle.value =
+				"鏈�澶у��=" +
+				batNum.max +
+				unit +
+				";鏈�灏忓��=" +
+				batNum.min +
+				unit +
+				";骞冲潎鍊�=" +
+				toFixed(batNum.avg, fixed) +
+				unit;
+		} else {
+			console.log("鏈幏鍙栧埌鍊�");
+		}
+
+		// 璁剧疆鏌辩姸鍥�
+		chart1.value.updateChart(monNames.value, { name, data }, bgDatas.value[chartType.value]);
+	}
+
+
+	// 鏍煎紡鍖栨粦鍧楁樉绀虹殑鍐呭
+	function formatTooltip(value) {
+		let index = getDataIndex(testTLong.value.length, value);
+		let test_long = formatSeconds(0);
+		if (index != -1) {
+			test_long = formatSeconds(testTLong[index]);
+		}
+		return test_long;
+	}
+	// 鎷栧姩婊戝潡鏃惰Е鍙�
+	function sliderInput() {
+		updateBarChart();
+	}
+	// 鏍规嵁鐧惧垎姣旇幏鍙栨樉绀虹殑鏁版嵁鐨勭瑪鏁�
+	function getDataIndex(num, percent) {
+		if (percent <= 0) {
+			return 0;
+		}
+		return Math.floor((num * percent) / 100) - 1;
+	}
+
+	function changeChartType() {
+		updateBarChart();
+	}
+
+	onMounted(() => {
+		if (chart0.value && chart2.value && chart3.value) {
+			echarts.connect([chart0.value.getChart(), chart2.value.getChart(), chart3.value.getChart()]);
+
+		}
+		getLists();
+	});
 </script>
 
 <template>
   <div class="page-his">
-    <div class="filter">
+    <div class="filter page-filter">
       <div class="item" v-for="(item, idx) in testTypes" :key="'list0_' + idx">
         <div class="label">{{ item.label }}</div>
         <div class="value">
-          <el-select
-            v-model="item.prop"
-            size="small"
-            clearable
-            placeholder="璇烽�夋嫨"
-          >
-            <el-option
-              v-for="(item, idx) in testRecordList[item.prop]"
-              :key="'list5_' + idx"
-              :label="item.label"
-              :value="item.value"
-            >
+          <el-select v-model="selectValues[item.prop]" size="small" placeholder="璇烽�夋嫨" @change="filterChange(item.prop)">
+            <el-option v-for="(item, idx) in testRecordList[item.prop]" :key="'list5_' + idx" :label="item.label"
+              :value="item.value">
             </el-option>
           </el-select>
         </div>
       </div>
     </div>
+    <div class="info">
+      <div :class="['status-item',]" v-for="(item, index) in statusList" :key="'status_' + index">
+        <div class="item-value" v-if="item.prop == 'captestTimelong' || item.prop == 'restTime'">
+          {{ testInfo[item.prop] ?
+          formatSeconds(testInfo[item.prop]) : '--' }}
+        </div>
+        <div class="item-value time" v-else-if="item.prop == 'testStarttime'">
+          {{ testInfo[item.prop] || '--' }}
+        </div>
+        <div class="item-value" v-else>
+          {{ testInfo[item.prop]}}{{ item.unit }}
+        </div>
+        <div class="item-name">{{ item.label }}</div>
+      </div>
+      <div class="info-item" v-for="(item, index) in infoList" :key="'info_' + index">
+        <div class="label">{{ item.label }}({{ item.unit }})</div>
+        <div class="value">{{ testInfo[item.prop] }}</div>
+      </div>
+    </div>
+    <div class="main">
+      <div class="grid">
+        <div class="g-item">
+          <card title="绔數鍘嬫姌绾垮浘(V)">
+            <line-chart ref="chart0"></line-chart>
+          </card>
+        </div>
+        <div class="g-item">
+          <card :title="monBarTitle">
+            <template #tools>
+              <el-select v-model="chartType" :disabled="!currProp" size="small" @change="changeChartType">
+                <el-option v-for="item in chartTypes" :key="item.value" :label="item.label"
+                  :value="item.value"></el-option>
+              </el-select>
+            </template>
+            <bar-chart ref="chart1"></bar-chart>
+          </card>
+        </div>
+        <div class="g-item">
+          <card title="鐢垫睜鐢垫祦鎶樼嚎鍥�(A)">
+            <line-chart ref="chart2"></line-chart>
+          </card>
+        </div>
+        <div class="g-item">
+          <card title="鍗曚綋鐢靛帇(V)">
+            <line-chart ref="chart3"></line-chart>
+          </card>
+        </div>
+      </div>
+    </div>
+    <div class="footer">
+      <el-slider v-model="slider" size="small" :format-tooltip="formatTooltip" @input="sliderInput" />
+    </div>
   </div>
 </template>
 
 <style scoped lang="less">
+.page-his {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
 
-</style>
\ No newline at end of file
+.filter {
+  background: #073451;
+  display: flex;
+  // flex-wrap: wrap;
+  align-items: center;
+  padding: 8px;
+  font-size: 16px;
+  color: #45beea;
+
+  .item {
+    flex: 1;
+    display: flex;
+
+    &~.item {
+      margin-left: 10px;
+    }
+
+    .label {
+      margin-right: 10px;
+
+      &::after {
+        content: ":";
+      }
+    }
+
+    .value {
+      flex: 1;
+    }
+  }
+}
+
+.info {
+  height: 72px;
+  display: flex;
+  flex-direction: row;
+
+  .status-item {
+    flex: 1;
+    font-size: 14px;
+    font-weight: 700;
+    color: #50c7f1;
+    // border: 1px solid #0F6B79;
+    border-radius: 6px;
+    margin: 4px 2px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    box-shadow: inset 0 0 30px -10px #0F6B79;
+    background: radial-gradient(circle at -10% center, #1F6571 5%, transparent 20%) no-repeat,
+      radial-gradient(circle at 110% center, #1F6571 5%, transparent 20%) no-repeat,
+      radial-gradient(circle at center -72%, #1F6571 12%, transparent 50%) no-repeat,
+      radial-gradient(circle at center 138%, #1F6571 12%, transparent 50%) no-repeat;
+
+    .item-value {
+      margin-bottom: 6px;
+      color: #ff0;
+      font-size: 20px;
+
+      &.time {
+        white-space: nowrap;
+        font-size: 12px;
+      }
+    }
+
+    .item-name {
+      color: #6DCCE6;
+    }
+  }
+
+  .info-item {
+    flex: 1.2;
+    display: flex;
+    align-items: center;
+    margin-left: 2px;
+
+    .label {
+      color: #6DCCE6;
+      font-size: 12px;
+      margin-bottom: 4px;
+
+      &::after {
+        content: ":";
+      }
+    }
+
+    .value {
+      color: #6DCCE6;
+      font-size: 14px;
+      background: #134263;
+      flex: 1;
+      border-radius: 4px;
+      padding-left: 6px;
+      margin-left: 4px;
+      margin-right: 6px;
+      min-height: 1.8em;
+      display: flex;
+      align-items: center;
+    }
+  }
+}
+
+.main {
+  flex: 1;
+  padding: 8px;
+
+  .grid {
+    height: 100%;
+    display: grid;
+    grid-template-columns: repeat(2, 1fr);
+    grid-template-rows: repeat(2, 1fr);
+    grid-gap: 10px 8px;
+    place-content: stretch;
+
+    // place-items: center stretch;
+    // justify-items: stretch;
+    // align-items: stretch;
+    .g-item {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+
+      :deep(.card) {
+        width: 100%;
+
+        .el-select {
+          width: 140px;
+        }
+      }
+    }
+  }
+}
+
+.footer {
+  padding: 0 8px;
+}
+</style>
diff --git a/src/views/history/index.vue b/src/views/history/index.vue
index 7673a6e..1b758b9 100644
--- a/src/views/history/index.vue
+++ b/src/views/history/index.vue
@@ -1,5 +1,5 @@
 <script setup name="history">
-import { ref, reactive, watch, onMounted } from "vue";
+import { ref, reactive, watch, onMounted, onActivated } from "vue";
 import siteList from "@/components/siteList/index.vue";
 import  getQueryString  from "@/utils/getQueryString";
 import formatSeconds from '@/utils/formatSeconds';
@@ -12,10 +12,64 @@
 const route = useRoute();
 const router = useRouter();
 
-const fullName = ref('婀栧寳鐪�-姝︽眽甯�-姝︽槍鍖�-姝︽槍鏈烘埧-鐢垫睜缁�1');
-const pageTab = ref('his-test');
+const flag = ref(Math.random());
+
+const curStationId = ref(
+  getQueryString("stationId") || ''
+);
+
+const curPowerId = ref(
+  getQueryString("powerId") || ''
+);
+
+const curBattgroupId = ref(
+  getQueryString("battgroupId") || ''
+);
+
+const curDevId = ref(
+  getQueryString("devId") || ''
+);
+
+
+const fullName = ref('');
+const pageTab = ref(getQueryString('pageTab') || 'his-test');
 
 const show_num = ref(5);
+function testRecordChange() {
+  
+}
+
+function leafClick(item) {
+  // console.log('item', item, '=============');
+  curStationId.value = item.stationId;
+  curPowerId.value = item.powerId;
+  curBattgroupId.value = item.battgroupId || 0;
+  curDevId.value = item.devId || 0;
+  // fullName.value = item.fullName;
+}
+
+function goRt() {
+  router.push({
+    path: '/datas/realtime',
+    query: {
+      stationId: curStationId.value || 0,
+      powerId: curPowerId.value || 0,
+      devId: curDevId.value || 0,
+      battgroupId: curBattgroupId.value || 0,
+      pageFlag: Math.random(),
+    }
+  });
+}
+
+onActivated(async () => {
+  let pageFlag = getQueryString("pageFlag");
+  // console.log('pageFlag', pageFlag, flag.value, '=============');
+  
+  if (pageFlag && pageFlag != flag.value) {
+    pageTab.value = getQueryString('pageTab') || 'his-test';
+    flag.value = pageFlag;
+  }
+});
 
 </script>
 
@@ -32,7 +86,8 @@
         </div>
         <div class="p-title">{{ fullName }}</div>
         <div class="btn-grp pos">
-          <div class="data-granularity" v-if="pageTab === 'his-test'">
+          <!-- <div class="data-granularity" v-if="pageTab === 'his-test'"> -->
+          <div class="data-granularity" >
             <label style="font-size: 12px; margin-right: 8px">鏄剧ず绮掑害:</label>
               <el-select
                 v-model="show_num"
@@ -52,14 +107,14 @@
                 <el-option :value="10" label="脳10"></el-option>
               </el-select>
           </div>
-          <el-button type="primary" size="small">瀹炴椂鐩戞祴</el-button>
+          <el-button type="primary" size="small" @click="goRt">瀹炴椂鐩戞祴</el-button>
         </div>
       </div>
       <div class="page-main">
         <!-- 鍘嗗彶娴嬭瘯鏁版嵁 -->
-        <his-test v-if="pageTab == 'his-test'"></his-test>
+        <his-test :battgroupId="curBattgroupId" :num="show_num" v-if="pageTab == 'his-test'"></his-test>
         <!-- 鍘嗗彶瀹炴椂鏁版嵁 -->
-        <his-real v-if="pageTab == 'his-real'"></his-real>
+        <his-real :battgroupId="curBattgroupId" :num="show_num" v-if="pageTab == 'his-real'"></his-real>
       </div>
     </div>
   </div>
diff --git a/src/views/realtime/bar8.vue b/src/views/realtime/bar8.vue
deleted file mode 100644
index d57e788..0000000
--- a/src/views/realtime/bar8.vue
+++ /dev/null
@@ -1,170 +0,0 @@
-<script setup>
-	import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue";
-	import * as echarts from 'echarts';
-
-
-
-
-	function getOptions() {
-		let option = {
-			backgroundColor: '#001037',
-			grid: {
-				top: '10%',
-				left: '5%',
-				right: '2%',
-				bottom: '14%',
-			},
-			tooltip: {
-				show: false,
-			},
-			xAxis: {
-				data: ['1鏈�', '2鏈�', '3鏈�', '4鏈�', '5鏈�', '6鏈�', '7鏈�', '8鏈�', '9鏈�', '10鏈�', '11鏈�', '12鏈�'],
-				axisLine: {
-					lineStyle: {
-						color: 'transparent', //搴曢儴杈规棰滆壊
-					},
-				},
-				axisLabel: {
-					textStyle: {
-						color: '#fff', //搴曢儴鏂囧瓧棰滆壊
-						fontSize: 12,
-					},
-				},
-			},
-			yAxis: [
-				{
-					type: 'value',
-					splitLine: {
-						show: true,
-						lineStyle: {
-							color: 'rgba(255,255,255,0.2)', //缃戞牸绾跨殑棰滆壊
-							width: 1,
-							type: 'solid',
-						},
-					},
-					axisLine: {
-						show: false,
-						lineStyle: {
-							color: 'transparent', //宸﹁竟妗嗛鑹�
-						},
-					},
-					axisLabel: {
-						show: true,
-						fontSize: 12,
-						textStyle: {
-							color: '#ADD6FF', //宸︽枃瀛楅鑹�
-						},
-					},
-				},
-			],
-			series: [
-				{
-					name: '姣曚笟瀛﹀憳',
-					type: 'bar',
-					barWidth: 30,
-					showBackground: true,
-					backgroundStyle: {
-						color: 'rgba(21,136,209,0.1)',
-						// color: '#f00',
-					},
-					itemStyle: {
-						normal: {
-							color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-								{
-									offset: 0,
-									// color: '#00FFE3',//娓愬彉1
-									color: 'rgba(21,136,209,1)', //娓愬彉1
-									// color: '#0f0', //娓愬彉1
-								},
-								{
-									offset: 1,
-									// color: '#4693EC',//娓愬彉2
-									color: 'rgba(21,136,209,1)', //娓愬彉2
-									// color: '#0f0', //娓愬彉2
-								},
-							]),
-						},
-					},
-					data: [20, 80, 100, 40, 34, 90, 60, 20, 80, 100, 40, 34],
-					z: 0,
-					zlevel: 0,
-				},
-				{
-					type: 'pictorialBar',
-					barWidth: 30,
-					itemStyle: {
-						normal: {
-							color: 'rgba(0,63,119,1)', //鏁版嵁鐨勯棿闅旈鑹�
-							// color: '#f00', //鏁版嵁鐨勯棿闅旈鑹�
-						},
-					},
-					symbolRepeat: 'fixed',
-					symbolMargin: 3,
-					symbol: 'rect',
-					symbolSize: [30, 4],
-					symbolPosition: 'end',
-					symbolOffset: [0, 0],
-					data: [20, 80, 100, 40, 34, 90, 60, 20, 80, 100, 40, 34],
-					z: 1,
-					zlevel: 0,
-				},
-			],
-		};
-
-		return option;
-	}
-
-	let myChart;
-	const chartContainer = ref();
-
-	function initChart() {
-		if (chartContainer.value) {
-			myChart = echarts.init(chartContainer.value, "custom", {
-				rendererOptions: {
-					eventListenerOptions: {
-						passive: true // 鍚敤琚姩浜嬩欢鐩戝惉鍣�
-					}
-				}
-			});
-
-
-			let option = getOptions();
-			myChart.setOption(option);
-
-			// 鐩戝惉绐楀彛鍙樺寲閲嶆柊娓叉煋鍥捐〃
-			window.addEventListener("resize", () => {
-				myChart.resize();
-			});
-		}
-	}
-
-	function updateChart(xLabels, datas) {
-		let option = getOptions(xLabels, datas);
-		myChart.setOption(option);
-	}
-
-	onMounted(() => {
-		initChart();
-	});
-</script>
-
-<template>
-  <div class="chart-wraper">
-    <div class="chart" ref="chartContainer"></div>
-  </div>
-</template>
-
-<style scoped lang="less">
-.chart-wraper {
-  height: 100%;
-  position: relative;
-
-  .chart {
-    position: absolute;
-    left: 0;
-    top: 0;
-    right: 0;
-    bottom: 0;
-  }
-}
-</style>
diff --git a/src/views/realtime/devAlarmParams.vue b/src/views/realtime/devAlarmParams.vue
new file mode 100644
index 0000000..4a5989a
--- /dev/null
+++ b/src/views/realtime/devAlarmParams.vue
@@ -0,0 +1,312 @@
+<script setup>
+import { ref, onMounted, reactive, watch, nextTick, computed } from "vue";
+
+
+import useElement from "@/hooks/useElement.js";
+	const { $loading, $message, $confirm } = useElement();
+
+import {
+  getAlarmFromDevice,
+  setAlarmFromDevice,
+} from "@/api/alarm.js";
+
+const emit = defineEmits(['update:visible']);
+
+const props = defineProps({
+  devId: {
+    type: [String, Number],
+  },
+  visible: {
+    type: Boolean,
+    default: false
+  },
+});
+
+const layout = {
+  gutter: 16,
+  span: 8,
+}
+
+const startFlag = ref(false);
+const setFlag = ref(false);
+
+// TODO 鍙傛暟鑼冨洿
+
+const form1 = reactive({
+  num: '',
+  devId: '',
+  // opCmd: '',
+  groupvolHighVal: '',
+  groupvolLowVal: '',
+  monvolHighVal: '',
+  monvolLowVal: '',
+  montmpHighVal: '',
+  montmpLowVal: '',
+  monresHighVal: '',
+  monresLowVal: '',
+  moncapHighVal: '',
+  moncapLowVal: '',
+  battgroupnum: '',
+  onlinevolHighVal: '',
+  onlinevolLowVal: '',
+  onlinevolEn: '',
+  groupvolEn: '',
+  monvolEn: '',
+  montmpEn: '',
+  monresEn: '',
+  moncapEn: '',
+  discurrHighVal: '',
+  discurrEn: '',
+  chrcurrHighVal: '',
+  chrcurrEn: '',
+});
+
+async function getParam() {
+  let loading = $loading();
+  let res = await getAlarmFromDevice(props.devId);
+  let { code, data, data2 } = res;
+  loading.close();
+  if (code && data) {
+    $message.success('鎿嶄綔鎴愬姛');
+    setFlag.value = true;
+  } else {
+    $message.error('鎿嶄綔澶辫触');
+    // setFlag.value = false;
+    setFlag.value = true;
+  }
+  if (data2) {
+    for(let key in form1) {
+      form1[key] = data2[key];
+    }
+  }
+}
+
+
+async function setParam() {
+  let loading = $loading();
+  let res = await setAlarmFromDevice(form1);
+  let { code, data } = res;
+  loading.close();
+  if (code && data) {
+    $message.success('鎿嶄綔鎴愬姛');
+    startFlag.value = true;
+  } else {
+    $message.error('鎿嶄綔澶辫触');
+    // startFlag.value = false;
+    startFlag.value = true;
+  }
+}
+
+function close () {
+  emit('update:visible', false);
+}
+
+
+
+
+onMounted(() => {
+  getParam();
+});
+</script>
+
+<template>
+  <div class="param-contain">
+    <el-form ref="formRef" :model="form1" label-width="10em">
+        <el-row :gutter="layout.gutter">
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="缁勭鐢靛帇楂橀槇鍊�" prop="groupvolHighVal">
+              <el-input v-model="form1.groupvolHighVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="缁勭鐢靛帇浣庨槇鍊�" prop="groupvolLowVal">
+              <el-input v-model="form1.groupvolLowVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="缁勭鐢靛帇鍛婅浣胯兘" prop="groupvolEn">
+              <el-checkbox
+                :checked="form1.groupvolEn == 0"
+                @change="(v) => form1.groupvolEn = v ? 0 : 1"
+              ></el-checkbox>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋鐢靛帇楂橀槇鍊�" prop="monvolHighVal">
+              <el-input v-model="form1.monvolHighVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋鐢靛帇浣庨槇鍊�" prop="monvolLowVal">
+              <el-input v-model="form1.monvolLowVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋鐢靛帇鍛婅浣胯兘" prop="monvolEn">
+              <el-checkbox
+                :checked="form1.monvolEn == 0"
+                @change="(v) => form1.monvolEn = v ? 0 : 1"
+              ></el-checkbox>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋娓╁害楂橀槇鍊�" prop="montmpHighVal">
+              <el-input v-model="form1.montmpHighVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋娓╁害浣庨槇鍊�" prop="montmpLowVal">
+              <el-input v-model="form1.montmpLowVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋娓╁害鍛婅浣胯兘" prop="montmpEn">
+              <el-checkbox
+                :checked="form1.montmpEn == 0"
+                @change="(v) => form1.montmpEn = v ? 0 : 1"
+              ></el-checkbox>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋鍐呴樆楂橀槇鍊�" prop="monresHighVal">
+              <el-input v-model="form1.monresHighVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋鍐呴樆浣庨槇鍊�" prop="monresLowVal">
+              <el-input v-model="form1.monresLowVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋鍐呴樆鍛婅浣胯兘" prop="monresEn">
+              <el-checkbox
+                :checked="form1.monresEn == 0"
+                @change="(v) => form1.monresEn = v ? 0 : 1"
+              ></el-checkbox>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋瀹归噺楂橀槇鍊�" prop="moncapHighVal">
+              <el-input v-model="form1.moncapHighVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋瀹归噺浣庨槇鍊�" prop="moncapLowVal">
+              <el-input v-model="form1.moncapLowVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍗曚綋瀹归噺鍛婅浣胯兘" prop="moncapEn">
+              <el-checkbox
+                :checked="form1.moncapEn == 0"
+                @change="(v) => form1.moncapEn = v ? 0 : 1"
+              ></el-checkbox>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍦ㄧ嚎鐢靛帇楂橀槇鍊�" prop="onlinevolHighVal">
+              <el-input v-model="form1.onlinevolHighVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍦ㄧ嚎鐢靛帇浣庨槇鍊�" prop="onlinevolLowVal">
+              <el-input v-model="form1.onlinevolLowVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍦ㄧ嚎鐢靛帇鍛婅浣胯兘" prop="onlinevolEn">
+              <el-checkbox
+                :checked="form1.onlinevolEn == 0"
+                @change="(v) => form1.onlinevolEn = v ? 0 : 1"
+              ></el-checkbox>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+            :offset="layout.span"
+          >
+            <el-form-item label="鏀剧數鐢垫祦涓婇檺闃堝��" prop="discurrHighVal">
+              <el-input v-model="form1.discurrHighVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鏀剧數鐢垫祦鍛婅浣胯兘" prop="discurrEn">
+              <el-checkbox
+                :checked="form1.discurrEn == 0"
+                @change="(v) => form1.discurrEn = v ? 0 : 1"
+              ></el-checkbox>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+            :offset="layout.span"
+          >
+            <el-form-item label="鍏呯數鐢垫祦涓婇檺闃堝��" prop="chrcurrHighVal">
+              <el-input v-model="form1.chrcurrHighVal"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col
+            :span="layout.span"
+          >
+            <el-form-item label="鍏呯數鐢垫祦鍛婅浣胯兘" prop="chrcurrEn">
+              <el-checkbox
+                :checked="form1.chrcurrEn == 0"
+                @change="(v) => form1.chrcurrEn = v ? 0 : 1"
+              ></el-checkbox>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div class="footer">
+        <el-button @click="close">鍏抽棴</el-button>
+        <el-button type="primary" :disabled="!setFlag" @click="setParam">璁剧疆</el-button>
+        <el-button type="primary" @click="getParam">璇诲彇</el-button>
+      </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.footer {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 8px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/realtime/index.vue b/src/views/realtime/index.vue
index 7db41d7..c4a8d94 100644
--- a/src/views/realtime/index.vue
+++ b/src/views/realtime/index.vue
@@ -1,11 +1,17 @@
 <script setup name="realtime">
-import { ref, reactive, watch, onMounted } from "vue";
+import { ref, reactive, watch, onMounted, onActivated } from "vue";
 import tabPower from "./tabs/power.vue";
 import tabSystem from "./tabs/system.vue";
 import tabVol from './tabs/vol.vue';
+import tabRes from './tabs/res.vue';
+import tabTemp from './tabs/temp.vue';
+// import tabThreeD from './tabs/threeD.vue';
+// import tabSelf from './tabs/self.vue';
+import tabManage from './tabs/manage.vue';
 import siteList from "@/components/siteList/index.vue";
 import  getQueryString  from "@/utils/getQueryString";
 import formatSeconds from '@/utils/formatSeconds';
+import battAlarmParams from '@/views/alarm/battAlarmParams.vue';
 
 
 import { useRoute, useRouter } from "vue-router";
@@ -44,10 +50,10 @@
 });
 
 const statusList = reactive([
-	{ label: '绯荤粺鐘舵��', prop: 'systemState', unit: '' },
-	{ label: '璁惧鐘舵��', prop: 'devState', unit: '' },
-	{ label: '鐢垫簮鐘舵��', prop: 'pwrState', unit: '' },
-	{ label: '鐢垫睜鐘舵��', prop: 'battState', unit: '' },
+	{ label: '绯荤粺鐘舵��', prop: 'systemStateName', unit: '' },
+	{ label: '璁惧鐘舵��', prop: 'devStateName', unit: '' },
+	{ label: '鐢垫簮鐘舵��', prop: 'pwrStateName', unit: '' },
+	{ label: '鐢垫睜鐘舵��', prop: 'battStateName', unit: '' },
 	{ label: '姣嶇嚎鐢靛帇', prop: 'vbusVol', unit: 'V' },
 	{ label: '鍦ㄧ嚎鐢靛帇', prop: 'onlineVol', unit: 'V' },
 	{ label: '缁勭鐢靛帇', prop: 'captestGroupvol', unit: 'V' },
@@ -81,7 +87,7 @@
 
 const acTab = ref(tabs.value[0].name);
 
-const fullName = ref('婀栧寳鐪�-姝︽眽甯�-姝︽槍鍖�-姝︽槍鏈烘埧-鐢垫睜缁�1');
+const fullName = ref('');
 const topData = ref({});
 
 
@@ -102,8 +108,69 @@
   sendMessage();
 }
 
+const visibles = reactive({
+  powerAlarmSet: false,
+  battAlarmSet: false
+});
+
 function btnClick(item) {
   console.log('item', item, '=============');
+    // 鏀逛负璺宠浆
+  switch(item.name) {
+    case 'powerAlarmSet':
+      router.push({
+        path: '/alarm/power-setting',
+        query: {
+          stationId: curStationId.value || 0,
+          powerId: curPowerId.value || 0,
+          devId: curDevId.value || 0,
+          battgroupId: curBattgroupId.value || 0,
+          pageFlag: Math.random(),
+        }
+      });
+      break;
+    case 'battAlarmSet':
+      // visibles.battAlarmSet = true;
+      router.push({
+        path: '/alarm/batt-setting',
+        query: {
+          stationId: curStationId.value || 0,
+          powerId: curPowerId.value || 0,
+          devId: curDevId.value || 0,
+          battgroupId: curBattgroupId.value || 0,
+          pageFlag: Math.random(),
+        }
+      });
+      break;
+    case 'img':
+      break;
+    case 'history':
+      router.push({
+        path: '/datas/history',
+        query: {
+          stationId: curStationId.value || 0,
+          powerId: curPowerId.value || 0,
+          devId: curDevId.value || 0,
+          battgroupId: curBattgroupId.value || 0,
+          pageTab: 'his-test',
+          pageFlag: Math.random(),
+        }
+      });
+      break;
+    case 'hisRt':
+      router.push({
+        path: '/datas/history',
+        query: {
+          stationId: curStationId.value || 0,
+          powerId: curPowerId.value || 0,
+          devId: curDevId.value || 0,
+          battgroupId: curBattgroupId.value || 0,
+          pageTab: 'his-real',
+          pageFlag: Math.random(),
+        }
+      });
+      break;
+  }
   
 }
 function leafClick(item) {
@@ -114,19 +181,6 @@
   curDevId.value = item.devId || 0;
 
   sendMessage();
-
-  // if (getQueryString("stationId")) {
-  //   router.push({
-  //     path: route.path,
-  //     query: {
-  //       stationId: item.stationId,
-  //       powerId: item.powerId,
-  //       battgroupId: item.battgroupId || undefined,
-  //       devId: item.devId || undefined
-  //     }
-  //   })
-  // }
-  // fullName.value = item.fullName;
 }
 
 
@@ -143,14 +197,15 @@
       }
       topData.value = data;
       if (realRes.code && realRes.data) {
-        // rtData.
-        rtData['system'] = realRes.data2;
+        rtData[realRes.data2.pageType] = realRes.data2;
       }
     }
   }
-)
+);
 
-
+onActivated(() => {
+  sendMessage();
+});
 
 onMounted(() => {
   sendMessage();
@@ -199,16 +254,22 @@
           <tab-system :data="rtData['system']" :powerId="curPowerId" :devId="curDevId" :battgroupId="curBattgroupId"></tab-system>
         </div>
         <div class="tab-contain" v-if="acTab == 'power'">
-          <tab-power></tab-power>
+          <tab-power :data="rtData['power']"></tab-power>
         </div>
         <div class="tab-contain" v-if="acTab == 'vol'">
-          <tab-vol></tab-vol>
+          <tab-vol :data="rtData['vol']"></tab-vol>
         </div>
-        <div class="tab-contain" v-if="acTab == 'res'">3</div>
-        <div class="tab-contain" v-if="acTab == 'tmp'">4</div>
+        <div class="tab-contain" v-if="acTab == 'res'">
+          <tab-res :data="rtData['res']"></tab-res>
+        </div>
+        <div class="tab-contain" v-if="acTab == 'tmp'">
+          <tab-temp :data="rtData['tmp']"></tab-temp>
+        </div>
         <div class="tab-contain" v-if="acTab == '3D'">5</div>
         <div class="tab-contain" v-if="acTab == 'self'">6</div>
-        <div class="tab-contain" v-if="acTab == 'manage'">7</div>
+        <div class="tab-contain" v-if="acTab == 'manage'">
+          <tab-manage :data="rtData['manage']"></tab-manage>
+        </div>
         <!-- <div class="tab-contain" v-if="acTab == 'powerAlarmSet'">8</div>
         <div class="tab-contain" v-if="acTab == 'battAlarmSet'">9</div>
         <div class="tab-contain" v-if="acTab == 'img'">10</div>
@@ -216,6 +277,10 @@
         <div class="tab-contain" v-if="acTab == 'hisRt'">12</div> -->
       </div>
     </div>
+    <!-- 鐢垫睜鍛婅鍙傛暟 -->
+    <!-- <el-dialog v-model="visibles.battAlarmSet" title="鐢垫睜鍛婅鍙傛暟" width="900">
+      <batt-alarm-params @close="visibles.battAlarmSet = false" v-if="visibles.battAlarmSet" :id="curBattgroupId"></batt-alarm-params>
+    </el-dialog> -->
   </div>
 </template>
 
diff --git a/src/views/realtime/tabs/manage.vue b/src/views/realtime/tabs/manage.vue
new file mode 100644
index 0000000..08416c7
--- /dev/null
+++ b/src/views/realtime/tabs/manage.vue
@@ -0,0 +1,222 @@
+<script setup name="manage">
+import { ref, reactive, computed, watch, nextTick, onMounted } from "vue";
+import info from '@/components/info.vue';
+import bar from '@/components/echarts/bar5.vue';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: {},
+  },
+});
+
+
+const pOption = [
+  {
+    label: "绔欑偣ID",
+    props: "stationId",
+  },
+  {
+    label: "绔欑偣鍚嶇О",
+    props: "stationName",
+  },
+  {
+    label: "鐢垫簮璁惧IP",
+    props: "powerIp",
+  },
+  {
+    label: "鐢垫簮璁惧鍚嶇О",
+    props: "powerName",
+  },
+  {
+    label: "鐢熶骇鍘傚",
+    props: "company",
+  },
+  {
+    label: "鐢垫簮鍨嬪彿",
+    props: "powerModel",
+  },
+  {
+    label: "鎶曞叆浣跨敤鏃ユ湡",
+    props: "powerInuseTimeStr",
+  },
+  {
+    label: "鐢垫簮ID",
+    props: "powerId",
+  },
+];
+
+const bOption = [
+  {
+    label: "绔欑偣ID",
+    props: "stationId",
+  },
+  {
+    label: "绔欑偣鍚嶇О",
+    props: "stationName",
+  },
+  {
+    label: "鏍囩О瀹归噺",
+    props: "moncapstd",
+  },
+  {
+    label: "鍗曚綋鐢靛帇",
+    props: "monvolstd",
+  },
+  {
+    label: "鏍囩О鍗曚綋鍐呴樆",
+    props: "monresstd",
+  },
+  // {
+  //   label: "鐢垫睜鐢熶骇鏃ユ湡",
+  //   props: "",
+  // },
+  {
+    label: "鎶曞叆浣跨敤鏃ユ湡",
+    props: "inuseTimeStr",
+  },
+  {
+    label: "鐢垫睜鍝佺墝",
+    props: "product",
+  },
+  {
+    label: "鐢垫睜鍨嬪彿",
+    props: "battModel",
+  },
+  {
+    label: "璁惧IP",
+    props: "devIp",
+  },
+  {
+    label: "璁惧ID",
+    props: "devId",
+  },
+  {
+    label: "鐢垫睜缁処D",
+    props: "battgroupId",
+  },
+];
+
+const rtInfo = computed(() => {
+  let binf = props.data.binf || {};
+  let pinf = props.data.pinf || {};
+  let sinf = props.data.sinf || {};
+  return {
+    ...sinf,
+    ...pinf,
+    ...binf,
+    inuseTimeStr: binf.inuseTime ? binf.inuseTime.substring(0, 10) : "",
+    powerInuseTimeStr: pinf.powerInuseTime ? pinf.powerInuseTime.substring(0, 10) : "",
+  }
+});
+
+
+
+
+onMounted(() => {
+
+});
+</script>
+
+<template>
+  <div class="tab-content">
+    <div class="p-left">
+      <card title="鐢垫簮淇℃伅">
+        <template #tools>
+          <div class="btn">鐢垫簮淇℃伅绠$悊</div>
+        </template>
+        <div class="main">
+          <div class="info">
+            <div class="row" v-for="(p, idx) in pOption" :key="'p_' + idx">
+              <div class="label">{{ p.label }}</div>
+              <div class="value">{{ rtInfo[p.props] }}</div>
+            </div>
+          </div>
+        </div>
+      </card>
+    </div>
+    <div class="p-right">
+      <card title="鐢垫睜淇℃伅">
+        <template #tools>
+          <div class="btn">鐢垫睜淇℃伅绠$悊</div>
+        </template>
+        <div class="main">
+          <div class="info">
+            <div class="row" v-for="(b, idx) in bOption" :key="'b_' + idx">
+              <div class="label">{{ b.label }}</div>
+              <div class="value">{{ rtInfo[b.props] }}</div>
+            </div>
+          </div>
+        </div>
+      </card>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.tab-content {
+  display: flex;
+  flex-direction: row;
+  height: 100%;
+  padding: 10px;
+
+  .btn {
+    background: linear-gradient(69deg, #6EABE4, #6EABE4 25%, #0A3E77 75%, #0A3E77);
+    border: 1px solid #4D81BA;
+    display: inline-block;
+    font-size: 14px;
+    padding: 4px 10px;
+    color: #fff;
+    cursor: pointer;
+  }
+
+  .main {
+    padding: 40px 18px 10px 18px;
+  }
+  .info {
+    border: 1px solid #146C9C;
+    padding: 4px;
+    .row {
+      display: flex;
+      height: 36px;
+      flex-direction: row;
+      background: rgba(0, 0, 0, 0.1);
+      font-size: 14px;
+      .label {
+        background: rgba(7,111,232, 0.5);
+        width: 180px;
+        color: #fff;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin-right: 2em;
+      }
+      .value {
+        flex: 1;
+        display: flex;
+        align-items: center;
+      }
+      &:nth-child(2n) {
+        background: rgba(200, 200, 255, 0.1);
+      }
+      &:hover {
+        background: rgba(200, 200, 255, 0.2);
+      }
+    }
+  }
+
+  .p-left {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    margin-right: 10px;
+
+  }
+  .p-right {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+  }
+
+}
+</style>
diff --git a/src/views/realtime/tabs/power.vue b/src/views/realtime/tabs/power.vue
index 7630054..3ca8ef0 100644
--- a/src/views/realtime/tabs/power.vue
+++ b/src/views/realtime/tabs/power.vue
@@ -1,32 +1,166 @@
 <script setup name="Power">
-import { ref } from "vue";
-const lineIdx = ref(0);
+import { ref, reactive, computed, nextTick, watch, onMounted } from "vue";
+import bar from '@/components/echarts/bar2.vue';
+import bar1 from '@/components/echarts/bar3.vue';
+import bar2 from '@/components/echarts/bar1.vue';
+import bar4 from '@/components/echarts/bar4.vue';
+import gauge from '@/components/echarts/gauge1.vue';
+import water from '@/components/echarts/water.vue';
+import ycTag from '@/components/ycTag.vue';
 
+import getBinaryDigits from '@/utils/getBinaryDigits.js';
+
+const lineIdx = ref(0);
+const chart0 = ref(null);
+const chart1 = ref(null);
+const chart2 = ref(null);
+const chart3 = ref(null);
+const chart4 = ref(null);
+const chart5 = ref(null);
+const chart6 = ref(null);
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: {},
+  },
+});
+
+// 鏁存祦鍣ㄥ垪琛� 鏈�澶�16涓�
+const modelList = computed(() => {
+  return props.data.powerInf && props.data.powerInf.modelCfg ? getBinaryDigits(props.data.powerInf.modelCfg).map((v, i) => ({ value: v, label: i + 1 })).filter(vv => vv.value).map(v => v.label) : [];
+});
+
+const state = computed(() => {
+  let rtData = props.data.pwrdevAcdcdata;
+  return modelList.value.map((item) => !rtData[`isAcdcmod${item}Off`]);
+});
+
+const volList = computed(() => {
+  let rtData = props.data.pwrdevAcdcdata;
+  return modelList.value.map((item) => rtData[`m${item}OutVol`]);
+});
+
+watch(
+  () => props.data,
+  () => {
+    nextTick(() => {
+      updateRt();
+    });
+  },
+  { immediate: true, deep: true }
+);
+
+function updateAcin() {
+  let rtData = props.data.pwrdevAcdcdata;
+  let line = lineIdx.value + 1;
+  if (chart0.value) {
+    chart0.value.updateChart(['A', 'B', 'C'], [rtData[`acin${line}Vola`], rtData[`acin${line}Volb`], rtData[`acin${line}Volc`]]);
+  }
+  if (chart1.value) {
+    chart1.value.updateChart(['A', 'B', 'C'], [rtData[`acin${line}Curra`], rtData[`acin${line}Currb`], rtData[`acin${line}Currc`]]);
+  }
+}
+
+function updateRt() {
+  let rtData = props.data.pwrdevAcdcdata;
+  updateAcin();
+  if (chart2.value) {
+    chart2.value.updateChart(['A', 'B', 'C'], [rtData[`acoutVola`], rtData[`acoutVolb`], rtData[`acoutVolc`]]);
+  }
+  if (chart3.value) {
+    chart3.value.updateChart(rtData.dcoutVol);
+  }
+  if (chart4.value) {
+    chart4.value.updateChart(rtData.dcoutCurr);
+  }
+  if (chart5.value) {
+    chart5.value.updateChart(modelList.value.map((item) => `${item}#`), volList.value);
+  }
+  if (chart6.value) {
+    chart6.value.updateChart(modelList.value.map((item) => `${item}#`), volList.value);
+  }
+}
+
+onMounted(() => {
+  
+});
 </script>
 
 <template>
   <div class="tab-content">
     <div class="p-left">
       <div class="p-item">
-        <card title="浜ゆ祦杈撳叆鐢靛帇">
+        <card title="浜ゆ祦杈撳叆">
           <template #tools>
-            <el-radio-group class="line-idx" v-model="lineIdx" size="small">
+            <el-radio-group class="line-idx" v-model="lineIdx" @change="updateAcin" size="small">
               <el-radio-button label="涓�璺�" :value="0" />
               <el-radio-button label="浜岃矾" :value="1" />
             </el-radio-group>
           </template>
+          <div class="wrap">
+            <div class="g-vol">
+              <bar ref="chart0"></bar>
+            </div>
+            <div class="g-curr">
+              <bar1 ref="chart1"></bar1>
+            </div>
+          </div>
         </card>
       </div>
       <div class="p-item">
-        <card title="浜ゆ祦姣嶇嚎鐢靛帇"></card>
+        <card title="浜ゆ祦姣嶇嚎鐢靛帇">
+          <div class="wrap2">
+            <div class="g-vol">
+              <bar2 :barW="40" ref="chart2"></bar2>
+            </div>
+            <div class="g-vol">
+              <gauge ref="chart3"></gauge>
+            </div>
+            <div class="g-vol">
+              <water ref="chart4"></water>
+            </div>
+          </div>
+        </card>
       </div>
     </div>
     <div class="p-right">
       <div class="p-item">
-        <card title="鏁存祦鍣ㄥ紑鍏崇姸鎬�"></card>
+        <card title="鏁存祦鍣ㄥ紑鍏崇姸鎬�">
+          <div class="wrap scroll">
+            <div class="grid">
+              <div class="item" v-for="(i, idx) in modelList" :key="'list_' + idx">
+                <yc-tag>
+                  <div class="item-content">
+                    <div class="idx">{{ i }}#</div>
+                    <el-switch
+                      v-model="state[idx]"
+                      class="opacity1"
+                      disabled
+                      inline-prompt
+                      active-text="寮�鏈�"
+                      inactive-text="鍏虫満"
+                      style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
+                      />
+                  </div>
+                </yc-tag>
+              </div>
+            </div>
+          </div>
+        </card>
       </div>
       <div class="p-item large">
-        <card title="鏁存祦鍣ㄨ緭鍑虹數娴�"></card>
+        <card title="鏁存祦鍣ㄨ緭鍑虹數鍘�">
+          <div class="wrap">
+            <div class="g-vol g-item">
+              <bar4 ref="chart5"></bar4>
+            </div>
+            <div class="panel-title">鏁存祦鍣ㄨ緭鍑虹數娴�</div>
+            <div class="g-curr g-item">
+              <bar4 ref="chart6"></bar4>
+            </div>
+          </div>
+        </card>
       </div>
     </div>
   </div>
@@ -46,6 +180,27 @@
     .p-item {
       flex: 1;
       margin: 8px;
+
+      .wrap {
+        height: 100%;
+        display: flex;
+        .g-vol {
+          flex: 1;
+        }
+        .g-curr {
+          flex: 1;
+        }
+      }
+      .wrap2 {
+        height: 100%;
+        display: flex;
+        .g-vol {
+          flex: 1;
+          &~.g-vol {
+            margin-left: 18px;
+          }
+        }
+      }
     }
   }
 
@@ -57,9 +212,48 @@
     .p-item {
       flex: 1;
       margin: 8px;
+      .wrap.scroll {
+        height: 100%;
+        overflow-y: auto;
+      }
+      .grid {
+        // height: 100%;
+        padding: 10px;
+        display: grid;
+        grid-template-columns: repeat(6, 1fr);
+        // grid-template-rows: repeat(2, 1fr);
+        grid-gap: 10px 6px;
+        place-content: stretch;
+        // place-items: center stretch;
+        // justify-items: stretch;
+        // align-items: stretch;
+        .item-content {
+          height: 100%;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          .idx {
+            background: #0ff;
+            color: #000;
+            font-weight: 700;
+            padding: 2px 6px;
+            border-radius: 10px;
+            margin-right: 10px;
+            font-size: 17px;
+          }
+        }
+      }
 
       &.large {
         flex: 2;
+        .wrap {
+          height: 100%;
+          display: flex;
+          flex-direction: column;
+          .g-item {
+            flex: 1;
+          }
+        }
       }
     }
   }
diff --git a/src/views/realtime/tabs/res.vue b/src/views/realtime/tabs/res.vue
new file mode 100644
index 0000000..eddb5ed
--- /dev/null
+++ b/src/views/realtime/tabs/res.vue
@@ -0,0 +1,137 @@
+<script setup name="res">
+import { ref, reactive, computed, watch, nextTick, onMounted } from "vue";
+import info from '@/components/info.vue';
+import bar from '@/components/echarts/bar5.vue';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: {},
+  },
+});
+
+const chart0 = ref(null);
+
+watch(
+  () => props.data,
+  () => {
+    nextTick(() => {
+      updateRt();
+    });
+  },
+  { immediate: true, deep: true }
+);
+
+const list = computed(() => {
+  let res = [];
+  let rt = props.data.rtdataList;
+  if (rt && rt.length) {
+    res = rt.map((v) => `${v.monNum}#`);
+  }
+  return res;
+});
+
+const chartData = computed(() => {
+  let res = [];
+  let rt = props.data.rtdataList;
+  if (rt && rt.length) {
+    res = rt.map((v) => v.monRes);
+  }
+  return res;
+});
+
+function updateRt() {
+  
+  if(chart0.value) {
+    chart0.value.updateChart(list.value, chartData.value);
+  }
+}
+
+
+onMounted(() => {
+
+});
+</script>
+
+<template>
+  <div class="tab-content">
+    <div class="p-left">
+      <card title="鍗曚綋鍐呴樆">
+        <div class="wrap">
+          <div class="row">
+            <div class="item">
+              <info label="鏈�澶у��" :value="data.maxData"></info>
+            </div>
+            <div class="item">
+              <info label="鏈�灏忓��" :value="data.minData"></info>
+            </div>
+            <div class="item">
+              <info label="骞冲潎鍊�" :value="data.avgData"></info>
+            </div>
+          </div>
+          <div class="main">
+            <bar ref="chart0"></bar>
+          </div>
+        </div>
+      </card>
+    </div>
+    <div class="p-right">
+      <div class="btn">瀛e害鏇茬嚎璁板綍</div>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.tab-content {
+  display: flex;
+  flex-direction: row;
+  height: 100%;
+  padding: 10px;
+
+  .p-left {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    margin-right: 10px;
+
+    .wrap {
+      display: flex;
+      flex-direction: column;
+      height: 100%;
+      .row {
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        .item {
+          min-width: 170px;
+          &~.item {
+            margin-left: 20px;
+          }
+        }
+      }
+      .main {
+        flex: 1;
+      }
+    }
+  }
+  .p-right {
+    .btn {
+      font-size: 14px;
+      margin: 2px 4px;
+      cursor: pointer;
+      border: 1px solid #3D9CC9;
+      box-shadow: inset 0 0 10px 4px #3D9CC9;
+      padding: 6px 12px;
+      text-align: center;
+      border-radius: 4px;
+
+      &:hover {
+        color: #FDFE01;
+        border: 1px solid #DF7B26;
+        box-shadow: inset 0 0 10px 4px #DF7B26;
+      }
+    }
+  }
+
+}
+</style>
diff --git a/src/views/realtime/tabs/system.vue b/src/views/realtime/tabs/system.vue
index 72c663f..dcde4af 100644
--- a/src/views/realtime/tabs/system.vue
+++ b/src/views/realtime/tabs/system.vue
@@ -1,11 +1,20 @@
-<script setup>
-import { nextTick, ref, watch, onMounted } from "vue";
+<script setup name="tabSystem">
+import { nextTick, ref, reactive, computed, watch, onMounted } from "vue";
 import svgDiagram from '@/components/svgDiagram.vue';
 import info from '@/components/info.vue';
 import lineChart from '@/components/echarts/line1.vue';
 import lineChart2 from '@/components/echarts/line2.vue';
+import hrParams from '@/components/hrParams.vue';
+import devAlarmParams from '../devAlarmParams.vue';
+
+import lineChart3 from '@/components/echarts/line-scroll.vue';
 // import lineChart from '@/components/echarts/BaseChart.vue';
 // import lineChart from '../bar8.vue';
+import moment from 'moment';
+import getBinaryDigits from '@/utils/getBinaryDigits.js';
+
+import useElement from "@/hooks/useElement.js";
+	const { $loading, $message, $confirm } = useElement();
 
 
 import {
@@ -13,6 +22,11 @@
 	getHalfHourPwrHisAcinData,
 	getHalfHourPwrHisDcoutData,
 } from "@/api/realtime";
+
+import {
+  stopDis,
+  restart,
+} from '@/api/control';
 
 const props = defineProps({
 	data: {
@@ -37,6 +51,66 @@
 const chart1 = ref(null);
 const chart2 = ref(null);
 
+const labels_0 = [
+	[
+		['涓�璺疉鐩哥數娴�', 'acin1Curra'],
+		['涓�璺疊鐩哥數娴�', 'acin1Currb'],
+		['涓�璺疌鐩哥數娴�', 'acin1Currc'],
+		['浜岃矾A鐩哥數娴�', 'acin2Curra'],
+		['浜岃矾B鐩哥數娴�', 'acin2Currb'],
+		['浜岃矾C鐩哥數娴�', 'acin2Currc'],
+	],
+	[
+		['涓�璺疉鐩哥數鍘�', 'acin1Vola'],
+		['涓�璺疊鐩哥數鍘�', 'acin1Volb'],
+		['涓�璺疌鐩哥數鍘�', 'acin1Volc'],
+		['浜岃矾A鐩哥數鍘�', 'acin2Vola'],
+		['浜岃矾B鐩哥數鍘�', 'acin2Volb'],
+		['浜岃矾C鐩哥數鍘�', 'acin2Volc'],
+	]
+];
+
+const labels_1 = reactive([[], []]);
+
+const devRt = ref({
+  devIp: "127.0.0.0",
+  devVersion: "1",
+  devId: 0,
+  devOnline: 0,
+  recordDatetime: "",
+  devTesttype: 0,
+  devTestgroupnum: 0,
+  devWorkstate: -1,
+  devAlarmstate: 0,
+  devTemp: 0.0,
+  devResTestState: 0,
+  devOnlinevollow: 0,
+  devEachgroupBattsum: 0,
+  devCaptestOnlinevol: 0.0,
+  devCaptestGroupvol: 0.0,
+  devCaptestCurr: 0.0,
+  devCaptestCap: 0.0,
+  devCaptestTimelong: 0,
+  devRestestCount: 0,
+  devCommcount: 0,
+  devErrcommcount: 0,
+  devRxnullerrcount: 0,
+  devLastCaptestStopType: 0,
+  devCondvoldp: 0.0,
+  devConresist: 0.0,
+  devConresist1: 0.0,
+  dev61850alarms: "",
+  devCondvoldp1: 0.0,
+  groupVol1: 0.0,
+  groupVol2: 0.0,
+  groupCurr1: 0.0,
+  groupCurr2: 0.0,
+});
+
+const battRt = ref({
+  groupCurr: 0,
+});
+
 watch(
 	() => tabIdx0.value,
 	() => {
@@ -60,71 +134,444 @@
 watch(
 	() => props.powerId,
 	(n) => {
-    if (!n) return;
+		if (!n) return;
 
 		nextTick(() => {
-			getAcinData();
-			getDevData();
-			getDcoutData();
+			// getAcinData();
+			// getDevData();
+			// getDcoutData();
+			numChange('acin');
+			numChange('dcout');
+			numChange('dev');
 		});
 	},
 	{ immediate: true }
-)
+);
+
+watch(
+	() => props.data,
+	(n) => {
+		if (!n) return;
+		nextTick(() => {
+			updateRt();
+      if (n.deviceState) {
+        devRt.value = n.deviceState;
+      }
+      if (n.battRtstate) {
+        battRt.value = n.battRtstate;
+      }
+		});
+	},
+	{ immediate: true, deep: true }
+);
+
+const show_num = reactive({
+	acin: 5,
+	dcout: 5,
+	dev: 5,
+});
+
+// 鐢ㄦ潵缁樺浘鐨勬暟鎹�
+const chartData = reactive({
+	acin: [],
+	dcout: [],
+	dev: [],
+});
+
+const modelCfg = ref([]);
+const startIdx = ref(0);
+
+// 鍗婂皬鏃剁殑鏁版嵁鏉℃暟 1绉掍竴绗旇
+const counter = 30 * 60;
+
+let xLabels1 = ref([]);
+let xLabels2 = ref([]);
+
+// 鏍规嵁绮掑害 鍜屾煡璇㈢粨鏋� 琛ュ叏鏁版嵁
+function completeData(type) {
+	// 鏍规嵁绮掑害 璁$畻鍑洪渶瑕佺殑鏉℃暟
+	let num = Math.ceil(counter / show_num[type]);
+	let _num = num - chartData[type].length;
+	let obj = null;
+	let res = [...chartData[type]];
+	switch (type) {
+		case 'acin':
+			obj = {
+				acin1Vola: 0,
+				acin1Volb: 0,
+				acin1Volc: 0,
+				acin2Vola: 0,
+				acin2Volb: 0,
+				acin2Volc: 0,
+				acin1Curra: 0,
+				acin1Currb: 0,
+				acin1Currc: 0,
+				acin2Curra: 0,
+				acin2Currb: 0,
+				acin2Currc: 0,
+			};
+			break;
+		case 'dcout':
+			obj = {
+				m1Outcurr: 0.0,
+				m2Outcurr: 0.0,
+				m3Outcurr: 0.0,
+				m4Outcurr: 0.0,
+				m5Outcurr: 0.0,
+				m6Outcurr: 0.0,
+				m7Outcurr: 0.0,
+				m8Outcurr: 0.0,
+				m9Outcurr: 0.0,
+				m10Outcurr: 0.0,
+				m11Outcurr: 0.0,
+				m12Outcurr: 0.0,
+				m13Outcurr: 0.0,
+				m14Outcurr: 0.0,
+				m15Outcurr: 0.0,
+				m16Outcurr: 0.0,
+				m1OutVol: 0.0,
+				m2OutVol: 0.0,
+				m3OutVol: 0.0,
+				m4OutVol: 0.0,
+				m5OutVol: 0.0,
+				m6OutVol: 0.0,
+				m7OutVol: 0.0,
+				m8OutVol: 0.0,
+				m9OutVol: 0.0,
+				m10OutVol: 0.0,
+				m11OutVol: 0.0,
+				m12OutVol: 0.0,
+				m13OutVol: 0.0,
+				m14OutVol: 0.0,
+				m15OutVol: 0.0,
+				m16OutVol: 0.0,
+				moutputvol: 0.0,
+			};
+			break;
+		case 'dev':
+			obj = {
+				groupVol: 0.0,
+				onlineVol: 0.0,
+				groupCurr: 0.0,
+				groupTmp: 0.0,
+				loadCurr: 0.0,
+			};
+			break;
+	}
+	let _xLabels1 = chartData['dcout'].map(item => item.recordDatetime);
+	let _xLabels2 = chartData['dev'].map(item => item.recordDatetime);
+	// 鏁版嵁鏈�灏忔椂闂�
+	let minTime = chartData[type].length ? chartData[type][0].recordDatetime : moment().format('YYYY-MM-DD HH:mm:ss');
+	if (_num > 0) {
+		for (let i = _num; i--;) {
+			minTime = moment(minTime).subtract(show_num[type], 'seconds').format('YYYY-MM-DD HH:mm:ss');
+			res.unshift({
+				recordDatetime: minTime,
+				...obj,
+			});
+			_xLabels1.unshift(minTime);
+			_xLabels2.unshift(minTime);
+		}
+	}
+	switch (type) {
+		case 'acin':
+			break;
+		case 'dcout':
+			xLabels1.value = yLabels.value.length ? _xLabels1 : [];
+			break;
+		case 'dev':
+			xLabels2.value = _xLabels2;
+			break;
+	}
+	chartData[type] = res;
+}
+
 
 function tabIdx0Change() {
-	// TODO
-	if (chart0.value) {
-		chart0.value.updateChart([1, 2, 3], [100, 200, 300]);
-	}
+	updateChart0();
 }
 
 function tabIdx1Change() {
-	// TODO
+	updateChart1();
+}
+
+async function getAcinData() {
+	let { code, data, data2 } = await getHalfHourPwrHisAcinData(props.powerId, show_num.acin);
+	let list = [];
+	if (code && data) {
+		list = data2;
+	}
+	return list;
+}
+
+async function getDevData() {
+	let { code, data, data2 } = await getHalfHourBattDevData(props.battgroupId, show_num.dev);
+	let list = [];
+	if (code && data) {
+		list = data2;
+	}
+	return list;
+}
+
+async function getDcoutData() {
+	let { code, data, data2, data3 } = await getHalfHourPwrHisDcoutData(props.powerId, show_num.dcout);
+	let list = [];
+	let cfg = [];
+	if (code && data) {
+		list = data2;
+		cfg = getBinaryDigits(data3).map((v, i) => ({ value: v, label: i + 1 })).filter(vv => vv.value).map(v => v.label);
+	}
+	console.log('cfg', cfg, '=============', data3);
+
+	modelCfg.value = cfg;
+	if (cfg.length < 4) {
+		startIdx.value = 0;
+	}
+	// setLabel1();
+	return list;
+}
+
+const yLabels = computed(() => {
+	let res = modelCfg.value.map((idx) => `${idx}#鏁存祦鍣╜);
+	if (modelCfg.value.length > 4) {
+		res = res.slice(startIdx.value, startIdx.value + 4);
+	}
+	return res;
+});
+
+// function setLabel1() {
+//   // console.log('??', modelCfg.value, '=============');
+//   if (modelCfg.value.length <= 4) {
+//     yLabels.value = modelCfg.value.map((idx) => `${idx}#鏁存祦鍣╜);
+//   } else {
+//     yLabels.value = modelCfg.value.slice(startIdx.value, startIdx.value + 4).map((idx) => `${idx}#鏁存祦鍣╜);
+//   }
+// }
+
+const chartData1 = ref([]);
+
+function formatData1() {
+	let res = [];
+	for (let i = 0, len = chartData['dcout'].length; i < len; i++) {
+		yLabels.value.forEach((item, idx) => {
+			res[idx] = res[idx] || [];
+			let type = ['curr', 'Vol'][tabIdx1.value];
+			let _prop = `m${idx + 1}Out${type}`;
+
+			res[idx].push(chartData['dcout'][i][_prop]);
+		});
+	}
+	// console.log('res format', res, yLabels.value, '=============');
+
+	chartData1.value = res;
+}
+
+
+function stopHrTest() {
+  $confirm("鍋滄鏍稿娴嬭瘯", async () => {
+    let loading = $loading();
+    let res = await stopDis(props.powerId, props.battgroupId);
+    loading.close();
+    let { code, data } = res;
+    if (code && data) {
+      $message.success('鎿嶄綔鎴愬姛');
+    } else {
+      $message.error('鎿嶄綔澶辫触');
+    }
+  });
+}
+
+function remoteRestart() {
+  $confirm("杩滅▼閲嶅惎", async () => {
+    let loading = $loading();
+    let res = await restart(props.powerId, props.battgroupId);
+    loading.close();
+    let { code, data } = res;
+    if (code && data) {
+      $message.success('鎿嶄綔鎴愬姛');
+    } else {
+      $message.error('鎿嶄綔澶辫触');
+    }
+  });
+}
+
+const devAlmVisible = ref(false);
+function showDevAlarmParam() {
+  devAlmVisible.value = true;
+}
+
+
+async function numChange(type) {
+	switch (type) {
+		case 'acin':
+			chartData.acin = await getAcinData();
+			completeData('acin');
+			updateChart0();
+			break;
+		case 'dcout':
+			chartData.dcout = await getDcoutData();
+			// setLabel1();
+			completeData('dcout');
+			formatData1();
+			updateChart1();
+			break;
+		case 'dev':
+			chartData.dev = await getDevData();
+			completeData('dev');
+			updateChart2();
+			break;
+	}
+
+}
+
+const battInfo = ref({});
+// 鏇存柊瀹炴椂鏁版嵁
+function updateRt() {
+	let pwrData = props.data.pwrdevAcdcdata;
+	if (!pwrData) {
+		return false;
+	}
+	// 淇敼涓変釜鍥捐〃鐨勬暟鎹�
+	// chart0  chartData['acin']
+	// 鏍规嵁绮掑害 璁$畻鍑洪渶瑕佺殑鏉℃暟
+	// let num = Math.ceil(counter / show_num['acin']);
+	chartData['acin'].shift();
+	chartData['acin'].push(pwrData);
+	updateChart0();
+
+	// chart1  chartData['dcout']
+	// 鏍规嵁绮掑害 璁$畻鍑洪渶瑕佺殑鏉℃暟
+	if (!chartData1.value.length) {
+		modelCfg.value = getBinaryDigits(props.data.powerInf.modelCfg).map((v, i) => ({ value: v, label: i + 1 })).filter(vv => vv.value).map(v => v.label);
+		pwrData.recordDatetime
+		let minTime = pwrData.recordDatetime;
+		let num = Math.ceil(counter / show_num['dcout']);
+		let _label = [];
+		let list = [];
+		for (let i = num; i--;) {
+			minTime = moment(minTime).subtract(show_num['dcout'], 'seconds').format('YYYY-MM-DD HH:mm:ss');
+			list.unshift({
+				recordDatetime: minTime,
+				m1Outcurr: 0.0,
+				m2Outcurr: 0.0,
+				m3Outcurr: 0.0,
+				m4Outcurr: 0.0,
+				m5Outcurr: 0.0,
+				m6Outcurr: 0.0,
+				m7Outcurr: 0.0,
+				m8Outcurr: 0.0,
+				m9Outcurr: 0.0,
+				m10Outcurr: 0.0,
+				m11Outcurr: 0.0,
+				m12Outcurr: 0.0,
+				m13Outcurr: 0.0,
+				m14Outcurr: 0.0,
+				m15Outcurr: 0.0,
+				m16Outcurr: 0.0,
+				m1OutVol: 0.0,
+				m2OutVol: 0.0,
+				m3OutVol: 0.0,
+				m4OutVol: 0.0,
+				m5OutVol: 0.0,
+				m6OutVol: 0.0,
+				m7OutVol: 0.0,
+				m8OutVol: 0.0,
+				m9OutVol: 0.0,
+				m10OutVol: 0.0,
+				m11OutVol: 0.0,
+				m12OutVol: 0.0,
+				m13OutVol: 0.0,
+				m14OutVol: 0.0,
+				m15OutVol: 0.0,
+				m16OutVol: 0.0,
+				moutputvol: 0.0,
+			});
+			_label.unshift(minTime);
+		}
+		xLabels1.value = _label;
+		chartData['dcout'] = list;
+	}
+
+	xLabels1.value.shift();
+	xLabels1.value.push(pwrData.recordDatetime);
+	chartData['dcout'].shift();
+	chartData['dcout'].push(pwrData);
+	nextTick(() => {
+
+		formatData1();
+		updateChart1();
+	});
+
+
+	// chart2  chartData['dev']
+	// 鏍规嵁绮掑害 璁$畻鍑洪渶瑕佺殑鏉℃暟
+	// let num = Math.ceil(counter / show_num['dev']);
+	// TODO battRtstate 缂哄皯loadCurr
+	let devObj = props.data.battRtstate;
+	xLabels1.value.shift();
+	xLabels1.value.push(devObj.recordDatetime);
+	chartData['dev'].shift();
+	chartData['dev'].push(devObj);
+	updateChart2();
+
+	// 钃勭數姹犱俊鎭�
+	battInfo.value = props.data.sticRtdata;
+}
+
+// 鍙栧墠鍗婂皬鏃舵暟鎹� 鏇存柊鍥捐〃
+
+// 鏇存柊鍥捐〃 1 2 3
+function updateChart0() {
+	if (chart0.value) {
+		chart0.value.updateChart(labels_0[tabIdx0.value], chartData['acin']);
+	}
+}
+
+function updateChart1() {
 	if (chart1.value) {
-		chart1.value.updateChart([1, 2, 3], [100, 200, 300]);
+		chart1.value.updateChart(xLabels1.value, chartData1.value);
 	}
 }
 
-async function getAcinData(granularity = 5) {
-	let { code, data, data2 } = await getHalfHourPwrHisAcinData(props.powerId, granularity);
-	let list = [];
-	if (code && data) {
-		list = data2;
+function updateChart2() {
+	if (chart2.value) {
+		chart2.value.updateChart(xLabels2.value, chartData['dev']);
 	}
-	return list;
 }
 
-async function getDevData(granularity = 5) {
-	let { code, data, data2 } = await getHalfHourBattDevData(props.battgroupId, granularity);
-	let list = [];
-	if (code && data) {
-		list = data2;
-	}
-	return list;
+function scrollHandler(data) {
+	console.log('data', data, '=============');
+
+	startIdx.value += data * 1;
+	nextTick(() => {
+		// updateChart1();
+	})
 }
 
-async function getDcoutData(granularity = 5) {
-	let { code, data, data2 } = await getHalfHourPwrHisDcoutData(props.powerId, granularity);
-	let list = [];
-	if (code && data) {
-		list = data2;
-	}
-	return list;
+const hrParamTitle = ref('鏍稿娴嬭瘯');
+const hrParamVisible = ref(false);
+function startHrTest() {
+	hrParamVisible.value = true;
 }
+
 
 onMounted(async () => {
+	numChange('acin');
+	numChange('dcout');
+	numChange('dev');
+
 	// await getAcinData();
 	// await getDevData();
 	// await getDcoutData();
 
-	if (chart2.value) {
-		chart2.value.updateChart(['04:12', '04:13', '04:14'], {
-			'璁惧娓╁害': [100, 200, 220],
-			'缁勭鐢垫祦': [100, 200, 220],
-			'缁勭鐢靛帇': [100, 200, 220],
-			'璐熻浇鐢垫祦': [100, 200, 220],
-		});
-	}
+	// if (chart1.value) {
+	// 	chart1.value.updateChart(['04:12', '04:13', '04:14'], {
+	// 		'璁惧娓╁害': [100, 200, 220],
+	// 		'缁勭鐢垫祦': [100, 200, 220],
+	// 		'缁勭鐢靛帇': [100, 200, 220],
+	// 		'璐熻浇鐢垫祦': [100, 200, 220],
+	// 	});
+	// }
 });
 </script>
 
@@ -173,23 +620,23 @@
           </div>
         </div>
         <div class="p-main">
-          <svg-diagram class="svg-diagram"></svg-diagram>
+          <svg-diagram :data="devRt" :battRt="battRt" class="svg-diagram"></svg-diagram>
         </div>
         <div class="p-right">
           <div class="control-contain">
             <div class="control-title">
               <svg-icon icon-class="controls"></svg-icon><span>鎺у埗绠$悊</span>
             </div>
-            <div class="control-btn">鏍稿娴嬭瘯</div>
-            <div class="control-btn">鍋滄鏍稿娴嬭瘯</div>
+            <div class="control-btn" @click="startHrTest">鏍稿娴嬭瘯</div>
+            <div class="control-btn" @click="stopHrTest">鍋滄鏍稿娴嬭瘯</div>
           </div>
           <div class="control-contain">
             <div class="control-title">
               <svg-icon icon-class="dev"></svg-icon><span>璁惧绠$悊</span>
             </div>
-            <div class="control-btn">杩滅▼閲嶅惎</div>
+            <div class="control-btn" @click="remoteRestart">杩滅▼閲嶅惎</div>
             <div class="control-btn">绯荤粺鍙傛暟璁剧疆</div>
-            <div class="control-btn">鍛婅鍙傛暟璁剧疆</div>
+            <div class="control-btn" @click="showDevAlarmParam">鍛婅鍙傛暟璁剧疆</div>
           </div>
           <div class="control-contain no-wrap">
             <div class="control-btn">鏀剧數鐢宠</div>
@@ -201,59 +648,181 @@
       <div class="card-item">
         <card title="浜ゆ祦杈撳叆">
           <template #tools>
+            <div class="page-filter">
+              <div class="label">绮掑害</div>
+              <div class="value">
+                <el-select
+                  v-model="show_num['acin']"
+                  size="small"
+                  style="width: 50px"
+                  @change="numChange('acin')"
+                >
+                  <el-option
+                    v-for="(n, i) in 10"
+                    :key="'list0_' + i"
+                    :label="'x' + n"
+                    :value="n"
+                  />
+                </el-select>
+              </div>
+            </div>
             <el-radio-group class="tab-idx" v-model="tabIdx0" size="small">
               <el-radio-button label="鐢垫祦" :value="0" />
               <el-radio-button label="鐢靛帇" :value="1" />
             </el-radio-group>
-            <svg-icon class-name="btn-setting" icon-class="setting"></svg-icon>
           </template>
-          <line-chart
-            ref="chart0"
-            :type="['鐢垫祦', '鐢靛帇'][tabIdx0]"
-          ></line-chart>
+          <line-chart ref="chart0"></line-chart>
         </card>
       </div>
       <div class="card-item">
-        <card title="鐩存祦杈撳叆">
+        <card title="鐩存祦杈撳嚭">
           <template #tools>
+            <div class="page-filter">
+              <div class="label">绮掑害</div>
+              <div class="value">
+                <el-select
+                  v-model="show_num['dcout']"
+                  size="small"
+                  style="width: 50px"
+                  @change="numChange('dcout')"
+                >
+                  <el-option
+                    v-for="(n, i) in 10"
+                    :key="'list0_' + i"
+                    :label="'x' + n"
+                    :value="n"
+                  />
+                </el-select>
+              </div>
+            </div>
             <el-radio-group class="tab-idx" v-model="tabIdx1" size="small">
               <el-radio-button label="鐢垫祦" :value="0" />
               <el-radio-button label="鐢靛帇" :value="1" />
             </el-radio-group>
-            <svg-icon class-name="btn-setting" icon-class="setting"></svg-icon>
           </template>
-          <line-chart
+          <line-chart3
             ref="chart1"
             :type="['鐢垫祦', '鐢靛帇'][tabIdx1]"
-          ></line-chart>
+            :yLabels="yLabels"
+            :start-idx="startIdx"
+            :mode-count="modelCfg.length"
+            @scroll="scrollHandler"
+          ></line-chart3>
         </card>
       </div>
       <div class="card-item">
         <card title="鏍稿璁惧淇℃伅">
           <template #tools>
-            <svg-icon class-name="btn-setting" icon-class="setting"></svg-icon>
+            <div class="page-filter">
+              <div class="label">绮掑害</div>
+              <div class="value">
+                <el-select
+                  v-model="show_num['dev']"
+                  size="small"
+                  style="width: 50px"
+                  @change="numChange('dev')"
+                >
+                  <el-option
+                    v-for="(n, i) in 10"
+                    :key="'list0_' + i"
+                    :label="'x' + n"
+                    :value="n"
+                  />
+                </el-select>
+              </div>
+            </div>
+            <!-- <svg-icon class-name="btn-setting" icon-class="setting"></svg-icon> -->
           </template>
-          <line-chart2
-            ref="chart2"
-            :type="['鐢垫祦', '鐢靛帇'][tabIdx1]"
-          ></line-chart2>
+          <line-chart2 ref="chart2"></line-chart2>
         </card>
       </div>
       <div class="card-item">
         <card title="钃勭數姹犱俊鎭�">
           <div class="batt grid">
-            <info label="鏈�澶у閲�" value="#3 8Ah"></info>
-            <info label="鏈�灏忓閲�" value="100"></info>
-            <info label="鏈�楂樺唴闃�" value="100"></info>
-            <info label="鏈�浣庡唴闃�" value="100"></info>
-            <info label="鏈�楂樼數鍘�" value="100"></info>
-            <info label="鏈�浣庣數鍘�" value="100"></info>
-            <info label="鏈�楂樻俯搴�" value="100"></info>
-            <info label="鏈�浣庢俯搴�" value="100"></info>
+            <info label="鏈�澶у閲�">
+              <template
+                #value
+                v-if="battInfo.maxCapNumList && battInfo.maxCapNumList.length"
+              >
+                <span class="mon-num">#{{ battInfo.maxCapNumList[0] }}</span>
+                <span class="val">{{ battInfo.maxCap }}Ah</span>
+              </template>
+            </info>
+            <info label="鏈�灏忓閲�">
+              <template
+                #value
+                v-if="battInfo.minCapNumList && battInfo.minCapNumList.length"
+              >
+                <span class="mon-num">#{{ battInfo.minCapNumList[0] }}</span>
+                <span class="val">{{ battInfo.minCap }}Ah</span>
+              </template>
+            </info>
+            <info label="鏈�楂樺唴闃�">
+              <template
+                #value
+                v-if="battInfo.maxResNumList && battInfo.maxResNumList.length"
+              >
+                <span class="mon-num">#{{ battInfo.maxResNumList[0] }}</span>
+                <span class="val">{{ battInfo.maxRes }}m惟</span>
+              </template>
+            </info>
+            <info label="鏈�浣庡唴闃�">
+              <template
+                #value
+                v-if="battInfo.minResNumList && battInfo.minResNumList.length"
+              >
+                <span class="mon-num">#{{ battInfo.minResNumList[0] }}</span>
+                <span class="val">{{ battInfo.minRes }}m惟</span>
+              </template>
+            </info>
+            <info label="鏈�楂樼數鍘�">
+              <template
+                #value
+                v-if="battInfo.maxVolNumList && battInfo.maxVolNumList.length"
+              >
+                <span class="mon-num">#{{ battInfo.maxVolNumList[0] }}</span>
+                <span class="val">{{ battInfo.maxVol }}V</span>
+              </template>
+            </info>
+            <info label="鏈�浣庣數鍘�">
+              <template
+                #value
+                v-if="battInfo.minVolNumList && battInfo.minVolNumList.length"
+              >
+                <span class="mon-num">#{{ battInfo.minVolNumList[0] }}</span>
+                <span class="val">{{ battInfo.minVol }}V</span>
+              </template>
+            </info>
+            <info label="鏈�楂樻俯搴�">
+              <template
+                #value
+                v-if="battInfo.maxTmpNumList && battInfo.maxTmpNumList.length"
+              >
+                <span class="mon-num">#{{ battInfo.maxTmpNumList[0] }}</span>
+                <span class="val">{{ battInfo.maxTmp }}鈩�</span>
+              </template>
+            </info>
+            <info label="鏈�浣庢俯搴�">
+              <template
+                #value
+                v-if="battInfo.minTmpNumList && battInfo.minTmpNumList.length"
+              >
+                <span class="mon-num">#{{ battInfo.minTmpNumList[0] }}</span>
+                <span class="val">{{ battInfo.minTmp }}鈩�</span>
+              </template>
+            </info>
           </div>
         </card>
       </div>
     </div>
+    <!-- 璁剧疆鏍稿鍙傛暟 -->
+    <el-dialog v-model="hrParamVisible" :title="hrParamTitle" width="960">
+      <hr-params :devId="devId" v-model:visible="hrParamVisible" :battgroupId="battgroupId"></hr-params>
+    </el-dialog>
+    <!-- 璁剧疆璁惧鍛婅鍙傛暟 -->
+    <el-dialog v-model="devAlmVisible" title="璁惧鍛婅鍙傛暟" width="960">
+      <dev-alarm-params :devId="devId" v-model:visible="devAlmVisible"></dev-alarm-params>
+    </el-dialog>
   </div>
 </template>
 
@@ -462,5 +1031,30 @@
       color: #fff;
     }
   }
+
+  .page-filter {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    margin-right: 6px;
+    margin-top: 0;
+    margin-bottom: 0;
+    padding: 0;
+    background: transparent;
+    border: 0 none;
+
+    .label {
+      font-size: 12px;
+      margin-right: 6px;
+
+      &::after {
+        content: ":";
+      }
+    }
+  }
+
+  .mon-num {
+    margin-right: 1em;
+  }
 }
 </style>
diff --git a/src/views/realtime/tabs/temp.vue b/src/views/realtime/tabs/temp.vue
new file mode 100644
index 0000000..4fe44d4
--- /dev/null
+++ b/src/views/realtime/tabs/temp.vue
@@ -0,0 +1,137 @@
+<script setup name="temp">
+import { ref, reactive, computed, watch, nextTick, onMounted } from "vue";
+import info from '@/components/info.vue';
+import bar from '@/components/echarts/bar5.vue';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: {},
+  },
+});
+
+const chart0 = ref(null);
+
+watch(
+  () => props.data,
+  () => {
+    nextTick(() => {
+      updateRt();
+    });
+  },
+  { immediate: true, deep: true }
+);
+
+const list = computed(() => {
+  let res = [];
+  let rt = props.data.rtdataList;
+  if (rt && rt.length) {
+    res = rt.map((v) => `${v.monNum}#`);
+  }
+  return res;
+});
+
+const chartData = computed(() => {
+  let res = [];
+  let rt = props.data.rtdataList;
+  if (rt && rt.length) {
+    res = rt.map((v) => v.monTmp);
+  }
+  return res;
+});
+
+function updateRt() {
+  
+  if(chart0.value) {
+    chart0.value.updateChart(list.value, chartData.value);
+  }
+}
+
+
+onMounted(() => {
+
+});
+</script>
+
+<template>
+  <div class="tab-content">
+    <div class="p-left">
+      <card title="鍗曚綋娓╁害">
+        <div class="wrap">
+          <div class="row">
+            <div class="item">
+              <info label="鏈�澶у��" :value="data.maxData"></info>
+            </div>
+            <div class="item">
+              <info label="鏈�灏忓��" :value="data.minData"></info>
+            </div>
+            <div class="item">
+              <info label="骞冲潎鍊�" :value="data.avgData"></info>
+            </div>
+          </div>
+          <div class="main">
+            <bar ref="chart0"></bar>
+          </div>
+        </div>
+      </card>
+    </div>
+    <div class="p-right">
+      <div class="btn">瀛e害鏇茬嚎璁板綍</div>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.tab-content {
+  display: flex;
+  flex-direction: row;
+  height: 100%;
+  padding: 10px;
+
+  .p-left {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    margin-right: 10px;
+
+    .wrap {
+      display: flex;
+      flex-direction: column;
+      height: 100%;
+      .row {
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        .item {
+          min-width: 170px;
+          &~.item {
+            margin-left: 20px;
+          }
+        }
+      }
+      .main {
+        flex: 1;
+      }
+    }
+  }
+  .p-right {
+    .btn {
+      font-size: 14px;
+      margin: 2px 4px;
+      cursor: pointer;
+      border: 1px solid #3D9CC9;
+      box-shadow: inset 0 0 10px 4px #3D9CC9;
+      padding: 6px 12px;
+      text-align: center;
+      border-radius: 4px;
+
+      &:hover {
+        color: #FDFE01;
+        border: 1px solid #DF7B26;
+        box-shadow: inset 0 0 10px 4px #DF7B26;
+      }
+    }
+  }
+
+}
+</style>
diff --git a/src/views/realtime/tabs/vol.vue b/src/views/realtime/tabs/vol.vue
index 9044e8c..89459a3 100644
--- a/src/views/realtime/tabs/vol.vue
+++ b/src/views/realtime/tabs/vol.vue
@@ -1,16 +1,137 @@
-<script setup>
-import { ref } from "vue";
-import test from '@/components/info.vue';
+<script setup name="vol">
+import { ref, reactive, computed, watch, nextTick, onMounted } from "vue";
+import info from '@/components/info.vue';
+import bar from '@/components/echarts/bar5.vue';
 
+const props = defineProps({
+  data: {
+    type: Object,
+    default: {},
+  },
+});
+
+const chart0 = ref(null);
+
+watch(
+  () => props.data,
+  () => {
+    nextTick(() => {
+      updateRt();
+    });
+  },
+  { immediate: true, deep: true }
+);
+
+const list = computed(() => {
+  let res = [];
+  let rt = props.data.rtdataList;
+  if (rt && rt.length) {
+    res = rt.map((v) => `${v.monNum}#`);
+  }
+  return res;
+});
+
+const chartData = computed(() => {
+  let res = [];
+  let rt = props.data.rtdataList;
+  if (rt && rt.length) {
+    res = rt.map((v) => v.monVol);
+  }
+  return res;
+});
+
+function updateRt() {
+  
+  if(chart0.value) {
+    chart0.value.updateChart(list.value, chartData.value);
+  }
+}
+
+
+onMounted(() => {
+
+});
 </script>
 
 <template>
-  <test
-    label="鐢靛帇"
-    value="123"
-  ></test>
+  <div class="tab-content">
+    <div class="p-left">
+      <card title="鍗曚綋鐢靛帇">
+        <div class="wrap">
+          <div class="row">
+            <div class="item">
+              <info label="鏈�澶у��" :value="data.maxData"></info>
+            </div>
+            <div class="item">
+              <info label="鏈�灏忓��" :value="data.minData"></info>
+            </div>
+            <div class="item">
+              <info label="骞冲潎鍊�" :value="data.avgData"></info>
+            </div>
+          </div>
+          <div class="main">
+            <bar ref="chart0"></bar>
+          </div>
+        </div>
+      </card>
+    </div>
+    <div class="p-right">
+      <div class="btn">瀛e害鏇茬嚎璁板綍</div>
+    </div>
+  </div>
 </template>
 
 <style scoped lang="less">
+.tab-content {
+  display: flex;
+  flex-direction: row;
+  height: 100%;
+  padding: 10px;
 
-</style>
\ No newline at end of file
+  .p-left {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    margin-right: 10px;
+
+    .wrap {
+      display: flex;
+      flex-direction: column;
+      height: 100%;
+      .row {
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        .item {
+          min-width: 170px;
+          &~.item {
+            margin-left: 20px;
+          }
+        }
+      }
+      .main {
+        flex: 1;
+      }
+    }
+  }
+  .p-right {
+    .btn {
+      font-size: 14px;
+      margin: 2px 4px;
+      cursor: pointer;
+      border: 1px solid #3D9CC9;
+      box-shadow: inset 0 0 10px 4px #3D9CC9;
+      padding: 6px 12px;
+      text-align: center;
+      border-radius: 4px;
+
+      &:hover {
+        color: #FDFE01;
+        border: 1px solid #DF7B26;
+        box-shadow: inset 0 0 10px 4px #DF7B26;
+      }
+    }
+  }
+
+}
+</style>
diff --git a/src/views/statistics/battBad.vue b/src/views/statistics/battBad.vue
new file mode 100644
index 0000000..1faec76
--- /dev/null
+++ b/src/views/statistics/battBad.vue
@@ -0,0 +1,526 @@
+<script setup name="battBad">
+	import { ref, reactive, onMounted, computed, nextTick } from "vue";
+	import { storeToRefs } from "pinia";
+	import { Search, Plus } from "@element-plus/icons-vue";
+	import ycCard from "@/components/ycCard/index.vue";
+	import addEdit from "../datas/addEdit.vue";
+	import { ElMessage } from "element-plus";
+	import useElement from "@/hooks/useElement.js";
+  import { useUserStore } from '@/store/user';
+
+  import useStation from "@/hooks/useStationList.js";
+  const { provice, city, country, stationName,
+    proviceList, cityList, countryList, stationList,
+  } = useStation();
+
+  import { useRouter } from "vue-router";
+  const router = useRouter();
+
+  import { ExportFile } from '@/utils/exportFile.js';
+
+
+  import powerTypes from '@/utils/const/const_powerType.js';
+  import hrTypes from '@/utils/const/const_hrTestType.js';
+  import {
+    getBattPerformance,
+  } from "@/api/station";
+
+  const userStore = useUserStore();
+  const { uid, uname } = storeToRefs(userStore);
+  import moment from 'moment';
+
+  import formatSeconds from '@/utils/formatSeconds';
+  import {
+    toFixed,
+    digits,
+  } from '@/utils/toFixed';
+
+  import {
+    getPerformanceStatistic,
+    getPerVolAndRes9Statistic,
+  } from "@/api/statistic.js";
+
+	const { $loading, $message, $confirm } = useElement();
+
+
+	const headers = [
+    {
+      prop: "stationName",
+      label: "绔欑偣鍚嶇О",
+      width: "160",
+    },
+    {
+      prop: "battgroupName",
+      label: "鐢垫睜缁勫悕绉�",
+      width: "80",
+    },
+    {
+      prop: "monvolstd",
+      label: "鏍囩О鐢典綋鐢靛帇",
+      width: "100",
+    },
+    {
+      prop: "moncount",
+      label: "鍗曚綋鏁扮洰",
+      width: "100",
+    },
+    {
+      prop: "moncapstd",
+      label: "鏍囩О瀹归噺",
+      width: "160",
+    },
+    {
+      prop: "product",
+      label: "鐢垫睜鍝佺墝",
+      width: "160",
+    },
+    {
+      prop: "inuseYear",
+      label: "浣跨敤骞撮檺",
+      width: "80",
+    },
+    {
+      prop: "realCap",
+      label: "棰勪及瀹為檯瀹归噺",
+      width: "80",
+    },
+    {
+      prop: "capperformance",
+      label: "鐢垫睜鎬ц兘璇勪及",
+      width: "80",
+    },
+  ];
+
+   const testType = ref('');
+  const hrTypeList = computed(() => {
+    return Object.keys(hrTypes).map(v => {
+      return {
+        value: v,
+        label: hrTypes[v],
+      };
+    });
+  });
+
+  
+	const background = ref(true);
+	const disabled = ref(false);
+	const pageCurr = ref(1);
+	const pageSize = ref(10);
+	const total = ref(0);
+	const addEditVisible = ref(false);
+	const dialogTitle = ref("");
+	const currentAreaId = ref();
+	const currentAreaIds = ref([]);
+  const testStartDate = ref('');
+  const testEndDate = ref('');
+	const datas = reactive({
+		tableData: [],
+		rowData: {},
+	});
+
+  const statisticalType = ref(0);
+
+  
+
+
+  // 璁$畻灞炴�х敓鎴� picker-options锛堟洿绠�娲侊級
+  const startDisabledDate = (time) =>  testEndDate.value ? moment(testEndDate.value).isBefore(time) || moment().isBefore(time) : moment().isBefore(time);
+
+  const endDisabledDate = (time) => testStartDate.value ? moment(time).isBefore(testStartDate.value) || moment().isBefore(time) : moment().isBefore(time);
+
+  const performance = ref('');
+  const performanceList = ref([]);
+
+  function getPerformancList() {
+    getBattPerformance()
+      .then((res) => {
+        let { code, data, data2 } = res;
+        let list = [];
+        if (code && data) {
+          // console.log(data);
+          list = Object.keys(data2).map((key) => ({ value: key, label: data2[key] }));
+        }
+        performanceList.value = list;
+      })
+      .catch((err) => {
+        console.log(err);
+      });
+  }
+
+  const apiFn = computed(() => {
+    let fn = '';
+    switch(statisticalType.value) {
+      case 0:
+        fn = getPerformanceStatistic;
+        break;
+      case 1:
+        fn = getPerVolAndRes9Statistic;
+        break;
+    }
+    return fn;
+  });
+
+  function typeChange() {
+    pageCurr.value = 1;
+    getList();
+  }
+
+
+	function getList() {
+		let loading = $loading();
+    let params = {
+      provice: provice.value || undefined,
+      city: city.value || undefined,
+      country: country.value || undefined,
+      stationName: stationName.value || undefined,
+      pageNum: pageCurr.value,
+      pageSize: pageSize.value,
+
+      performance: 2,
+      testStartTime: testStartDate.value ? testStartDate.value + ' 00:00:00' : undefined,
+      testEndTime: testEndDate.value ? testEndDate.value + ' 23:59:59' : undefined,
+    };
+
+		apiFn.value(params)
+			.then((res) => {
+				let { code, data, data2 } = res;
+				let list = [];
+				let _total = 0;
+				if (code && data) {
+					// console.log(data);
+					list = data2.list.map(v => ({
+            ...v,
+          }));
+					_total = data2.total;
+				}
+				loading.close();
+				// tableData.length = 0;
+				// tableData.push(...list);
+				datas.tableData = list;
+				total.value = _total;
+			})
+			.catch((err) => {
+				console.log(err);
+				loading.close();
+			});
+	}
+
+	// 灞曠ず鏁版嵁鏁伴噺
+	function handleSizeChange(val) {
+		pageSize.value = val;
+		getList();
+	}
+	// 缈婚〉
+	function handleCurrentChange(val) {
+		pageCurr.value = val;
+		getList();
+	}
+
+  function filterChange() {
+    nextTick(() => {
+      pageCurr.value = 1;
+      getList();
+    });
+  }
+
+  function goRt (row) {
+    router.push({
+      path: '/datas/realtime',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function goHis (row) {
+    router.push({
+      path: '/datas/history',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageTab: 'his-real',
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function exportExcel() {
+    ExportFile(headers, datas.tableData, "鍔e寲鐢垫睜缁勬暟缁熻");
+  }
+
+	onMounted(() => {
+    getPerformancList();
+		getList();
+	});
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+    </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 10}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">璁板綍鏃堕棿娈�</div>
+                <div class="value" style="grid-column: span 7;">
+                  <el-date-picker
+                    v-model="testStartDate"
+                    type="date"
+                    size="small"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    :disabled-date="startDisabledDate"
+                  />
+                  -
+                  <el-date-picker
+                    v-model="testEndDate"
+                    size="small"
+                    type="date"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    :disabled-date="endDisabledDate"
+                  />
+                </div>
+              <div class="grid-item">
+                <div class="label">缁熻鏂瑰紡</div>
+                <div class="value">
+                  <el-select
+                    v-model="statisticalType"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="typeChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      label="瀹归噺"
+                      :value="0"
+                    />
+                    <el-option
+                      label="鐢靛帇鎴栧唴闃�"
+                      :value="1"
+                    />
+                  </el-select>
+                </div>
+              </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table class="yc-table" stripe height="100%" size="small" :data="datas.tableData" style="width: 100%">
+                  <el-table-column type="index" fixed="left" label="搴忓彿" width="60"></el-table-column>
+                  <el-table-column v-for="header in headers" :key="header.prop" :prop="header.prop" :label="header.label"
+                    :min-width="header.width" align="center">
+                    <template #default="scope">{{ scope.row[header.prop] }}</template>  
+                  </el-table-column>
+                  <el-table-column label="鎿嶄綔" fixed="right" width="240" align="center">
+                    <template #default="scope">
+                      <el-button type="warning" size="small" @click="goRt(scope.row)">瀹炴椂鐩戞祴</el-button>
+                      <el-button type="primary" size="small" @click="goHis(scope.row)">鍘嗗彶鏁版嵁</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="getList" :icon="Search">鏌ヨ</el-button>
+            </div>
+            <div class="el-page-container">
+              <el-pagination v-model:current-page="pageCurr" v-model:page-size="pageSize"
+                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]" size="small" :disabled="disabled"
+                :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel">瀵煎嚭</el-button>
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer"></div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+.max-width {
+  max-width: 200px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/statistics/battCell.vue b/src/views/statistics/battCell.vue
index 8c65998..1fa9ce6 100644
--- a/src/views/statistics/battCell.vue
+++ b/src/views/statistics/battCell.vue
@@ -233,8 +233,9 @@
     return allGraphInstance.getDataURL({ pixelRatio: 1, backgroundColor: "#fff" });
   }
 
+
   async function exportFile () {
-    let img0 = chart0.value.getChart().getDataURL({ pixelRatio: 1, backgroundColor: "#fff" });
+    let img0 = chart0.value.getDataURL();
 
     let params = {
       ...lastParams.value,
@@ -246,6 +247,7 @@
       damageVolPic: createGraphByOpt(chartData.chart2.labels, chartData.chart2.volDatas),
       damageResPic: createGraphByOpt(chartData.chart2.labels, chartData.chart2.resDatas),
     };
+
     // console.log('params', 'export', params, '=============');
     let loading = $loading();
     try {
diff --git a/src/views/statistics/battCompare0.vue b/src/views/statistics/battCompare0.vue
index 9e6be5e..ae2208f 100644
--- a/src/views/statistics/battCompare0.vue
+++ b/src/views/statistics/battCompare0.vue
@@ -352,7 +352,7 @@
                 </div>
               </div>
               <div class="grid-item">
-                <div class="label">鐢垫睜鍝佺墝</div>
+                <div class="label">鐢垫睜鎬ц兘</div>
                 <div class="value">
                   <el-select
                     v-model="performance"
@@ -372,7 +372,7 @@
                 </div>
               </div>
               <div class="grid-item">
-                <div class="label">鐢垫睜鎬ц兘</div>
+                <div class="label">鐢垫睜鍝佺墝</div>
                 <div class="value">
                   <el-select
                     v-model="product"
diff --git a/src/views/statistics/battCompare1.vue b/src/views/statistics/battCompare1.vue
index 24f2d2e..f17c94e 100644
--- a/src/views/statistics/battCompare1.vue
+++ b/src/views/statistics/battCompare1.vue
@@ -278,7 +278,7 @@
   }
 
   function exportExcel() {
-    ExportFile(headers, datas.tableData, "钃勭數姹犵粍瀵规瘮鍒嗘瀽--鍚屼竴鍝佺墝鍚屼竴鏃堕棿");
+    ExportFile(headers, datas.tableData, "钃勭數姹犵粍瀵规瘮鍒嗘瀽--涓嶅悓鍝佺墝鍚屼竴鏃堕棿");
   }
 
   onMounted(() => {
@@ -379,7 +379,7 @@
                 </div>
               </div>
               <div class="grid-item">
-                <div class="label">鐢垫睜鍝佺墝</div>
+                <div class="label">鐢垫睜鎬ц兘</div>
                 <div class="value">
                   <el-select
                     v-model="performance"
diff --git a/src/views/statistics/battCompare2.vue b/src/views/statistics/battCompare2.vue
new file mode 100644
index 0000000..ba5a691
--- /dev/null
+++ b/src/views/statistics/battCompare2.vue
@@ -0,0 +1,579 @@
+<script setup name="battCompare2">
+  import { ref, reactive, onMounted, computed, nextTick } from "vue";
+  import { storeToRefs } from "pinia";
+  import { Search, Plus } from "@element-plus/icons-vue";
+  import ycCard from "@/components/ycCard/index.vue";
+  import addEdit from "../datas/addEdit.vue";
+  import { ElMessage } from "element-plus";
+  import useElement from "@/hooks/useElement.js";
+  import { useUserStore } from '@/store/user';
+
+  import useStation from "@/hooks/useStationList.js";
+  const { provice, city, country, stationName,
+    proviceList, cityList, countryList, stationList,
+  } = useStation();
+
+  import { useRouter } from "vue-router";
+  const router = useRouter();
+
+  import { ExportFile } from '@/utils/exportFile.js';
+
+
+  import powerTypes from '@/utils/const/const_powerType.js';
+  import hrTypes from '@/utils/const/const_hrTestType.js';
+  import {
+    getBattPerformance,
+    getMonCapByUid,
+    getBatteryBrand,
+  } from "@/api/station";
+
+  const userStore = useUserStore();
+  const { uid, uname } = storeToRefs(userStore);
+  import moment from 'moment';
+
+  import formatSeconds from '@/utils/formatSeconds';
+  import {
+    toFixed,
+    digits,
+  } from '@/utils/toFixed';
+
+  import {
+    getBattCompare17,
+  } from "@/api/statistic.js";
+
+  const { $loading, $message, $confirm } = useElement();
+
+
+  const headers = [
+    {
+      prop: "stationName",
+      label: "绔欑偣鍚嶇О",
+      width: "160",
+    },
+    {
+      prop: "devName",
+      label: "璁惧鍚嶇О",
+      width: "80",
+    },
+    {
+      prop: "battgroupName",
+      label: "鐢垫睜缁勫悕绉�",
+      width: "80",
+    },
+    {
+			prop: "product",
+			label: "鐢垫睜鍝佺墝",
+			width: "100",
+		},
+    {
+			prop: "inuseTime",
+			label: "鎶曡繍鏃堕棿",
+			width: "100",
+		},
+    {
+			prop: "monvolstd",
+			label: "鐢垫睜瑙勬牸",
+			width: "100",
+		},
+    {
+      prop: "monrealCap",
+			label: "鍗曚綋瀹為檯瀹归噺",
+			width: "80",
+		},
+    {
+			prop: "monprecentCapStr",
+			label: "瀹归噺鐧惧垎姣�",
+			width: "80",
+		},
+    {
+      prop: "moncapperformance",
+      label: "鐢垫睜鎬ц兘",
+      width: "80",
+    },
+	];
+
+   const testType = ref('');
+  const hrTypeList = computed(() => {
+    return Object.keys(hrTypes).map(v => {
+      return {
+        value: v,
+        label: hrTypes[v],
+      };
+    });
+  });
+
+  
+  const background = ref(true);
+  const disabled = ref(false);
+  const pageCurr = ref(1);
+  const pageSize = ref(10);
+  const total = ref(0);
+  const addEditVisible = ref(false);
+  const dialogTitle = ref("");
+  const currentAreaId = ref();
+  const currentAreaIds = ref([]);
+  const inuseStartTime = ref('');
+  const inuseEndTime = ref('');
+  
+  const datas = reactive({
+    tableData: [],
+    rowData: {},
+  });
+
+
+  // 璁$畻灞炴�х敓鎴� picker-options锛堟洿绠�娲侊級
+  const startDisabledDate = (time) =>  inuseEndTime.value ? moment(inuseEndTime.value).isBefore(time) || moment().isBefore(time) : moment().isBefore(time);
+
+  const endDisabledDate = (time) => inuseStartTime.value ? moment(time).isBefore(inuseStartTime.value) || moment().isBefore(time) : moment().isBefore(time);
+
+  const performance = ref('');
+  const performanceList = ref([]);
+
+  function getPerformancList() {
+    getBattPerformance()
+      .then((res) => {
+        let { code, data, data2 } = res;
+        let list = [];
+        if (code && data) {
+          // console.log(data);
+          list = Object.keys(data2).map((key) => ({ value: key, label: data2[key] }));
+        }
+        performanceList.value = list;
+      })
+      .catch((err) => {
+        console.log(err);
+      });
+  }
+
+  const product = ref('');
+  const productList = ref([]);
+
+  function getProductList() {
+    getBatteryBrand().then((res) => {
+      let { code, data, data2 } = res;
+      let list = [];
+      if (code && data) {
+        list = data2;
+      }
+      productList.value = list;
+    });
+  }
+
+  const moncapstd = ref('');
+  const monCapList = ref([]);
+
+// 鑾峰彇鏍囩О瀹归噺
+  function getMonCapList() {
+    getMonCapByUid().then((res) => {
+      let { code, data, data2 } = res;
+      let list = [];
+      if (code && data) {
+        list = data2;
+      }
+      monCapList.value = list;
+    });
+  }
+
+
+
+  function getList() {
+    let loading = $loading();
+    let params = {
+      provice: provice.value || undefined,
+      city: city.value || undefined,
+      country: country.value || undefined,
+      stationName: stationName.value || undefined,
+      pageNum: pageCurr.value,
+      pageSize: pageSize.value,
+
+      performance: performance.value || undefined,
+      product: product.value || undefined,
+      inuseStartTime: inuseStartTime.value ? inuseStartTime.value + ' 00:00:00' : undefined,
+      inuseEndTime: inuseEndTime.value ? inuseEndTime.value + ' 23:59:59' : undefined,
+    };
+
+    getBattCompare17(params)
+      .then((res) => {
+        let { code, data, data2 } = res;
+        let list = [];
+        let _total = 0;
+        if (code && data) {
+          // console.log(data);
+          list = data2.list.map(v => ({
+            ...v,
+            monprecentCapStr: toFixed(v.monprecentCap, digits.PREC) + '%',
+          }));
+          _total = data2.total;
+        }
+        loading.close();
+        // tableData.length = 0;
+        // tableData.push(...list);
+        datas.tableData = list;
+        total.value = _total;
+      })
+      .catch((err) => {
+        console.log(err);
+        loading.close();
+      });
+  }
+
+  // 灞曠ず鏁版嵁鏁伴噺
+  function handleSizeChange(val) {
+    pageSize.value = val;
+    getList();
+  }
+  // 缈婚〉
+  function handleCurrentChange(val) {
+    pageCurr.value = val;
+    getList();
+  }
+
+  function filterChange() {
+    nextTick(() => {
+      pageCurr.value = 1;
+      getList();
+    });
+  }
+
+  function goRt (row) {
+    router.push({
+      path: '/datas/realtime',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function goHis (row) {
+    router.push({
+      path: '/datas/history',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageTab: 'his-real',
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function exportExcel() {
+    ExportFile(headers, datas.tableData, "钃勭數姹犵粍瀵规瘮鍒嗘瀽--鍚屼竴鍝佺墝涓嶅悓鏃堕棿");
+  }
+
+  onMounted(() => {
+    getPerformancList();
+    getProductList();
+    // getMonCapList();
+    getList();
+  });
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+    </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 10}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鐢垫睜鎬ц兘</div>
+                <div class="value">
+                  <el-select
+                    v-model="performance"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in performanceList"
+                      :key="'list7_' + idx"
+                      :label="item.label"
+                      :value="item.value"
+                    />
+                  </el-select>
+                </div>
+              </div>
+              <!-- <div class="grid-item">
+                <div class="label">鏍囩О瀹归噺</div>
+                <div class="value">
+                  <el-select
+                    v-model="moncapstd"
+                    filterable
+                    clearable
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in monCapList"
+                      :key="'list11_' + idx"
+                      :label="item"
+                      :value="item"
+                    />
+                  </el-select>
+                </div>
+              </div> -->
+              <div class="grid-item">
+                <div class="label">鐢垫睜鎬ц兘</div>
+                <div class="value">
+                  <el-select
+                    v-model="product"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in productList"
+                      :key="'list6_' + idx"
+                      :label="item"
+                      :value="item"
+                    />
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鎶曡繍鏃堕棿娈�</div>
+                <div class="value" style="grid-column: span 7;">
+                  <el-date-picker
+                    v-model="inuseStartTime"
+                    type="date"
+                    size="small"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    :disabled-date="startDisabledDate"
+                  />
+                  -
+                  <el-date-picker
+                    v-model="inuseEndTime"
+                    size="small"
+                    type="date"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    :disabled-date="endDisabledDate"
+                  />
+                </div>
+              </div>
+              <!-- <div class="grid-item">
+                <el-button type="primary" size="small" >璁剧疆鏉冮噸</el-button>
+              </div> -->
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table class="yc-table" stripe height="100%" size="small" :data="datas.tableData" style="width: 100%">
+                  <el-table-column type="index" fixed="left" label="搴忓彿" width="60"></el-table-column>
+                  <el-table-column v-for="header in headers" :key="header.prop" :prop="header.prop" :label="header.label"
+                    :min-width="header.width" align="center">
+                    <template #default="scope">{{ scope.row[header.prop] }}</template>  
+                  </el-table-column>
+                  <el-table-column label="鎿嶄綔" fixed="right" width="240" align="center">
+                    <template #default="scope">
+                      <el-button type="warning" size="small" @click="goRt(scope.row)">瀹炴椂鐩戞祴</el-button>
+                      <el-button type="primary" size="small" @click="goHis(scope.row)">鍘嗗彶鏁版嵁</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="getList" :icon="Search">鏌ヨ</el-button>
+            </div>
+            <div class="el-page-container">
+              <el-pagination v-model:current-page="pageCurr" v-model:page-size="pageSize"
+                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]" size="small" :disabled="disabled"
+                :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel">瀵煎嚭</el-button>
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer"></div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+.max-width {
+  max-width: 200px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/statistics/battDamage.vue b/src/views/statistics/battDamage.vue
new file mode 100644
index 0000000..d46cf94
--- /dev/null
+++ b/src/views/statistics/battDamage.vue
@@ -0,0 +1,501 @@
+<script setup name="battDamage">
+	import { ref, reactive, onMounted, computed, nextTick } from "vue";
+	import { storeToRefs } from "pinia";
+	import { Search, Plus } from "@element-plus/icons-vue";
+	import ycCard from "@/components/ycCard/index.vue";
+	import addEdit from "../datas/addEdit.vue";
+	import { ElMessage } from "element-plus";
+	import useElement from "@/hooks/useElement.js";
+  import { useUserStore } from '@/store/user';
+
+  import useStation from "@/hooks/useStationList.js";
+  const { provice, city, country, stationName,
+    proviceList, cityList, countryList, stationList,
+  } = useStation();
+
+  import { useRouter } from "vue-router";
+  const router = useRouter();
+
+  import { ExportFile } from '@/utils/exportFile.js';
+
+
+  import powerTypes from '@/utils/const/const_powerType.js';
+  import hrTypes from '@/utils/const/const_hrTestType.js';
+  import {
+    getBattPerformance,
+  } from "@/api/station";
+
+  const userStore = useUserStore();
+  const { uid, uname } = storeToRefs(userStore);
+  import moment from 'moment';
+
+  import formatSeconds from '@/utils/formatSeconds';
+  import {
+    toFixed,
+    digits,
+  } from '@/utils/toFixed';
+
+  import {
+    getPerformanceStatistic,
+  } from "@/api/statistic.js";
+
+	const { $loading, $message, $confirm } = useElement();
+
+
+	const headers = [
+    {
+      prop: "stationName",
+      label: "绔欑偣鍚嶇О",
+      width: "160",
+    },
+    {
+      prop: "battgroupName",
+      label: "鐢垫睜缁勫悕绉�",
+      width: "80",
+    },
+    {
+      prop: "monvolstd",
+      label: "鏍囩О鐢典綋鐢靛帇",
+      width: "100",
+    },
+    {
+      prop: "moncount",
+      label: "鍗曚綋鏁扮洰",
+      width: "100",
+    },
+    {
+      prop: "moncapstd",
+      label: "鏍囩О瀹归噺",
+      width: "160",
+    },
+    {
+      prop: "product",
+      label: "鐢垫睜鍝佺墝",
+      width: "160",
+    },
+    {
+      prop: "inuseYear",
+      label: "浣跨敤骞撮檺",
+      width: "80",
+    },
+    {
+      prop: "realCap",
+      label: "棰勪及瀹為檯瀹归噺",
+      width: "80",
+    },
+    {
+      prop: "capperformance",
+      label: "鐢垫睜鎬ц兘璇勪及",
+      width: "80",
+    },
+  ];
+
+   const testType = ref('');
+  const hrTypeList = computed(() => {
+    return Object.keys(hrTypes).map(v => {
+      return {
+        value: v,
+        label: hrTypes[v],
+      };
+    });
+  });
+
+  
+	const background = ref(true);
+	const disabled = ref(false);
+	const pageCurr = ref(1);
+	const pageSize = ref(10);
+	const total = ref(0);
+	const addEditVisible = ref(false);
+	const dialogTitle = ref("");
+	const currentAreaId = ref();
+	const currentAreaIds = ref([]);
+  const testStartDate = ref('');
+  const testEndDate = ref('');
+	const datas = reactive({
+		tableData: [],
+		rowData: {},
+	});
+
+
+  // 璁$畻灞炴�х敓鎴� picker-options锛堟洿绠�娲侊級
+  const startDisabledDate = (time) =>  testEndDate.value ? moment(testEndDate.value).isBefore(time) || moment().isBefore(time) : moment().isBefore(time);
+
+  const endDisabledDate = (time) => testStartDate.value ? moment(time).isBefore(testStartDate.value) || moment().isBefore(time) : moment().isBefore(time);
+
+  const performance = ref('');
+  const performanceList = ref([]);
+
+  function getPerformancList() {
+    getBattPerformance()
+      .then((res) => {
+        let { code, data, data2 } = res;
+        let list = [];
+        if (code && data) {
+          // console.log(data);
+          list = Object.keys(data2).map((key) => ({ value: key, label: data2[key] }));
+        }
+        performanceList.value = list;
+      })
+      .catch((err) => {
+        console.log(err);
+      });
+  }
+
+
+	function getList() {
+		let loading = $loading();
+    let params = {
+      provice: provice.value || undefined,
+      city: city.value || undefined,
+      country: country.value || undefined,
+      stationName: stationName.value || undefined,
+      pageNum: pageCurr.value,
+      pageSize: pageSize.value,
+
+      performance: 3,
+      testStartTime: testStartDate.value ? testStartDate.value + ' 00:00:00' : undefined,
+      testEndTime: testEndDate.value ? testEndDate.value + ' 23:59:59' : undefined,
+    };
+
+		getPerformanceStatistic(params)
+			.then((res) => {
+				let { code, data, data2 } = res;
+				let list = [];
+				let _total = 0;
+				if (code && data) {
+					// console.log(data);
+					list = data2.list.map(v => ({
+            ...v,
+          }));
+					_total = data2.total;
+				}
+				loading.close();
+				// tableData.length = 0;
+				// tableData.push(...list);
+				datas.tableData = list;
+				total.value = _total;
+			})
+			.catch((err) => {
+				console.log(err);
+				loading.close();
+			});
+	}
+
+	// 灞曠ず鏁版嵁鏁伴噺
+	function handleSizeChange(val) {
+		pageSize.value = val;
+		getList();
+	}
+	// 缈婚〉
+	function handleCurrentChange(val) {
+		pageCurr.value = val;
+		getList();
+	}
+
+  function filterChange() {
+    nextTick(() => {
+      pageCurr.value = 1;
+      getList();
+    });
+  }
+
+  function goRt (row) {
+    router.push({
+      path: '/datas/realtime',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function goHis (row) {
+    router.push({
+      path: '/datas/history',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageTab: 'his-real',
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function exportExcel() {
+    ExportFile(headers, datas.tableData, "鎹熷潖鐢垫睜缁勬暟缁熻");
+  }
+
+	onMounted(() => {
+    getPerformancList();
+		getList();
+	});
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+    </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 10}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <!-- <div class="grid-item">
+                <div class="label">鐢垫睜鎬ц兘</div>
+                <div class="value">
+                  <el-select
+                    v-model="performance"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in performanceList"
+                      :key="'list7_' + idx"
+                      :label="item.label"
+                      :value="item.value"
+                    />
+                  </el-select>
+                </div>
+              </div> -->
+              <div class="grid-item">
+                <div class="label">璁板綍鏃堕棿娈�</div>
+                <div class="value" style="grid-column: span 7;">
+                  <el-date-picker
+                    v-model="testStartDate"
+                    type="date"
+                    size="small"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    :disabled-date="startDisabledDate"
+                  />
+                  -
+                  <el-date-picker
+                    v-model="testEndDate"
+                    size="small"
+                    type="date"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    :disabled-date="endDisabledDate"
+                  />
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table class="yc-table" stripe height="100%" size="small" :data="datas.tableData" style="width: 100%">
+                  <el-table-column type="index" fixed="left" label="搴忓彿" width="60"></el-table-column>
+                  <el-table-column v-for="header in headers" :key="header.prop" :prop="header.prop" :label="header.label"
+                    :min-width="header.width" align="center">
+                    <template #default="scope">{{ scope.row[header.prop] }}</template>  
+                  </el-table-column>
+                  <el-table-column label="鎿嶄綔" fixed="right" width="240" align="center">
+                    <template #default="scope">
+                      <el-button type="warning" size="small" @click="goRt(scope.row)">瀹炴椂鐩戞祴</el-button>
+                      <el-button type="primary" size="small" @click="goHis(scope.row)">鍘嗗彶鏁版嵁</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="getList" :icon="Search">鏌ヨ</el-button>
+            </div>
+            <div class="el-page-container">
+              <el-pagination v-model:current-page="pageCurr" v-model:page-size="pageSize"
+                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]" size="small" :disabled="disabled"
+                :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel">瀵煎嚭</el-button>
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer"></div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+.max-width {
+  max-width: 200px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/statistics/battGood.vue b/src/views/statistics/battGood.vue
new file mode 100644
index 0000000..caae696
--- /dev/null
+++ b/src/views/statistics/battGood.vue
@@ -0,0 +1,501 @@
+<script setup name="battGood">
+	import { ref, reactive, onMounted, computed, nextTick } from "vue";
+	import { storeToRefs } from "pinia";
+	import { Search, Plus } from "@element-plus/icons-vue";
+	import ycCard from "@/components/ycCard/index.vue";
+	import addEdit from "../datas/addEdit.vue";
+	import { ElMessage } from "element-plus";
+	import useElement from "@/hooks/useElement.js";
+  import { useUserStore } from '@/store/user';
+
+  import useStation from "@/hooks/useStationList.js";
+  const { provice, city, country, stationName,
+    proviceList, cityList, countryList, stationList,
+  } = useStation();
+
+  import { useRouter } from "vue-router";
+  const router = useRouter();
+
+  import { ExportFile } from '@/utils/exportFile.js';
+
+
+  import powerTypes from '@/utils/const/const_powerType.js';
+  import hrTypes from '@/utils/const/const_hrTestType.js';
+  import {
+    getBattPerformance,
+  } from "@/api/station";
+
+  const userStore = useUserStore();
+  const { uid, uname } = storeToRefs(userStore);
+  import moment from 'moment';
+
+  import formatSeconds from '@/utils/formatSeconds';
+  import {
+    toFixed,
+    digits,
+  } from '@/utils/toFixed';
+
+  import {
+    getPerformanceStatistic,
+  } from "@/api/statistic.js";
+
+	const { $loading, $message, $confirm } = useElement();
+
+
+	const headers = [
+    {
+      prop: "stationName",
+      label: "绔欑偣鍚嶇О",
+      width: "160",
+    },
+    {
+      prop: "battgroupName",
+      label: "鐢垫睜缁勫悕绉�",
+      width: "80",
+    },
+    {
+      prop: "monvolstd",
+      label: "鏍囩О鐢典綋鐢靛帇",
+      width: "100",
+    },
+    {
+      prop: "moncount",
+      label: "鍗曚綋鏁扮洰",
+      width: "100",
+    },
+    {
+      prop: "moncapstd",
+      label: "鏍囩О瀹归噺",
+      width: "160",
+    },
+    {
+      prop: "product",
+      label: "鐢垫睜鍝佺墝",
+      width: "160",
+    },
+    {
+      prop: "inuseYear",
+      label: "浣跨敤骞撮檺",
+      width: "80",
+    },
+    {
+      prop: "realCap",
+      label: "棰勪及瀹為檯瀹归噺",
+      width: "80",
+    },
+    {
+      prop: "capperformance",
+      label: "鐢垫睜鎬ц兘璇勪及",
+      width: "80",
+    },
+  ];
+
+   const testType = ref('');
+  const hrTypeList = computed(() => {
+    return Object.keys(hrTypes).map(v => {
+      return {
+        value: v,
+        label: hrTypes[v],
+      };
+    });
+  });
+
+  
+	const background = ref(true);
+	const disabled = ref(false);
+	const pageCurr = ref(1);
+	const pageSize = ref(10);
+	const total = ref(0);
+	const addEditVisible = ref(false);
+	const dialogTitle = ref("");
+	const currentAreaId = ref();
+	const currentAreaIds = ref([]);
+  const testStartDate = ref('');
+  const testEndDate = ref('');
+	const datas = reactive({
+		tableData: [],
+		rowData: {},
+	});
+
+
+  // 璁$畻灞炴�х敓鎴� picker-options锛堟洿绠�娲侊級
+  const startDisabledDate = (time) =>  testEndDate.value ? moment(testEndDate.value).isBefore(time) || moment().isBefore(time) : moment().isBefore(time);
+
+  const endDisabledDate = (time) => testStartDate.value ? moment(time).isBefore(testStartDate.value) || moment().isBefore(time) : moment().isBefore(time);
+
+  const performance = ref('');
+  const performanceList = ref([]);
+
+  function getPerformancList() {
+    getBattPerformance()
+      .then((res) => {
+        let { code, data, data2 } = res;
+        let list = [];
+        if (code && data) {
+          // console.log(data);
+          list = Object.keys(data2).map((key) => ({ value: key, label: data2[key] }));
+        }
+        performanceList.value = list;
+      })
+      .catch((err) => {
+        console.log(err);
+      });
+  }
+
+
+	function getList() {
+		let loading = $loading();
+    let params = {
+      provice: provice.value || undefined,
+      city: city.value || undefined,
+      country: country.value || undefined,
+      stationName: stationName.value || undefined,
+      pageNum: pageCurr.value,
+      pageSize: pageSize.value,
+
+      performance: 1,
+      testStartTime: testStartDate.value ? testStartDate.value + ' 00:00:00' : undefined,
+      testEndTime: testEndDate.value ? testEndDate.value + ' 23:59:59' : undefined,
+    };
+
+		getPerformanceStatistic(params)
+			.then((res) => {
+				let { code, data, data2 } = res;
+				let list = [];
+				let _total = 0;
+				if (code && data) {
+					// console.log(data);
+					list = data2.list.map(v => ({
+            ...v,
+          }));
+					_total = data2.total;
+				}
+				loading.close();
+				// tableData.length = 0;
+				// tableData.push(...list);
+				datas.tableData = list;
+				total.value = _total;
+			})
+			.catch((err) => {
+				console.log(err);
+				loading.close();
+			});
+	}
+
+	// 灞曠ず鏁版嵁鏁伴噺
+	function handleSizeChange(val) {
+		pageSize.value = val;
+		getList();
+	}
+	// 缈婚〉
+	function handleCurrentChange(val) {
+		pageCurr.value = val;
+		getList();
+	}
+
+  function filterChange() {
+    nextTick(() => {
+      pageCurr.value = 1;
+      getList();
+    });
+  }
+
+  function goRt (row) {
+    router.push({
+      path: '/datas/realtime',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function goHis (row) {
+    router.push({
+      path: '/datas/history',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageTab: 'his-real',
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function exportExcel() {
+    ExportFile(headers, datas.tableData, "浼樿壇鐢垫睜缁勬暟缁熻");
+  }
+
+	onMounted(() => {
+    getPerformancList();
+		getList();
+	});
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+    </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 10}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <!-- <div class="grid-item">
+                <div class="label">鐢垫睜鎬ц兘</div>
+                <div class="value">
+                  <el-select
+                    v-model="performance"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in performanceList"
+                      :key="'list7_' + idx"
+                      :label="item.label"
+                      :value="item.value"
+                    />
+                  </el-select>
+                </div>
+              </div> -->
+              <div class="grid-item">
+                <div class="label">璁板綍鏃堕棿娈�</div>
+                <div class="value" style="grid-column: span 7;">
+                  <el-date-picker
+                    v-model="testStartDate"
+                    type="date"
+                    size="small"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    :disabled-date="startDisabledDate"
+                  />
+                  -
+                  <el-date-picker
+                    v-model="testEndDate"
+                    size="small"
+                    type="date"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    :disabled-date="endDisabledDate"
+                  />
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table class="yc-table" stripe height="100%" size="small" :data="datas.tableData" style="width: 100%">
+                  <el-table-column type="index" fixed="left" label="搴忓彿" width="60"></el-table-column>
+                  <el-table-column v-for="header in headers" :key="header.prop" :prop="header.prop" :label="header.label"
+                    :min-width="header.width" align="center">
+                    <template #default="scope">{{ scope.row[header.prop] }}</template>  
+                  </el-table-column>
+                  <el-table-column label="鎿嶄綔" fixed="right" width="240" align="center">
+                    <template #default="scope">
+                      <el-button type="warning" size="small" @click="goRt(scope.row)">瀹炴椂鐩戞祴</el-button>
+                      <el-button type="primary" size="small" @click="goHis(scope.row)">鍘嗗彶鏁版嵁</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="getList" :icon="Search">鏌ヨ</el-button>
+            </div>
+            <div class="el-page-container">
+              <el-pagination v-model:current-page="pageCurr" v-model:page-size="pageSize"
+                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]" size="small" :disabled="disabled"
+                :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel">瀵煎嚭</el-button>
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer"></div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+.max-width {
+  max-width: 200px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/statistics/chartView.vue b/src/views/statistics/chartView.vue
new file mode 100644
index 0000000..b15dc79
--- /dev/null
+++ b/src/views/statistics/chartView.vue
@@ -0,0 +1,82 @@
+<script setup name="chartView">
+// 骞村害宸叉斁鐢� 鏈斁鐢垫暟閲忕粺璁¢〉闈㈠彸渚у浘琛�
+import { ref, onMounted, } from "vue";
+import pie from "@/components/echarts/pie3d0.vue";
+import bar from '@/components/echarts/bar1.vue';
+
+// import {
+//   getDischr5Chart,
+// } from "@/api/statistic";
+
+const props = defineProps({
+  battData: {
+    type: Array,
+  },
+  teamData: {
+    type: Array,
+  }
+});
+
+const chart0 = ref(null);
+const chart1 = ref(null);
+
+// async function getInfo() {
+//   let {code, data, data2, data3} = await getDischr5Chart();
+//   let list0 = [];
+//   let list1 = [];
+//   if (code && data) {
+//     list0 = Object.keys(data3).map((key) => ({name: key,  value: data3[key]}));
+//     list1 = Object.keys(data2).map((key) => ({name: key,  ...data2[key]}));
+//   }
+//   return {list0, list1};
+// }
+
+
+
+onMounted(async () => {
+  // let {list0, list1} = await getInfo();
+  let _teamData = props.teamData;
+  if (chart0.value) {
+    chart0.value.updateChart(props.battData);
+  }
+  if (chart1.value) {
+    chart1.value.updateChart(_teamData.map(v => v.name), _teamData.map(v => v.value));
+  }
+});
+
+</script>
+
+<template>
+  <div class="chart-view">
+    <div class="top" v-if="battData">
+      <card title="鐢垫睜鎬ц兘缁熻">
+      <pie ref="chart0"></pie>
+      </card>
+    </div>
+    <div class="bottom">
+      <card :title="battData ? '鐝粍宸叉斁鐢电粺璁�' : '鐝粍鏈斁鐢电粺璁�'">
+      <bar ref="chart1"></bar>
+      </card>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.chart-view {
+
+  height: 420px;
+  background: #000;
+  padding: 10px;
+  display: flex;
+  // flex-direction: column;
+  .top {
+    flex: 1;
+    // width: 400px;
+    margin-right: 20px;
+  }
+  .bottom {
+    flex: 1;
+    // width: 400px;
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/views/statistics/disYear.vue b/src/views/statistics/disYear.vue
new file mode 100644
index 0000000..68b4ca8
--- /dev/null
+++ b/src/views/statistics/disYear.vue
@@ -0,0 +1,524 @@
+<script setup name="disYear">
+  import { ref, reactive, onMounted, computed, nextTick } from "vue";
+  import { storeToRefs } from "pinia";
+  import { Search, Plus } from "@element-plus/icons-vue";
+  import ycCard from "@/components/ycCard/index.vue";
+  import chartView from "./chartView.vue";
+  import { ElMessage } from "element-plus";
+  import useElement from "@/hooks/useElement.js";
+  import { useUserStore } from '@/store/user';
+
+  import useStation from "@/hooks/useStationList.js";
+  const { provice, city, country, stationName,
+    proviceList, cityList, countryList, stationList,
+  } = useStation();
+
+  import { useRouter } from "vue-router";
+  const router = useRouter();
+
+  import { ExportFile } from '@/utils/exportFile.js';
+
+
+  import powerTypes from '@/utils/const/const_powerType.js';
+  import hrTypes from '@/utils/const/const_hrTestType.js';
+  import {
+    getMonCapByUid,
+  } from "@/api/station";
+
+  const userStore = useUserStore();
+  const { uid, uname } = storeToRefs(userStore);
+  import moment from 'moment';
+
+  import formatSeconds from '@/utils/formatSeconds';
+  import {
+    toFixed,
+    digits,
+  } from '@/utils/toFixed';
+
+  import {
+    getDischr5Statistic,
+  } from "@/api/statistic.js";
+
+  const { $loading, $message, $confirm } = useElement();
+
+
+  const headers = [
+    {
+      prop: "provice",
+      label: "鐪�",
+      width: "100",
+    },
+    {
+      prop: "city",
+      label: "甯�",
+      width: "100",
+    },
+    {
+      prop: "country",
+      label: "鍖哄幙",
+      width: "100",
+    },
+    {
+      prop: "stationName",
+      label: "绔欑偣鍚嶇О",
+      width: "160",
+    },
+    {
+      prop: "battgroupName",
+      label: "鐢垫睜缁勫悕绉�",
+      width: "80",
+    },
+    {
+      prop: "testStartTime",
+      label: "寮�濮嬫祴璇曟椂闂�",
+      width: "160",
+    },
+    {
+      prop: "testTimelongStr",
+      label: "娴嬭瘯鏃堕暱",
+      width: "160",
+    },
+    {
+      prop: "testCap",
+      label: "娴嬭瘯瀹归噺",
+      width: "80",
+    },
+    {
+      prop: "stopReason",
+      label: "鍋滄鍘熷洜",
+      width: "100",
+    },
+    {
+      prop: "realCap",
+      label: "棰勪及瀹归噺",
+      width: "100",
+    },
+    {
+      prop: "capperformance",
+      label: "鐢垫睜鎬ц兘",
+      width: "80",
+    },
+  ];
+
+   const testType = ref('');
+  const hrTypeList = computed(() => {
+    return Object.keys(hrTypes).map(v => {
+      return {
+        value: v,
+        label: hrTypes[v],
+      };
+    });
+  });
+
+  const chartVisible = ref(false);
+  const background = ref(true);
+  const disabled = ref(false);
+  const pageCurr = ref(1);
+  const pageSize = ref(10);
+  const total = ref(0);
+  const addEditVisible = ref(false);
+  const dialogTitle = ref("");
+  const currentAreaId = ref();
+  const currentAreaIds = ref([]);
+  const testStartTime = ref('');
+  
+  const testEndTime = ref('');
+  
+  const datas = reactive({
+    tableData: [],
+    rowData: {},
+  });
+
+
+  // 璁$畻灞炴�х敓鎴� picker-options锛堟洿绠�娲侊級
+  const startDisabledDate = (time) =>  testEndTime.value ? moment(testEndTime.value).isBefore(time) || moment().isBefore(time) : moment().isBefore(time);
+
+  const endDisabledDate = (time) => testStartTime.value ? moment(time).isBefore(testStartTime.value) || moment().isBefore(time) : moment().isBefore(time);
+
+
+
+
+  const moncapstd = ref('');
+  const monCapList = ref([]);
+
+// 鑾峰彇鏍囩О瀹归噺
+  function getMonCapList() {
+    getMonCapByUid().then((res) => {
+      let { code, data, data2 } = res;
+      let list = [];
+      if (code && data) {
+        list = data2;
+      }
+      monCapList.value = list;
+    });
+  }
+
+ const teamData = ref(null);
+ const battData = ref(null);
+
+
+  async function getList() {
+    let loading = $loading();
+    let params = {
+      provice: provice.value || undefined,
+      city: city.value || undefined,
+      country: country.value || undefined,
+      stationName: stationName.value || undefined,
+      pageNum: pageCurr.value,
+      pageSize: pageSize.value,
+
+      testStartTime: testStartTime.value ? testStartTime.value + ' 00:00:00' : undefined,
+      testEndTime: testEndTime.value ? testEndTime.value + ' 23:59:59' : undefined,
+    };
+
+    let res = await getDischr5Statistic(params);
+      
+        let { code, data, data2, data3, data4 } = res;
+        let list = [];
+        let _total = 0;
+        let tData, bData;
+        if (code && data) {
+          // console.log(data);
+          list = data2.list.map(v => ({
+            ...v,
+            testTimelongStr: formatSeconds(v.testTimelong),
+          }));
+          _total = data2.total;
+          tData = Object.keys(data3).map((key) => ({name: key,  value: data3[key].dischargeNum}));
+          bData = Object.keys(data4).map((key) => ({name: key,  value: data4[key]}));
+        }
+        loading.close();
+        // tableData.length = 0;
+        // tableData.push(...list);
+        datas.tableData = list;
+        total.value = _total;
+        teamData.value = tData;
+        battData.value = bData;
+  }
+
+  // 灞曠ず鏁版嵁鏁伴噺
+  function handleSizeChange(val) {
+    pageSize.value = val;
+    getList();
+  }
+  // 缈婚〉
+  function handleCurrentChange(val) {
+    pageCurr.value = val;
+    getList();
+  }
+
+  function filterChange() {
+    nextTick(() => {
+      pageCurr.value = 1;
+      getList();
+    });
+  }
+
+  function goRt (row) {
+    router.push({
+      path: '/datas/realtime',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function goHis (row) {
+    router.push({
+      path: '/datas/history',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageTab: 'his-real',
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function exportExcel() {
+    ExportFile(headers, datas.tableData, "鏈勾搴﹀凡鏀剧數鏁伴噺缁熻");
+  }
+
+  onMounted(async () => {
+    // getMonCapList();
+    await getList();
+    chartVisible.value = true;
+  });
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+    </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 10}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <!-- <div class="grid-item">
+                <div class="label">鏍囩О瀹归噺</div>
+                <div class="value">
+                  <el-select
+                    v-model="moncapstd"
+                    filterable
+                    clearable
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in monCapList"
+                      :key="'list11_' + idx"
+                      :label="item"
+                      :value="item"
+                    />
+                  </el-select>
+                </div>
+              </div> -->
+              <div class="grid-item">
+                <div class="label">璁板綍鏃堕棿娈�</div>
+                <div class="value" style="grid-column: span 7;">
+                  <el-date-picker
+                    v-model="testStartTime"
+                    type="date"
+                    size="small"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    @change="filterChange"
+                    :disabled-date="startDisabledDate"
+                  />
+                  -
+                  <el-date-picker
+                    v-model="testEndTime"
+                    size="small"
+                    type="date"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    @change="filterChange"
+                    :disabled-date="endDisabledDate"
+                  />
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table class="yc-table" stripe height="100%" size="small" :data="datas.tableData" style="width: 100%">
+                  <el-table-column type="index" fixed="left" label="搴忓彿" width="60"></el-table-column>
+                  <el-table-column v-for="header in headers" :key="header.prop" :prop="header.prop" :label="header.label"
+                    :min-width="header.width" align="center">
+                    <template #default="scope">{{ scope.row[header.prop] }}</template>  
+                  </el-table-column>
+                  <el-table-column label="鎿嶄綔" fixed="right" width="160" align="center">
+                    <template #default="scope">
+                      <el-button type="primary" size="small" @click="goHis(scope.row)">鍘嗗彶鏁版嵁</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="getList" :icon="Search">鏌ヨ</el-button>
+            </div>
+            <div class="el-page-container">
+              <el-pagination v-model:current-page="pageCurr" v-model:page-size="pageSize"
+                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]" size="small" :disabled="disabled"
+                :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel">瀵煎嚭</el-button>
+              <el-button type="primary" round size="small" @click="chartVisible = true">鏌ョ湅缁熻鍥�</el-button>
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer">
+    </div>
+    <el-dialog v-model="chartVisible" title="缁熻鍥�" width="840">
+      <chart-view :battData="battData" :teamData="teamData"></chart-view>
+    </el-dialog>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+  .page-footer {
+    // margin-left: 10px;
+    // width: 380px;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+.max-width {
+  max-width: 200px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/statistics/nodisYear.vue b/src/views/statistics/nodisYear.vue
new file mode 100644
index 0000000..97a8b27
--- /dev/null
+++ b/src/views/statistics/nodisYear.vue
@@ -0,0 +1,511 @@
+<script setup name="nodisYear">
+  import { ref, reactive, onMounted, computed, nextTick } from "vue";
+  import { storeToRefs } from "pinia";
+  import { Search, Plus } from "@element-plus/icons-vue";
+  import ycCard from "@/components/ycCard/index.vue";
+  import chartView from "./chartView.vue";
+  import { ElMessage } from "element-plus";
+  import useElement from "@/hooks/useElement.js";
+  import { useUserStore } from '@/store/user';
+
+  import useStation from "@/hooks/useStationList.js";
+  const { provice, city, country, stationName,
+    proviceList, cityList, countryList, stationList,
+  } = useStation();
+
+  import { useRouter } from "vue-router";
+  const router = useRouter();
+
+  import { ExportFile } from '@/utils/exportFile.js';
+
+
+  import powerTypes from '@/utils/const/const_powerType.js';
+  import hrTypes from '@/utils/const/const_hrTestType.js';
+  import {
+    getMonCapByUid,
+  } from "@/api/station";
+
+  const userStore = useUserStore();
+  const { uid, uname } = storeToRefs(userStore);
+  import moment from 'moment';
+
+  import formatSeconds from '@/utils/formatSeconds';
+  import {
+    toFixed,
+    digits,
+  } from '@/utils/toFixed';
+
+  import {
+    getDischr6Statistic,
+  } from "@/api/statistic.js";
+
+  const { $loading, $message, $confirm } = useElement();
+
+
+  const headers = [
+    {
+      prop: "stationName",
+      label: "绔欑偣鍚嶇О",
+      width: "160",
+    },
+    {
+      prop: "battgroupName",
+      label: "鐢垫睜缁勫悕绉�",
+      width: "80",
+    },
+      {
+        prop: "monvolstd",
+        label: "鏍囧噯鍗曚綋鐢靛帇",
+        width: "100",
+      },
+      {
+        prop: "moncount",
+        label: "鍗曚綋鏁扮洰",
+        width: "100",
+      },
+      {
+        prop: "moncapstd",
+        label: "鏍囩О瀹归噺",
+        width: "100",
+      },
+    {
+      prop: "product",
+      label: "鐢垫睜鍝佺墝",
+      width: "160",
+    },
+    {
+      prop: "errorNum",
+      label: "寮傚父鍋滄娆℃暟",
+      width: "160",
+    },
+    {
+      prop: "stopListStr",
+      label: "寮傚父鍋滄鍘熷洜",
+      width: "180",
+    },
+    // {
+    //   prop: "stopReason",
+    //   label: "涓婁竴娆℃斁鐢垫暟鎹�",
+    //   width: "100",
+    // },
+  ];
+
+   const testType = ref('');
+  const hrTypeList = computed(() => {
+    return Object.keys(hrTypes).map(v => {
+      return {
+        value: v,
+        label: hrTypes[v],
+      };
+    });
+  });
+
+  
+  const background = ref(true);
+  const disabled = ref(false);
+  const pageCurr = ref(1);
+  const pageSize = ref(10);
+  const total = ref(0);
+  const addEditVisible = ref(false);
+  const dialogTitle = ref("");
+  const currentAreaId = ref();
+  const currentAreaIds = ref([]);
+  const testStartTime = ref('');
+  
+  const testEndTime = ref('');
+  const chartVisible = ref(false);
+  
+  const datas = reactive({
+    tableData: [],
+    rowData: {},
+  });
+
+
+  // 璁$畻灞炴�х敓鎴� picker-options锛堟洿绠�娲侊級
+  const startDisabledDate = (time) =>  testEndTime.value ? moment(testEndTime.value).isBefore(time) || moment().isBefore(time) : moment().isBefore(time);
+
+  const endDisabledDate = (time) => testStartTime.value ? moment(time).isBefore(testStartTime.value) || moment().isBefore(time) : moment().isBefore(time);
+
+
+
+
+  const moncapstd = ref('');
+  const monCapList = ref([]);
+
+// 鑾峰彇鏍囩О瀹归噺
+  function getMonCapList() {
+    getMonCapByUid().then((res) => {
+      let { code, data, data2 } = res;
+      let list = [];
+      if (code && data) {
+        list = data2;
+      }
+      monCapList.value = list;
+    });
+  }
+
+  const teamData = ref(null);
+
+  async function getList() {
+    let loading = $loading();
+    let params = {
+      provice: provice.value || undefined,
+      city: city.value || undefined,
+      country: country.value || undefined,
+      stationName: stationName.value || undefined,
+      pageNum: pageCurr.value,
+      pageSize: pageSize.value,
+
+      testStartTime: testStartTime.value ? testStartTime.value + ' 00:00:00' : undefined,
+      testEndTime: testEndTime.value ? testEndTime.value + ' 23:59:59' : undefined,
+    };
+
+    let res = await getDischr6Statistic(params);
+        let { code, data, data2, data3 } = res;
+        let list = [];
+        let _total = 0;
+        let tData;
+        if (code && data) {
+          // console.log(data);
+          list = data2.list.map(v => ({
+            ...v,
+            stopListStr: v.stopList.join('/') || '--',
+          }));
+          _total = data2.total;
+          tData = Object.keys(data3).map((key) => ({name: key,  value: data3[key].nochargeNum}));
+        }
+        loading.close();
+        // tableData.length = 0;
+        // tableData.push(...list);
+        datas.tableData = list;
+        total.value = _total;
+        teamData.value = tData;
+  }
+
+  // 灞曠ず鏁版嵁鏁伴噺
+  function handleSizeChange(val) {
+    pageSize.value = val;
+    getList();
+  }
+  // 缈婚〉
+  function handleCurrentChange(val) {
+    pageCurr.value = val;
+    getList();
+  }
+
+  function filterChange() {
+    nextTick(() => {
+      pageCurr.value = 1;
+      getList();
+    });
+  }
+
+  function goRt (row) {
+    router.push({
+      path: '/datas/realtime',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function goHis (row) {
+    router.push({
+      path: '/datas/history',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageTab: 'his-real',
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+  function exportExcel() {
+    ExportFile(headers, datas.tableData, "鏈勾搴︽湭鏀剧數鏁伴噺缁熻");
+  }
+
+  onMounted(async () => {
+    // getMonCapList();
+    await getList();
+    chartVisible.value = true;
+  });
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+    </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 10}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <!-- <div class="grid-item">
+                <div class="label">鏍囩О瀹归噺</div>
+                <div class="value">
+                  <el-select
+                    v-model="moncapstd"
+                    filterable
+                    clearable
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in monCapList"
+                      :key="'list11_' + idx"
+                      :label="item"
+                      :value="item"
+                    />
+                  </el-select>
+                </div>
+              </div> -->
+              <div class="grid-item">
+                <div class="label">璁板綍鏃堕棿娈�</div>
+                <div class="value" style="grid-column: span 7;">
+                  <el-date-picker
+                    v-model="testStartTime"
+                    type="date"
+                    size="small"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    @change="filterChange"
+                    :disabled-date="startDisabledDate"
+                  />
+                  -
+                  <el-date-picker
+                    v-model="testEndTime"
+                    size="small"
+                    type="date"
+                    placeholder="閫夋嫨鏃ユ湡"
+                    format="YYYY-MM-DD"
+                    value-format="YYYY-MM-DD"
+                    @change="filterChange"
+                    :disabled-date="endDisabledDate"
+                  />
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table class="yc-table" stripe height="100%" size="small" :data="datas.tableData" style="width: 100%">
+                  <el-table-column type="index" fixed="left" label="搴忓彿" width="60"></el-table-column>
+                  <el-table-column v-for="header in headers" :key="header.prop" :prop="header.prop" :label="header.label"
+                    :min-width="header.width" align="center">
+                    <template #default="scope">{{ scope.row[header.prop] }}</template>  
+                  </el-table-column>
+                  <el-table-column label="鎿嶄綔" fixed="right" width="220" align="center">
+                    <template #default="scope">
+                      <el-button type="warning" size="small" @click="goRt(scope.row)">瀹炴椂鐩戞帶</el-button>
+                      <el-button type="primary" size="small" v-if="scope.row.errorNum > 0" @click="goHis(scope.row)">鍘嗗彶鏁版嵁</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="getList" :icon="Search">鏌ヨ</el-button>
+            </div>
+            <div class="el-page-container">
+              <el-pagination v-model:current-page="pageCurr" v-model:page-size="pageSize"
+                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]" size="small" :disabled="disabled"
+                :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel">瀵煎嚭</el-button>
+              <el-button type="primary" round size="small" @click="chartVisible = true">鏌ョ湅缁熻鍥�</el-button>
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer">
+    </div>
+    <el-dialog v-model="chartVisible" title="缁熻鍥�" width="500">
+      <chart-view :teamData="teamData"></chart-view>
+    </el-dialog>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+  .page-footer {
+    // margin-left: 10px;
+    // width: 380px;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+.max-width {
+  max-width: 200px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/statistics/powerGood.vue b/src/views/statistics/powerGood.vue
new file mode 100644
index 0000000..9141c3c
--- /dev/null
+++ b/src/views/statistics/powerGood.vue
@@ -0,0 +1,595 @@
+<script setup name="powerGood">
+	import { ref, reactive, onMounted, computed, nextTick } from "vue";
+	import { storeToRefs } from "pinia";
+	import { Search, Plus } from "@element-plus/icons-vue";
+	import ycCard from "@/components/ycCard/index.vue";
+	import addEdit from "../datas/addEdit.vue";
+	import { ElMessage } from "element-plus";
+	import useElement from "@/hooks/useElement.js";
+  import { useUserStore } from '@/store/user';
+
+  import useStation from "@/hooks/useStationList.js";
+  const { provice, city, country, stationName,
+    proviceList, cityList, countryList, stationList,
+  } = useStation();
+
+  import { useRouter } from "vue-router";
+  const router = useRouter();
+
+  import { ExportFile } from '@/utils/exportFile.js';
+
+
+  import powerTypes from '@/utils/const/const_powerType.js';
+  import hrTypes from '@/utils/const/const_hrTestType.js';
+  import {
+    getPwrCapperformance,
+    getVoltageLevel,
+    getPowerBrand,
+    getBattGroupBZ,
+  } from "@/api/station";
+
+  const userStore = useUserStore();
+  const { uid, uname } = storeToRefs(userStore);
+  import moment from 'moment';
+
+  import formatSeconds from '@/utils/formatSeconds';
+  import {
+    toFixed,
+    digits,
+  } from '@/utils/toFixed';
+
+  import {
+    getPwr7Statistic,
+  } from "@/api/statistic.js";
+
+	const { $loading, $message, $confirm } = useElement();
+
+  const inuseYear = ref();
+  const pwrInuseYearList = [
+    {
+      value: -1,
+      label: '鍏ㄩ儴'
+    },
+    {
+      value: 3,
+      label: '3骞村唴'
+    },
+    {
+      value: 5,
+      label: '5骞村唴'
+    },
+    {
+      value: 1,
+      label: '5骞翠互涓�'
+    },
+  ]
+
+
+	const headers = [
+    {
+      prop: "stationName",
+      label: "绔欑偣鍚嶇О",
+      width: "220",
+    },
+    {
+      prop: "powerName",
+      label: "鐢垫簮鍚嶇О",
+      width: "120",
+    },
+    {
+      prop: "company",
+      label: "鍝佺墝",
+      width: "100",
+    },
+    {
+      prop: "stationType",
+      label: "鐢靛帇绛夌骇",
+      width: "100",
+    },
+    {
+      prop: "inuseTime",
+      label: "鎶曡繍鏃堕棿",
+      width: "140",
+    },
+    {
+      prop: "groupName",
+      label: "鎵�灞炵彮缁�",
+      width: "100",
+    },
+    {
+      prop: "performanceName",
+      label: "鐢垫簮鎬ц兘",
+      width: "80",
+    },
+  ];
+
+   const testType = ref('');
+  const hrTypeList = computed(() => {
+    return Object.keys(hrTypes).map(v => {
+      return {
+        value: v,
+        label: hrTypes[v],
+      };
+    });
+  });
+
+  
+	const background = ref(true);
+	const disabled = ref(false);
+	const pageCurr = ref(1);
+	const pageSize = ref(10);
+	const total = ref(0);
+	const addEditVisible = ref(false);
+	const dialogTitle = ref("");
+	const currentAreaId = ref();
+	const currentAreaIds = ref([]);
+  const testStartDate = ref('');
+  const testEndDate = ref('');
+	const datas = reactive({
+		tableData: [],
+		rowData: {},
+	});
+
+  const performance = ref('');
+  const performanceList = ref([]);
+
+  function getPerformancList() {
+    getPwrCapperformance()
+      .then((res) => {
+        let { code, data, data2 } = res;
+        let list = [];
+        if (code && data) {
+          // console.log(data);
+          list = Object.keys(data2).map((key) => ({ value: key, label: data2[key] }));
+        }
+        performanceList.value = list;
+      })
+      .catch((err) => {
+        console.log(err);
+      });
+  }
+
+  const company = ref('');
+  const companyList = ref([]);
+  async function getCompanyList() {
+    let res = await getPowerBrand();
+    let { code, data, data2 } = res;
+    let list = [];
+    if (code && data) {
+      list = data2;
+    }
+    companyList.value = list;
+  }
+
+  const stationType = ref('');
+  const stationTypeList = ref([]);
+
+  async function getStationTypeList() {
+    let res = await getVoltageLevel();
+    let { code, data, data2 } = res;
+    let list = [];
+    if (code && data) {
+      list = data2;
+    }
+    stationTypeList.value = list;
+  }
+
+  const groupName = ref('');
+  const groupNameList = ref([]);
+
+  async function getGroupList () {
+    let res = await getBattGroupBZ();
+    let { code, data, data2 } = res;
+    let list = [];
+    if (code && data) {
+      list = data2.map(v => ({ value: v.baojiGroupId, label: v.baojiGroupName }));
+    }
+    groupNameList.value = list;
+  }
+
+
+	function getList() {
+		let loading = $loading();
+    let params = {
+      provice: provice.value || undefined,
+      city: city.value || undefined,
+      country: country.value || undefined,
+      stationName: stationName.value || undefined,
+
+      pageNum: pageCurr.value,
+      pageSize: pageSize.value,
+
+      inuseYear: inuseYear.value == -1 ? undefined : inuseYear.value,
+      performance: performance.value || undefined,
+      company: company.value || undefined,
+      stationType: stationType.value || undefined,
+      groupName: groupName.value || undefined,
+    };
+
+		getPwr7Statistic(params)
+			.then((res) => {
+				let { code, data, data2 } = res;
+				let list = [];
+				let _total = 0;
+				if (code && data) {
+					// console.log(data);
+					list = data2.list.map(v => ({
+            ...v,
+          }));
+					_total = data2.total;
+				}
+				loading.close();
+				// tableData.length = 0;
+				// tableData.push(...list);
+				datas.tableData = list;
+				total.value = _total;
+			})
+			.catch((err) => {
+				console.log(err);
+				loading.close();
+			});
+	}
+
+	// 灞曠ず鏁版嵁鏁伴噺
+	function handleSizeChange(val) {
+		pageSize.value = val;
+		getList();
+	}
+	// 缈婚〉
+	function handleCurrentChange(val) {
+		pageCurr.value = val;
+		getList();
+	}
+
+  function filterChange() {
+    nextTick(() => {
+      pageCurr.value = 1;
+      getList();
+    });
+  }
+
+  // TODO 璺宠浆鍒扮數婧愬仴搴风姸鎬佺粺璁¢〉闈� 鍚庢湡淇敼
+  function goRt (row) {
+    router.push({
+      path: '/datas/realtime',
+      query: {
+        stationId: row.stationId || undefined,
+        powerId: row.powerId || undefined,
+        devId: row.devId || undefined,
+        battgroupId: row.battgroupId || undefined,
+        pageFlag: Math.random(),
+      }
+    });
+  }
+
+
+  function exportExcel() {
+    ExportFile(headers, datas.tableData, "浼樿壇鐢垫簮鏁伴噺缁熻");
+  }
+
+	onMounted(() => {
+    getPerformancList();
+    getCompanyList();
+    getStationTypeList();
+    getGroupList();
+
+		getList();
+	});
+</script>
+
+<template>
+  <div class="page-wrapper">
+    <!-- <div class="page-header">
+    </div> -->
+    <div class="page-content">
+      <yc-card is-full>
+        <div class="page-content-wrapper">
+          <div class="page-content-tools page-filter">
+            <div class="grid-container" :style="{'--counter': 10}">
+              <div class="grid-item">
+                <div class="label">鐪�</div>
+                <div class="value">
+                  <el-select
+                    v-model="provice"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨鐪�"
+                  >
+                    <el-option
+                      v-for="item in proviceList"
+                      :key="'l0_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">甯�</div>
+                <div class="value">
+                  <el-select
+                    v-model="city"
+                    size="small"
+                    clearable
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨甯�"
+                  >
+                    <el-option
+                      v-for="item in cityList"
+                      :key="'l1_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍖哄幙</div>
+                <div class="value">
+                  <el-select
+                    v-model="country"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨鍖哄幙"
+                  >
+                    <el-option
+                      v-for="item in countryList"
+                      :key="'l2_' + item"
+                      :label="item"
+                      :value="item"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">绔欑偣</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationName"
+                    clearable
+                    @change="filterChange"
+                    size="small"
+                    placeholder="璇烽�夋嫨绔欑偣"
+                  >
+                    <el-option
+                      v-for="item in stationList"
+                      :key="'l3_' + item.stationId"
+                      :label="item.stationName"
+                      :value="item.stationName"
+                    >
+                    </el-option>
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鍝佺墝</div>
+                <div class="value">
+                  <el-select
+                    v-model="company"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in companyList"
+                      :key="'list4_' + idx"
+                      :label="item"
+                      :value="item"
+                    />
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鐢靛帇绛夌骇</div>
+                <div class="value">
+                  <el-select
+                    v-model="stationType"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in stationTypeList"
+                      :key="'list8_' + idx"
+                      :label="item"
+                      :value="item"
+                    />
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鎶曡繍鏃堕棿</div>
+                <div class="value">
+                  <el-select
+                    v-model="inuseYear"
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in pwrInuseYearList"
+                      :key="'list9_' + idx"
+                      :label="item.label"
+                      :value="item.value"
+                    />
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鎵�灞炵彮缁�</div>
+                <div class="value">
+                  <el-select
+                    v-model="groupName"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in groupNameList"
+                      :key="'list6_' + idx"
+                      :label="item.label"
+                      :value="item.value"
+                    />
+                  </el-select>
+                </div>
+              </div>
+              <div class="grid-item">
+                <div class="label">鐢垫簮鎬ц兘</div>
+                <div class="value">
+                  <el-select
+                    v-model="performance"
+                    filterable
+                    clearable
+                    size="small"
+                    @change="filterChange"
+                    placeholder="璇烽�夋嫨"
+                  >
+                    <el-option
+                      v-for="(item, idx) in performanceList"
+                      :key="'list7_' + idx"
+                      :label="item.label"
+                      :value="item.value"
+                    />
+                  </el-select>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-table">
+            <div class="pos-rel">
+              <div class="pos-abs">
+                <el-table class="yc-table" stripe height="100%" size="small" :data="datas.tableData" style="width: 100%">
+                  <el-table-column type="index" fixed="left" label="搴忓彿" width="60"></el-table-column>
+                  <el-table-column v-for="header in headers" :key="header.prop" :prop="header.prop" :label="header.label"
+                    :min-width="header.width" align="center">
+                    <template #default="scope">{{ scope.row[header.prop] }}</template>  
+                  </el-table-column>
+                  <el-table-column label="鎿嶄綔" fixed="right" width="240" align="center">
+                    <template #default="scope">
+                      <el-button type="warning" size="small" @click="goRt(scope.row)">鐢垫簮鍋ュ悍鐘舵��</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </div>
+            </div>
+          </div>
+          <div class="page-content-page">
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="getList" :icon="Search">鏌ヨ</el-button>
+            </div>
+            <div class="el-page-container">
+              <el-pagination v-model:current-page="pageCurr" v-model:page-size="pageSize"
+                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]" size="small" :disabled="disabled"
+                :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+            </div>
+            <div class="page-tool">
+              <el-button type="primary" round size="small" @click="exportExcel">瀵煎嚭</el-button>
+            </div>
+          </div>
+        </div>
+      </yc-card>
+    </div>
+    <div class="page-footer"></div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.page-wrapper {
+  display: flex;
+  flex-direction: row;
+  // padding: 8px;
+  height: 100%;
+
+  .page-content {
+    flex: 1;
+  }
+}
+
+.page-content-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .page-content-tools {
+    padding-bottom: 8px;
+  }
+
+  .page-content-table {
+    // border-top: 1px solid var(--border-light-color);
+    box-sizing: border-box;
+    flex: 1;
+    margin-left: 26px;
+    margin-right: 26px;
+  }
+
+  .page-content-page {
+    padding: 8px 8px 0 8px;
+    text-align: center;
+
+    .el-page-container {
+      display: inline-block;
+      padding: 0 16px;
+    }
+
+    .page-tool {
+      display: inline-block;
+    }
+  }
+}
+
+.hdw-card-container {
+  width: 240px;
+  padding-right: 8px;
+  height: 100%;
+}
+
+.pos-rel {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .pos-abs {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.tools-filter {
+  display: inline-block;
+  font-size: 14px;
+
+  .tools-filter-item {
+    display: inline-block;
+    margin-right: 8px;
+
+    .filter-label {
+      display: inline-block;
+    }
+
+    .filter-content {
+      display: inline-block;
+    }
+  }
+}
+.max-width {
+  max-width: 200px;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.1