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