From a10f3b82e33756ed0cd62a0cbe83bab8674df16f Mon Sep 17 00:00:00 2001 From: he wei <858544502@qq.com> Date: 星期二, 03 六月 2025 08:00:58 +0800 Subject: [PATCH] UA 整理提交 --- src/components/echarts/BaseChart.vue | 363 ++ src/views/user/powerMager.vue | 6 src/styles/blue.css | 81 src/styles/blue.less | 122 src/assets/images/img-acdc.png | 0 src/layout/index.vue | 4 src/utils/excel/Blob.js | 204 + src/assets/images/img-batt1.png | 0 src/components/echarts/line1.vue | 246 + src/assets/images/img-batt.png | 0 src/components/svg/svgModule.vue | 107 src/views/statistics/power.vue | 516 +++ src/utils/getTreeDataByKey.js | 36 src/views/alarm/battAlarm.vue | 501 +++ src/views/user/baojiMager.vue | 12 src/icons/svg/arrow.svg | 1 src/icons/svg/stations.svg | 1 src/utils/excel/Export2Excel.js | 179 + src/components/svg/svgFlow.vue | 133 src/views/realtime/tabs/system.vue | 158 src/components/svg/svgSwitch.vue | 117 src/utils/getQueryString.js | 11 src/api/alarm.js | 18 src/views/statistics/devWorkstatus.vue | 416 ++ src/api/statistic.js | 34 src/components/svg/svgLock.vue | 39 src/router/index.js | 4 src/components/svg/svgDiode.vue | 78 src/icons/svg/workstatus.svg | 1 src/router/modules/alarm.js | 34 src/views/alarm/devAlarm.vue | 495 +++ src/components/svg/switchBox.vue | 62 src/router/modules/datas.js | 4 src/components/echarts/transparent.js | 112 src/components/svg/svgTextBox.vue | 68 src/utils/export2Excel.js | 147 src/components/svg/svgResistor.vue | 38 src/views/realtime/bar8.vue | 170 + src/components/svg/dotLine.vue | 53 src/views/user/MyCard.vue | 11 package-lock.json | 130 src/components/card.vue | 3 src/utils/toFixed.js | 16 src/components/siteList/ycTree.vue | 116 src/components/svg/svgFloor.vue | 45 src/icons/svg/dev.svg | 1 src/views/login/index.vue | 5 src/views/alarm/pwrAlarm.vue | 503 +++ src/utils/const/const_hrTestType.js | 7 src/views/datas/device.vue | 185 src/utils/const/const_digit.js | 9 src/components/svg/svgTextBorderBox.vue | 89 src/components/svg/svgText.vue | 63 src/icons/svg/dev1.svg | 1 src/assets/images/img-charge.png | 0 src/utils/exportFile.js | 19 src/views/statistics/station.vue | 421 ++ src/api/station.js | 23 src/components/siteList/index.vue | 311 + src/components/svg/svgStatus.vue | 57 src/components/svg/svgImg.vue | 38 src/views/realtime/index.vue | 255 + src/router/modules/statistics.js | 40 src/icons/svg/realtime1.svg | 1 src/views/statistics/battHr.vue | 487 +++ src/components/svg/stationSvg.vue | 35 src/components/svg/svgCabinet.vue | 258 + src/components/svg/svgStation.vue | 221 + src/components/svgDiagram.vue | 588 +++ src/icons/svg/alarm.svg | 1 src/components/info.vue | 54 src/views/user/index.vue | 4 src/assets/images/img-hr.png | 0 src/icons/svg/setting.svg | 1 src/assets/images/img-hr1.png | 0 src/components/svg/svgInputBox.vue | 82 src/components/svg/svgInputBorderBox.vue | 124 src/components/svg/svgDotRect.vue | 66 src/icons/svg/tongji.svg | 1 src/views/realtime/tabs/vol.vue | 16 src/views/statistics/batt.vue | 516 +++ src/globalComponents.js | 2 src/icons/svg/controls.svg | 1 src/components/svg/svgTriangle.vue | 39 package.json | 6 src/assets/images/img-charge1.png | 0 src/components/svg/svgLine.vue | 117 src/components/svg/svgPv.vue | 35 src/layout/components/AppMain.vue | 19 src/components/svg/svgArc.vue | 40 src/icons/svg/data.svg | 2 src/views/datas/addEdit.vue | 2 src/components/svg/svgDot.vue | 25 93 files changed, 9,420 insertions(+), 242 deletions(-) diff --git a/package-lock.json b/package-lock.json index 00823f6..c2c8579 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,14 +12,18 @@ "axios": "^1.7.2", "echarts": "^5.5.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", + "moment": "^2.30.1", "nprogress": "^0.2.0", "path-browserify": "^1.0.1", "pinia": "^2.1.7", + "pinyin-match": "^1.2.8", "vue": "^3.5.13", - "vue-router": "^4.3.3" + "vue-router": "^4.3.3", + "xlsx": "^0.18.5" }, "devDependencies": { "@rollup/plugin-commonjs": "^28.0.3", @@ -1488,6 +1492,15 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -1803,6 +1816,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmmirror.com/chalk/-/chalk-1.1.3.tgz", @@ -1909,6 +1935,15 @@ "node": ">=0.8" } }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/collection-visit/-/collection-visit-1.0.0.tgz", @@ -1973,6 +2008,18 @@ "license": "MIT", "engines": { "node": ">=0.10.0" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" } }, "node_modules/crypt": { @@ -2655,6 +2702,12 @@ } } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==", + "license": "MIT" + }, "node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-4.0.0.tgz", @@ -2730,6 +2783,15 @@ }, "engines": { "node": ">= 6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" } }, "node_modules/fragment-cache": { @@ -4018,6 +4080,15 @@ "node": ">=0.10.0" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz", @@ -4428,6 +4499,12 @@ "optional": true } } + }, + "node_modules/pinyin-match": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/pinyin-match/-/pinyin-match-1.2.8.tgz", + "integrity": "sha512-5rBwNuOjnOtZNEgX4OlTLYsmBcE9XSV1oF/KN9mLEsVNr8HdqMb2YRhR6iqHMeU8ZBKbx/oYBgHr04uIvOlxGg==", + "license": "SATA" }, "node_modules/posix-character-classes": { "version": "0.1.1", @@ -5387,6 +5464,18 @@ "node": ">=0.10.0" } }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmmirror.com/static-extend/-/static-extend-0.1.2.tgz", @@ -6241,6 +6330,45 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/zrender": { "version": "5.6.1", "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.6.1.tgz", diff --git a/package.json b/package.json index a25106f..d4aaf1f 100644 --- a/package.json +++ b/package.json @@ -13,14 +13,18 @@ "axios": "^1.7.2", "echarts": "^5.5.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", + "moment": "^2.30.1", "nprogress": "^0.2.0", "path-browserify": "^1.0.1", "pinia": "^2.1.7", + "pinyin-match": "^1.2.8", "vue": "^3.5.13", - "vue-router": "^4.3.3" + "vue-router": "^4.3.3", + "xlsx": "^0.18.5" }, "devDependencies": { "@rollup/plugin-commonjs": "^28.0.3", diff --git a/src/api/alarm.js b/src/api/alarm.js index 9630924..dbf7010 100644 --- a/src/api/alarm.js +++ b/src/api/alarm.js @@ -1,12 +1,12 @@ import request from "@/utils/request"; /** - * 纭鍛婅 + * 纭鐢垫睜鍛婅 * num */ -export function confirmAlm(num) { +export function confirmBattAlm(num) { return request({ - url: "lockAlm/confirmAlm", + url: "alm/updateBattConfrim", method: "GET", params: { num @@ -15,12 +15,12 @@ } /** - * 鍙栨秷鍛婅 + * 纭璁惧鍛婅 * num */ -export function cancelAlm(num) { +export function confirmDevAlm(num) { return request({ - url: "lockAlm/cancleAlm", + url: "alm/updateDevConfrim", method: "GET", params: { num @@ -29,12 +29,12 @@ } /** - * 鍒犻櫎鍛婅 + * 纭鐢垫簮鍛婅 * num */ -export function delAlm(num) { +export function confirmPwrAlm(num) { return request({ - url: "lockAlm/delAlm", + url: "alm/updatePwrConfrim", method: "GET", params: { num diff --git a/src/api/station.js b/src/api/station.js index 5144ef3..7910c53 100644 --- a/src/api/station.js +++ b/src/api/station.js @@ -77,6 +77,7 @@ }); } + /** * 鍒犻櫎鏈烘埧 */ @@ -230,6 +231,18 @@ }); } + +/** + * 鍒犻櫎鐢垫睜 璁惧 鐢垫簮 鏈烘埧 + */ +export function delBatt(stationId, powerId, battgroupId) { + return request({ + url: 'condition/delBatt', + method: 'GET', + params: { stationId, powerId, battgroupId } + }); +} + /** * 璁惧涓嬫坊鍔犵數姹犵粍 */ @@ -239,4 +252,14 @@ method: 'POST', data }); +} + +/** + * 绔欑偣鍒楄〃 鏍戠姸 + */ +export function getStationTree() { + return request({ + url: 'stationInf/getLeftStation', + method: 'GET' + }); } \ No newline at end of file diff --git a/src/api/statistic.js b/src/api/statistic.js new file mode 100644 index 0000000..b19edde --- /dev/null +++ b/src/api/statistic.js @@ -0,0 +1,34 @@ +import request from "@/utils/request"; + +/** + * 绔欑偣淇℃伅缁熻 + */ +export function getStationStatistic(data) { + return request({ + url: "statistic/getStationStatistic", + method: "POST", + data + }); +} + +/** + * 钃勭數姹犳牳瀹逛俊鎭粺璁� + */ +export function getBattTinfStatistic(data) { + return request({ + url: "statistic/getBattTinfStatistic", + method: "POST", + data + }); +} + +/** + * 璁惧宸ヤ綔鐘舵�佺粺璁� + */ +export function getDeviceStateStatistic(data) { + return request({ + url: "statistic/getDeviceStateStatistic", + method: "POST", + data + }); +} \ No newline at end of file diff --git a/src/assets/images/img-acdc.png b/src/assets/images/img-acdc.png index e115730..8c3bfc0 100644 --- a/src/assets/images/img-acdc.png +++ b/src/assets/images/img-acdc.png Binary files differ diff --git a/src/assets/images/img-batt.png b/src/assets/images/img-batt.png index 6e6f584..76c0fe5 100644 --- a/src/assets/images/img-batt.png +++ b/src/assets/images/img-batt.png Binary files differ diff --git a/src/assets/images/img-batt1.png b/src/assets/images/img-batt1.png new file mode 100644 index 0000000..6e6f584 --- /dev/null +++ b/src/assets/images/img-batt1.png Binary files differ diff --git a/src/assets/images/img-charge.png b/src/assets/images/img-charge.png index a6b7e8a..9e0772a 100644 --- a/src/assets/images/img-charge.png +++ b/src/assets/images/img-charge.png Binary files differ diff --git a/src/assets/images/img-charge1.png b/src/assets/images/img-charge1.png new file mode 100644 index 0000000..a6b7e8a --- /dev/null +++ b/src/assets/images/img-charge1.png Binary files differ diff --git a/src/assets/images/img-hr.png b/src/assets/images/img-hr.png index 45fe16a..e9a8ee3 100644 --- a/src/assets/images/img-hr.png +++ b/src/assets/images/img-hr.png Binary files differ diff --git a/src/assets/images/img-hr1.png b/src/assets/images/img-hr1.png new file mode 100644 index 0000000..45fe16a --- /dev/null +++ b/src/assets/images/img-hr1.png Binary files differ diff --git a/src/components/card.vue b/src/components/card.vue index 1761a87..3419cf6 100644 --- a/src/components/card.vue +++ b/src/components/card.vue @@ -44,12 +44,15 @@ .title { padding-left: 1.4em; + font-size: 24px; background: url("@/assets/images/tb1.png") 6px center e('/') auto 82% no-repeat; } .tools { position: absolute; top: 6px; right: 6px; + display: flex; + align-items: center; } .content { flex: 1; diff --git a/src/components/echarts/BaseChart.vue b/src/components/echarts/BaseChart.vue new file mode 100644 index 0000000..daa57a5 --- /dev/null +++ b/src/components/echarts/BaseChart.vue @@ -0,0 +1,363 @@ +<script setup name="BaseChart"> +import * as echarts from "echarts"; +import "./transparent"; +import { onMounted, onBeforeUnmount, ref, nextTick } from "vue"; + +const chart_instance = ref(null); +let exportChart_instance = ref(null); + +const chart = ref(null); +const exportChart = ref(null); +const fullScreenFlag = ref(false); +const emit = defineEmits(["click"]); + + + onMounted(() => { + console.log('base mounted',chart.value, '============='); + + chart_instance.value = echarts.init(chart.value, "transparent"); + exportChart_instance.value = echarts.init(exportChart.value, "transparent"); + + let option = getOptions(); + + nextTick(() => { + chart_instance.value.resize(); + chart_instance.value.setOption(option); + }); + window.addEventListener("resize", resize); + + }); + + onBeforeUnmount(() => { + window.removeEventListener("resize", resize); + dispose(); + }); + + function getOptions() { + + const option = { + // title: { + // text: '璇锋眰鏁�', + // textStyle: { + // fontWeight: 'normal', + // fontSize: 16, + // color: '#F1F1F3' + // }, + // left: '6%' + // }, + tooltip: { + trigger: 'axis', + axisPointer: { + lineStyle: { + color: '#57617B' + } + } + }, + // legend: { + // icon: 'rect', + // itemWidth: 14, + // itemHeight: 5, + // itemGap: 13, + // data: ['绉诲姩', '鐢典俊', '鑱旈��'], + // right: '4%', + // textStyle: { + // fontSize: 12, + // color: '#F1F1F3' + // } + // }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: [{ + type: 'category', + boundaryGap: false, + axisLine: { + lineStyle: { + color: '#57617B' + } + }, + data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55'] + }, { + axisPointer: { + show: false + }, + axisLine: { + lineStyle: { + color: '#57617B' + } + }, + axisTick: { + show: false + }, + + position: 'bottom', + offset: 20, + data: ['', '', '', '', '', '', '', '', '', '', { + value: '鍛ㄥ叚', + textStyle: { + align: 'left' + } + }, '鍛ㄦ棩'] + }], + yAxis: [{ + type: 'value', + name: '鍗曚綅锛�%锛�', + axisTick: { + show: false + }, + axisLine: { + lineStyle: { + color: '#57617B' + } + }, + axisLabel: { + margin: 10, + textStyle: { + fontSize: 14 + } + }, + splitLine: { + lineStyle: { + color: '#57617B' + } + } + }], + series: [{ + name: '绉诲姩', + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 5, + showSymbol: false, + lineStyle: { + normal: { + width: 1 + } + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: 'rgba(137, 189, 27, 0.3)' + }, { + offset: 0.8, + color: 'rgba(137, 189, 27, 0)' + }], false), + shadowColor: 'rgba(0, 0, 0, 0.1)', + shadowBlur: 10 + } + }, + itemStyle: { + normal: { + color: 'rgb(137,189,27)', + borderColor: 'rgba(137,189,2,0.27)', + borderWidth: 12 + + } + }, + data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122] + }, { + name: '鐢典俊', + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 5, + showSymbol: false, + lineStyle: { + normal: { + width: 1 + } + }, + areaStyle: { + normal: { + 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: { + normal: { + color: 'rgb(0,136,212)', + borderColor: 'rgba(0,136,212,0.2)', + borderWidth: 12 + + } + }, + data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150] + }, { + name: '鑱旈��', + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 5, + showSymbol: false, + lineStyle: { + normal: { + width: 1 + } + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: 'rgba(219, 50, 51, 0.3)' + }, { + offset: 0.8, + color: 'rgba(219, 50, 51, 0)' + }], false), + shadowColor: 'rgba(0, 0, 0, 0.1)', + shadowBlur: 10 + } + }, + itemStyle: { + normal: { + + color: 'rgb(219,50,51)', + borderColor: 'rgba(219,50,51,0.2)', + borderWidth: 12 + } + }, + data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122] + },] + }; + + return option; + } + + function getChart() { + return chart_instance.value; + } + + function setOption(option) { + if (chart_instance.value) { + chart_instance.value.setOption(option); + } + } + + function fullScreen() { + fullScreenFlag.value = !fullScreenFlag.value; + nextTick(() => { + resize(); + }); + } + + function getDataURL() { + let base64 = ""; + if (exportChart_instance.value) { + let option = chart_instance.value.getOption(); + option.xAxis[0].axisLine.lineStyle = { + color: "#000", + }; + option.xAxis[0].axisLabel.textStyle.color = "#000"; + + option.yAxis[0].axisLine.lineStyle = { + color: "#000", + }; + option.yAxis[0].axisLabel.textStyle.color = "#000"; + exportChart_instance.value.setOption(option); + base64 = exportChart_instance.value.getDataURL({ + pixelRatio: 1, + backgroundColor: "#fff", + }); + } + return base64; + } + + function resize() { + if (chart_instance.value) { + chart_instance.value.resize(); + console.log('resize', '============='); + + } + } + + function dispose() { + disposeChart(chart_instance.value); + disposeChart(exportChart_instance.value); + } + + function disposeChart(chart) { + if (chart) { + chart.dispose(); // 閿�姣佸疄渚� + } + } + + function handleClick() { + emit("click", true); + } + + defineExpose({ + getChart, + setOption, + getDataURL, + }); +</script> + +<template> + <div + class="e-chart-root" + :class="{ 'full-screen': fullScreenFlag }" + > + <!-- @click="handleClick" + @dblclick="fullScreen" --> + <div class="e-chart-container"> + <div class="e-chart" ref="chart"></div> + <slot name="tools"></slot> + </div> + <div class="export-chart-wrapper"> + <div class="export-chart" ref="exportChart"></div> + </div> + </div> +</template> + + +<style scoped> +.e-chart-root { + position: relative; +} +/* chart wrapper css */ +.e-chart-root, +.e-chart { + height: 100%; + box-sizing: border-box; +} +.e-chart-container { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + box-sizing: border-box; +} +.e-chart-root.full-screen .e-chart-container { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-size: 100% 100%; + z-index: 9999; +} + +/* export chart wrapper css */ +.export-chart-wrapper { + position: relative; + width: 0; + height: 0; + overflow: hidden; +} +.export-chart { + position: absolute; + width: 600px; + height: 400px; +} +</style> diff --git a/src/components/echarts/line1.vue b/src/components/echarts/line1.vue new file mode 100644 index 0000000..facffb1 --- /dev/null +++ b/src/components/echarts/line1.vue @@ -0,0 +1,246 @@ +<script setup> + import { onMounted, ref, watchEffect, nextTick, onBeforeUnmount } from "vue"; + import * as echarts from 'echarts'; + import baseChart from "./BaseChart.vue"; + + const chart = ref(null); + + + function getOptions() { + + const option = { + title: { + text: '璇锋眰鏁�', + textStyle: { + fontWeight: 'normal', + fontSize: 16, + color: '#F1F1F3' + }, + left: '6%' + }, + tooltip: { + trigger: 'axis', + axisPointer: { + lineStyle: { + color: '#57617B' + } + } + }, + // legend: { + // icon: 'rect', + // itemWidth: 14, + // itemHeight: 5, + // itemGap: 13, + // data: ['绉诲姩', '鐢典俊', '鑱旈��'], + // right: '4%', + // textStyle: { + // fontSize: 12, + // color: '#F1F1F3' + // } + // }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: [{ + type: 'category', + boundaryGap: false, + axisLine: { + lineStyle: { + color: '#57617B' + } + }, + data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55'] + }, { + axisPointer: { + show: false + }, + axisLine: { + lineStyle: { + color: '#57617B' + } + }, + axisTick: { + show: false + }, + + position: 'bottom', + offset: 20, + data: ['', '', '', '', '', '', '', '', '', '', { + value: '鍛ㄥ叚', + textStyle: { + align: 'left' + } + }, '鍛ㄦ棩'] + }], + yAxis: [{ + type: 'value', + name: '鍗曚綅锛�%锛�', + axisTick: { + show: false + }, + axisLine: { + lineStyle: { + color: '#57617B' + } + }, + axisLabel: { + margin: 10, + textStyle: { + fontSize: 14 + } + }, + splitLine: { + lineStyle: { + color: '#57617B' + } + } + }], + series: [{ + name: '绉诲姩', + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 5, + showSymbol: false, + lineStyle: { + normal: { + width: 1 + } + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: 'rgba(137, 189, 27, 0.3)' + }, { + offset: 0.8, + color: 'rgba(137, 189, 27, 0)' + }], false), + shadowColor: 'rgba(0, 0, 0, 0.1)', + shadowBlur: 10 + } + }, + itemStyle: { + normal: { + color: 'rgb(137,189,27)', + borderColor: 'rgba(137,189,2,0.27)', + borderWidth: 12 + + } + }, + data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122] + }, { + name: '鐢典俊', + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 5, + showSymbol: false, + lineStyle: { + normal: { + width: 1 + } + }, + areaStyle: { + normal: { + 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: { + normal: { + color: 'rgb(0,136,212)', + borderColor: 'rgba(0,136,212,0.2)', + borderWidth: 12 + + } + }, + data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150] + }, { + name: '鑱旈��', + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 5, + showSymbol: false, + lineStyle: { + normal: { + width: 1 + } + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: 'rgba(219, 50, 51, 0.3)' + }, { + offset: 0.8, + color: 'rgba(219, 50, 51, 0)' + }], false), + shadowColor: 'rgba(0, 0, 0, 0.1)', + shadowBlur: 10 + } + }, + itemStyle: { + normal: { + + color: 'rgb(219,50,51)', + borderColor: 'rgba(219,50,51,0.2)', + borderWidth: 12 + } + }, + data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122] + },] + }; + + 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) { + let option = getOptions(xLabels, datas); + // if (myChart) { + + // myChart.setOption(option); + // } + } + + 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/transparent.js b/src/components/echarts/transparent.js new file mode 100644 index 0000000..8664f03 --- /dev/null +++ b/src/components/echarts/transparent.js @@ -0,0 +1,112 @@ +import * as echarts from "echarts"; + +let theme = { + version: 1, + themeName: "transparent", + theme: { + seriesCnt: 3, + backgroundColor: "rgba(0, 0, 0, 0)", + titleColor: "#00ffff", + subtitleColor: "#00ffff", + textColorShow: false, + textColor: "#333", + markTextColor: "#ffffff", + color: [ + "#22cbbc", + "#91cc75", + "#fac858", + "#ee6666", + "#73c0de", + "#3ba272", + "#fc8452", + "#9a60b4", + "#ea7ccc", + ], + borderColor: "#4adfd2", + borderWidth: "0", + visualMapColor: ["#48dcd4", "#d88273", "#f6efa6"], + legendTextColor: "#ffffff", + kColor: "#eb5454", + kColor0: "#47b262", + kBorderColor: "#eb5454", + kBorderColor0: "#47b262", + kBorderWidth: 1, + lineWidth: "2", + symbolSize: "8", + symbol: "circle", + symbolBorderWidth: "0", + lineSmooth: true, + graphLineWidth: 1, + graphLineColor: "#aaa", + mapLabelColor: "#000", + mapLabelColorE: "rgb(100,0,0)", + mapBorderColor: "#444", + mapBorderColorE: "#444", + mapBorderWidth: 0.5, + mapBorderWidthE: 1, + mapAreaColor: "#eee", + mapAreaColorE: "rgba(255,215,0,0.8)", + axes: [ + { + type: "all", + name: "閫氱敤鍧愭爣杞�", + axisLineShow: true, + axisLineColor: "#6E7079", + axisTickShow: true, + axisTickColor: "#6E7079", + axisLabelShow: true, + axisLabelColor: "#6E7079", + splitLineShow: true, + splitLineColor: ["#E0E6F1"], + splitAreaShow: false, + splitAreaColor: ["rgba(250,250,250,0.2)", "rgba(210,219,238,0.2)"], + }, + { + type: "category", + name: "绫荤洰鍧愭爣杞�", + axisLineShow: true, + axisLineColor: "#ffffff", + axisTickShow: true, + axisTickColor: "#00ffff", + axisLabelShow: true, + axisLabelColor: "#ffffff", + splitLineShow: false, + splitLineColor: ["#E0E6F1"], + splitAreaShow: true, + splitAreaColor: ["rgba(160,158,222,0.2)", "rgba(210,219,238,0.2)"], + }, + { + type: "value", + name: "鏁板�煎潗鏍囪酱", + axisLineShow: true, + axisLineColor: "#ffffff", + axisTickShow: true, + axisTickColor: "#00ffff", + axisLabelShow: true, + axisLabelColor: "#00ffff", + splitLineShow: true, + splitLineColor: ["#E0E6F1"], + splitAreaShow: false, + splitAreaColor: ["rgba(250,250,250,0.2)", "rgba(210,219,238,0.2)"], + }, + ], + axisSeperateSetting: true, + toolboxColor: "#00ffff", + toolboxEmphasisColor: "#ffffff", + tooltipAxisColor: "#ffffff", + tooltipAxisWidth: 1, + timelineLineColor: "#DAE1F5", + timelineLineWidth: 2, + timelineItemColor: "#A4B1D7", + timelineItemColorE: "#FFF", + timelineCheckColor: "#316bf3", + timelineCheckBorderColor: "fff", + timelineItemBorderWidth: 1, + timelineControlColor: "#A4B1D7", + timelineControlBorderColor: "#A4B1D7", + timelineControlBorderWidth: 1, + timelineLabelColor: "#A4B1D7", + }, +}; + +echarts.registerTheme("transparent", theme); \ No newline at end of file diff --git a/src/components/info.vue b/src/components/info.vue new file mode 100644 index 0000000..14f102b --- /dev/null +++ b/src/components/info.vue @@ -0,0 +1,54 @@ +<script setup> +import { ref } from "vue"; +const props = defineProps({ + label: { + type: String, + default: "", + }, + value: { + type: String, + default: "", + }, +}); +</script> + +<template> + <div class="info"> + <div class="label">{{ label }}</div> + <div class="value">{{ value }}</div> + </div> +</template> + +<style scoped lang="less"> +.info { + display: flex; + background: #193B69; + height: 32px; + font-size: 14px; + + .label { + min-width: 6em; + color: #fff; + background: linear-gradient(#3476BE, #3476BE) left center e('/') 2px 100% no-repeat, + linear-gradient(#1E497E, #1E497E) center center e('/') contain no-repeat; + display: flex; + align-items: center; + justify-content: flex-end; + padding-right: 0.6em; + &::after { + content: ':'; + } + } + + .value { + flex: 1; + display: flex; + align-items: center; + justify-content: flex-start; + padding-left: 1em; + color: #48a5d0; + background: linear-gradient(#3476BE, #3476BE) left center e('/') 2px 46% no-repeat, + linear-gradient(#377ED2, #377ED2) right bottom e('/') 3px 3px no-repeat; + } +} +</style> diff --git a/src/components/siteList/index.vue b/src/components/siteList/index.vue new file mode 100644 index 0000000..5f06e3a --- /dev/null +++ b/src/components/siteList/index.vue @@ -0,0 +1,311 @@ +<script setup> +import { ref, reactive, onMounted, computed, onActivated } from "vue"; +import YcTree from "./ycTree.vue"; +import getQueryString from "@/utils/getQueryString"; +import pinyinMatch from 'pinyin-match'; + +import { + getStationTree, +} from '@/api/station.js'; + +import getTreeDataByKey from "@/utils/getTreeDataByKey"; + +const emit = defineEmits(["leaf-click"]); +const flag = ref(Math.random()); +const treeFlag = ref(0); +const defaultExpandedKeys = ref([ + getQueryString("stationId"), +]); + + + +const currentNodeKey = ref(getQueryString("battgroupId") || getQueryString("powerId") || ""); +const expanded = ref([]); +const currentKey = ref(''); + +const filterText = ref(""); +const treeData = ref([]); +const siteList = ref([]); +const siteListCopy = ref([]); +const treeRef = ref(null); + +const getCurrentKey = computed(() => { + return currentNodeKey.value ? currentNodeKey.value : currentKey.value; +}); + +const expandedKeys = computed(() => { + // let parentKey = defaultExpandedKeys.value.join('-'); + let parentKey = defaultExpandedKeys.value[0]; + if (parentKey) { + return [parentKey]; + } else { + let _expanded = expanded.value; + return _expanded; + } +}); + +function filterMethod(val) { + if (val) { + siteList.value = siteListCopy.value.filter((item) => { + return pinyinMatch.match(item, val); + }); + } else { + siteList.value = siteListCopy.value; + } +} + +const hideFlag = ref(false); + +function toggleChange() { + // emit("toggleChange"); + hideFlag.value = !hideFlag.value; +} + +function filterChange(val) { + if (val) { + let homeInfo = siteListCopy.value.filter(v => v.id == val); + + if (homeInfo.length) { + let item = homeInfo[0]; + defaultExpandedKeys.value = [item.id]; + + let expandedNode = getTreeDataByKey(expandedKeys.value[0], treeData.value, 'key'); + if (expandedNode != -1) { + expanded.value = [expandedNode.key]; + currentNodeKey.value = expandedNode.children[0].isleaf ? expandedNode.children[0].key : expandedNode.children[0].children[0].key; + leafClick(expandedNode.children[0].isleaf ? expandedNode.children[0] : expandedNode.children[0].children[0]); + } + } + } +} + +function nodeClick(data) { + // console.log('nodeClick', data, '============='); + +} + +function leafClick(data) { + console.log('leafClick', data, '============='); + emit('leaf-click', data); +} + +async function getSiteList() { + let { code, data, data2 } = await getStationTree(); + let list = []; + if (code && data) { + list = data2; + } + formatData(list); + +} + +function formatData(list) { + let sites = []; + list.forEach(v => { + let pro = v.provice; + let citys = v.cityList; + v.label = pro; + v.key = pro; + v.children = citys; + citys.forEach(v1 => { + let city = v1.city; + let countries = v1.countryList; + v1.label = city; + v1.key = city; + v1.children = countries; + + countries.forEach(v2 => { + let country = v2.country; + let _list = v2.stationList; + v2.label = country; + v2.key = country; + v2.children = _list; + _list.forEach(v3 => { + v3.label = v3.stationName; + v3.key = v3.stationId; + let powerList = v3.pinflist; + v3.children = powerList; + sites.push({ + label: `${pro}-${city}-${country}-${v3.stationName}`, + id: v3.stationId, + data: { + provice: pro, + city: city, + country: country, + stationName: v3.stationName, + children: powerList + } + }); + powerList.forEach(v4 => { + v4.label = v4.powerName; + v4.key = `${v4.stationId}-${v4.powerId}`; + v4.children = v4.battList; + v4.isleaf = !v4.battList.length; + + v4.battList.forEach(v5 => { + v5.label = `${v5.devName}-${v5.battgroupName}`; + v5.key = `${v5.stationId}-${v5.powerId}-${v5.devId}-${v5.battgroupId}`; + v5.isleaf = true; + }); + }); + }); + }); + }); + }); + + siteListCopy.value = sites.map(v => v); + treeData.value = list; + if (sites.length) { + let expandedNode = getTreeDataByKey(sites[0].id, treeData.value, 'key'); + if (expandedNode != -1) { + expanded.value = [expandedNode.key]; + let selectKey = expandedNode.children[0].isleaf ? expandedNode.children[0].key : expandedNode.children[0].children[0].key; + currentNodeKey.value = selectKey; + let res = getTreeDataByKey(selectKey, treeData.value, 'key'); + + leafClick(res); + // leafClick(expandedNode.children[0].isleaf ? expandedNode.children[0] : expandedNode.children[0].children[0]); + } + } +} + +function updateSelect() { + let stationId = getQueryString("stationId"); + let powerId = getQueryString("powerId"); + let battgroupId = getQueryString("battgroupId"); + let devId = getQueryString("devId"); + if (stationId) { + let expandedNode = getTreeDataByKey(stationId, treeData.value, 'key'); + console.log('expandedNode', expandedNode, '============='); + + if (expandedNode != -1) { + expanded.value = [expandedNode.key]; + // 鏍规嵁涓嶅悓鎯呭喌閫変腑瑕佹墦寮�鐨勫彾瀛愯妭鐐� + // 濡傛灉鍙湁stationId 鍒欐墦寮�stationId鐨勭涓�涓猵owerId 鎴栦笅闈㈢殑 鐨勭涓�涓猙attgroupId + // 濡傛灉鏈塸owerId 1,鐢垫簮鏄彾瀛愯妭鐐� 鍒欐墦寮�杩欎釜瀵瑰簲鐨勭數婧� 2,鐢垫簮涓嶆槸鍙跺瓙鑺傜偣 a,濡傛灉鍙湁璁惧id 鍒欐墦寮�鐢垫簮childern鐨勭涓�涓瓑浜庡垯璁惧id鐨勭數姹犵粍 b,濡傛灉鏈塨attgroupId 鍒欐墦寮�杩欎釜瀵瑰簲鐨勭數姹犵粍 c,濡傛灉鏈塪evId 鍒欐墦寮�鐢垫簮涓嬬涓�涓數姹犵粍 + let selectKey = ''; + if (powerId) { + // 鐢垫簮鑺傜偣 + let powerNode = getTreeDataByKey(`${stationId}-${powerId}`, treeData.value, 'key'); + if (powerNode.isleaf) { + selectKey = powerNode.key; + } else { + if (battgroupId) { + selectKey = `${stationId}-${powerId}-${devId}-${battgroupId}`; + } else if (devId) { + selectKey = powerNode.children.filter(v => v.devId == devId)[0].key; + } else { + selectKey = powerNode.children[0].key; + } + } + } else { + selectKey = expandedNode.children[0].isleaf ? expandedNode.children[0].key : expandedNode.children[0].children[0].key; + } + currentNodeKey.value = selectKey; + + // console.log('currentKey', currentKey.value, 'expanded', expanded.value, 'getCurrentKey', getCurrentKey.value, '============='); + treeFlag.value = Math.random(); + let res = getTreeDataByKey(selectKey, treeData.value, 'key'); + // console.log('res', res, '============='); + + + leafClick(res); + } + } +} + +onActivated(async () => { + if (!treeData.value.length) { + await getSiteList(); + } + let pageFlag = getQueryString("pageFlag"); + console.log('pageFlag', pageFlag, flag.value, '============='); + + if (pageFlag &&pageFlag != flag.value) { + updateSelect(); + flag.value = pageFlag; + } +}); + + +onMounted(() => { + getSiteList(); +}); + +</script> + +<template> + <card + title="绔欑偣鍒楄〃" + :class="['site-list', { 'hide': hideFlag }]" + > + <flex-layout> + <template v-slot:header> + <el-select + size="small" + v-model="filterText" + class="search" + filterable + clearable + :filter-method="filterMethod" + placeholder="璇烽�夋嫨" + @change="filterChange" + > + <el-option + v-for="(item, idx) in siteList" + :key="'site_' + idx" + :label="item.label" + :value="item.id" + /> + </el-select> + </template> + <yc-tree + ref="treeRef" + :data="treeData" + :key="treeFlag" + :default-expand-keys="expandedKeys" + :current-node-key="getCurrentKey" + @node-click="nodeClick" + @leaf-click="leafClick" + ></yc-tree> + </flex-layout> + <div class="btn" @click="toggleChange"> + <svg-icon icon-class="arrow"></svg-icon> + </div> + </card> +</template> + +<style scoped lang="less"> +.site-list { + width: 320px; + position: relative; + transition: all 0.5s ease; + .btn { + display: flex; + position: absolute; + right: 0; + top: 50%; + width: 30px; + height: 80px; + background: rgba(0, 0, 0, 0.5); + cursor: pointer; + transform: translateY(-50%) rotate(180deg); + transform-origin: center center; + transition: all 0.5s ease; + align-items: center; + justify-content: center; + + } + &.hide { + transform: translate(-100%, 0); + margin-right: -320px; + .btn { + right: -8px; + transform: translate(100%, -50%) rotate(0deg); + } + } + :deep(.flex-layout-header) { + padding: 6px 10px; + } +} +</style> \ No newline at end of file diff --git a/src/components/siteList/ycTree.vue b/src/components/siteList/ycTree.vue new file mode 100644 index 0000000..3bb65fb --- /dev/null +++ b/src/components/siteList/ycTree.vue @@ -0,0 +1,116 @@ +<script setup> +import { ref, reactive, watch, onMounted, nextTick } from "vue"; +const props = defineProps({ + data: { + type: Array, + default() { + return []; + } + }, + defaultExpandKeys: { + type: Array, + default() { + return [] + } + }, + currentNodeKey: { + type: [String, Number], + default: "" + }, +}); + +const tree = ref(null); +const current = ref(''); +const defaultProps = reactive({ + children: 'children', + label: 'label', + isLeaf: 'isLeaf', +}); + +watch( + () => props.currentNodeKey, + (val) => { + nextTick(() => { + current.value = val; + tree.value.setCurrentKey(val); + }); + } +); + +const emit = defineEmits(['node-click', 'leaf-click']); + +function nodeClick(data, node) { + node.isCurrent = node.isLeaf; + if (node.isLeaf && current.value != node.key) { + current.value = node.key; + emit('leaf-click', data, node); + } else { + emit('node-click', data, node); + } + tree.value.setCurrentKey(current.value); +} + +function nodeExpand(data, node) { + node.isCurrent = node.isLeaf; + if (!node.isLeaf && current.value != node.key) { + emit('node-click', data, node); + } +} + +function nodeCollapse(data, node) { + loopClose(node.childrenNodes); +} + +function loopClose(childNodes) { + if(!childNodes || childNodes.length === 0) { + return; + } + childNodes.map(item=>{ + item.expanded = false; + loopClose(item.childNodes); + }); +} + + +onMounted(() => { + setTimeout(() => { + if(tree.value) { + tree.value.setCurrentKey(props.currentNodeKey); + current.value = props.currentNodeKey; + } + }, 500); +}); + + +</script> + +<template> + <el-tree + class="filter-tree" + :props="defaultProps" + :auto-expand-parent="true" + node-key="key" + ref="tree" + :data="data" + :default-expanded-keys="defaultExpandKeys" + :current-node-key="currentNodeKey" + @node-collapse="nodeCollapse" + @node-click="nodeClick" + @node-expand="nodeExpand" + > + <template #default="{ node }"> + <span class="span-ellipsis"> + <span :title="node.label">{{ node.label }}</span> + </span> + </template> + </el-tree> +</template> + +<style scoped lang="less"> +.filter-tree { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +</style> diff --git a/src/components/svg/dotLine.vue b/src/components/svg/dotLine.vue new file mode 100644 index 0000000..40d3d01 --- /dev/null +++ b/src/components/svg/dotLine.vue @@ -0,0 +1,53 @@ +<script setup> +import { ref } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + points: { + type: Array, + default() { + return [ + [0, 0], + [10, 10], + ]; + }, + }, + color: { + type: String, + default: "#804000", + }, + dotIndexs: { + type: Array, + default() { + return [0] + } + }, + dotR: { + type: [Number, String], + default: 4 + } +}); + +</script> + +<template> +<g + ref="g" + :transform="'translate(' + offset.join(',') + ')'" + > + <polyline + :points="points.join(' ')" + stroke-dasharray="4,2" + :stroke="color" + style="fill: none; stroke-width: 2" + /> + </g> +</template> + +<style scoped lang="less"> + +</style> \ No newline at end of file diff --git a/src/components/svg/stationSvg.vue b/src/components/svg/stationSvg.vue new file mode 100644 index 0000000..71aff37 --- /dev/null +++ b/src/components/svg/stationSvg.vue @@ -0,0 +1,35 @@ +<script> +import rightPublic from "@/components/svg/rightPublic/index.vue"; +import rightSwitch from "@/components/svg/rightSwitch/index.vue"; +import tenToTwelve from "@/components/svg/tenToTwelve/index.vue"; +import sevenToNine from "@/components/svg/sevenToNine/index.vue"; +export default { + name: "stationSvg", + components: {rightPublic, rightSwitch, tenToTwelve, sevenToNine}, + props: { + type: { + type: Number, + default: 1 + } + }, + data() { + return {}; + }, + methods: {}, + mounted() { + + } +} +</script> + +<template> + <right-switch v-if="type === 4"></right-switch> + <right-public v-else-if="type === 3"></right-public> + <ten-to-twelve v-else-if="type === 2"></ten-to-twelve> + <seven-to-nine v-else-if="1"></seven-to-nine> + <div v-else>鏈煡鎷撴墤鍥撅紝鑱旂郴绠$悊鍛樻柊澧烇紒锛侊紒</div> +</template> + +<style scoped lang="less"> + +</style> diff --git a/src/components/svg/svgArc.vue b/src/components/svg/svgArc.vue new file mode 100644 index 0000000..1d7767a --- /dev/null +++ b/src/components/svg/svgArc.vue @@ -0,0 +1,40 @@ +<script setup name="SvgArc"> + import { ref, computed } from "vue"; + const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + isVertical: { + type: Boolean, + default: false + }, + r: { + type: [Number, String], + default: 8, + }, + color: { + type: String, + default: "#4cb5e2", + }, + lineWidth: { + type: [Number, String], + default: 2, + }, + }); + + const path = computed(() => { + let r = props.r; + let end = props.isVertical ? `0,${r*2}` : `${r*2},0`; + let path = `M 0,0 A ${r},${r} 0 1 1 ${end}`; + return path; + }); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <path :d="path" :stroke="color" :stroke-width="lineWidth" fill="none" /> + </g> +</template> diff --git a/src/components/svg/svgCabinet.vue b/src/components/svg/svgCabinet.vue new file mode 100644 index 0000000..4526f78 --- /dev/null +++ b/src/components/svg/svgCabinet.vue @@ -0,0 +1,258 @@ +<script setup> +import { ref, computed, onMounted } from "vue"; +import svgLock from "./svgLock.vue"; +const emit = defineEmits(["showInfo"]); + +const props = defineProps({ + offset: { + type: Array, + default: [0, 0], + }, + width: { + type: [Number, String], + default: 80, + }, + lineWidth: { + type: [Number, String], + default: 2, + }, + color: { + type: String, + default: "#804000", + }, + offColor: { + type: String, + // default: '#888', + default: '#f00', + }, + onColor: { + type: String, + default: '#0f0', + }, + disabled: { + type: Boolean, + default: false, + }, + onLine0: { + type: [Number, String], + }, + onLine1: { + type: [Number, String], + }, + lock0: { + type: Boolean, + default: false, + }, + lock1: { + type: Boolean, + default: false, + }, +}); + +/** + * 0 ------- 1 + /| /| + / | / | + 3 ------- 2 | + | | | | + | 4 ---- |-- 5 + | / | / + |/ |/ + 7 ------- 6 + */ +const x0 = computed(() => { + return props.width / 2 - props.width / 6; +}); + +const x1 = computed(() => { + return props.width; +}); + +const x2 = computed(() => { + return props.width / 2 + props.width / 6; +}); + +const x3 = computed(() => { + return 0; +}); + +const y0 = computed(() => { + return 0; +}); + +const y1 = computed(() => { + return props.width * 2 / 4; +}); + +const y2 = computed(() => { + return props.width * 2 * 3 / 4; +}); + +const y3 = computed(() => { + return props.width * 2; +}); + +const y4 = computed(() => { + return props.width * 2 * 5 / 8; +}); + +const y5 = computed(() => { + return props.width * 2 * 3 / 8; +}); + +const strokeColor = computed(() => { + return props.disabled ? 'rgba(125,125,125,0.2)' : props.color; +}); + +const statusColor0 = computed(() => { + if (props.disabled || !props.onLine0) return '#888'; + return props.lock0 ? props.onColor : props.offColor; +}); + +const statusColor1 = computed(() => { + if (props.disabled || !props.onLine1) return '#888'; + return props.lock1 ? props.onColor : props.offColor; +}); + +const onLineColor0 = computed(() => { + if (props.disabled) return '#888'; + switch(props.onLine0) { + case 1: + return props.onColor; + case 0: + return props.offColor; + default: + return '#888'; + } +}); + +const onLineColor1 = computed(() => { + if (props.disabled) return '#888'; + + switch(props.onLine1) { + case 1: + return props.onColor; + case 0: + return props.offColor; + default: + return '#888'; + } +}); + +function showInfo(idx, event) { + if (props.disabled) return; + emit("showInfo", { idx, event }); +} + + + +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <!-- 0-1 --> + <line :x1="x0" :x2="x1" :y1="y0" :y2="y0" :stroke="strokeColor" :stroke-width="lineWidth" /> + <!-- 0-3 --> + <line + :x1="x0" + :y1="y0" + :x2="x3" + :y2="y1" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 3-2 --> + <line + :x1="x3" + :y1="y1" + :x2="x2" + :y2="y1" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 2-1 --> + <line + :x1="x2" + :y1="y1" + :x2="x1" + :y2="y0" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 3-7 --> + <line :x1="x3" :x2="x3" :y1="y1" :y2="y3" :stroke="strokeColor" :stroke-width="lineWidth" /> + <!-- 7-6 --> + <line + :x1="x3" + :y1="y3" + :x2="x2" + :y2="y3" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 2-6 --> + <line + :x1="x2" + :y1="y1" + :x2="x2" + :y2="y3" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 5-6 --> + <line + :x1="x1" + :y1="y2" + :x2="x2" + :y2="y3" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 1-5 --> + <line :x1="x1" :x2="x1" :y1="y0" :y2="y2" :stroke="strokeColor" :stroke-width="lineWidth" /> + <!-- 0-4 --> + <line + :x1="x0" + :y1="y0" + :x2="x0" + :y2="y2" + stroke-dasharray="4,2" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 4-5 --> + <line + :x1="x0" + :y1="y2" + :x2="x1" + :y2="y2" + stroke-dasharray="4,2" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 4-7 --> + <line + :x1="x0" + :y1="y2" + :x2="x3" + :y2="y3" + stroke-dasharray="4,2" + :stroke="strokeColor" + :stroke-width="lineWidth" + /> + <!-- 鍓嶉棬閿� --> + <svg-lock :offset="[x3 + 6, y4 - 14]" + :lockFillColor="statusColor0" + :stateColor="onLineColor0" + @mouseenter="showInfo(0, $event)" + ></svg-lock> + <!-- 鍚庨棬閿� --> + <svg-lock :offset="[x1 - 14, y5 - 10]" + :lockFillColor="statusColor1" + :stateColor="onLineColor1" + @mouseenter="showInfo(1, $event)" + ></svg-lock> + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgDiode.vue b/src/components/svg/svgDiode.vue new file mode 100644 index 0000000..efc4b84 --- /dev/null +++ b/src/components/svg/svgDiode.vue @@ -0,0 +1,78 @@ +<script setup name="SvgDiode"> +import { ref, computed } from "vue"; +const props = defineProps({ + len: { + type: Number, + default: 20, + }, + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + color: { + type: String, + default: "#f59a23", + }, + lineWidth: { + type: [Number, String], + default: 2, + }, + // 鏂瑰悜涓轰簩鏋佺瀵奸�氭柟鍚� 涓夎褰㈡寚鍚� + direct: { + type: String, + default: "left", + validator: (v) => ["left", "right", "top", "bottom"].includes(v), + }, +}); + +const y1 = computed(() => { + let len = props.len; + return len / -2; +}); + +const y2 = computed(() => { + let len = props.len; + return len / 2; +}); + +const points = computed(() => { + let len = props.len; + let lineWidth = props.lineWidth; + let len2 = len / 2; + return [ + [lineWidth, 0], + [lineWidth + Math.cos((30 * Math.PI) / 180) * len, len2], + [lineWidth + Math.cos((30 * Math.PI) / 180) * len, -len2], + ].join(" "); +}); + +const transform = computed(() => { + let { offset, direct, lineWidth, len } = props; + let rotate = ""; + switch (direct) { + case "left": + rotate = ""; + break; + case "right": + rotate = `rotate(180 0 0) translate(-${lineWidth + Math.cos((30 * Math.PI) / 180) * len} 0)`; + break; + case "top": + rotate = "rotate(90 0 0)"; + break; + case "bottom": + rotate = `rotate(270 0 0) translate(-${lineWidth + Math.cos((30 * Math.PI) / 180) * len} 0)`; + break; + } + return `translate(${offset.join(",")}) ${rotate}`; +}); + +</script> + +<template> + <g :transform="transform"> + <polygon :points="points" stroke="none" :fill="color" /> + <line :y1="y1" :y2="y2" :stroke-width="lineWidth" :stroke="color"></line> + </g> +</template> \ No newline at end of file diff --git a/src/components/svg/svgDot.vue b/src/components/svg/svgDot.vue new file mode 100644 index 0000000..55daa65 --- /dev/null +++ b/src/components/svg/svgDot.vue @@ -0,0 +1,25 @@ +<script setup> +import { ref } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default: [0, 0], + }, + r: { + type: [Number, String], + default: 6, + }, + color: { + type: String, + default: "#804000", + }, +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <circle :r="r" :fill="color" /> + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgDotRect.vue b/src/components/svg/svgDotRect.vue new file mode 100644 index 0000000..ef4485e --- /dev/null +++ b/src/components/svg/svgDotRect.vue @@ -0,0 +1,66 @@ +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <rect + :width="width" + :height="height" + :stroke="color" + :fill="fillColor" + :stroke-width='strokeWidth' + :stroke-dasharray='strokeDasharray' + :stroke-dashoffset='strokeDashoffset' + :rx="rx" + :ry="ry" + /> + </g> +</template> + +<script setup name="SvgDotRect"> +import { ref } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + width: { + type: [Number, String], + default: 4, + }, + height: { + type: [Number, String], + default: 4, + }, + color: { + type: String, + default: "#0ff", + }, + fillColor: { + type: String, + // default: 'transparent', + default: '#00000066', + }, + rx: { + type: [Number, String], + default: 0, + }, + ry: { + type: [Number, String], + default: 0, + }, + strokeWidth: { + type: [Number, String], + default: 0, + }, + strokeDasharray: { + type: String, + default: '8 4', + }, + strokeDashoffset: { + type: [Number, String], + default: 0, + }, +}); +</script> + +<style scoped></style> diff --git a/src/components/svg/svgFloor.vue b/src/components/svg/svgFloor.vue new file mode 100644 index 0000000..e2271b4 --- /dev/null +++ b/src/components/svg/svgFloor.vue @@ -0,0 +1,45 @@ +<script setup> +import { ref } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + points: { + type: Array, + default() { + return [ + ]; + }, + }, + color: { + type: String, + default: 'rgba(0, 255, 255, 0.2)', + }, + fillColor: { + type: String, + default: "#032134", + } +}); + +</script> + +<template> +<g + ref="g" + :transform="'translate(' + offset.join(',') + ')'" + > + <polygon + :points="points.join(' ')" + :stroke="color" + :fill="fillColor" + style="stroke-width: 2" + /> + </g> +</template> + +<style scoped lang="less"> + +</style> \ No newline at end of file diff --git a/src/components/svg/svgFlow.vue b/src/components/svg/svgFlow.vue new file mode 100644 index 0000000..2c77f90 --- /dev/null +++ b/src/components/svg/svgFlow.vue @@ -0,0 +1,133 @@ +<script setup> +import { ref, computed } from "vue"; + +const props = defineProps({ + offset: { + type: Array, + default: () => [0, 0], + }, + /** + * 姣忎竴娈佃矾寰勪竴涓璞� + * { + * points: [], + * 鐐逛箣鍓嶆槸鍚﹂渶瑕佸渾瑙� 涓暟姣攑oints灏戜袱涓� 鍦嗚涓簍rue + * roundCornerFlags: [], + * } + */ + lineList: { + type: Array, + default: () => [], + }, + color: { + type: String, + // default: "#67aa57", + default: "#fff", + }, + lineWidth: { + type: Number, + default: 16, + }, + r: { + type: [Number, String], + default: 6 + }, +}); + +function calcVectorProperties(A, B) { + let [x0, y0] = A; + let [x1, y1] = B; + // 璁$畻鍚戦噺鍒嗛噺 + const dx = x1 - x0; + const dy = y1 - y0; + + // 璁$畻鍚戦噺鐨勬ā闀匡紙娆у嚑閲屽緱璺濈锛� + const magnitude = Math.sqrt(dx * dx + dy * dy); + if (magnitude < props.r) { + throw new Error('涓ょ偣涔嬮棿璺濈杩囪繎'); + } + + // 澶勭悊闆跺悜閲忔儏鍐碉紙閬垮厤闄や互闆讹級 + const normalizedVector = magnitude === 0 + ? [0, 0] + : [ dx / magnitude, dy / magnitude ]; + + // 璁$畻鍚戦噺涓巟杞存鏂瑰悜鐨勫す瑙掞紙寮у害锛� + // Math.atan2 杩斿洖鍊艰寖鍥达細[-蟺, 蟺] + const angleRadians = Math.atan2(normalizedVector[1], normalizedVector[0]); + + // AB涓婄B鐐圭殑璺濈r璺濈鐨勭偣鐨勫潗鏍囷紙x2, y2锛� + const x2 = x1 - props.r * normalizedVector[0]; + const y2 = y1 - props.r * normalizedVector[1]; + + return { + x2, + y2 + }; +} + +const pathList = computed(() => { + let list = props.lineList; + let res = []; + for (let i = 0, len = list.length; i < len; i++) { + let { points, roundCornerFlags, lineColor } = list[i]; + let path = `M ${points[0].join(",")} `; + for (let j = 1, len2 = points.length; j < len2; j++) { + let str = ''; + let p0 = points[j - 1], + p1 = points[j], + p2 = points[j + 1]; + + if (j < len2 - 1 && roundCornerFlags[j - 1]) { + let { x2, y2 } = calcVectorProperties(p0, p1); + let { x2: x3, y2: y3 } = calcVectorProperties(p2, p1); + str = ` L ${x2},${y2} Q ${p1.join(",")} ${x3},${y3} `; + } else { + str = ` L ${points[j].join(",")} ` + } + path += str; + } + res.push({path, lineColor}); + } + return res; +}); + +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <path v-for="(item, index) in pathList" :key="'path0_' + index" + fill="none" + :d="item['path']" + :stroke-width="2" + :stroke="item['lineColor']" + stroke-linecap="round" + stroke-linejoin="round" + > + <animate attributeName="stroke-width" values="2;8;2" dur="2s" repeatCount="indefinite" /> + <animate attributeName="opacity" values="1;0.4;1" dur="2s" repeatCount="indefinite" /> + </path> + <path v-for="(item, index) in pathList" :key="'path1_' + index" + fill="none" + :d="item['path']" + :stroke-width="lineWidth - 4" + stroke="rgba(255,255,255, 0.4)" + stroke-linecap="round" + stroke-linejoin="round" + stroke-dasharray="18 142" + stroke-dashoffset="174" + > + <animate attributeName="stroke-dashoffset" from="174" to="14" dur="4s" repeatCount="indefinite" /> + <animate attributeName="stroke-width" :values="`${lineWidth - 8};${lineWidth + 4};${lineWidth - 8}`" dur="2s" repeatCount="indefinite" /> + </path> + <path v-for="(item, index) in pathList" :key="'path2_' + index" + :d="item['path']" :stroke="color" :stroke-width="lineWidth" + fill="none" + stroke-linecap="round" + stroke-linejoin="round" + stroke-dasharray="4 156" + stroke-dashoffset="160"> + <animate attributeName="stroke-dashoffset" from="160" to="0" dur="4s" repeatCount="indefinite" /> + <animate attributeName="stroke-width" :values="`${lineWidth - 8};${lineWidth + 8};${lineWidth - 8}`" dur="2s" repeatCount="indefinite" /> + </path> + </g> +</template> \ No newline at end of file diff --git a/src/components/svg/svgImg.vue b/src/components/svg/svgImg.vue new file mode 100644 index 0000000..17fca05 --- /dev/null +++ b/src/components/svg/svgImg.vue @@ -0,0 +1,38 @@ +<script setup> +import { ref, } from "vue"; +const props = defineProps({ + img: { + type: String, + default: "", + }, + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + width: { + type: Number, + default: 40, + }, + height: { + type: Number, + default: 160, + }, +}) + +</script> + +<template> + <g :transform="'translate(' + offset.join(',') + ')'"> + <image + :width="width" + :height="height" + :xlink:href="img" + /> + </g> +</template> + +<style scoped lang="less"> + +</style> \ No newline at end of file diff --git a/src/components/svg/svgInputBorderBox.vue b/src/components/svg/svgInputBorderBox.vue new file mode 100644 index 0000000..3bcb6b7 --- /dev/null +++ b/src/components/svg/svgInputBorderBox.vue @@ -0,0 +1,124 @@ +<script setup> +import { ref, computed } from "vue"; + +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + borderWidth: { + type: [Number, String], + default: 6, + }, + width: { + type: [Number, String], + default: 142, + }, + height: { + type: [Number, String], + default: 72, + }, + color: { + type: String, + default: "url(#colorBorder0)", + }, + fillColor: { + type: String, + default: '#989898', + }, + tColor: { + type: String, + default: "#fff", + }, + text: { + type: [Number, String], + default: "Text", + }, + inputValue: { + type: [Number, String], + default: 0, + }, + fontSize: { + type: [Number, String], + default: 16, + }, + textAnchor: { + type: String, + validator: (v) => ["start", "middle", "end"].includes(v), + default: "middle", + }, + unit: { + type: String, + default: "", + }, +}); + +const _width = computed(() => { + return props.width - 2 * props.borderWidth; +}); + +const _height = computed(() => { + return props.height - 2 * props.borderWidth; +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <rect + :width="width" + :height="height" + :stroke="color" + :fill="fillColor" + style="stroke-width: 1" + /> + <rect + :x="borderWidth" + :y="borderWidth" + :width="_width" + :height="_height" + stroke="url(#colorBorder0_reverse)" + :fill="fillColor" + style="stroke-width: 1" + /> + <text + :x="width / 2" + :y="height / 2" + :dy="fontSize * -0.5" + :fill="tColor" + :text-anchor="textAnchor" + :font-size="fontSize" + >{{ text }}</text + > + <rect + :x="width / 2 - 44" + :y="height / 2" + :width="58" + :height="22" + stroke="none" + fill="#000" + /> + <text + :x="width / 2 - 15" + :y="height / 2 + 11" + :dy="fontSize / 2.6" + fill="#0f0" + text-anchor="middle" + :font-size="fontSize" + >{{ inputValue }}</text + > + <text + v-if="unit" + :x="width / 2 +24" + :y="height / 2 + 11" + :dy="fontSize / 2.6" + :fill="tColor" + text-anchor="start" + :font-size="fontSize" + >{{ unit }}</text + > + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgInputBox.vue b/src/components/svg/svgInputBox.vue new file mode 100644 index 0000000..c6556af --- /dev/null +++ b/src/components/svg/svgInputBox.vue @@ -0,0 +1,82 @@ +<script setup> +import { ref } from "vue"; + +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + width: { + type: [Number, String], + default: 58, + }, + height: { + type: [Number, String], + default: 22, + }, + color: { + type: String, + default: "#aaa", + }, + fillColor: { + type: String, + default: 'transparent', + }, + tColor: { + type: String, + default: "#0e0", + }, + text: { + type: [Number, String], + default: "Text", + }, + unit: { + type: String, + default: "", + }, + fontSize: { + type: [Number, String], + default: 16, + }, + textAnchor: { + type: String, + validator: (v) => ["start", "middle", "end"].includes(v), + default: "middle", + }, +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <rect + :width="width" + :height="height" + :stroke="color" + :fill="fillColor" + style="stroke-width: 2" + /> + <text + :x="width / 2" + :y="height / 2" + :dy="fontSize / 2.4" + :fill="tColor" + :text-anchor="textAnchor" + :font-size="fontSize" + >{{ text }}</text + > + <text + v-if="unit" + :x="width + 10" + :y="height / 2" + :dy="fontSize / 2.4" + :fill="color" + text-anchor="start" + :font-size="fontSize" + >{{ unit }}</text + > + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgLine.vue b/src/components/svg/svgLine.vue new file mode 100644 index 0000000..a89f8a9 --- /dev/null +++ b/src/components/svg/svgLine.vue @@ -0,0 +1,117 @@ +<script setup> +import { ref, computed } from "vue"; + +const props = defineProps({ + offset: { + type: Array, + default: () => [0, 0], + }, + points: { + type: Array, + default: () => [ + [0, 0], + [10, 10], + ], + }, + color: { + type: String, + default: "#804000", + }, + roundCornerFlag: { + type: Boolean, + default: false + }, + lineWidth: { + type: Number, + default: 2, + }, + currColor: { + type: String, + default: "#0f0", + }, + r: { + type: [Number, String], + default: 6 + }, +}); + +function calcVectorProperties(A, B) { + let [x0, y0] = A; + let [x1, y1] = B; + // 璁$畻鍚戦噺鍒嗛噺 + const dx = x1 - x0; + const dy = y1 - y0; + + // 璁$畻鍚戦噺鐨勬ā闀匡紙娆у嚑閲屽緱璺濈锛� + const magnitude = Math.sqrt(dx * dx + dy * dy); + if (magnitude < props.r) { + throw new Error('涓ょ偣涔嬮棿璺濈杩囪繎'); + } + + // 澶勭悊闆跺悜閲忔儏鍐碉紙閬垮厤闄や互闆讹級 + const normalizedVector = magnitude === 0 + ? [0, 0] + : [ dx / magnitude, dy / magnitude ]; + + // 璁$畻鍚戦噺涓巟杞存鏂瑰悜鐨勫す瑙掞紙寮у害锛� + // Math.atan2 杩斿洖鍊艰寖鍥达細[-蟺, 蟺] + const angleRadians = Math.atan2(normalizedVector[1], normalizedVector[0]); + + // AB涓婄B鐐圭殑璺濈r璺濈鐨勭偣鐨勫潗鏍囷紙x2, y2锛� + const x2 = x1 - props.r * normalizedVector[0]; + const y2 = y1 - props.r * normalizedVector[1]; + + return { + normalizedVector, + angleRadians, + x2, + y2 + }; +} + + +const path = computed(() => { + let points = props.points; + let path = `M ${points[0].join(",")} `; + for (let i = 1, len = points.length; i < len; i++) { + let str = ''; + let p0 = points[i - 1], + p1 = points[i], + p2 = points[i + 1]; + + if (props.roundCornerFlag) { + if (i == len - 1) { + str = ` L ${p1.join(",")} `; + } else { + let { x2, y2 } = calcVectorProperties(p0, p1); + let { x2: x3, y2: y3 } = calcVectorProperties(p2, p1); + str = ` L ${x2},${y2} Q ${p1.join(",")} ${x3},${y3} `; + } + } else { + str = ` L ${points[i].join(",")} ` + } + path += str; + } + return path; +}); +const pointsStr = computed(() => { + return props.points.join(" "); +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <!-- <defs> + <circle id="ball" :r="ballR" /> + </defs> --> + <!-- <polyline + :points="pointsStr" + :stroke="color" + :stroke-width="lineWidth" + style="fill: none" + /> --> + <path :d="path" :stroke="color" :stroke-width="lineWidth" style="fill: none;"></path> + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgLock.vue b/src/components/svg/svgLock.vue new file mode 100644 index 0000000..a107e18 --- /dev/null +++ b/src/components/svg/svgLock.vue @@ -0,0 +1,39 @@ +<script setup> +import { ref } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + stateColor: { + type: String, + default: "#804000", + }, + lockFillColor: { + type: String, + default: "#804000", + }, +}); + +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <rect + :width="8" + :height="20" + stroke="transparent" + fill="transparent" + style="stroke-width: 2" + ref="lock0" + /> + <rect x="1" y="0" width="6" height="6" rx="2" ry="2" :fill="stateColor" stroke="none" /> + <path d="M809.6 416.64h-53.76V308.48c0-135.68-108.096-243.84-243.2-243.84-135.04 0-243.2 108.16-243.2 243.84v108.16h-53.76c-29.44 0-53.76 24.32-53.76 53.76v433.28c0 29.44 24.32 53.76 53.76 53.76h593.92c30.08 0 54.4-24.32 54.4-53.76V470.4c0-29.44-24.32-53.76-54.4-53.76z m-135.04 0H350.72V308.48c0-89.6 72.96-162.56 161.92-162.56a162.56 162.56 0 0 1 161.92 162.56v108.16z" :fill="lockFillColor" transform="translate(-2, 8) scale(0.012)"></path> + </g> +</template> + +<style scoped lang="less"> + +</style> \ No newline at end of file diff --git a/src/components/svg/svgModule.vue b/src/components/svg/svgModule.vue new file mode 100644 index 0000000..cc6c4a1 --- /dev/null +++ b/src/components/svg/svgModule.vue @@ -0,0 +1,107 @@ +<script setup> +import { ref, computed } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + fillColor: { + type: String, + default: "#073451", + }, + lineWidth: { + type: [Number, String], + default: 2, + }, + color: { + type: String, + default: "#4ec5f7", + }, + text: { + type: [String, Array], + default: '', + }, + fontSize: { + type: [Number, String], + default: 14, + }, + width: { + type: [Number, String], + default: 130, + }, + height: { + type: [Number, String], + default: 130, + }, + img: { + type: String, + default: '', + }, + imgWidth: { + type: [Number, String], + default: 120, + }, + imgHeight: { + type: [Number, String], + default: 90, + }, + rx: { + type: [Number, String], + default: 8, + }, + ry: { + type: [Number, String], + default: 8, + } +}); + +const imgX = computed(() => { + return (props.width - props.imgWidth) / 2; +}); + +const imgY = computed(() => { + return props.text ? (props.height - props.imgHeight + props.fontSize * 1.2) / 2 : (props.height - props.imgHeight) / 2; +}); + +const textX = computed(() => { + return props.width / 2; +}); + +const textY = computed(() => { + return props.fontSize * 1.2; +}); + +</script> + +<template> + <g :transform="'translate(' + offset.join(',') + ')'"> + <rect + :width="width" + :height="height" + :stroke="color" + :fill="fillColor" + :stroke-width='lineWidth' + :rx="rx" + :ry="ry" + /> + <image + :x="imgX" + :y="imgY" + :width="imgWidth" + :height="imgHeight" + :xlink:href="img" + /> + <text + v-if="text" + :x="textX" + :y="textY" + :dy="fontSize/2" + :fill="color" + text-anchor="middle" + :font-size="fontSize" + >{{ text }}</text + > + </g> +</template> \ No newline at end of file diff --git a/src/components/svg/svgPv.vue b/src/components/svg/svgPv.vue new file mode 100644 index 0000000..2b88e7b --- /dev/null +++ b/src/components/svg/svgPv.vue @@ -0,0 +1,35 @@ +<script setup> +import { ref } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + r: { + type: [Number, String], + default: 18, + }, + color: { + type: String, + default: "#804000", + }, +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <circle :r="r" :stroke="color" stroke-width="2" fill="none" /> + <!-- :x="r * -1" --> + <text + :dy="r * 0.8" + :fill="color" + text-anchor="middle" + :font-size="r * 1.6" + >V</text + > + </g> +</template> + +<style scoped lang="less"></style> \ No newline at end of file diff --git a/src/components/svg/svgResistor.vue b/src/components/svg/svgResistor.vue new file mode 100644 index 0000000..dbaa6c5 --- /dev/null +++ b/src/components/svg/svgResistor.vue @@ -0,0 +1,38 @@ +<script setup> +import { ref } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + width: { + type: [Number, String], + default: 14, + }, + height: { + type: [Number, String], + default: 34, + }, + color: { + type: String, + default: "#804000", + }, +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <rect + :x="width / -2" + :width="width" + :height="height" + :stroke="color" + fill="none" + style="stroke-width: 2" + /> + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgStation.vue b/src/components/svg/svgStation.vue new file mode 100644 index 0000000..0139abd --- /dev/null +++ b/src/components/svg/svgStation.vue @@ -0,0 +1,221 @@ +<script setup> +import { ref, computed, onMounted, onBeforeUnmount, } from "vue"; +import svgLine from '@/components/svg/svgLine.vue'; +import switchBox from '@/components/svg/switchBox.vue'; +import svgText from '@/components/svg/svgText.vue'; + + +import svgFloor from '@/components/svg/svgFloor.vue'; +import svgCabinet from '@/components/svg/svgCabinet.vue'; + +const currentCabinetIdx = ref(-1); +const currentLockIdx = ref(-1); +const infoVisisble = ref(false); +const left = ref(0); +const top = ref(0); +const settingVisible = ref(false); +const viewInfo = ref({}); + +const props = defineProps({ + rtData: { + type: Array, + default: () => [], + }, + locationInfo: { + type: Object, + default: () => ({ + control: [], + all: [] + }), + }, +}); + +const cabinetsList = computed(() => { + return props.locationInfo.control.map(v => v.screenFlag).filter(v => v); +}); + +const lockStatus = computed(() => { + // props.rtData; + let arr = []; + for(let i = 0; i < 20; i++) { + let lock1 = getInfo(i + 1, 1); + let lock2 = getInfo(i + 1, 2); + arr.push([lock1, lock2]); + } + // console.log('arr', arr, '============='); + + return arr; +}); + +function getInfo(idx, doorIdx) { + let lock = props.locationInfo.control.filter(v=>v.screenFlag == idx && v.addressFlag == doorIdx); + let lockId; + if (lock.length) { + lockId = lock[0].lockId; + } + let info = props.rtData.filter(v => v.lockId == lockId); + // console.log('idx', idx, doorIdx, info.length ? info[0] : {}, '============='); + + return info.length ? info[0] : {}; +} + + +function showInfo(data, idx) { + // console.log(data, idx); + currentCabinetIdx.value = idx; + currentLockIdx.value = data.idx; + left.value = data.event.clientX + 'px'; + top.value = data.event.clientY + 'px'; + // console.log('top, left', top.value, left.value, '============='); + + viewInfo.value = getInfo(idx + 1, data.idx + 1); + // console.log('viewInfo', viewInfo.value, '============='); + + if (!viewInfo.value.lockId) return; + infoVisisble.value = true; +} + +function hideInfo() { + infoVisisble.value = false; +} + +onMounted(() => { + window.addEventListener('resize', hideInfo); +}); + +onBeforeUnmount(() => { + window.removeEventListener('resize', hideInfo); +}); + +defineExpose({ + hideInfo +}); + +</script> + +<template> + <svg + v-bind="$attrs" + width="100%" + height="100%" + viewBox="0 0 1566 712" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + style="position: relative" + > + + <svg-text + :offset="[783, 44]" + textAnchor="middle" + fontSize="28" + text="鏈烘埧鏈烘煖" + ></svg-text> + + <svg-floor + :offset="[0, 0]" + :points="[ + [320, 210], + [1410, 210], + [ 1210, 570], + [10, 570], + ]" + ></svg-floor> + + <svg-cabinet + v-for="(i, idx) in 10" + :key="'list0_' + idx" + :offset="[300 + idx * 110, 100]" + :disabled="cabinetsList.every(v => v !== (idx + 1))" + :onLine0="lockStatus[idx][0]['lockOnline']" + :onLine1="lockStatus[idx][1]['lockOnline']" + :lock0="lockStatus[idx][0]['lockState'] == 0" + :lock1="lockStatus[idx][1]['lockState'] == 0" + @showInfo="(eData) => showInfo(eData, idx)" + ></svg-cabinet> + + <svg-cabinet + v-for="(i, idx) in 10" + :key="'list1_' + idx" + :offset="[40 + idx * 120, 400]" + :disabled="cabinetsList.every(v => v !== (idx + 11))" + :onLine0="lockStatus[idx + 10][0]['lockOnline']" + :onLine1="lockStatus[idx + 10][1]['lockOnline']" + :lock0="lockStatus[idx + 10][0]['lockState'] == 0" + :lock1="lockStatus[idx + 10][1]['lockState'] == 0" + @showInfo="(eData) => showInfo(eData, idx + 10)" + ></svg-cabinet> + <div class="setting"></div> + </svg> + + <teleport to='body' v-if="infoVisisble"> + <div class="info" v-if="infoVisisble" :style="{ left, top }"> + <!-- 绗瑊{ currentCabinetIdx + 1 }}涓煖 + {{ currentLockIdx == 0 ? "鍓嶉棬" : "鍚庨棬" }}閿� --> + <div class="item lock-id"> + <div class="label">閿佸叿ID:</div> + <div class="value">{{ viewInfo.lockId }}</div> + </div> + <div class="item lock-name"> + <div class="label">閿佸叿鍚嶇О:</div> + <div class="value">{{ viewInfo.lockName }}</div> + </div> + <div class="item online"> + <div class="label">鍦ㄧ嚎鐘舵��:</div> + <div class="value">{{ viewInfo.lockOnline ? "鍦ㄧ嚎" : "绂荤嚎" }}</div> + </div> + <div class="item is-lock" v-if="viewInfo.lockOnline"> + <div class="label">閿佸叿鐘舵��:</div> + <div class="value">{{ viewInfo.lockState == 0 ? "宸查棴閿�" : "宸插紑閿�" }}</div> + </div> + <div class="item" v-if="viewInfo.lockOnline"> + <div class="label">钃濈墮鐘舵��:</div> + <div class="value">{{ viewInfo.blState == 0 ? '钃濈墮鍏抽棴' : '钃濈墮寮�鍚�' }}</div> + </div> + </div> + <div class="mask" @mouseenter="hideInfo"></div> + </teleport> +</template> + +<style scoped lang="less"> +.info { + position: absolute; + background: #0ff; + color: #000; + z-index: 999999; + cursor: pointer; + padding: 8px; + transform: translate(-100%, -100%); + border-radius: 4px; + .item { + display: flex; + align-items: center; + .label { + width: 5em; + margin-right: 0.4em; + text-align: right; + } + .value { + flex: 1; + } + } + &::after { + content: ''; + position: absolute; + left: 80%; + top: 80%; + width: 22%; + height: 22%; + z-index: -1; + } +} +.mask { + position: fixed; + left: 0; + top: 0; + right: 0; + bottom: 0; + // background: rgba(0, 0, 0, 0.4); + z-index: 999998; +} + +</style> diff --git a/src/components/svg/svgStatus.vue b/src/components/svg/svgStatus.vue new file mode 100644 index 0000000..3844ff4 --- /dev/null +++ b/src/components/svg/svgStatus.vue @@ -0,0 +1,57 @@ +<script setup> +import { ref } from "vue"; +const colors = ['#0f0', '#f00']; + +const props = defineProps({ + r: { + type: [Number, String], + default: 6, + }, + offset: { + type: Array, + default: () => [0, 0], + }, + text: { + type: String, + default: 'Text', + }, + fontSize: { + type: [Number, String], + default: 16, + }, + color: { + type: String, + default: "#fff", + }, + // 鐘舵�� 0姝e父 1鏁呴殰 + status: { + type: Number, + default: 0, + }, + +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <circle + :cx="r" + :cy="r" + :r="r" + :stroke="status ? colors[1] : colors[0]" + stroke-width="2" + :fill="status ? colors[1] : 'none'" + /> + <text + :x="r * 2 + fontSize" + :y="r" + :dy="fontSize/2.6" + :fill="color" + text-anchor="start" + :font-size="fontSize" + >{{ text }}</text + > + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgSwitch.vue b/src/components/svg/svgSwitch.vue new file mode 100644 index 0000000..77f0029 --- /dev/null +++ b/src/components/svg/svgSwitch.vue @@ -0,0 +1,117 @@ +<script setup name="SvgSwitch"> +import { ref, computed, onMounted, watch, nextTick, } from "vue"; +const props = defineProps({ + r: { + type: Number, + default: 3, + }, + len: { + type: Number, + default: 60, + }, + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + isVertical: { + type: Boolean, + default: false, + }, + state: { + type: Boolean, + defalut: false, + }, + points: { + type: Array, + default() { + return [ + [0, 0], + [10, 10], + ]; + }, + }, + color: { + type: String, + default: "#f59a23", + }, + currColor: { + type: String, + default: "#0f0", + }, + lineWidth: { + type: [Number, String], + default: 2, + }, + turnStart: { + type: Boolean, + default: true + } +}); + +const cx = computed(() => { + let { isVertical, len } = props; + return isVertical ? 0 : len; +}); +const cy = computed(() => { + let { isVertical, len } = props; + return isVertical ? len : 0; +}); + +const pointsStr = computed(() => { + return props.points.join(" "); +}); + +const fromDeg = ref(-2); +const toDeg = ref(-38); + +watch( + () => props.state, + (n) => { + nextTick(() => { + changeSwitch(); + }); + }, + { immediate: true } +); + +const anim = ref(null); + +function changeSwitch() { + if (props.state) { + fromDeg.value = -38; + toDeg.value = -2; + } else { + fromDeg.value = -2; + toDeg.value = -38; + } + // 閲嶆柊寮�鍚姩鐢� + anim.value?.beginElement(); +} + +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <circle :r="r" style="fill: #fff; stroke: none"></circle> + <circle :r="r" :cx="cx" :cy="cy" style="fill: #fff; stroke: none"></circle> + <line :x1="turnStart ? 0 : cx" :y1="turnStart ? 0 : cy" :x2="turnStart ? cx : 0" :y2="turnStart ? cy : 0" :stroke-width="lineWidth" :stroke="color"> + <animateTransform + ref="anim" + attributeName="transform" + attributeType="XML" + type="rotate" + :from="[fromDeg, turnStart ? 0 : cx, turnStart ? 0 : cy].join(',')" + :to="[toDeg, turnStart ? 0 : cx, turnStart ? 0 : cy].join(',')" + dur="0.3s" + repeatCount="1" + fill="freeze" + /> + </line> + </g> +</template> + + +<style scoped lang="less"> +</style> diff --git a/src/components/svg/svgText.vue b/src/components/svg/svgText.vue new file mode 100644 index 0000000..8d0217a --- /dev/null +++ b/src/components/svg/svgText.vue @@ -0,0 +1,63 @@ +<script setup> +import { ref } from "vue"; + +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + color: { + type: String, + default: "#fff", + }, + text: { + type: [String, Array], + default: 'Text', + }, + fontSize: { + type: [Number, String], + default: 16, + }, + textAnchor: { + type: String, + validator: (v) => ["start", "middle", "end"].includes(v), + default: 'start', + }, + isVertical: { + type: Boolean, + default: false + } +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <text + v-if="typeof props.text === 'string'" + :dy="fontSize/2" + :fill="color" + :text-anchor="textAnchor" + :font-size="fontSize" + :writing-mode="isVertical ? 'vertical-rl' : 'horizontal-tb'" + style="text-orientation: upright;" + >{{ text }}</text + > + <text + v-else + :fill="color" + :text-anchor="textAnchor" + :font-size="fontSize" + :writing-mode="isVertical ? 'vertical-rl' : 'horizontal-tb'" + style="text-orientation: upright;" + > + <tspan :dy="fontSize / 2" :x="isVertical ? (idx - (props.text.length - 1) / 2) * fontSize * 1.2 : 0" :y="isVertical ? 0 : (idx - (props.text.length - 1) / 2) * fontSize * 1.2" v-for="(item, idx) in props.text" :key="'t_' + idx"> + {{ item }} + </tspan> + </text + > + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgTextBorderBox.vue b/src/components/svg/svgTextBorderBox.vue new file mode 100644 index 0000000..cafd46b --- /dev/null +++ b/src/components/svg/svgTextBorderBox.vue @@ -0,0 +1,89 @@ +<script setup> +import { ref, computed } from "vue"; + +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + borderWidth: { + type: [Number, String], + default: 6, + }, + width: { + type: [Number, String], + default: 142, + }, + height: { + type: [Number, String], + default: 42, + }, + color: { + type: String, + default: "url(#colorBorder0)", + }, + fillColor: { + type: String, + default: '#989898', + }, + tColor: { + type: String, + default: "#fff", + }, + text: { + type: [Number, String], + default: "Text", + }, + fontSize: { + type: [Number, String], + default: 16, + }, + textAnchor: { + type: String, + validator: (v) => ["start", "middle", "end"].includes(v), + default: "middle", + }, +}); + +const _width = computed(() => { + return props.width - 2 * props.borderWidth; +}); + +const _height = computed(() => { + return props.height - 2 * props.borderWidth; +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <rect + :width="width" + :height="height" + :stroke="color" + :fill="fillColor" + style="stroke-width: 1" + /> + <rect + :x="borderWidth" + :y="borderWidth" + :width="_width" + :height="_height" + stroke="url(#colorBorder0_reverse)" + :fill="fillColor" + style="stroke-width: 1" + /> + <text + :x="width / 2" + :y="height / 2" + :dy="fontSize / 2.6" + :fill="tColor" + :text-anchor="textAnchor" + :font-size="fontSize" + >{{ text }}</text + > + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgTextBox.vue b/src/components/svg/svgTextBox.vue new file mode 100644 index 0000000..1df0720 --- /dev/null +++ b/src/components/svg/svgTextBox.vue @@ -0,0 +1,68 @@ +<script setup> +import { ref } from "vue"; + +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + width: { + type: [Number, String], + default: 142, + }, + height: { + type: [Number, String], + default: 38, + }, + color: { + type: String, + default: "#0ff", + }, + fillColor: { + type: String, + default: '#989898', + }, + tColor: { + type: String, + default: "#fff", + }, + text: { + type: [Number, String], + default: "Text", + }, + fontSize: { + type: [Number, String], + default: 16, + }, + textAnchor: { + type: String, + validator: (v) => ["start", "middle", "end"].includes(v), + default: "middle", + }, +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <rect + :width="width" + :height="height" + :stroke="color" + :fill="fillColor" + style="stroke-width: 2" + /> + <text + :x="width / 2" + :y="height / 2" + :dy="fontSize / 2" + :fill="tColor" + :text-anchor="textAnchor" + :font-size="fontSize" + >{{ text }}</text + > + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/svgTriangle.vue b/src/components/svg/svgTriangle.vue new file mode 100644 index 0000000..64bcdcb --- /dev/null +++ b/src/components/svg/svgTriangle.vue @@ -0,0 +1,39 @@ +<script setup> +import { ref, computed } from "vue"; +const props = defineProps({ + offset: { + type: Array, + default() { + return [0, 0]; + }, + }, + width: { + type: [Number, String], + default: 14, + }, + color: { + type: String, + default: "#804000", + }, +}); + +const points = computed(() => { + return [ + [props.width / -2, 0], + [props.width / 2, 0], + [0, props.width], + ]; +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <polygon + :points="points.join(' ')" + :stroke="color" + style="fill: none; stroke-width: 2" + /> + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svg/switchBox.vue b/src/components/svg/switchBox.vue new file mode 100644 index 0000000..167b5d0 --- /dev/null +++ b/src/components/svg/switchBox.vue @@ -0,0 +1,62 @@ +<script setup> +import { ref, computed, } from "vue"; +const width = 18; +const borderWidth = 2; +const colors = ["#0d0", "#FF0000", "#804000"]; + +const props = defineProps({ + offset: { + type: Array, + default: () => [0, 0], + }, + points: { + type: Array, + default: () => [ + [0, 0], + [10, 10], + ], + }, + color: { + type: String, + default: "#804000", + }, + // 寮�鍏崇姸鎬� 0 鏂紑 1 闂悎 2 鏈煡 + status: { + type: Number, + default: 0, + }, + currColor: { + type: String, + default: "#0f0", + }, +}); + +const fillColor = computed(() => { + return props.status ? colors[props.status] : 'transparent'; +}); + +const strokeColor = computed(() => { + return colors[props.status]; +}); +</script> + +<template> + <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> + <rect + :width="width" + :height="width" + :stroke="`url(${props.status == 2 ? '#colorBorder1' : '#colorBorder0'})`" + stroke-width="2" + /> + <rect + x="2" + y="2" + :width="width - 4" + :height="width - 4" + :fill="fillColor" + :stroke="strokeColor" + /> + </g> +</template> + +<style scoped lang="less"></style> diff --git a/src/components/svgDiagram.vue b/src/components/svgDiagram.vue new file mode 100644 index 0000000..5a53bda --- /dev/null +++ b/src/components/svgDiagram.vue @@ -0,0 +1,588 @@ +<script setup> +import { ref, computed, onMounted, onBeforeUnmount } from "vue"; +import svgLine from '@/components/svg/svgLine.vue'; +import svgDotRect from '@/components/svg/svgDotRect.vue'; +import svgText from '@/components/svg/svgText.vue'; +import svgSwitch from '@/components/svg/svgSwitch.vue'; +import svgImg from '@/components/svg/svgImg.vue'; +import svgArc from '@/components/svg/svgArc.vue'; +import svgDiode from '@/components/svg/svgDiode.vue'; +import svgModule from '@/components/svg/svgModule.vue'; +import svgFlow from '@/components/svg/svgFlow.vue'; + +import imgAcdc from '@/assets/images/img-acdc.png'; +import imgBatt from '@/assets/images/img-batt.png'; +import imgCharge from '@/assets/images/img-charge.png'; +import imgHr from '@/assets/images/img-hr.png'; + +const lineColor = "#4cb5e2"; +const lineColor1 = "#ed973e"; +const switchColor = "#f00"; +const switchWidth = 40; +const diodeWidth = 20; +const disColor = "#f00"; +const charColor = "#0f0"; + +// 鏍稿鏀剧數 +const line0 = [ + { + points: [ + [932, 260], + [932, 230], + [1262, 230], + [1262, 260], + ], + roundCornerFlags: [false, false], + lineColor: disColor + }, + { + points: [ + [1262, 390], + [1262, 420], + [932, 420], + [932, 390], + ], + roundCornerFlags: [true, false], + lineColor: disColor + } +]; + +// 鏍稿鍏呯數 +const line1 = [ + { + points: [ + [682, 79], + [682, 50], + [1262, 50], + [1262, 70], + ], + roundCornerFlags: [true, true], + lineColor: charColor + }, + { + points: [ + [1262, 200], + [1262, 230], + [932, 230], + [932, 260], + ], + roundCornerFlags: [false, false], + lineColor: charColor + }, + { + points: [ + [932, 390], + [932, 420], + [770, 420], + [770, 359], + ], + roundCornerFlags: [false, true], + lineColor: charColor + } +]; + +// 鐩磋繛鍏呯數 +const line2 = [ + { + points: [ + [682, 79], + [682, 50], + [932, 50], + [932, 260], + ], + roundCornerFlags: [true, false], + lineColor: charColor + }, + { + points: [ + [932, 390], + [932, 420], + [770, 420], + [770, 359], + ], + roundCornerFlags: [false, true], + lineColor: charColor + } +]; +// 鍋滅數鏀剧數 +const line3 = [ + { + points: [ + [932, 260], + [932, 174], + [1006, 174], + [1006, 80], + [932, 80], + [932, 50], + [682, 50], + [682, 79], + ], + roundCornerFlags: [false, true, true, false, false, true], + lineColor: disColor + }, + { + points: [ + [770, 359], + [770, 420], + [932, 420], + [932, 390], + ], + roundCornerFlags: [true, false], + lineColor: disColor + } +]; + +const state_k1 = ref(true); +const state_k2 = ref(true); +const state_k3 = ref(true); +const currentCabinetIdx = ref(-1); +const currentLockIdx = ref(-1); +const infoVisisble = ref(false); +const left = ref(0); +const top = ref(0); +const settingVisible = ref(false); +const viewInfo = ref({}); + +const props = defineProps({ + state: { + type: [Number, String], + default: 3, + }, +}); + +const flowList = computed(() => { + let res = []; + + switch(props.state) { + // 鏍稿鏀剧數 + case 0: + res = line0; + break; + // 鏍稿鍏呯數 + case 1: + res = line1; + break; + // 鐩磋繛鍏呯數 + case 2: + res = line2; + break; + // 鍋滅數鏀剧數 + case 3: + res = line3; + break; + } + + return res; +}); + +</script> + +<template> + <svg + v-bind="$attrs" + width="100%" + height="100%" + viewBox="0 0 1350 440" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + style="position: relative" + > + <svg-dot-rect + :offset="[18, 36]" + width="720" + height="384" + color="#fff" + fillColor="transparent" + :rx="8" + :ry="8" + :strokeWidth="2" + ></svg-dot-rect> + <svg-line + :points="[ + [58, 130], + [134, 130], + ]" + :color='lineColor' + ></svg-line> + <svg-switch + :offset="[134, 130]" + :len="switchWidth" + :color='switchColor' + ></svg-switch> + <svg-line + :points="[ + [174, 130], + [236, 130], + [236, 218], + ]" + roundCornerFlag + :color='lineColor' + ></svg-line> + + <svg-line + :points="[ + [58, 218], + [134, 218], + ]" + :color='lineColor' + ></svg-line> + <svg-switch + :offset="[134, 218]" + :len="switchWidth" + :color='switchColor' + ></svg-switch> + <svg-line + :points="[ + [174, 218], + [272, 218], + ]" + :color='lineColor' + ></svg-line> + <!-- 124 194 --> + <svg-dot-rect + :offset="[252, 124]" + width="124" + height="194" + :color="lineColor" + fillColor="transparent" + strokeDasharray="none" + :rx="8" + :ry="8" + :strokeWidth="2" + ></svg-dot-rect> + <!-- 32 106 --> + <svg-line + :points="[ + [304, 164], + [272, 164], + [272, 270], + [304, 270], + ]" + :color='lineColor' + ></svg-line> + <svg-switch + :offset="[304, 164]" + :len="switchWidth" + :color='switchColor' + ></svg-switch> + <svg-switch + :offset="[304, 270]" + :len="switchWidth" + :color='switchColor' + ></svg-switch> + <svg-line + :points="[ + [344, 164], + [422, 164], + ]" + :color='lineColor' + ></svg-line> + <svg-line + :points="[ + [344, 270], + [422, 270], + ]" + :color='lineColor' + ></svg-line> + <!-- 336 --> + <svg-line + :points="[ + [422, 50], + [422, 386], + ]" + :color='lineColor' + ></svg-line> + <svg-line + :points="[ + [422, 88], + [472, 88], + ]" + :color='lineColor' + ></svg-line> + <svg-line + :points="[ + [422, 212], + [472, 212], + ]" + :color='lineColor' + ></svg-line> + <svg-line + :points="[ + [422, 350], + [472, 350], + ]" + :color='lineColor' + ></svg-line> + <svg-img + :img="imgAcdc" + :width="130" + :height="48" + :offset="[472, 64]" + ></svg-img> + <svg-img + :img="imgAcdc" + :width="130" + :height="48" + :offset="[472, 188]" + ></svg-img> + <svg-img + :img="imgAcdc" + :width="130" + :height="48" + :offset="[472, 326]" + ></svg-img> + <!-- 18 80 --> + <svg-line + :points="[ + [602, 79], + [682, 79], + ]" + :color='lineColor1' + ></svg-line> + <!-- 124 --> + <svg-line + :points="[ + [602, 203], + [682, 203], + ]" + :color='lineColor1' + ></svg-line> + <!-- 262 580 20 --> + <svg-line + :points="[ + [602, 341], + [682, 341], + [682, 50], + [1262, 50], + [1262, 70], + ]" + roundCornerFlag + :color='lineColor1' + ></svg-line> + + <svg-line + :points="[ + [602, 97], + [676, 97], + ]" + :color='lineColor' + ></svg-line> + <svg-arc + :offset="[676, 97]" + r="6" + ></svg-arc> + <svg-line + :points="[ + [688, 97], + [770, 97], + [770, 420], + [1080, 420], + ]" + roundCornerFlag + :color='lineColor' + ></svg-line> + <svg-line + :points="[ + [602, 221], + [676, 221], + ]" + :color='lineColor' + ></svg-line> + <svg-arc + :offset="[676, 221]" + r="6" + ></svg-arc> + <svg-line + :points="[ + [688, 221], + [770, 221], + ]" + :color='lineColor' + ></svg-line> + <svg-line + :points="[ + [602, 359], + [770, 359], + ]" + :color='lineColor' + ></svg-line> + <svg-switch + :offset="[1080, 420]" + :len="switchWidth" + :color='switchColor' + :state="state_k3" + ></svg-switch> + <svg-text + :offset="[1100, 382]" + text="K3" + textAnchor="middle" + ></svg-text> + <svg-line + :points="[ + [1120, 420], + [1262, 420], + [1262, 390], + ]" + roundCornerFlag + :color='lineColor' + ></svg-line> + <!-- 250 50 --> + <svg-line + :points="[ + [932, 50], + [932, 100], + ]" + :color='lineColor1' + ></svg-line> + <svg-switch + :offset="[932, 100]" + isVertical + :len="switchWidth" + :color='switchColor' + :state="state_k1" + :turnStart="false" + ></svg-switch> + <svg-text + :offset="[900, 120]" + text="K1" + textAnchor="end" + ></svg-text> + <svg-text + :offset="[1026, 120]" + text="D1" + textAnchor="start" + ></svg-text> + <svg-text + :offset="[1100, 150]" + text="娓╁害:12掳C" + textAnchor="middle" + ></svg-text> + <svg-text + :offset="[918, 240]" + text="0.2A" + textAnchor="end" + ></svg-text> + <svg-line + :points="[ + [932, 140], + [932, 260], + ]" + :color='lineColor1' + ></svg-line> + <svg-line + :points="[ + [932, 80], + [1006, 80], + [1006, 174], + [932, 174], + ]" + roundCornerFlag + :color='lineColor1' + ></svg-line> + <svg-line + :points="[ + [974, 80], + [974, 174], + ]" + roundCornerFlag + :color='lineColor1' + ></svg-line> + <svg-line + :points="[ + [932, 390], + [932, 420], + ]" + :color='lineColor' + ></svg-line> + <svg-diode + :offset="[1006, 114]" + direct="top" + :len="diodeWidth" + :color='lineColor1' + ></svg-diode> + <svg-diode + :offset="[974, 114]" + direct="top" + :len="diodeWidth" + :color='lineColor1' + ></svg-diode> + <svg-line + :points="[ + [932, 230], + [1080, 230], + ]" + :color='lineColor1' + ></svg-line> + <svg-line + :points="[ + [1120, 230], + [1262, 230], + [1262, 200], + ]" + :color='lineColor1' + ></svg-line> + <svg-line + :points="[ + [1262, 230], + [1262, 260], + ]" + :color='lineColor' + ></svg-line> + <svg-switch + :offset="[1080, 230]" + :len="switchWidth" + :color='switchColor' + :state="state_k2" + ></svg-switch> + <svg-text + :offset="[1100, 192]" + text="K2" + textAnchor="middle" + ></svg-text> + <svg-module + :offset="[865, 260]" + :img="imgBatt" + text="鐢垫睜" + ></svg-module> + <svg-module + :offset="[1197, 70]" + text="鍏呯數妯″潡" + :img="imgCharge" + ></svg-module> + <svg-module + :offset="[1197, 260]" + text="鏍稿妯″潡" + :img="imgHr" + ></svg-module> + <!-- 鏂囨湰 --> + <svg-text + :offset="[58, 110]" + text="闃查浄" + ></svg-text> + <svg-text + :offset="[58, 236]" + text="浜ゆ祦杈撳叆" + ></svg-text> + <svg-text + :offset="[304, 338]" + text="ATS" + ></svg-text> + <svg-text + :offset="[422, 398]" + text="AC220V" + textAnchor="middle" + ></svg-text> + <svg-text + :offset="[642, 54]" + text="220V" + textAnchor="middle" + ></svg-text> + <svg-flow + :lineList="flowList" + ></svg-flow> + </svg> +</template> + +<style scoped lang="less"> + +</style> \ No newline at end of file diff --git a/src/globalComponents.js b/src/globalComponents.js index f2ec1f2..5bb2ec4 100644 --- a/src/globalComponents.js +++ b/src/globalComponents.js @@ -1,7 +1,9 @@ import card from '@/components/card.vue'; import ycCard from '@/components/ycCard/index.vue'; +import flexLayout from '@/components/FlexLayout.vue'; export function registerGlobalComponents(app) { + app.component('flexLayout', flexLayout); app.component('card', card); app.component('ycCard', ycCard); } \ No newline at end of file diff --git a/src/icons/svg/alarm.svg b/src/icons/svg/alarm.svg new file mode 100644 index 0000000..52270ad --- /dev/null +++ b/src/icons/svg/alarm.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M891.547826 794.445913h-98.393043v-337.430261a281.822609 281.822609 0 0 0-238.992696-277.682087v-17.586087a42.162087 42.162087 0 0 0-84.368696 0v17.630609a281.822609 281.822609 0 0 0-238.992695 277.682087v337.430261h-98.393044a14.113391 14.113391 0 0 0-14.113391 14.024348v56.32c0 7.746783 6.322087 13.979826 14.113391 13.979826h298.073044c8.236522 29.651478 35.172174 51.556174 67.450434 51.556174h28.13774c32.278261 0 59.213913-21.904696 67.450434-51.556174h298.028522a13.979826 13.979826 0 0 0 14.06887-13.979826V808.514783a13.979826 13.979826 0 0 0-14.06887-14.06887z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/arrow.svg b/src/icons/svg/arrow.svg new file mode 100644 index 0000000..27b0cc9 --- /dev/null +++ b/src/icons/svg/arrow.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1035 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" ><path d="M530.850448 573.163313c32.005172-31.883636 32.111192-87.434343-0.069818-119.489939C399.437114 322.845737 268.507336 191.603071 137.436629 60.506505c-12.621576-12.625455-27.585939-20.686869-45.26804-23.540364-3.529697-0.570182-7.085253-0.999434-10.630465-1.499798-1.025293 0-2.055758 0-3.081051 0-4.035232 0.575354-8.111838 0.943838-12.091475 1.757091-33.298101 6.818909-54.838303 26.616242-63.959919 59.278222-3.201293 11.479919-2.806949 24.85398-1.135192 35.701657 1.751919 11.344162 7.11499 21.818182 14.479515 30.904889 3.444364 4.252444 7.050343 8.418263 10.918788 12.291879 111.045818 111.127273 222.142061 222.222222 333.247354 333.293899 1.444202 1.444202 3.227152 2.554828 5.187232 4.080485-2.121697 2.222545-3.475394 3.696485-4.879515 5.100606C252.653437 625.450667 145.164468 733.112889 37.416912 840.506182c-15.829333 15.773737-33.541172 31.162182-36.146424 54.273293-1.233455 10.908444-1.859232 22.111677 0 32.929616 0.919273 5.363071 3.262061 10.423596 5.494949 15.358707 23.655434 52.318384 89.514667 64.241778 130.66602 23.186101C268.668953 835.315071 399.501761 703.987071 530.850448 573.163313L530.850448 573.163313zM78.451902 35.466343l-12.091475 1.757091C70.345235 36.410182 74.421841 36.041697 78.451902 35.466343L78.451902 35.466343zM551.467498 36.441212c-38.000485 2.858667-70.434909 37.034667-71.651556 75.106263-0.79903 24.979394 8.131232 45.650747 25.691798 63.197091 111.383273 111.252687 222.661818 222.615273 334.015354 333.893818 1.534707 1.534707 3.686141 2.448808 6.595232 4.327434-3.35903 2.667313-5.116121 3.803798-6.565495 5.253172-68.050747 68.000323-136.075636 136.035556-204.100525 204.065616C591.916791 765.814949 548.391619 809.360808 504.845761 852.880808c-19.449535 19.439192-28.328081 42.706747-24.045899 70.054788 4.829091 30.919111 22.440081 52.516202 51.712 63.010909 29.450343 10.550303 56.692364 4.803232 80.49002-15.848727 1.944566-1.682101 3.798626-3.470222 5.616485-5.288081 130.121697-130.111354 259.955071-260.509737 390.546101-390.141414 33.272242-33.035636 33.454545-88.934141 1.206303-121.050505C879.016912 322.804364 748.093599 191.557818 617.028064 60.456081c-12.626747-12.626747-27.611798-20.655838-45.288727-23.505455-3.534869-0.570182-7.090424-0.994263-10.635636-1.484283-1.030465 0-2.055758 0-3.086222 0.005172C555.835013 35.799919 553.659013 36.274424 551.467498 36.441212L551.467498 36.441212zM551.467498 36.441212"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/controls.svg b/src/icons/svg/controls.svg new file mode 100644 index 0000000..bf0851f --- /dev/null +++ b/src/icons/svg/controls.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M885.7 63.6H138.3c-41.1 0-74.7 33.6-74.7 74.7v560.5c0 41.1 33.6 74.7 74.7 74.7h224.2c0 41.1-33.6 74.7-74.7 74.7-31.8 0-56.1 24.3-56.1 56.1s24.3 56.1 56.1 56.1h448.4c31.8 0 56.1-24.3 56.1-56.1s-24.3-56.1-56.1-56.1c-41.1 0-74.7-33.6-74.7-74.7h224.2c41.1 0 74.7-33.6 74.7-74.7V138.3c0-41.1-33.6-74.7-74.7-74.7zM754.9 568.1H697c-9.3 43-46.7 74.7-91.6 74.7-44.8 0-82.2-31.8-91.6-74.7H269.1c-9.3 0-18.7-9.3-18.7-18.7 0-9.3 9.3-18.7 18.7-18.7h244.8c9.3-43 46.7-74.7 91.6-74.7 44.8 0 82.2 31.8 91.6 74.7H755c9.3 0 18.7 9.3 18.7 18.7-0.1 9.3-9.5 18.7-18.8 18.7z m0-261.6H510.1c-9.3 43-46.7 74.7-91.6 74.7-44.8 0-82.2-31.8-91.6-74.7H269c-9.3 0-18.7-9.3-18.7-18.7 0-9.3 9.3-18.7 18.7-18.7h58c9.3-43 46.7-74.7 91.6-74.7 44.8 0 82.2 31.8 91.6 74.7H755c9.3 0 18.7 9.3 18.7 18.7-0.1 9.3-9.5 18.7-18.8 18.7z"></path><path d="M605.4 549.4m-56.1 0a56.1 56.1 0 1 0 112.2 0 56.1 56.1 0 1 0-112.2 0Z"></path><path d="M418.6 287.8m-56.1 0a56.1 56.1 0 1 0 112.2 0 56.1 56.1 0 1 0-112.2 0Z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/data.svg b/src/icons/svg/data.svg index 05b58d4..002c363 100644 --- a/src/icons/svg/data.svg +++ b/src/icons/svg/data.svg @@ -1 +1 @@ -<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M896 405.333333v128c0 106.026667-171.946667 192-384 192s-384-85.973333-384-192v-128c0 106.026667 171.946667 192 384 192s384-85.973333 384-192z m-768 213.333334c0 106.026667 171.946667 192 384 192s384-85.973333 384-192v128c0 106.026667-171.946667 192-384 192s-384-85.973333-384-192v-128z m384-106.666667c-212.053333 0-384-85.973333-384-192S299.946667 128 512 128s384 85.973333 384 192-171.946667 192-384 192z" fill="#000000"></path></svg> \ No newline at end of file +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M896 405.333333v128c0 106.026667-171.946667 192-384 192s-384-85.973333-384-192v-128c0 106.026667 171.946667 192 384 192s384-85.973333 384-192z m-768 213.333334c0 106.026667 171.946667 192 384 192s384-85.973333 384-192v128c0 106.026667-171.946667 192-384 192s-384-85.973333-384-192v-128z m384-106.666667c-212.053333 0-384-85.973333-384-192S299.946667 128 512 128s384 85.973333 384 192-171.946667 192-384 192z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/dev.svg b/src/icons/svg/dev.svg new file mode 100644 index 0000000..c0e56a9 --- /dev/null +++ b/src/icons/svg/dev.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M838.4 294.4v166.4H192V294.4h646.4z m44.8-76.8H147.2c-19.2 0-32 12.8-32 32v256c0 19.2 12.8 32 32 32h736c19.2 0 32-12.8 32-32v-256c0-19.2-19.2-32-32-32z m-6.4 588.8H147.2c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h723.2c19.2 0 38.4 19.2 38.4 38.4 6.4 25.6-12.8 38.4-32 38.4z m0-128H147.2c-19.2 0-38.4-19.2-38.4-38.4s19.2-38.4 38.4-38.4h723.2c19.2 0 38.4 19.2 38.4 38.4 6.4 19.2-12.8 38.4-32 38.4z m-179.2-300.8a38.4 38.4 0 1 0 76.8 0 38.4 38.4 0 0 0-76.8 0z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/dev1.svg b/src/icons/svg/dev1.svg new file mode 100644 index 0000000..b0bce23 --- /dev/null +++ b/src/icons/svg/dev1.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M64 192l128 0 0 64 448 0 0-64 128 0 0 256 64 0 0-320-192 0 0-64-64 0 0-64-320 0 0 64-64 0 0 64-192 0 0 896 128 0 0-64-64 0 0-768zM256 128l64 0 0-64 192 0 0 64 64 0 0 64-320 0 0-64zM192 512l0 448 128 0 0 64 128 0 0-64 320 0 0 64 128 0 0-64 128 0 0-448-832 0zM960 896l-704 0 0-320 704 0 0 320zM384 704l-64 0 0-64 64 0 0 64zM512 704l-64 0 0-64 64 0 0 64zM640 704l-64 0 0-64 64 0 0 64zM384 832l-64 0 0-64 64 0 0 64zM512 832l-64 0 0-64 64 0 0 64zM640 832l-64 0 0-64 64 0 0 64zM832 832l64 0 0-192-192 0 0 192 128 0zM768 704l64 0 0 64-64 0 0-64z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/realtime1.svg b/src/icons/svg/realtime1.svg new file mode 100644 index 0000000..b354973 --- /dev/null +++ b/src/icons/svg/realtime1.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1280 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M640.00064 0c353.472 0 640 286.528 640 640 0 128.576-37.952 248.32-103.168 348.544H103.16864A636.992 636.992 0 0 1 0.00064 640C0.00064 286.528 286.52864 0 640.00064 0z m0 205.76c-119.04 0-231.04 46.4-315.136 130.56a442.816 442.816 0 0 0-130.56 315.136 45.696 45.696 0 0 0 91.392 0 352 352 0 0 1 103.808-250.496A352 352 0 0 1 640.00064 297.216a352 352 0 0 1 250.496 103.744 352 352 0 0 1 103.808 250.496 45.696 45.696 0 0 0 91.392 0c0-119.04-46.336-230.976-130.56-315.136A442.816 442.816 0 0 0 640.00064 205.76z m28.928 406.336a113.92 113.92 0 0 0-41.728 7.872L528.51264 521.28a45.696 45.696 0 1 0-64.64 64.64l98.688 98.752a114.304 114.304 0 1 0 106.368-72.576z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/setting.svg b/src/icons/svg/setting.svg new file mode 100644 index 0000000..ab39b83 --- /dev/null +++ b/src/icons/svg/setting.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M890.53893 559.569946c2.114575-16.294021 3.482653-32.587042 3.482653-49.999309 0-17.288351-1.61691-33.582371-3.482653-49.999309l107.461589-84.078346c9.701463-7.587887 12.313703-21.393584 6.094893-32.588041l-101.864361-176.241244c-6.094893-11.192458-19.90059-15.297692-31.094048-11.192458l-126.864515 50.993639c-26.492149-20.397256-55.098873-37.187942-86.068005-49.999309L638.801558 21.392585C637.185646 9.079882 626.612771 0 613.802403 0H409.948765c-12.686452 0-23.384243 9.203798-25.000154 21.392585l-19.402926 135.072984c-31.094048 12.686452-59.575856 30.099718-86.068005 49.999309l-126.864515-50.994638c-11.815039-4.601899-24.999155 0-31.094048 11.194457L19.655755 342.90594c-6.715475 11.193458-3.481654 24.999155 6.094893 32.587042l107.46159 84.078346c-2.114575 16.293021-3.482653 33.083707-3.482653 49.999309 0 16.914602 1.61691 33.581372 3.482653 49.999309L25.626732 643.648292C15.92427 651.235179 13.313029 665.040877 19.531839 676.234334l101.864361 176.241244c6.093894 11.194457 19.90059 15.298691 31.094048 11.194457l126.864515-50.995638c26.492149 20.398255 55.097874 37.18994 86.068005 50.000309l19.401926 135.072984c1.61691 12.188787 12.189786 21.392585 25.000154 21.392585h203.852639c12.686452 0 23.383244-9.203798 25.000154-21.392585l19.401926-135.072984c31.094048-12.686452 59.576855-30.099718 86.069005-49.99931l126.864515 50.994639c11.815039 4.601899 24.999155 0 31.093049-11.194457L1003.970496 676.234334c6.094893-11.193458 3.482653-24.999155-6.093893-32.586042l-107.337673-84.078346zM511.938042 688.050372c-98.381708 0-178.355819-79.974111-178.355819-178.355819s79.974111-178.355819 178.355819-178.355818S690.293861 411.312846 690.293861 509.694553s-79.974111 178.355819-178.355819 178.355819z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/stations.svg b/src/icons/svg/stations.svg new file mode 100644 index 0000000..e3755e5 --- /dev/null +++ b/src/icons/svg/stations.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" ><path d="M1024 733v131c0 53-43 96-96 96h-96c-53 0-96-43-96-96V733c0-53 43-96 96-96 8.8 0 16-7.2 16-16v-77c0-17.7-14.3-32-32-32H560c-8.8 0-16 7.2-16 16v94c0 8.3 6.7 15 15 15h1c53 0 96 43 96 96v131c0 53-43 96-96 96h-96c-53 0-96-43-96-96V733c0-53 43-96 96-96h1c8.3 0 15-6.7 15-15v-94c0-8.8-7.2-16-16-16H208c-17.7 0-32 14.3-32 32v77c0 8.8 7.2 16 16 16 53 0 96 43 96 96v131c0 53-43 96-96 96H96c-53 0-96-43-96-96V733c0-53 43-96 96-96 8.8 0 16-7.2 16-16v-77c0-53 43-96 96-96h256c8.8 0 16-7.2 16-16v-48h-96c-53 0-96-43-96-96V144c0-53 43-96 96-96h256c53 0 96 43 96 96v144c0 53-43 96-96 96h-96v48c0 8.8 7.2 16 16 16h256c53 0 96 43 96 96v77c0 8.8 7.2 16 16 16 53 0 96 43 96 96z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/tongji.svg b/src/icons/svg/tongji.svg new file mode 100644 index 0000000..361b6ca --- /dev/null +++ b/src/icons/svg/tongji.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M912.6912 861.8496h-798.72a30.72 30.72 0 1 0 0 61.44h798.72a30.72 30.72 0 0 0 0-61.44z"></path><path d="M651.264 121.856m56.3712 0l85.248 0q56.3712 0 56.3712 56.3712l0 553.9328q0 56.3712-56.3712 56.3712l-85.248 0q-56.3712 0-56.3712-56.3712l0-553.9328q0-56.3712 56.3712-56.3712Z"></path><path d="M411.8016 288.3072m56.3712 0l85.248 0q56.3712 0 56.3712 56.3712l0 387.4816q0 56.3712-56.3712 56.3712l-85.248 0q-56.3712 0-56.3712-56.3712l0-387.4816q0-56.3712 56.3712-56.3712Z"></path><path d="M154.0608 365.7216m56.3712 0l85.248 0q56.3712 0 56.3712 56.3712l0 310.0672q0 56.3712-56.3712 56.3712l-85.248 0q-56.3712 0-56.3712-56.3712l0-310.0672q0-56.3712 56.3712-56.3712Z"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/workstatus.svg b/src/icons/svg/workstatus.svg new file mode 100644 index 0000000..8614329 --- /dev/null +++ b/src/icons/svg/workstatus.svg @@ -0,0 +1 @@ +<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M624.1 376.9L430.7 446c1.3 7.3 2.3 14.8 2.3 22.5 0 29.1-10.3 55.5-26.9 76.7l88 95.3c18.5-12 40.5-19.1 64.2-19.1 6.9 0 13.5 0.9 20 2l76.8-215.5c-12.6-7.8-23.2-18.4-31-31z"></path><path d="M512 0C229.2 0 0 229.2 0 512s229.2 512 512 512 512-229.2 512-512S794.8 0 512 0z m193.6 422.5c-4.2 0-8.3-0.7-12.4-1.2l-76.9 215.8c35.9 20.3 60.4 58.4 60.4 102.7 0 65.4-53 118.4-118.4 118.4s-118.4-53-118.4-118.4c0-27.1 9.4-51.7 24.7-71.7L376.7 573c-19.8 13.1-43.5 20.8-69 20.8-69.2 0-125.3-56.1-125.3-125.3 0-69.2 56.1-125.3 125.3-125.3 47.2 0 87.8 26.4 109.1 64.9l193.9-69.2c-0.5-4.1-1.3-8.2-1.3-12.4 0-53.1 43.1-96.2 96.2-96.2s96.2 43.1 96.2 96.2-43 96-96.2 96z"></path></svg> \ No newline at end of file diff --git a/src/layout/components/AppMain.vue b/src/layout/components/AppMain.vue index 6a64c48..936c590 100644 --- a/src/layout/components/AppMain.vue +++ b/src/layout/components/AppMain.vue @@ -1,9 +1,9 @@ <template> - <section class="app-main"> + <section :class="['app-main', {'no-decoration': route.meta.decoration === false}]"> <router-view v-slot="{ Component, route }"> <transition name="fade-transform" mode="out-in"> <keep-alive :include="cachedViews"> - <component :is="Component" :key="route.fullPath" /> + <component :is="Component" :key="route.name" /> </keep-alive> </transition> </router-view> @@ -14,6 +14,10 @@ import { defineComponent } from 'vue'; import { useTagsViewStore } from '@/store/tagsView'; import { storeToRefs } from 'pinia'; +import { useRoute, useRouter } from "vue-router"; +const route = useRoute(); +const router = useRouter(); + const tagsViewStore = useTagsViewStore(); const { cachedViews } = storeToRefs(tagsViewStore); @@ -35,10 +39,7 @@ .hasTagsView { .app-main { - /* 84 = navbar + tags-view = 50 + 34 */ - // height: 100vh; - - height: calc(100vh - 148px); + // height: calc(100vh - 148px); background: url("@/assets/images/bg-side.png") calc(100% + 8px) top e('/') auto 80% no-repeat; // position: relative; z-index: 0; @@ -53,6 +54,12 @@ transform: scaleX(-1); background: url("@/assets/images/bg-side.png") calc(100% + 8px) top e('/') auto 80% no-repeat; } + &.no-decoration { + background: transparent; + &::before { + background: transparent; + } + } } // .fixed-header+.app-main { diff --git a/src/layout/index.vue b/src/layout/index.vue index 9f28ae7..b2afd95 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -13,7 +13,7 @@ </div> <tags-view class="tags-view" v-if="needTagsView" /> <div class="main-wrap pos-r"> - <app-main class="app-main pos-full" /> + <app-main class="pos-full" /> </div> <!-- <right-panel v-if="showSettings"> <settings /> @@ -50,7 +50,7 @@ const route = useRoute(); const router = useRouter(); -console.log('TagsView', TagsView, '============='); +console.log('TagsView', TagsView, route , '============='); const appStore = useAppStore(); diff --git a/src/router/index.js b/src/router/index.js index e694f9b..506b8bd 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -5,6 +5,8 @@ // import generalRouter from './modules/general'; import systemRouter from './modules/system'; import datasRouter from './modules/datas'; +import alarmRouter from './modules/alarm'; +import statisticsRouter from './modules/statistics'; /* Layout */ const Layout = () => import('@/layout/index.vue'); @@ -79,6 +81,8 @@ // generalRouter, systemRouter, datasRouter, + alarmRouter, + statisticsRouter, // 404 page must be placed at the end !!! { path: '/:pathMatch(.*)*', redirect: '/404', meta: { hidden: true }} ]; diff --git a/src/router/modules/alarm.js b/src/router/modules/alarm.js new file mode 100644 index 0000000..5924905 --- /dev/null +++ b/src/router/modules/alarm.js @@ -0,0 +1,34 @@ +const Layout = () => import('@/layout/index.vue'); + +const systemRouter = { + path: '/alarm', + component: Layout, + redirect: 'noRedirect', + name: 'alarm', + meta: { + title: '鍛婅绠$悊', + icon: 'alarm' + }, + children: [ + { + path: 'batt', + component: () => import('@/views/alarm/battAlarm.vue'), + name: 'battAlarm', + meta: { title: '鐢垫睜瀹炴椂鍛婅', icon: 'alarm', noCache: false } + }, + { + path: 'dev', + component: () => import('@/views/alarm/devAlarm.vue'), + name: 'devAlarm', + meta: { title: '璁惧瀹炴椂鍛婅', icon: 'alarm', noCache: false } + }, + { + path: 'pwr', + component: () => import('@/views/alarm/pwrAlarm.vue'), + name: 'pwrAlarm', + meta: { title: '鐢垫簮瀹炴椂鍛婅', icon: 'alarm', noCache: false } + }, + ] +}; + +export default systemRouter; diff --git a/src/router/modules/datas.js b/src/router/modules/datas.js index 741ed2e..1cc00ef 100644 --- a/src/router/modules/datas.js +++ b/src/router/modules/datas.js @@ -14,13 +14,13 @@ path: 'realtime', component: () => import('@/views/realtime/index.vue'), name: 'realtime', - meta: { title: '瀹炴椂鐩戞祴', icon: 'component', noCache: false } + meta: { title: '瀹炴椂鐩戞祴', icon: 'realtime1', noCache: false, decoration: false } }, { path: 'device', component: () => import('@/views/datas/device.vue'), name: 'device', - meta: { title: '璁惧绠$悊', icon: 'component', noCache: false } + meta: { title: '璁惧绠$悊', icon: 'dev1', noCache: false } }, ] }; diff --git a/src/router/modules/statistics.js b/src/router/modules/statistics.js new file mode 100644 index 0000000..4b69287 --- /dev/null +++ b/src/router/modules/statistics.js @@ -0,0 +1,40 @@ +const Layout = () => import('@/layout/index.vue'); + +const systemRouter = { + path: '/statistics', + component: Layout, + redirect: 'noRedirect', + name: 'Statistics', + meta: { + title: '缁熻绠$悊', + icon: 'tongji' + }, + children: [ + // { + // path: 'power', + // component: () => import('@/views/statistics/power.vue'), + // name: 'power', + // meta: { title: '鐢垫簮缁熻', icon: 'component', noCache: false } + // }, + { + path: 'dev-workstatus', + component: () => import('@/views/statistics/devWorkstatus.vue'), + name: 'devWorkstatus', + meta: { title: '璁惧宸ヤ綔鐘舵�佺粺璁�', icon: 'workstatus', noCache: false } + }, + { + path: 'batt-hr', + component: () => import('@/views/statistics/battHr.vue'), + name: 'battHr', + meta: { title: '钃勭數姹犳牳瀹逛俊鎭粺璁�', icon: 'component', noCache: false } + }, + { + path: 'station', + component: () => import('@/views/statistics/station.vue'), + name: 'station', + meta: { title: '绔欑偣缁熻', icon: 'stations', noCache: false } + }, + ] +}; + +export default systemRouter; diff --git a/src/styles/blue.css b/src/styles/blue.css index 5448ec5..8e65b8a 100644 --- a/src/styles/blue.css +++ b/src/styles/blue.css @@ -3,7 +3,7 @@ --light-color: #00feff; --bg-color: #072d44; --el-text-color-placeholder: #4ba1fa; - --el-fill-color-lighter: #1F3C64; + --el-fill-color-lighter: #1f3c64; --border-light-color: #143a92; --filter-input-border-color: rgba(255, 227, 41, 0.2); --el-dialog-bg-color: var(--bg-color); @@ -52,7 +52,7 @@ --el-tree-node-content-height: 26px; --el-tree-node-hover-bg-color: #214865; --el-tree-text-color: var(--el-text-color-regular); - --el-tree-expand-icon-color: #1FCBE1; + --el-tree-expand-icon-color: #1fcbe1; background: none; color: #ffffff; cursor: default; @@ -75,10 +75,10 @@ --el-table-header-text-color: #fff; --el-table-row-hover-bg-color: #1a5a8b; --el-table-current-row-bg-color: var(--el-color-primary-light-9); - --el-table-header-bg-color: #1F3C64; + --el-table-header-bg-color: #1f3c64; --el-table-fixed-box-shadow: var(--el-box-shadow-light); --el-table-bg-color: var(--bg-color); - --el-table-tr-bg-color: #0D2B4D; + --el-table-tr-bg-color: #0d2b4d; --el-table-expanded-cell-bg-color: var(--el-fill-color-blank); --el-table-index: var(--el-index-normal); background-color: var(--bg-color); @@ -123,10 +123,11 @@ background: transparent; } html.blue-theme .ys-title { - font-family: 'YouSheBiaoTiHei'; + font-family: "YouSheBiaoTiHei"; } html.blue-theme .panel-title { - font-family: 'YouSheBiaoTiHei'; + font-family: "YouSheBiaoTiHei"; + font-size: 24px; padding-left: 1.4em; background: url("@/assets/images/tb1.png") 6px center / auto 82% no-repeat; } @@ -134,16 +135,16 @@ color: #1fcbe1; } .el-tabs--border-card > .el-tabs__header.el-tabs__header { - border-bottom: 1px solid #00fefe; + border-bottom: 1px solid #1c4975; background-color: #00243e; } .el-tabs--border-card > .el-tabs__header.el-tabs__header .el-tabs__item { - color: #00fefe; + color: #fff; } .el-tabs--border-card > .el-tabs__header.el-tabs__header .el-tabs__item.is-active { - background-color: #00fefe; - border-color: #00fefe; - color: #041f6c; + background-color: #014886; + border-color: #014886; + color: #fff; } .el-pagination__sizes.el-pagination__sizes, .el-pagination__total.el-pagination__total { @@ -151,9 +152,9 @@ font-size: 16px; } .el-pagination .el-select__wrapper.el-select__wrapper { - background-color: #134BA8; + background-color: #134ba8; color: #fff; - box-shadow: 0 0 0 1px #436DA8 inset; + box-shadow: 0 0 0 1px #436da8 inset; } .el-pagination .el-select__wrapper.el-select__wrapper .el-select__placeholder, .el-pagination .el-select__wrapper.el-select__wrapper .el-select__input { @@ -181,8 +182,8 @@ color: #fff; } .el-pagination__jump.el-pagination__jump .el-input__wrapper { - background-color: #134BA8; - box-shadow: 0 0 0 1px #436DA8 inset; + background-color: #134ba8; + box-shadow: 0 0 0 1px #436da8 inset; } .el-pagination__jump.el-pagination__jump .el-input__wrapper .el-input__inner { color: #fff; @@ -203,8 +204,8 @@ } .el-transfer .el-checkbox__input.is-indeterminate .el-checkbox__inner, .el-transfer .el-checkbox__input.is-checked .el-checkbox__inner { - background-color: #46CAFE; - border-color: #46CAFE; + background-color: #46cafe; + border-color: #46cafe; } .el-transfer .el-checkbox__input.is-indeterminate .el-checkbox__inner::before, .el-transfer .el-checkbox__input.is-checked .el-checkbox__inner::before { @@ -216,14 +217,14 @@ } .page-filter { display: table; - border-bottom: 1px solid #304A75; + border-bottom: 1px solid #304a75; margin-top: 8px; padding: 6px; margin-bottom: 6px; } .page-filter .el-select__wrapper.el-select__wrapper { background-color: #103047; - color: #48A5D0; + color: #48a5d0; box-shadow: 0 0 0 1px #103047 inset; } .page-filter .el-select__placeholder { @@ -231,16 +232,56 @@ } .page-filter .table-row { display: table-row; + table-layout: fixed; } .page-filter .table-row .table-cell { display: table-cell; white-space: nowrap; - color: #48A5D0; + color: #48a5d0; + font-size: 16px; } .page-filter .table-cell.text-right { text-align: right; padding-right: 10px; } +.page-filter .el-date-editor .el-input__wrapper { + align-items: center; + background-color: #103047; + background-image: none; + border-radius: var(--el-input-border-radius, var(--el-border-radius-base)); + box-shadow: 0 0 0 1px #103047 inset; + cursor: text; + display: inline-flex; + flex-grow: 1; + justify-content: center; + padding: 1px 11px; +} +.page-filter .el-date-editor .el-input__wrapper .el-input__inner { + color: #48a5d0; +} +.page-filter .grid-container { + display: grid; + grid-template-columns: repeat(var(--counter), auto 1fr); + gap: 12px; + /* 鍒椾箣闂寸殑闂磋窛 */ + padding: 10px; +} +.page-filter .grid-container .grid-item { + color: #48a5d0; + display: contents; + /* 浣块」鐩唴瀹圭洿鎺ュ弬涓庣綉鏍煎竷灞� */ +} +.page-filter .grid-container .grid-item .label { + white-space: nowrap; + margin-right: -6px; + margin-left: 1em; + color: #48a5d0; + font-size: 16px; + text-align: right; +} +.page-filter .grid-container .grid-item .label::after { + content: ":"; +} .pos-r { position: relative; } diff --git a/src/styles/blue.less b/src/styles/blue.less index 7bbfa30..2992f14 100644 --- a/src/styles/blue.less +++ b/src/styles/blue.less @@ -5,7 +5,7 @@ --bg-color: #072d44; --el-text-color-placeholder: #4ba1fa; // --el-fill-color-lighter: var(--bg-color); - --el-fill-color-lighter: #1F3C64; + --el-fill-color-lighter: #1f3c64; --border-light-color: #143a92; --filter-input-border-color: rgba(255, 227, 41, 0.2); --el-dialog-bg-color: var(--bg-color); @@ -83,7 +83,7 @@ --el-tree-node-content-height: 26px; --el-tree-node-hover-bg-color: #214865; --el-tree-text-color: var(--el-text-color-regular); - --el-tree-expand-icon-color: #1FCBE1; + --el-tree-expand-icon-color: #1fcbe1; background: none; color: #ffffff; cursor: default; @@ -110,10 +110,10 @@ --el-table-row-hover-bg-color: #1a5a8b; --el-table-current-row-bg-color: var(--el-color-primary-light-9); // --el-table-header-bg-color: #021f31; - --el-table-header-bg-color: #1F3C64; + --el-table-header-bg-color: #1f3c64; --el-table-fixed-box-shadow: var(--el-box-shadow-light); --el-table-bg-color: var(--bg-color); - --el-table-tr-bg-color: #0D2B4D; + --el-table-tr-bg-color: #0d2b4d; --el-table-expanded-cell-bg-color: var(--el-fill-color-blank); --el-table-index: var(--el-index-normal); background-color: var(--bg-color); @@ -155,7 +155,6 @@ } } - .page-content { padding-bottom: 20px; .el-table { @@ -164,34 +163,35 @@ } .ys-title { - font-family: 'YouSheBiaoTiHei'; + font-family: "YouSheBiaoTiHei"; } .panel-title { - font-family: 'YouSheBiaoTiHei'; + font-family: "YouSheBiaoTiHei"; + font-size: 24px; padding-left: 1.4em; - background: url("@/assets/images/tb1.png") 6px center e('/') auto 82% no-repeat; + background: url("@/assets/images/tb1.png") 6px center e("/") auto 82% + no-repeat; } } - .el-tree.el-tree.el-tree { color: #1fcbe1; } .el-tabs--border-card > .el-tabs__header.el-tabs__header { - border-bottom: 1px solid #00fefe; + border-bottom: 1px solid #1c4975; background-color: #00243e; } .el-tabs--border-card > .el-tabs__header.el-tabs__header .el-tabs__item { - color: #00fefe; + color: #fff; } .el-tabs--border-card > .el-tabs__header.el-tabs__header .el-tabs__item.is-active { - background-color: #00fefe; - border-color: #00fefe; - color: #041f6c; + background-color: #014886; + border-color: #014886; + color: #fff; } .el-pagination__sizes.el-pagination__sizes, @@ -201,9 +201,9 @@ } .el-pagination .el-select__wrapper.el-select__wrapper { - background-color: #134BA8; + background-color: #134ba8; color: #fff; - box-shadow: 0 0 0 1px #436DA8 inset; + box-shadow: 0 0 0 1px #436da8 inset; } .el-pagination .el-select__wrapper.el-select__wrapper .el-select__placeholder, .el-pagination .el-select__wrapper.el-select__wrapper .el-select__input { @@ -221,7 +221,6 @@ cursor: not-allowed; } - .el-pagination .el-pager.el-pager.el-pager li { background: transparent; color: #fff; @@ -234,14 +233,14 @@ color: #fff; } .el-pagination__jump.el-pagination__jump .el-input__wrapper { - background-color: #134BA8; - box-shadow: 0 0 0 1px #436DA8 inset; + background-color: #134ba8; + box-shadow: 0 0 0 1px #436da8 inset; } .el-pagination__jump.el-pagination__jump .el-input__wrapper .el-input__inner { color: #fff; } -.el-tree-node:focus>.el-tree-node__content.el-tree-node__content { +.el-tree-node:focus > .el-tree-node__content.el-tree-node__content { background: transparent; } @@ -254,7 +253,6 @@ outline: none; } - .el-tooltip__popper.el-tooltip__popper { z-index: 9999; /* 璁剧疆杈冮珮鐨� z-index */ } @@ -262,8 +260,8 @@ .el-transfer { .el-checkbox__input.is-indeterminate .el-checkbox__inner, .el-checkbox__input.is-checked .el-checkbox__inner { - background-color: #46CAFE; - border-color: #46CAFE; + background-color: #46cafe; + border-color: #46cafe; &::before { background-color: #333; } @@ -273,17 +271,17 @@ } } -// 鎼滅储鏉′欢鏍峰紡 +// 鎼滅储鏉′欢鏍峰紡 .page-filter { display: table; - border-bottom: 1px solid #304A75; + border-bottom: 1px solid #304a75; margin-top: 8px; padding: 6px; margin-bottom: 6px; .el-select__wrapper.el-select__wrapper { background-color: #103047; - color: #48A5D0; + color: #48a5d0; box-shadow: 0 0 0 1px #103047 inset; } .el-select__placeholder { @@ -291,16 +289,73 @@ } .table-row { - display: table-row; + display: table-row; + table-layout: fixed; } .table-row .table-cell { - display: table-cell; - white-space: nowrap; - color: #48A5D0; + display: table-cell; + white-space: nowrap; + color: #48a5d0; + font-size: 16px; } .table-cell.text-right { - text-align: right; + text-align: right; padding-right: 10px; + } + + .el-date-editor { + .el-input__wrapper { + align-items: center; + background-color: #103047; + background-image: none; + border-radius: var( + --el-input-border-radius, + var(--el-border-radius-base) + ); + box-shadow: 0 0 0 1px #103047 inset; + cursor: text; + display: inline-flex; + flex-grow: 1; + justify-content: center; + padding: 1px 11px; + .el-input__inner { + color: #48a5d0; + } + } + } + + .grid-container { + display: grid; + grid-template-columns: repeat(var(--counter), auto 1fr); + // gap: 15px; /* 鍧囧寑闂撮殧 */ + // padding: 10px; + + gap: 12px; /* 鍒椾箣闂寸殑闂磋窛 */ + padding: 10px; + .grid-item { + color: #48a5d0; + // display: flex; + // align-items: center; + display: contents; /* 浣块」鐩唴瀹圭洿鎺ュ弬涓庣綉鏍煎竷灞� */ + .label { + white-space: nowrap; + // font-weight: bold; + margin-right: -6px; + margin-left: 1em; + color: #48a5d0; + font-size: 16px; + text-align: right; + &::after { + content: ":"; + } + } + .value { + // flex-grow: 1; + // overflow: hidden; + // text-overflow: ellipsis; + // white-space: nowrap; + } + } } } @@ -318,7 +373,8 @@ .page-contain { height: 100%; &.bg-footer { - background: url("@/assets/images/bg_bottom.png") center calc(100% - 20px) e('/') 100% auto no-repeat; + background: url("@/assets/images/bg_bottom.png") center calc(100% - 20px) + e("/") 100% auto no-repeat; } .page-main { padding-left: 20px; @@ -330,4 +386,4 @@ @font-face { font-family: "YouSheBiaoTiHei"; src: url(./YouSheBiaoTiHei-2.ttf) format("truetype"); -} \ No newline at end of file +} diff --git a/src/utils/const/const_digit.js b/src/utils/const/const_digit.js new file mode 100644 index 0000000..195535c --- /dev/null +++ b/src/utils/const/const_digit.js @@ -0,0 +1,9 @@ +// 鍏ㄥ眬灏忔暟浣嶆暟 +export default { + // 鐧惧垎姣� + PREC: 2, + // 鐢靛帇 + VOL: 3, + // 鐢垫祦 + CURR: 3, +} \ No newline at end of file diff --git a/src/utils/const/const_hrTestType.js b/src/utils/const/const_hrTestType.js new file mode 100644 index 0000000..09bab73 --- /dev/null +++ b/src/utils/const/const_hrTestType.js @@ -0,0 +1,7 @@ +export default { + // TODO + 1: '鏍稿鏀剧數', + 2: '鏍稿鍏呯數', + 3: '鐩戞帶鏀剧數', + 4: '鐩戞帶鍏呯數' +} \ No newline at end of file diff --git a/src/utils/excel/Blob.js b/src/utils/excel/Blob.js new file mode 100644 index 0000000..3fa0b67 --- /dev/null +++ b/src/utils/excel/Blob.js @@ -0,0 +1,204 @@ +/* eslint-disable */ +/* Blob.js*/ + +/*global self, unescape */ +/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, + plusplus: true */ + +/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ + +(function(view) { + "use strict"; + + view.URL = view.URL || view.webkitURL; + + if (view.Blob && view.URL) { + try { + new Blob; + return; + } catch (e) {} + } + + // Internally we use a BlobBuilder implementation to base Blob off of + // in order to support older browsers that only have BlobBuilder + var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) { + var + get_class = function(object) { + return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; + }, + FakeBlobBuilder = function BlobBuilder() { + this.data = []; + }, + FakeBlob = function Blob(data, type, encoding) { + this.data = data; + this.size = data.length; + this.type = type; + this.encoding = encoding; + }, + FBB_proto = FakeBlobBuilder.prototype, + FB_proto = FakeBlob.prototype, + FileReaderSync = view.FileReaderSync, + FileException = function(type) { + this.code = this[this.name = type]; + }, + file_ex_codes = ( + "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " + + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" + ).split(" "), + file_ex_code = file_ex_codes.length, + real_URL = view.URL || view.webkitURL || view, + real_create_object_URL = real_URL.createObjectURL, + real_revoke_object_URL = real_URL.revokeObjectURL, + URL = real_URL, + btoa = view.btoa, + atob = view.atob + + , + ArrayBuffer = view.ArrayBuffer, + Uint8Array = view.Uint8Array + + , + origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/; + FakeBlob.fake = FB_proto.fake = true; + while (file_ex_code--) { + FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; + } + // Polyfill URL + if (!real_URL.createObjectURL) { + URL = view.URL = function(uri) { + var + uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a"), + uri_origin; + uri_info.href = uri; + if (!("origin" in uri_info)) { + if (uri_info.protocol.toLowerCase() === "data:") { + uri_info.origin = null; + } else { + uri_origin = uri.match(origin); + uri_info.origin = uri_origin && uri_origin[1]; + } + } + return uri_info; + }; + } + URL.createObjectURL = function(blob) { + var + type = blob.type, + data_URI_header; + if (type === null) { + type = "application/octet-stream"; + } + if (blob instanceof FakeBlob) { + data_URI_header = "data:" + type; + if (blob.encoding === "base64") { + return data_URI_header + ";base64," + blob.data; + } else if (blob.encoding === "URI") { + return data_URI_header + "," + decodeURIComponent(blob.data); + } + if (btoa) { + return data_URI_header + ";base64," + btoa(blob.data); + } else { + return data_URI_header + "," + encodeURIComponent(blob.data); + } + } else if (real_create_object_URL) { + return real_create_object_URL.call(real_URL, blob); + } + }; + URL.revokeObjectURL = function(object_URL) { + if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { + real_revoke_object_URL.call(real_URL, object_URL); + } + }; + FBB_proto.append = function(data /*, endings*/ ) { + var bb = this.data; + // decode data to a binary string + if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { + var + str = "", + buf = new Uint8Array(data), + i = 0, + buf_len = buf.length; + for (; i < buf_len; i++) { + str += String.fromCharCode(buf[i]); + } + bb.push(str); + } else if (get_class(data) === "Blob" || get_class(data) === "File") { + if (FileReaderSync) { + var fr = new FileReaderSync; + bb.push(fr.readAsBinaryString(data)); + } else { + // async FileReader won't work as BlobBuilder is sync + throw new FileException("NOT_READABLE_ERR"); + } + } else if (data instanceof FakeBlob) { + if (data.encoding === "base64" && atob) { + bb.push(atob(data.data)); + } else if (data.encoding === "URI") { + bb.push(decodeURIComponent(data.data)); + } else if (data.encoding === "raw") { + bb.push(data.data); + } + } else { + if (typeof data !== "string") { + data += ""; // convert unsupported types to strings + } + // decode UTF-16 to binary string + bb.push(unescape(encodeURIComponent(data))); + } + }; + FBB_proto.getBlob = function(type) { + if (!arguments.length) { + type = null; + } + return new FakeBlob(this.data.join(""), type, "raw"); + }; + FBB_proto.toString = function() { + return "[object BlobBuilder]"; + }; + FB_proto.slice = function(start, end, type) { + var args = arguments.length; + if (args < 3) { + type = null; + } + return new FakeBlob( + this.data.slice(start, args > 1 ? end : this.data.length), type, this.encoding + ); + }; + FB_proto.toString = function() { + return "[object Blob]"; + }; + FB_proto.close = function() { + this.size = 0; + delete this.data; + }; + return FakeBlobBuilder; + }(view)); + + view.Blob = function(blobParts, options) { + var type = options ? (options.type || "") : ""; + var builder = new BlobBuilder(); + if (blobParts) { + for (var i = 0, len = blobParts.length; i < len; i++) { + if (Uint8Array && blobParts[i] instanceof Uint8Array) { + builder.append(blobParts[i].buffer); + } else { + builder.append(blobParts[i]); + } + } + } + var blob = builder.getBlob(type); + if (!blob.slice && blob.webkitSlice) { + blob.slice = blob.webkitSlice; + } + return blob; + }; + + var getPrototypeOf = Object.getPrototypeOf || function(object) { + return object.__proto__; + }; + view.Blob.prototype = getPrototypeOf(new view.Blob()); +}( + typeof self !== "undefined" && self || + typeof window !== "undefined" && window || + this +)); diff --git a/src/utils/excel/Export2Excel.js b/src/utils/excel/Export2Excel.js new file mode 100644 index 0000000..73c2fae --- /dev/null +++ b/src/utils/excel/Export2Excel.js @@ -0,0 +1,179 @@ +/* eslint-disable */ +require('script-loader!file-saver'); +require('./Blob.js') +require('script-loader!xlsx/dist/xlsx.core.min'); + +function generateArray(table) { + var out = []; + var rows = table.querySelectorAll('tr'); + var ranges = []; + for (var R = 0; R < rows.length; ++R) { + var outRow = []; + var row = rows[R]; + var columns = row.querySelectorAll('td'); + for (var C = 0; C < columns.length; ++C) { + var cell = columns[C]; + var colspan = cell.getAttribute('colspan'); + var rowspan = cell.getAttribute('rowspan'); + var cellValue = cell.innerText; + if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue; + + //Skip ranges + ranges.forEach(function(range) { + if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) { + for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null); + } + }); + + //Handle Row Span + if (rowspan || colspan) { + rowspan = rowspan || 1; + colspan = colspan || 1; + ranges.push({ + s: { + r: R, + c: outRow.length + }, + e: { + r: R + rowspan - 1, + c: outRow.length + colspan - 1 + } + }); + }; + + //Handle Value + outRow.push(cellValue !== "" ? cellValue : null); + + //Handle Colspan + if (colspan) + for (var k = 0; k < colspan - 1; ++k) outRow.push(null); + } + out.push(outRow); + } + return [out, ranges]; +}; + +function datenum(v, date1904) { + if (date1904) v += 1462; + var epoch = Date.parse(v); + return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); +} + +function sheet_from_array_of_arrays(data, opts) { + var ws = {}; + var range = { + s: { + c: 10000000, + r: 10000000 + }, + e: { + c: 0, + r: 0 + } + }; + for (var R = 0; R != data.length; ++R) { + for (var C = 0; C != data[R].length; ++C) { + if (range.s.r > R) range.s.r = R; + if (range.s.c > C) range.s.c = C; + if (range.e.r < R) range.e.r = R; + if (range.e.c < C) range.e.c = C; + var cell = { + v: data[R][C] + }; + if (cell.v == null) continue; + var cell_ref = XLSX.utils.encode_cell({ + c: C, + r: R + }); + + if (typeof cell.v === 'number') cell.t = 'n'; + else if (typeof cell.v === 'boolean') cell.t = 'b'; + else if (cell.v instanceof Date) { + cell.t = 'n'; + cell.z = XLSX.SSF._table[14]; + cell.v = datenum(cell.v); + } else cell.t = 's'; + + ws[cell_ref] = cell; + } + } + if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range); + return ws; +} + +function Workbook() { + if (!(this instanceof Workbook)) return new Workbook(); + this.SheetNames = []; + this.Sheets = {}; +} + +function s2ab(s) { + var buf = new ArrayBuffer(s.length); + var view = new Uint8Array(buf); + for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; + return buf; +} + +export function export_table_to_excel(id) { + var theTable = document.getElementById(id); + console.log('a') + var oo = generateArray(theTable); + var ranges = oo[1]; + + /* original data */ + var data = oo[0]; + var ws_name = "SheetJS"; + console.log(data); + + var wb = new Workbook(), + ws = sheet_from_array_of_arrays(data); + + /* add ranges to worksheet */ + // ws['!cols'] = ['apple', 'banan']; + ws['!merges'] = ranges; + + /* add worksheet to workbook */ + wb.SheetNames.push(ws_name); + wb.Sheets[ws_name] = ws; + + var wbout = XLSX.write(wb, { + bookType: 'xlsx', + bookSST: false, + type: 'binary' + }); + + saveAs(new Blob([s2ab(wbout)], { + type: "application/octet-stream" + }), "test.xlsx") +} + +function formatJson(jsonData) { + console.log(jsonData) +} + +export function export_json_to_excel(th, jsonData, defaultTitle) { + + /* original data */ + + var data = jsonData; + data.unshift(th); + var ws_name = "SheetJS"; + + var wb = new Workbook(), + ws = sheet_from_array_of_arrays(data); + + + /* add worksheet to workbook */ + wb.SheetNames.push(ws_name); + wb.Sheets[ws_name] = ws; + + var wbout = XLSX.write(wb, { + bookType: 'xlsx', + bookSST: false, + type: 'binary' + }); + var title = defaultTitle || '鍒楄〃' + saveAs(new Blob([s2ab(wbout)], { + type: "application/octet-stream" + }), title + ".xlsx") +} diff --git a/src/utils/export2Excel.js b/src/utils/export2Excel.js new file mode 100644 index 0000000..d3302ec --- /dev/null +++ b/src/utils/export2Excel.js @@ -0,0 +1,147 @@ +import { saveAs } from "file-saver"; +import * as XLSX from "xlsx"; +/** + * + * @param {Object} workbook 宸ヤ綔钖� + * @param {Object} worksheet 宸ヤ綔琛� + * @param {Object} cell 鍗曞厓鏍� + * 鏍囪锛屽紩鐢ㄥ崟鍏冩牸鏃舵墍浣跨敤鐨勫湴鍧�鏍煎紡锛堝锛欰1銆丆7锛� + */ +function datenum(v, date1904) { + if (date1904) v += 1462; + var epoch = Date.parse(v); + return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); +} +function sheetFromArrayOfArrays(data, opts) { + var ws = {}; + var range = { + s: { + c: 10000000, + r: 10000000, + }, + e: { + c: 0, + r: 0, + }, + }; + for (var R = 0; R !== data.length; ++R) { + for (var C = 0; C !== data[R].length; ++C) { + if (range.s.r > R) range.s.r = R; + if (range.s.c > C) range.s.c = C; + if (range.e.r < R) range.e.r = R; + if (range.e.c < C) range.e.c = C; + var cell = { + v: data[R][C], // v琛ㄧず鍗曞厓鏍煎師濮嬪�硷紝 t琛ㄧず鍐呭绫诲瀷锛宻-string绫诲瀷锛宯-number绫诲瀷锛宐-boolean绫诲瀷锛宒-date绫诲瀷锛岀瓑绛� + }; + if (cell.v == null) continue; + /** + * 閫氳繃鍦板潃瀵硅薄 { r: R, c: C } 鏉ヨ幏鍙栧崟鍏冩牸锛孯 鍜� C 鍒嗗埆浠h〃浠� 0 寮�濮嬬殑琛屽拰鍒楃殑绱㈠紩銆� + * XLSX.utils 涓殑 encode_cell/decode_cell 鏂规硶鍙互杞崲鍗曞厓鏍煎湴鍧� + * XLSX.utils.encode_cell({ r: 7, c: 2 }) ===銆� C7 + */ + var cellRef = XLSX.utils.encode_cell({ c: C, r: R }); + if (typeof cell.v === "number") cell.t = "n"; + else if (typeof cell.v === "boolean") cell.t = "b"; + else if (cell.v instanceof Date) { + cell.t = "n"; + cell.z = XLSX.SSF._table[14]; + cell.v = datenum(cell.v); + } else cell.t = "s"; + ws[cellRef] = cell; + } + } + // ws['!ref']锛氳〃绀烘墍鏈夊崟鍏冩牸鐨勮寖鍥达紝渚嬪浠嶢1鍒癋8鍒欒褰曚负A1:F8 + if (range.s.c < 10000000) ws["!ref"] = XLSX.utils.encode_range(range); + return ws; +} +function Workbook() { + if (!(this instanceof Workbook)) return new Workbook(); + this.SheetNames = []; + this.Sheets = {}; +} +// 瀛楃涓茶浆涓篈rrayBuffer +function s2ab(s) { + var buf = new ArrayBuffer(s.length); + var view = new Uint8Array(buf); + for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff; + return buf; +} +/** + * + * @param {Array} multiHeader 澶氳琛ㄥご + * @param {Array} header 琛ㄥご + * @param {Array} data 鏁版嵁 + * @param {String} filename 鏂囦欢鍚� + * @param {Array} merges 鍚堝苟鍗曞厓鏍� + * @param {Boolean} autoWidth 鏄惁璁剧疆鍗曞厓鏍煎搴� + * @param {String} bookType 瑕佺敓鎴愮殑鏂囦欢绫诲瀷 + */ +export function exportJsonToExcel({ + multiHeader = [], + header, + data, + filename, + merges = [], + autoWidth = true, + bookType = "xlsx", +} = {}) { + filename = filename || "excel-list"; + data = [...data]; + data.unshift(header); + for (let i = multiHeader.length - 1; i > -1; i--) { + data.unshift(multiHeader[i]); + } + var wsName = "SheetJS"; + var wb = new Workbook(); + var ws = sheetFromArrayOfArrays(data); + if (merges.length > 0) { + // ws[!merges]锛氬瓨鏀句竴浜涘崟鍏冩牸鍚堝苟淇℃伅锛屾槸涓�涓暟缁勶紝姣忎釜鏁扮粍鐢卞寘鍚玸鍜宔鏋勬垚鐨勫璞$粍鎴愶紝s琛ㄧず寮�濮嬶紝e琛ㄧず缁撴潫锛宺琛ㄧず琛岋紝c琛ㄧず鍒� + if (!ws["!merges"]) ws["!merges"] = []; + merges.forEach((item) => { + ws["!merges"].push(XLSX.utils.decode_range(item)); + }); + } + if (autoWidth) { + /* 璁剧疆worksheet姣忓垪鐨勬渶澶у搴� */ + const colWidth = data.map((row) => + row.map((val) => { + /* 鍏堝垽鏂槸鍚︿负null/undefined */ + if (val == null) { + return { wch: 10 }; + } else if (val.toString().charCodeAt(0) > 255) { + /* 鍐嶅垽鏂槸鍚︿负涓枃 */ + return { + wch: val.toString().length * 2, + }; + } else { + return { + wch: val.toString().length, + }; + } + }) + ); + /* 浠ョ涓�琛屼负鍒濆鍊� */ + let result = colWidth[0]; + for (let i = 1; i < colWidth.length; i++) { + for (let j = 0; j < colWidth[i].length; j++) { + if (result[j] && result[j]["wch"] < colWidth[i][j]["wch"]) { + result[j]["wch"] = colWidth[i][j]["wch"]; + } + } + } + // ws['!cols']璁剧疆鍗曞厓鏍煎搴�, [{'wch': 10},{'wch': 10}] ===> 绗竴鍒楀拰绗簩鍒楄缃簡瀹藉害 + ws["!cols"] = result; + } + /* add worksheet to workbook */ + wb.SheetNames.push(wsName); + wb.Sheets[wsName] = ws; + var wbout = XLSX.write(wb, { + bookType: bookType, + bookSST: false, // 鏄惁鐢熸垚Shared String Table锛屽畼鏂硅В閲婃槸锛屽鏋滃紑鍚敓鎴愰�熷害浼氫笅闄嶏紝浣嗗湪浣庣増鏈琁OS璁惧涓婃湁鏇村ソ鐨勫吋瀹规�� + type: "binary", + }); + saveAs( + new Blob([s2ab(wbout)], { type: "application/octet-stream" }), + `${filename}.${bookType}` + ); +} diff --git a/src/utils/exportFile.js b/src/utils/exportFile.js new file mode 100644 index 0000000..d0247bc --- /dev/null +++ b/src/utils/exportFile.js @@ -0,0 +1,19 @@ +import { exportJsonToExcel } from "./export2Excel"; + +function ExportFile(headers, list, name) { + let tHeader = []; + let filterVal = []; + headers.map((item, index) => { + tHeader.push(item.label); + filterVal.push(item.prop); + }); + let excelData = formatJson(filterVal, list); + + exportJsonToExcel({header: tHeader, data: excelData, filename: name}); +} + +function formatJson(filterVal, jsonData) { + return jsonData.map(v => filterVal.map(j => v[j])); +} + +export { ExportFile }; \ No newline at end of file diff --git a/src/utils/getQueryString.js b/src/utils/getQueryString.js new file mode 100644 index 0000000..057054b --- /dev/null +++ b/src/utils/getQueryString.js @@ -0,0 +1,11 @@ +//鑾峰彇杩炴帴涓殑鎸囧畾鍙傛暟 +function getQueryString(name) { + var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); + var r = window.location.href.replace(/^.*\?/, '').match(reg); + if (r != null) { + return decodeURI(r[2]); + } + return null; +} + +export default getQueryString; \ No newline at end of file diff --git a/src/utils/getTreeDataByKey.js b/src/utils/getTreeDataByKey.js new file mode 100644 index 0000000..c7af637 --- /dev/null +++ b/src/utils/getTreeDataByKey.js @@ -0,0 +1,36 @@ +/** + * 鏍规嵁key鍊艰幏鍙栨爲鐘惰妭鐐圭殑瀵硅薄 + * + * @param {[String]} key 鏌ヨ鐨勫�� + * @param {[Array]} treeData 鏍戠姸鏁版嵁 + * @param {[String]} nodeKey 瀵规瘮鐨勫睘鎬у悕锛岄粯璁や负id + * @param {[String]} childKey 瀛愯妭鐐圭殑灞炴�у悕 榛樿涓篶hildren + * @return {[Object]} 杩斿洖key鎵�鍦ㄧ殑鐨勫璞� -1琛ㄧず鏈幏鍙栧埌 + */ +function getTreeDataByKey(key, treeData, nodeKey, childKey) { + let id = nodeKey?nodeKey:'id'; + let child = childKey?childKey:'children'; + // 妫�娴嬫暟鎹笉鏄暟缁勶紙涓柇鍥炶皟鍑芥暟锛� + if(!(treeData instanceof Array)) { + return -1; + } + let result = -1; + // 閬嶅巻鏍戠姸鏁版嵁鑾峰彇涓庡彲浠ュ搴旂殑瀵硅薄 + for(let i=0; i<treeData.length; i++) { + let item = treeData[i]; + if(item[id] == key) { + result = item; + break; + }else { + result = getTreeDataByKey(key, item[child], nodeKey, childKey); + if(result != -1) { + break; + } + } + } + + return result; +} + +export default getTreeDataByKey; + diff --git a/src/utils/toFixed.js b/src/utils/toFixed.js new file mode 100644 index 0000000..d947af2 --- /dev/null +++ b/src/utils/toFixed.js @@ -0,0 +1,16 @@ +import digits from './const/const_digit'; + +function isNumeric(str) { + return !isNaN(Number(str)); +} + +function toFixed(value, bit) { + if (!isNumeric(value) || !isNumeric(bit)) return value; + const num = Math.pow(10, bit); + return Math.round(value * num) / num; +} + +export { + digits, + toFixed +}; \ No newline at end of file diff --git a/src/views/alarm/battAlarm.vue b/src/views/alarm/battAlarm.vue new file mode 100644 index 0000000..081c54e --- /dev/null +++ b/src/views/alarm/battAlarm.vue @@ -0,0 +1,501 @@ +<script setup name="battAlarm"> + import { ref, reactive, onMounted, computed, nextTick, watch, } 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 useStation from "@/hooks/useStationList.js"; + const { provice, city, country, stationName, + proviceList, cityList, countryList, stationList, + } = 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 useWebSocket from "@/hooks/useWebSocket.js"; + const { message, sendData } = useWebSocket("battAlmReal"); + + + import { + confirmBattAlm, + } from "@/api/alarm.js"; + + const { $loading, $message, $confirm } = useElement(); + + const alarmLevel = ref(); + const alarmLevels = [ + { + label: '涓�绾у憡璀�', + value: 1, + }, + { + label: '浜岀骇鍛婅', + value: 2, + }, + { + label: '涓夌骇鍛婅', + value: 3, + }, + { + label: '鍥涚骇鍛婅', + value: 4, + }, + ]; + +const headers = [ + // { + // prop: "provice", + // label: "鐪�", + // width: "80", + // }, + // { + // prop: "city", + // label: "甯�", + // width: "80", + // }, + // { + // prop: "country", + // label: "鍖哄幙", + // width: "80", + // }, + { + prop: "stationName", + label: "鏈烘埧鍚嶇О", + width: "160", + }, + // { + // prop: "stationType", + // label: "鐢靛帇绛夌骇", + // width: "80", + // }, + { + prop: "battgroupName", + label: "鐢垫睜缁勫悕绉�", + width: "120", + }, + { + prop: "almId", + label: "鍛婅绫诲瀷", + width: "120", + }, + { + prop: "almValue", + label: "鍛婅鍊�", + width: "120", + }, + { + prop: "monNum", + label: "鍗曚綋缂栧彿", + width: "120", + }, + { + prop: "almLevelStr", + label: "鍛婅绛夌骇", + width: "120", + }, + { + prop: "almStartTime", + label: "鍛婅寮�濮嬫椂闂�", + width: "120", + }, + { + prop: "almIsConfirmed", + label: "鍛婅鏄惁纭", + width: "120", + }, + { + prop: "almConfirmedTime", + label: "鍛婅纭鏃堕棿", + width: "120", + }, + ]; + + 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 datas = reactive({ + tableData: [], + rowData: {}, + }); + + // const tableData = reactive([]); + // const rowData = reactive({}); + + // const userStore = useUserStore(); + // const { uid, uname } = storeToRefs(userStore); + + // almIds: [119001], + // almLevel: "1", + // city: "姝︽眽甯�", + // country: "涓滆タ婀栧尯", + // pageNum: 1, + // pageSize: 10, + // provice: "婀栧寳鐪�", + // stationName: "娴嬭瘯鏈烘埧6", + function sendMessage() { + let params = { + // almIds: [119001], + almLevel: alarmLevel.value || undefined, + provice: provice.value || undefined, + city: city.value || undefined, + country: country.value || undefined, + stationName: stationName.value || undefined, + pageNum: pageCurr.value, + pageSize: pageSize.value, + }; + sendData(JSON.stringify(params)); + } + + function selectChange() { + nextTick(() => { + sendMessage(); + }); + } + + watch( + () => message.value, + (n) => { + if (n) { + let {code, data, data2} = JSON.parse(n); + let list = []; + let _total = 0; + if (code && data) { + // console.log(data); + list = data2.list.map(v => ({ + ...v, + almLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almLevel], + almIsConfirmedStr: ['鏈‘璁�', '宸茬‘璁�'][v.almIsConfirmed], + // roleName: roles[v.role], + })); + _total = data2.total; + } + datas.tableData = list; + total.value = _total; + } + } + ); + + + // 灞曠ず鏁版嵁鏁伴噺 + function handleSizeChange(val) { + pageSize.value = val; + sendMessage(); + } + // 缈婚〉 + function handleCurrentChange(val) { + pageCurr.value = val; + sendMessage(); + } + + function confirmAlarm(record) { + $confirm("纭鍛婅", () => { + let loading = $loading(); + confirmBattAlm(record.num) + .then((res) => { + let { code, data } = res; + loading.close(); + if (code && data) { + $message.success("鎿嶄綔鎴愬姛"); + sendMessage(); + } else { + $message.success("鎿嶄綔澶辫触"); + } + }) + .catch((err) => { + loading.close(); + console.log(err); + }); + }); + } + + 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, "鐢垫睜瀹炴椂鍛婅"); + } + + function goRt (row) { + router.push({ + path: '/datas/realtime', + query: { + id: row.battgroupId + } + }); + } + + + onMounted(() => { + sendMessage(); + }); +</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="table-row"> + <div class="table-cell text-right">鐪侊細</div> + <div class="table-cell"> + <el-select + v-model="provice" + size="small" + clearable + placeholder="璇烽�夋嫨鐪�" + @change="selectChange" + > + <el-option + v-for="item in proviceList" + :key="'l0_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">甯傦細</div> + <div class="table-cell"> + <el-select + v-model="city" + size="small" + clearable + placeholder="璇烽�夋嫨甯�" + @change="selectChange" + > + <el-option + v-for="item in cityList" + :key="'l1_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鍖哄幙:</div> + <div class="table-cell"> + <el-select + v-model="country" + clearable + size="small" + placeholder="璇烽�夋嫨鍖哄幙" + @change="selectChange" + > + <el-option + v-for="item in countryList" + :key="'l2_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">绔欑偣:</div> + <div class="table-cell"> + <el-select + v-model="stationName" + clearable + size="small" + placeholder="璇烽�夋嫨绔欑偣" + @change="selectChange" + > + <el-option + v-for="item in stationList" + :key="'l3_' + item.stationId" + :label="item.stationName" + :value="item.stationName" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鍛婅绛夌骇:</div> + <div class="table-cell"> + <el-select + v-model="alarmLevel" + clearable + size="small" + placeholder="璇烽�夋嫨鍛婅绛夌骇" + @change="selectChange" + > + <el-option + v-for="item in alarmLevels" + :key="item.value" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </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" v-if="!scope.row.almIsConfirmed" + @click="confirmAlarm(scope.row)">纭鍛婅</el-button> + <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="sendMessage" :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> + <!-- 寮圭獥 --> + <!-- <el-dialog :title="dialogTitle" v-model="addEditVisible" top="0" :close-on-click-modal="false" class="dialog-center" + width="860px" center> + <add-edit v-if="addEditVisible" @success="onOk" :info="datas.rowData" @cancel="onCanel"></add-edit> + </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; + } + + .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> \ No newline at end of file diff --git a/src/views/alarm/devAlarm.vue b/src/views/alarm/devAlarm.vue new file mode 100644 index 0000000..268b4f2 --- /dev/null +++ b/src/views/alarm/devAlarm.vue @@ -0,0 +1,495 @@ +<script setup name="devAlarm"> + import { ref, reactive, onMounted, computed, nextTick, watch, } 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 useStation from "@/hooks/useStationList.js"; + const { provice, city, country, stationName, + proviceList, cityList, countryList, stationList, + } = 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 useWebSocket from "@/hooks/useWebSocket.js"; + const { message, sendData } = useWebSocket("devAlmReal"); + + import { + confirmDevAlm, + } from "@/api/alarm.js"; + + const { $loading, $message, $confirm } = useElement(); + + const alarmLevel = ref(); + const alarmLevels = [ + { + label: '涓�绾у憡璀�', + value: 1, + }, + { + label: '浜岀骇鍛婅', + value: 2, + }, + { + label: '涓夌骇鍛婅', + value: 3, + }, + { + label: '鍥涚骇鍛婅', + value: 4, + }, + ]; + +const headers = [ + // { + // prop: "provice", + // label: "鐪�", + // width: "80", + // }, + // { + // prop: "city", + // label: "甯�", + // width: "80", + // }, + // { + // prop: "country", + // label: "鍖哄幙", + // width: "80", + // }, + { + prop: "fullName", + label: "鏈烘埧鍚嶇О", + width: "160", + }, + // { + // prop: "stationType", + // label: "鐢靛帇绛夌骇", + // width: "80", + // }, + { + prop: "devName", + label: "璁惧鍚嶇О", + width: "120", + }, + { + prop: "almId", + label: "鍛婅绫诲瀷", + width: "120", + }, + { + prop: "almValue", + label: "鍛婅鍊�", + width: "120", + }, + { + prop: "almLevelStr", + label: "鍛婅绛夌骇", + width: "120", + }, + { + prop: "almStartTime", + label: "鍛婅寮�濮嬫椂闂�", + width: "120", + }, + { + prop: "almIsConfirmed", + label: "鍛婅鏄惁纭", + width: "120", + }, + { + prop: "almConfirmedTime", + label: "鍛婅纭鏃堕棿", + width: "120", + }, + ]; + + 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 datas = reactive({ + tableData: [], + rowData: {}, + }); + + // const tableData = reactive([]); + // const rowData = reactive({}); + + // const userStore = useUserStore(); + // const { uid, uname } = storeToRefs(userStore); + + // almIds: [119001], + // almLevel: "1", + // city: "姝︽眽甯�", + // country: "涓滆タ婀栧尯", + // pageNum: 1, + // pageSize: 10, + // provice: "婀栧寳鐪�", + // stationName: "娴嬭瘯鏈烘埧6", + function sendMessage() { + let params = { + // almIds: [119001], + almLevel: alarmLevel.value || undefined, + provice: provice.value || undefined, + city: city.value || undefined, + country: country.value || undefined, + stationName: stationName.value || undefined, + pageNum: pageCurr.value, + pageSize: pageSize.value, + }; + sendData(JSON.stringify(params)); + } + + function selectChange() { + nextTick(() => { + sendMessage(); + }); + } + + watch( + () => message.value, + (n) => { + if (n) { + let {code, data, data2} = JSON.parse(n); + let list = []; + let _total = 0; + if (code && data) { + // console.log(data); + list = data2.list.map(v => ({ + ...v, + almLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almLevel], + almIsConfirmedStr: ['鏈‘璁�', '宸茬‘璁�'][v.almIsConfirmed], + // roleName: roles[v.role], + })); + _total = data2.total; + } + datas.tableData = list; + total.value = _total; + } + } + ); + + + // 灞曠ず鏁版嵁鏁伴噺 + function handleSizeChange(val) { + pageSize.value = val; + sendMessage(); + } + // 缈婚〉 + function handleCurrentChange(val) { + pageCurr.value = val; + sendMessage(); + } + + function confirmAlarm(record) { + $confirm("纭鍛婅", () => { + let loading = $loading(); + confirmDevAlm(record.num) + .then((res) => { + let { code, data } = res; + loading.close(); + if (code && data) { + $message.success("鎿嶄綔鎴愬姛"); + sendMessage(); + } else { + $message.success("鎿嶄綔澶辫触"); + } + }) + .catch((err) => { + loading.close(); + console.log(err); + }); + }); + } + + 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, "鐢垫睜瀹炴椂鍛婅"); + } + + function goRt (row) { + router.push({ + path: '/datas/realtime', + query: { + id: row.battgroupId + } + }); + } + + + onMounted(() => { + sendMessage(); + }); +</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="table-row"> + <div class="table-cell text-right">鐪侊細</div> + <div class="table-cell"> + <el-select + v-model="provice" + size="small" + clearable + placeholder="璇烽�夋嫨鐪�" + @change="selectChange" + > + <el-option + v-for="item in proviceList" + :key="'l0_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">甯傦細</div> + <div class="table-cell"> + <el-select + v-model="city" + size="small" + clearable + placeholder="璇烽�夋嫨甯�" + @change="selectChange" + > + <el-option + v-for="item in cityList" + :key="'l1_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鍖哄幙:</div> + <div class="table-cell"> + <el-select + v-model="country" + clearable + size="small" + placeholder="璇烽�夋嫨鍖哄幙" + @change="selectChange" + > + <el-option + v-for="item in countryList" + :key="'l2_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">绔欑偣:</div> + <div class="table-cell"> + <el-select + v-model="stationName" + clearable + size="small" + placeholder="璇烽�夋嫨绔欑偣" + @change="selectChange" + > + <el-option + v-for="item in stationList" + :key="'l3_' + item.stationId" + :label="item.stationName" + :value="item.stationName" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鍛婅绛夌骇:</div> + <div class="table-cell"> + <el-select + v-model="alarmLevel" + clearable + size="small" + placeholder="璇烽�夋嫨鍛婅绛夌骇" + @change="selectChange" + > + <el-option + v-for="item in alarmLevels" + :key="item.value" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </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" v-if="!scope.row.almIsConfirmed" + @click="confirmAlarm(scope.row)">纭鍛婅</el-button> + <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="sendMessage" :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> + <!-- 寮圭獥 --> + <!-- <el-dialog :title="dialogTitle" v-model="addEditVisible" top="0" :close-on-click-modal="false" class="dialog-center" + width="860px" center> + <add-edit v-if="addEditVisible" @success="onOk" :info="datas.rowData" @cancel="onCanel"></add-edit> + </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; + } + + .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> \ No newline at end of file diff --git a/src/views/alarm/pwrAlarm.vue b/src/views/alarm/pwrAlarm.vue new file mode 100644 index 0000000..a830a18 --- /dev/null +++ b/src/views/alarm/pwrAlarm.vue @@ -0,0 +1,503 @@ +<script setup name="pwrAlarm"> + import { ref, reactive, onMounted, computed, nextTick, watch, } 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 useStation from "@/hooks/useStationList.js"; + const { provice, city, country, stationName, + proviceList, cityList, countryList, stationList, + } = 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 useWebSocket from "@/hooks/useWebSocket.js"; + const { message, sendData } = useWebSocket("pwrAlmReal"); + + import { + getAllUser, + deleteUser, + dropRole, + improveRole, + resetSnId, + } from "@/api/user"; + + import { + confirmPwrAlm, + } from "@/api/alarm.js"; + + const { $loading, $message, $confirm } = useElement(); + + const alarmLevel = ref(); + const alarmLevels = [ + { + label: '涓�绾у憡璀�', + value: 1, + }, + { + label: '浜岀骇鍛婅', + value: 2, + }, + { + label: '涓夌骇鍛婅', + value: 3, + }, + { + label: '鍥涚骇鍛婅', + value: 4, + }, + ]; + +const headers = [ + // { + // prop: "provice", + // label: "鐪�", + // width: "80", + // }, + // { + // prop: "city", + // label: "甯�", + // width: "80", + // }, + // { + // prop: "country", + // label: "鍖哄幙", + // width: "80", + // }, + { + prop: "fullName", + label: "鏈烘埧鍚嶇О", + width: "160", + }, + // { + // prop: "stationType", + // label: "鐢靛帇绛夌骇", + // width: "80", + // }, + { + prop: "powerName", + label: "鐢垫簮鍚嶇О", + width: "120", + }, + { + prop: "almId", + label: "鍛婅绫诲瀷", + width: "120", + }, + { + prop: "almValue", + label: "鍛婅鍊�", + width: "120", + }, + { + prop: "almLevelStr", + label: "鍛婅绛夌骇", + width: "120", + }, + { + prop: "almStartTime", + label: "鍛婅寮�濮嬫椂闂�", + width: "120", + }, + { + prop: "almIsConfirmed", + label: "鍛婅鏄惁纭", + width: "120", + }, + { + prop: "almConfirmedTime", + label: "鍛婅纭鏃堕棿", + width: "120", + }, + ]; + + 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 datas = reactive({ + tableData: [], + rowData: {}, + }); + + // const tableData = reactive([]); + // const rowData = reactive({}); + + // const userStore = useUserStore(); + // const { uid, uname } = storeToRefs(userStore); + + // almIds: [119001], + // almLevel: "1", + // city: "姝︽眽甯�", + // country: "涓滆タ婀栧尯", + // pageNum: 1, + // pageSize: 10, + // provice: "婀栧寳鐪�", + // stationName: "娴嬭瘯鏈烘埧6", + function sendMessage() { + let params = { + // almIds: [119001], + almLevel: alarmLevel.value || undefined, + provice: provice.value || undefined, + city: city.value || undefined, + country: country.value || undefined, + stationName: stationName.value || undefined, + pageNum: pageCurr.value, + pageSize: pageSize.value, + }; + sendData(JSON.stringify(params)); + } + + function selectChange() { + nextTick(() => { + sendMessage(); + }); + } + + watch( + () => message.value, + (n) => { + if (n) { + let {code, data, data2} = JSON.parse(n); + let list = []; + let _total = 0; + if (code && data) { + // console.log(data); + list = data2.list.map(v => ({ + ...v, + almLevelStr: ['', '涓�绾у憡璀�', '浜岀骇鍛婅', '涓夌骇鍛婅', '鍥涚骇鍛婅'][v.almLevel], + almIsConfirmedStr: ['鏈‘璁�', '宸茬‘璁�'][v.almIsConfirmed], + // roleName: roles[v.role], + })); + _total = data2.total; + } + datas.tableData = list; + total.value = _total; + } + } + ); + + + // 灞曠ず鏁版嵁鏁伴噺 + function handleSizeChange(val) { + pageSize.value = val; + sendMessage(); + } + // 缈婚〉 + function handleCurrentChange(val) { + pageCurr.value = val; + sendMessage(); + } + + function confirmAlarm(record) { + $confirm("纭鍛婅", () => { + let loading = $loading(); + confirmPwrAlm(record.num) + .then((res) => { + let { code, data } = res; + loading.close(); + if (code && data) { + $message.success("鎿嶄綔鎴愬姛"); + sendMessage(); + } else { + $message.success("鎿嶄綔澶辫触"); + } + }) + .catch((err) => { + loading.close(); + console.log(err); + }); + }); + } + + 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, "鐢垫睜瀹炴椂鍛婅"); + } + + function goRt (row) { + router.push({ + path: '/datas/realtime', + query: { + id: row.battgroupId + } + }); + } + + + onMounted(() => { + sendMessage(); + }); +</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="table-row"> + <div class="table-cell text-right">鐪侊細</div> + <div class="table-cell"> + <el-select + v-model="provice" + size="small" + clearable + placeholder="璇烽�夋嫨鐪�" + @change="selectChange" + > + <el-option + v-for="item in proviceList" + :key="'l0_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">甯傦細</div> + <div class="table-cell"> + <el-select + v-model="city" + size="small" + clearable + placeholder="璇烽�夋嫨甯�" + @change="selectChange" + > + <el-option + v-for="item in cityList" + :key="'l1_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鍖哄幙:</div> + <div class="table-cell"> + <el-select + v-model="country" + clearable + size="small" + placeholder="璇烽�夋嫨鍖哄幙" + @change="selectChange" + > + <el-option + v-for="item in countryList" + :key="'l2_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">绔欑偣:</div> + <div class="table-cell"> + <el-select + v-model="stationName" + clearable + size="small" + placeholder="璇烽�夋嫨绔欑偣" + @change="selectChange" + > + <el-option + v-for="item in stationList" + :key="'l3_' + item.stationId" + :label="item.stationName" + :value="item.stationName" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鍛婅绛夌骇:</div> + <div class="table-cell"> + <el-select + v-model="alarmLevel" + clearable + size="small" + placeholder="璇烽�夋嫨鍛婅绛夌骇" + @change="selectChange" + > + <el-option + v-for="item in alarmLevels" + :key="item.value" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </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" v-if="!scope.row.almIsConfirmed" + @click="confirmAlarm(scope.row)">纭鍛婅</el-button> + <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="sendMessage" :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> + <!-- 寮圭獥 --> + <!-- <el-dialog :title="dialogTitle" v-model="addEditVisible" top="0" :close-on-click-modal="false" class="dialog-center" + width="860px" center> + <add-edit v-if="addEditVisible" @success="onOk" :info="datas.rowData" @cancel="onCanel"></add-edit> + </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; + } + + .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> \ No newline at end of file diff --git a/src/views/datas/addEdit.vue b/src/views/datas/addEdit.vue index e01751d..77df8df 100644 --- a/src/views/datas/addEdit.vue +++ b/src/views/datas/addEdit.vue @@ -448,7 +448,7 @@ form1[key] = info[key]; } - addBinfFlag.value = !!info.battgroupId * 1; + addBinfFlag.value = info.stationId ? !!info.battgroupId * 1 : 1; if (info.addBattFlag) { if (!info.devId) { addDevFlag.value = 1; diff --git a/src/views/datas/device.vue b/src/views/datas/device.vue index 306e0bf..75b4786 100644 --- a/src/views/datas/device.vue +++ b/src/views/datas/device.vue @@ -1,5 +1,5 @@ -<script setup name="UserManage"> - import { ref, reactive, onMounted, computed } from "vue"; +<script setup name="device"> + 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"; @@ -14,17 +14,16 @@ } = useStation(); import powerTypes from '@/utils/const/const_powerType.js'; + import { + delBatt, + getPowerBrand, + getVoltageLevel, + } from "@/api/station"; const userStore = useUserStore(); const { uid, uname } = storeToRefs(userStore); - import { - getAllUser, - deleteUser, - dropRole, - improveRole, - resetSnId, - } from "@/api/user"; + import { getDevList, @@ -149,6 +148,12 @@ width: "120", }, ]; + + const company = ref(""); + const companyList = ref([]); + const volLevels = ref([]); + const powerType = ref(''); + const stationType = ref(''); const background = ref(true); const disabled = ref(false); const pageCurr = ref(1); @@ -163,6 +168,10 @@ rowData: {}, }); + const powerTypeList = computed(() => { + return Object.keys(powerTypes).map(v => ({ label: powerTypes[v], value: v * 1 })); + }); + // const tableData = reactive([]); // const rowData = reactive({}); @@ -172,13 +181,15 @@ function getList() { let loading = $loading(); let params = { - // city: "", - // country: "", + provice: provice.value || undefined, + city: city.value || undefined, + country: country.value || undefined, + stationName: stationName.value || undefined, + powerType: powerType.value || undefined, + stationType: stationType.value || undefined, pageNum: pageCurr.value, pageSize: pageSize.value, // powerName: "", - // provice: "", - // stationName: "", }; getDevList(params) @@ -207,6 +218,30 @@ }); } + function getCompanyList() { + getPowerBrand().then((res) => { + let { code, data, data2 } = res; + let list = []; + if (code && data) { + list = data2; + } + companyList.value = list; + }); + } + + // 鑾峰彇鐢靛帇绛夌骇 + function getVolLevels() { + console.log("鑾峰彇鐢靛帇绛夌骇"); + getVoltageLevel().then((res) => { + let { code, data, data2 } = res; + let list = []; + if (code && data) { + list = data2; + } + volLevels.value = list; + }); + } + // 灞曠ず鏁版嵁鏁伴噺 function handleSizeChange(val) { pageSize.value = val; @@ -219,7 +254,7 @@ } function add() { dialogTitle.value = "娣诲姞璁惧"; - datas.rowData = null; + datas.rowData = {}; addEditVisible.value = true; } function edit(record) { @@ -241,13 +276,14 @@ } function confirmRemove(record) { - $confirm("鍒犻櫎璇ョ敤鎴�", () => { - remove(record.name); + $confirm("鍒犻櫎", () => { + let { stationId, powerId, battgroupId } = record; + remove(stationId, powerId, battgroupId||undefined); }); } - function remove(uname) { + function remove(stationId, powerId, battgroupId) { let loading = $loading(); - deleteUser(uname) + delBatt(stationId, powerId, battgroupId) .then((res) => { let { code, data } = res; loading.close(); @@ -270,59 +306,18 @@ function onCanel() { addEditVisible.value = false; } - function improveRolefn(record) { - let loading = $loading(); - improveRole(record.id) - .then((res) => { - let { code, data, msg } = res; - loading.close(); - if (code && data) { - $message.success(msg); - getList(); - } else { - $message.error(msg); - } - }) - .catch((err) => { - console.log(err); - loading.close(); - }); - } - function dropRolefn(record) { - let loading = $loading(); - dropRole(record.id) - .then((res) => { - let { code, data, msg } = res; - loading.close(); - if (code && data) { - $message.success(msg); - getList(); - } else { - $message.error(msg); - } - }) - .catch((err) => { - loading.close(); - console.log(err); - }); - } - function resetSnIdfn(record) { - $confirm("閲嶇疆璇ョ敤鎴峰瘑鐮�", () => { - let loading = $loading(); - resetSnId(record.id).then((res) => { - let { code, data, msg } = res; - if (code && data) { - $message.success(msg); - } else { - $message.error(msg); - } - loading.close(); - }); - }); - } + + function filterChange() { + nextTick(() => { + pageCurr.value = 1; + getList(); + }); + } onMounted(() => { + getCompanyList(); + getVolLevels(); getList(); }); </script> @@ -341,6 +336,8 @@ <el-select v-model="provice" size="small" + clearable + @change="filterChange" placeholder="璇烽�夋嫨鐪�" > <el-option @@ -357,6 +354,8 @@ <el-select v-model="city" size="small" + clearable + @change="filterChange" placeholder="璇烽�夋嫨甯�" > <el-option @@ -373,6 +372,8 @@ <el-select v-model="country" size="small" + clearable + @change="filterChange" placeholder="璇烽�夋嫨鍖哄幙" > <el-option @@ -389,6 +390,8 @@ <el-select v-model="stationName" size="small" + clearable + @change="filterChange" placeholder="璇烽�夋嫨绔欑偣" > <el-option @@ -400,16 +403,36 @@ </el-option> </el-select> </div> - <div class="table-cell text-right">鍝佺墝:</div> + <!-- <div class="table-cell text-right">鍝佺墝:</div> <div class="table-cell"> <el-select - v-model="country" + v-model="company" size="small" + clearable + @change="filterChange" placeholder="璇烽�夋嫨鍝佺墝" > <el-option - v-for="item in countryList" - :key="item.value" + v-for="(item, idx) in companyList" + :key="'list4_' + idx" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> --> + <div class="table-cell text-right">鐢垫簮绫诲瀷:</div> + <div class="table-cell"> + <el-select + v-model="powerType" + size="small" + clearable + @change="filterChange" + placeholder="璇烽�夋嫨鍝佺墝" + > + <el-option + v-for="(item, idx) in powerTypeList" + :key="'list4_' + idx" :label="item.label" :value="item.value" > @@ -419,15 +442,17 @@ <div class="table-cell text-right">鐢靛帇绛夌骇:</div> <div class="table-cell"> <el-select - v-model="country" + v-model="stationType" size="small" + clearable + @change="filterChange" placeholder="璇烽�夋嫨鐢靛帇绛夌骇" > <el-option - v-for="item in countryList" - :key="item.value" - :label="item.label" - :value="item.value" + v-for="(item, idx) in volLevels" + :key="'list5_' + idx" + :label="item" + :value="item" > </el-option> </el-select> @@ -445,11 +470,11 @@ </el-table-column> <el-table-column label="鎿嶄綔" fixed="right" width="240" align="center"> <template #default="scope"> - <el-button type="primary" size="small" :disabled="scope.row.name == uname" + <el-button type="primary" size="small" @click="edit(scope.row)">缂栬緫</el-button> - <el-button type="danger" size="small" :disabled="scope.row.name == uname" + <el-button type="danger" size="small" @click="confirmRemove(scope.row)">鍒犻櫎</el-button> - <el-button type="primary" size="small" :disabled="scope.row.name == uname" + <el-button type="primary" size="small" @click="addBatt(scope.row)">娣诲姞鐢垫睜缁�</el-button> </template> </el-table-column> diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 8e365e8..25d1150 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -145,6 +145,11 @@ password: '', verify: '' }); + +// TODO +loginForm.username = 'hw'; +loginForm.password = '123456'; + const loginRules = reactive({ username: [{ required: true, trigger: 'blur', validator: validateUsername }], password: [{ required: true, trigger: 'blur', validator: validatePassword }] diff --git a/src/views/realtime/bar8.vue b/src/views/realtime/bar8.vue new file mode 100644 index 0000000..d57e788 --- /dev/null +++ b/src/views/realtime/bar8.vue @@ -0,0 +1,170 @@ +<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/index.vue b/src/views/realtime/index.vue index 0b04e2f..a4943e1 100644 --- a/src/views/realtime/index.vue +++ b/src/views/realtime/index.vue @@ -1,23 +1,62 @@ -<script setup> -import { ref, reactive } from "vue"; +<script setup name="realtime"> +import { ref, reactive, watch, onMounted } from "vue"; import tabPower from "./tabs/power.vue"; import tabSystem from "./tabs/system.vue"; +import tabVol from './tabs/vol.vue'; +import siteList from "@/components/siteList/index.vue"; +import getQueryString from "@/utils/getQueryString"; +import formatSeconds from '@/utils/formatSeconds'; + +import { useRoute, useRouter } from "vue-router"; +import useWebsocket from "@/hooks/useWebsocket"; + +const route = useRoute(); +const router = useRouter(); + +const { message, sendData } = useWebsocket('real'); + +const curStationId = ref( + getQueryString("stationId") || '' +); + +const curPowerId = ref( + getQueryString("powerId") || '' +); + +const curBattgroupId = ref( + getQueryString("battgroupId") || '' +); + +const curDevId = ref( + getQueryString("devId") || '' +); + +const rtData = reactive({ + system: {}, + power: {}, + vol: {}, + res: {}, + tmp: {}, + threeD: {}, + self: {}, + manage: {}, +}); const statusList = reactive([ - { label: '绯荤粺鐘舵��', value: '鍏呯數' }, - { label: '璁惧鐘舵��', value: '姝e父' }, - { label: '鐢垫簮鐘舵��', value: '姝e父' }, - { label: '鐢垫睜鐘舵��', value: '姝e父' }, - { label: '姣嶇嚎鐢靛帇', value: 60 }, - { label: '鍦ㄧ嚎鐢靛帇', value: 60 }, - { label: '缁勭鐢靛帇', value: 60 }, - { label: '鐢垫睜鐢垫祦', value: 60 }, - { label: '娴嬭瘯鏃堕暱', value: 60 }, - { label: '娴嬭瘯瀹归噺', value: 60 }, - { label: '棰勪及鍓╀綑瀹归噺', value: 60 }, - { label: '棰勪及鍓╀綑缁埅', value: 60 }, - { label: '鍛婅', value: '鏃�' }, - { label: '鏇存柊鏃ユ湡', value: '2022-01-01' }, + { label: '绯荤粺鐘舵��', prop: 'systemState', unit: '' }, + { label: '璁惧鐘舵��', prop: 'devState', unit: '' }, + { label: '鐢垫簮鐘舵��', prop: 'pwrState', unit: '' }, + { label: '鐢垫睜鐘舵��', prop: 'battState', unit: '' }, + { label: '姣嶇嚎鐢靛帇', prop: 'vbusVol', unit: 'V' }, + { label: '鍦ㄧ嚎鐢靛帇', prop: 'onlineVol', unit: 'V' }, + { label: '缁勭鐢靛帇', prop: 'captestGroupvol', unit: 'V' }, + { label: '鐢垫睜鐢垫祦', prop: 'captestCurr', unit: 'A' }, + { label: '娴嬭瘯鏃堕暱', prop: 'captestTimelong', unit: '' }, + { label: '娴嬭瘯瀹归噺', prop: 'captestCap', unit: 'Ah' }, + { label: '棰勪及鍓╀綑瀹归噺', prop: 'restCap', unit: 'Ah' }, + { label: '棰勪及鍓╀綑缁埅', prop: 'restTime', unit: '' }, + { label: '鍛婅', prop: 'allALmNum', unit: '' }, + { label: '鏇存柊鏃ユ湡', prop: 'recordtime', unit: '' }, ]); const tabs = ref([ @@ -25,10 +64,13 @@ { label: '鐢垫簮', name: 'power' }, { label: '鐢靛帇', name: 'vol' }, { label: '鍐呴樆', name: 'res' }, - { label: '娓╁害', name: 'temp' }, - { label: '3D', name: '3d' }, + { label: '娓╁害', name: 'tmp' }, + { label: '3D', name: '3D' }, { label: '鑷剤鑳藉姏', name: 'self' }, { label: '绠$悊淇℃伅', name: 'manage' }, +]); + +const btns = ref([ { label: '鐢垫簮鍛婅鍙傛暟璁剧疆', name: 'powerAlarmSet' }, { label: '鐢垫睜鍛婅鍙傛暟璁剧疆', name: 'battAlarmSet' }, { label: '鍥剧墖', name: 'img' }, @@ -39,56 +81,139 @@ const acTab = ref(tabs.value[0].name); const fullName = ref('婀栧寳鐪�-姝︽眽甯�-姝︽槍鍖�-姝︽槍鏈烘埧-鐢垫睜缁�1'); +const topData = ref({}); + +function sendMessage() { + let params = { + stationId: curStationId.value || 0, + powerId: curPowerId.value || 0, + devId: curDevId.value || 0, + battgroupId: curBattgroupId.value || 0, + // system, power, vol, res, tmp, 3D, self, manage + pageType: acTab.value + }; + sendData(JSON.stringify(params)); +} function tabClick(item) { acTab.value = item.name; + sendMessage(); } + +function btnClick(item) { + console.log('item', item, '============='); + +} +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; + + 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; +} + + + +watch( + () => message.value, + (n) => { + if (n) { + let {data2: { topRes, realRes}} = JSON.parse(n); + let data = {}; + if (topRes.code && topRes.data) { + data = topRes.data2; + fullName.value = `${data.fullName} ${data.powerName} ${data.devName} ${data.battGroupName}`; + } + topData.value = data; + if (realRes.code && realRes.data) { + // rtData. + rtData['system'] = realRes.data2; + } + } + } +) + + + +onMounted(() => { + sendMessage(); +}); </script> <template> <div class="page-contain"> - <div class="page-header"> - <div class="p-title">{{ fullName }}</div> - <div class="status-bar"> - <div - :class="['status-item',]" - v-for="(item, index) in statusList" - :key="'status_' + index" - > - <div class="item-value">{{ item.value }}</div> - <div class="item-name">{{ item.label }}</div> + <site-list @leaf-click="leafClick"></site-list> + <div class="page-inner"> + <div class="page-header"> + <div class="p-title">{{ fullName }}</div> + <div class="status-bar"> + <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'">{{ topData[item.prop] ? formatSeconds(topData[item.prop]) : '--' }}</div> + <div class="item-value time" v-else-if="item.prop == 'recordtime'">{{ topData[item.prop] || '--' }}</div> + <div class="item-value" v-else>{{ topData[item.prop] || '--' }}{{ item.unit }}</div> + <div class="item-name">{{ item.label }}</div> + </div> + </div> + <div class="p-tabs"> + <div + :class="['tab-item', {'active': item.name == acTab}]" + v-for="(item, index) in tabs" + :key="'tab_' + index" + @click="tabClick(item)" + > + {{ item.label }} + </div> + <div + class="btn-item tab-item" + v-for="(item, index) in btns" + :key="'btn_' + index" + @click="btnClick(item)" + > + {{ item.label }} + </div> </div> </div> - <div class="p-tabs"> - <div - :class="['tab-item', {'active': item.name == acTab}]" - v-for="(item, index) in tabs" - :key="'tab_' + index" - @click="tabClick(item)" - > - {{ item.label }} + <div class="page-main"> + <div class="tab-contain" v-if="acTab == 'system'"> + <tab-system :data="rtData['system']"></tab-system> </div> + <div class="tab-contain" v-if="acTab == 'power'"> + <tab-power></tab-power> + </div> + <div class="tab-contain" v-if="acTab == 'vol'"> + <tab-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 == '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 == 'powerAlarmSet'">8</div> + <div class="tab-contain" v-if="acTab == 'battAlarmSet'">9</div> + <div class="tab-contain" v-if="acTab == 'img'">10</div> + <div class="tab-contain" v-if="acTab == 'history'">11</div> + <div class="tab-contain" v-if="acTab == 'hisRt'">12</div> --> </div> - </div> - <div class="page-main"> - <div class="tab-contain" v-if="acTab == 'system'"> - <tab-system></tab-system> - </div> - <div class="tab-contain" v-if="acTab == 'power'"> - <tab-power></tab-power> - </div> - <div class="tab-contain" v-if="acTab == 'vol'">2</div> - <div class="tab-contain" v-if="acTab == 'res'">3</div> - <div class="tab-contain" v-if="acTab == 'temp'">4</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 == 'powerAlarmSet'">8</div> - <div class="tab-contain" v-if="acTab == 'battAlarmSet'">9</div> - <div class="tab-contain" v-if="acTab == 'img'">10</div> - <div class="tab-contain" v-if="acTab == 'history'">11</div> - <div class="tab-contain" v-if="acTab == 'hisRt'">12</div> </div> </div> </template> @@ -96,7 +221,15 @@ <style scoped lang="less"> .page-contain { display: flex; - flex-direction: column; + padding: 8px 8px 8px 0; + margin-left: 8px; + overflow: hidden; + .page-inner { + display: flex; + flex-direction: column; + flex: 1; + margin-left: 8px; + } .page-header { // border: 1px solid #0ff; @@ -125,7 +258,7 @@ color: #50c7f1; // border: 1px solid #0F6B79; border-radius: 6px; - margin: 4px 6px; + margin: 4px 2px; display: flex; flex-direction: column; justify-content: center; @@ -140,6 +273,10 @@ margin-bottom: 6px; color: #ff0; font-size: 20px; + &.time { + white-space: nowrap; + font-size: 12px; + } } .item-name { @@ -171,6 +308,10 @@ background: #47CAFE; color: #03216e; } + &.btn-item { + background: #076fe8; + // border-radius: 6px; + } } } } diff --git a/src/views/realtime/tabs/system.vue b/src/views/realtime/tabs/system.vue index 574443b..0056ad8 100644 --- a/src/views/realtime/tabs/system.vue +++ b/src/views/realtime/tabs/system.vue @@ -1,5 +1,20 @@ <script setup> import { ref } from "vue"; +import svgDiagram from '@/components/svgDiagram.vue'; +import info from '@/components/info.vue'; +// import lineChart from '@/components/echarts/line1.vue'; +import lineChart from '@/components/echarts/BaseChart.vue'; +// import lineChart from '../bar8.vue'; + +const props = defineProps({ + data: { + type: Object, + default: {}, + }, +}); + +const tabIdx0 = ref(0); +const tabIdx1 = ref(0); </script> @@ -23,40 +38,42 @@ </div> </div> <div class="p-item"> - <div class="panel-title">褰撳墠鏍稿淇℃伅</div> + <div class="panel-title">涓婃鏍囧噯鏍稿淇℃伅</div> <div class="panel"> <div class="panel-row"> - <div class="label">鍋滄鍘熷洜</div> + <div class="label">寮�濮嬫椂闂�</div> <div class="value">鏃�</div> </div> <div class="panel-row"> - <div class="label">鍋滄鍘熷洜</div> + <div class="label">娴嬭瘯瀹归噺</div> <div class="value">鏃�</div> </div> <div class="panel-row"> - <div class="label">鍋滄鍘熷洜</div> + <div class="label">娴嬭瘯鏃堕暱</div> <div class="value">鏃�</div> </div> <div class="panel-row"> - <div class="label">鍋滄鍘熷洜</div> + <div class="label">棰勪及瀹归噺</div> <div class="value">鏃�</div> </div> <div class="panel-row"> - <div class="label">鍋滄鍘熷洜</div> + <div class="label">缁堟鍘熷洜</div> <div class="value">鏃�</div> </div> </div> </div> </div> - <div class="p-main"></div> + <div class="p-main"> + <svg-diagram class="svg-diagram"></svg-diagram> + </div> <div class="p-right"> <div class="control-contain"> - <div class="control-title">鎺у埗绠$悊</div> + <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> <div class="control-contain"> - <div class="control-title">璁惧绠$悊</div> + <div class="control-title"><svg-icon icon-class="dev"></svg-icon><span>璁惧绠$悊</span></div> <div class="control-btn">杩滅▼閲嶅惎</div> <div class="control-btn">绯荤粺鍙傛暟璁剧疆</div> <div class="control-btn">鍛婅鍙傛暟璁剧疆</div> @@ -69,16 +86,72 @@ </div> <div class="row row2"> <div class="card-item"> - <card title="浜ゆ祦杈撳叆"></card> + <card title="浜ゆ祦杈撳叆"> + <template #tools> + <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></line-chart> + </card> </div> <div class="card-item"> - <card title="鐩存祦杈撳叆"></card> + <card title="鐩存祦杈撳叆"> + <template #tools> + <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> + </card> </div> <div class="card-item"> - <card title="鏍稿璁惧淇℃伅"></card> + <card title="鏍稿璁惧淇℃伅"> + <template #tools> + <svg-icon class-name="btn-setting" icon-class="setting"></svg-icon> + </template> + </card> </div> <div class="card-item"> - <card title="钃勭數姹犱俊鎭�"></card> + <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> + </div> + </card> </div> </div> </div> @@ -106,6 +179,9 @@ margin: 8px; display: flex; flex-direction: column; + .panel-title { + font-size: 24px; + } .panel { border: 1px solid #5FA9CF; background: #073451; @@ -162,6 +238,9 @@ text-align: center; font-weight: 700; margin-bottom: 4px; + span { + margin-left: 0.6em; + } } .control-btn { margin: 2px 4px; @@ -206,5 +285,58 @@ } } } + .svg-diagram { + + } + + .btn-setting { + display: inline-block; + cursor: pointer; + margin-left: 0.4em; + transition: all 1.3s ease; + &:hover { + transform: rotate(360deg); + color: #FDFE01; + } + } + + .batt.grid { + height: 100%; + padding: 4px 6px; + display: grid; + grid-template-columns: repeat(2, 1fr); + // grid-template-rows: repeat(4, 1fr); + gap: 12px; + place-content: center; + } + + .tab-idx { + + :deep(.el-radio-button:first-child .el-radio-button__inner) { + border-left: 1px solid #4D81BA; + border-radius: 0; + box-shadow: none !important; + } + // .el-radio-button--small .el-radio-button__inner { + // border-radius: 0; + // font-size: 12px; + // padding: 5px 11px; + // } + :deep(.el-radio-button__inner) { + background: #183A55; + border: 1px solid #4D81BA; + border-left: 0; + border-radius: 0; + color: #fff; + font-weight: 500; + padding: 4px 10px; + } + :deep(.el-radio-button.is-active .el-radio-button__original-radio:not(:disabled)+.el-radio-button__inner) { + background: linear-gradient(69deg, #6EABE4, #6EABE4 25%, #0A3E77 75%, #0A3E77); + // border: 0 none; + box-shadow: none; + color: #fff; + } + } } </style> \ No newline at end of file diff --git a/src/views/realtime/tabs/vol.vue b/src/views/realtime/tabs/vol.vue new file mode 100644 index 0000000..9044e8c --- /dev/null +++ b/src/views/realtime/tabs/vol.vue @@ -0,0 +1,16 @@ +<script setup> +import { ref } from "vue"; +import test from '@/components/info.vue'; + +</script> + +<template> + <test + label="鐢靛帇" + value="123" + ></test> +</template> + +<style scoped lang="less"> + +</style> \ No newline at end of file diff --git a/src/views/statistics/batt.vue b/src/views/statistics/batt.vue new file mode 100644 index 0000000..166cff9 --- /dev/null +++ b/src/views/statistics/batt.vue @@ -0,0 +1,516 @@ +<script setup name="batt"> + import { ref, reactive, onMounted, computed } 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 powerTypes from '@/utils/const/const_powerType.js'; + import { + delBatt, + } from "@/api/station"; + + const userStore = useUserStore(); + const { uid, uname } = storeToRefs(userStore); + + + + import { + getDevList, + } from "@/api/station"; + + const { $loading, $message, $confirm } = useElement(); + + const headers = [ + { + prop: "provice", + label: "鐪�", + width: "80", + }, + { + prop: "city", + label: "甯�", + width: "80", + }, + { + prop: "country", + label: "鍖哄幙", + width: "80", + }, + { + prop: "stationName", + label: "鏈烘埧鍚嶇О", + width: "160", + }, + { + prop: "stationType", + label: "鐢靛帇绛夌骇", + width: "80", + }, + { + prop: "longitude", + label: "缁忓害", + width: "80", + }, + { + prop: "latitude", + label: "绾害", + width: "80", + }, + { + prop: "powerName", + label: "鐢垫簮鍚嶇О", + width: "80", + }, + { + prop: "powerTypeStr", + label: "鐢垫簮绫诲瀷", + width: "80", + }, + { + prop: "company", + label: "鐢垫簮鍝佺墝", + width: "80", + }, + { + prop: "powerModel", + label: "鐢垫簮鍨嬪彿", + width: "80", + }, + { + prop: "protocol", + label: "鐢垫簮鍗忚", + width: "80", + }, + { + prop: "powerIp", + label: "鐢垫簮IP", + width: "120", + }, + { + prop: "devName", + label: "璁惧鍚嶇О", + width: "120", + }, + { + prop: "devType", + label: "璁惧鍨嬪彿", + width: "120", + }, + { + prop: "devIp", + label: "璁惧IP", + width: "120", + }, + { + prop: "battgroupName", + label: "鐢垫睜缁勫悕绉�", + width: "120", + }, + { + prop: "moncount", + label: "鐢垫睜鍗曚綋涓暟", + width: "120", + }, + { + prop: "monvolstd", + label: "鐢垫睜鏍囩О鐢靛帇", + width: "120", + }, + { + prop: "moncapstd", + label: "鐢垫睜鏍囩О瀹归噺", + width: "120", + }, + { + prop: "monresstd", + label: "鐢垫睜鏍囩О鍐呴樆", + width: "120", + }, + { + prop: "product", + label: "鐢垫睜鍝佺墝", + width: "120", + }, + { + prop: "battModel", + label: "鐢垫睜鍨嬪彿", + width: "120", + }, + ]; + 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 datas = reactive({ + tableData: [], + rowData: {}, + }); + + // const tableData = reactive([]); + // const rowData = reactive({}); + + // const userStore = useUserStore(); + // const { uid, uname } = storeToRefs(userStore); + + function getList() { + let loading = $loading(); + let params = { + // city: "", + // country: "", + pageNum: pageCurr.value, + pageSize: pageSize.value, + // powerName: "", + // provice: "", + // stationName: "", + }; + + getDevList(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, + powerTypeStr: powerTypes[v.powerType], + // roleName: roles[v.role], + })); + _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 add() { + dialogTitle.value = "娣诲姞璁惧"; + datas.rowData = {}; + addEditVisible.value = true; + } + function edit(record) { + dialogTitle.value = "缂栬緫璁惧"; + addEditVisible.value = true; + console.log(record, '=======edit======'); + // if (record.ainfList.idPath) { + // ids = record.ainfList.idPath.split("_").map((v) => v * 1); + // } + // ids.push(record.areaId); + + datas.rowData = { ...record }; + } + + function addBatt(record) { + dialogTitle.value = "娣诲姞鐢垫睜缁�"; + datas.rowData = { ...record, addBattFlag: true }; + addEditVisible.value = true; + } + + function confirmRemove(record) { + $confirm("鍒犻櫎", () => { + let { stationId, powerId, battgroupId } = record; + remove(stationId, powerId, battgroupId||undefined); + }); + } + function remove(stationId, powerId, battgroupId) { + let loading = $loading(); + delBatt(stationId, powerId, battgroupId) + .then((res) => { + let { code, data } = res; + loading.close(); + if (code && data) { + $message.success("鎿嶄綔鎴愬姛"); + handleCurrentChange(1); + } else { + $message.success("鎿嶄綔澶辫触"); + } + }) + .catch((err) => { + loading.close(); + console.log(err); + }); + } + function onOk() { + addEditVisible.value = false; + handleCurrentChange(1); + } + function onCanel() { + addEditVisible.value = false; + } + + + onMounted(() => { + 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="table-row"> + <div class="table-cell text-right">鐪侊細</div> + <div class="table-cell"> + <el-select + v-model="provice" + size="small" + placeholder="璇烽�夋嫨鐪�" + > + <el-option + v-for="item in proviceList" + :key="'l0_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">甯傦細</div> + <div class="table-cell"> + <el-select + v-model="city" + size="small" + placeholder="璇烽�夋嫨甯�" + > + <el-option + v-for="item in cityList" + :key="'l1_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鍖哄幙:</div> + <div class="table-cell"> + <el-select + v-model="country" + size="small" + placeholder="璇烽�夋嫨鍖哄幙" + > + <el-option + v-for="item in countryList" + :key="'l2_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">绔欑偣:</div> + <div class="table-cell"> + <el-select + v-model="stationName" + 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 class="table-cell text-right">鍝佺墝:</div> + <div class="table-cell"> + <el-select + v-model="country" + size="small" + placeholder="璇烽�夋嫨鍝佺墝" + > + <el-option + v-for="item in countryList" + :key="item.value" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鐢靛帇绛夌骇:</div> + <div class="table-cell"> + <el-select + v-model="country" + size="small" + placeholder="璇烽�夋嫨鐢靛帇绛夌骇" + > + <el-option + v-for="item in countryList" + :key="item.value" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </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="primary" size="small" + @click="edit(scope.row)">缂栬緫</el-button> + <el-button type="danger" size="small" + @click="confirmRemove(scope.row)">鍒犻櫎</el-button> + <el-button type="primary" size="small" + @click="addBatt(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="add" :icon="Plus">娣诲姞</el-button> + <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"></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> + <add-edit v-if="addEditVisible" @success="onOk" :info="datas.rowData" @cancel="onCanel"></add-edit> + </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; + } + + .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> \ No newline at end of file diff --git a/src/views/statistics/battHr.vue b/src/views/statistics/battHr.vue new file mode 100644 index 0000000..5065b45 --- /dev/null +++ b/src/views/statistics/battHr.vue @@ -0,0 +1,487 @@ +<script setup name="battHr"> + 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 { + delBatt, + } 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 { + getBattTinfStatistic, + } from "@/api/statistic.js"; + + const { $loading, $message, $confirm } = useElement(); + + + const headers = [ + { + prop: "fullName", + label: "绔欑偣鍚嶇О", + width: "160", + }, + { + prop: "battgroupName", + label: "鐢垫睜缁勫悕绉�", + width: "80", + }, + { + prop: "testType", + label: "娴嬭瘯绫诲瀷", + width: "80", + }, + { + prop: "testStarttime", + label: "娴嬭瘯寮�濮嬫椂闂�", + width: "80", + }, + { + prop: "testCurr", + label: "娴嬭瘯鐢垫祦", + width: "80", + }, + { + prop: "testCap", + label: "娴嬭瘯瀹归噺", + width: "80", + }, + { + prop: "testTimelongStr", + label: "娴嬭瘯鏃堕暱", + width: "80", + }, + { + prop: "testStoptype", + label: "鍋滄鍘熷洜", + width: "80", + }, + { + prop: "restCap", + label: "棰勪及瀹為檯瀹归噺", + width: "80", + }, + { + prop: "precentCapStr", + label: "瀹归噺鐧惧垎姣�", + width: "80", + }, + { + prop: "restTimeStr", + 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); + + function getList() { + let loading = $loading(); + let params = { + provice: provice.value || undefined, + city: city.value || undefined, + country: country.value || undefined, + stationName: stationName.value || undefined, + testType: testType.value || undefined, + testStartTime: testStartDate.value ? testStartDate.value + ' 00:00:00' : undefined, + testEndTime: testEndDate.value ? testEndDate.value + ' 23:59:59' : undefined, + pageNum: pageCurr.value, + pageSize: pageSize.value, + }; + + getBattTinfStatistic(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, + testTimelongStr: formatSeconds(v.testTimelong), + restTimeStr: formatSeconds(v.restTime), + precentCapStr: toFixed(v.precentCap, 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/realtime', + query: { + id: row.battgroupId + } + }); + } + + function exportExcel() { + ExportFile(headers, datas.tableData, "钃勭數姹犳牳瀹逛俊鎭粺璁�"); + } + + onMounted(() => { + 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': 8}"> + <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="testType" + size="small" + clearable + @change="filterChange" + placeholder="璇烽�夋嫨" + > + <el-option + v-for="(item, idx) in hrTypeList" + :key="'list5_' + idx" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </div> + </div> + <div class="grid-item"> + <div class="label">娴嬭瘯寮�濮嬫椂闂�</div> + <div class="value" style="grid-column: span 5;"> + <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/devWorkstatus.vue b/src/views/statistics/devWorkstatus.vue new file mode 100644 index 0000000..ad76cfe --- /dev/null +++ b/src/views/statistics/devWorkstatus.vue @@ -0,0 +1,416 @@ +<script setup name="devWorkstatus"> + 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 { + delBatt, + } from "@/api/station"; + + const userStore = useUserStore(); + const { uid, uname } = storeToRefs(userStore); + + + + import { + getDeviceStateStatistic, + } from "@/api/statistic.js"; + + const { $loading, $message, $confirm } = useElement(); + + const headers = [ + { + prop: "fullName", + label: "绔欑偣鍚嶇О", + width: "160", + }, + { + prop: "devWorkstate", + label: "璁惧鐘舵��", + width: "80", + }, + { + prop: "devCaptestOnlinevol", + label: "鍦ㄧ嚎鐢靛帇", + width: "80", + }, + { + prop: "devCaptestGroupvol", + label: "缁勭鐢靛帇", + width: "80", + }, + { + prop: "devCaptestCurr", + label: "缁勭鐢垫祦", + width: "80", + }, + { + prop: "devTemp", + label: "璁惧娓╁害", + width: "80", + }, + { + prop: "devCaptestTimelong", + label: "娴嬭瘯鏃堕暱", + width: "80", + }, + { + prop: "devCaptestCap", + label: "娴嬭瘯瀹归噺", + width: "80", + }, + ]; + + const workstateList = [{ + value: 1, + label: '杩愯涓�', + },]; + const devWorkstate = ref(''); + + 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 datas = reactive({ + tableData: [], + rowData: {}, + }); + + // const tableData = reactive([]); + // const rowData = reactive({}); + + // const userStore = useUserStore(); + // const { uid, uname } = storeToRefs(userStore); + + + function getList() { + let loading = $loading(); + let params = { + provice: provice.value || undefined, + city: city.value || undefined, + country: country.value || undefined, + stationName: stationName.value || undefined, + devWorkstate: devWorkstate.value || undefined, + pageNum: pageCurr.value, + pageSize: pageSize.value, + }; + + getDeviceStateStatistic(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, + powerId: row.powerId, + devId: row.devId, + pageFlag: Math.random(), + } + }); + } + + function goHis (row) { + router.push({ + path: '/datas/realtime', + query: { + id: row.battgroupId + } + }); + } + + function exportExcel() { + ExportFile(headers, datas.tableData, "璁惧宸ヤ綔鐘舵�佺粺璁�"); + } + + onMounted(() => { + 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="table-row"> + <div class="table-cell text-right">鐪侊細</div> + <div class="table-cell"> + <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 class="table-cell text-right">甯傦細</div> + <div class="table-cell"> + <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 class="table-cell text-right">鍖哄幙:</div> + <div class="table-cell"> + <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 class="table-cell text-right">绔欑偣:</div> + <div class="table-cell"> + <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 class="table-cell text-right">璁惧宸ヤ綔鐘舵��:</div> + <div class="table-cell"> + <el-select + v-model="devWorkstate" + size="small" + clearable + @change="filterChange" + placeholder="璇烽�夋嫨" + > + <el-option + v-for="(item, idx) in workstateList" + :key="'list5_' + idx" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </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; + } + } +} +</style> \ No newline at end of file diff --git a/src/views/statistics/power.vue b/src/views/statistics/power.vue new file mode 100644 index 0000000..6f16465 --- /dev/null +++ b/src/views/statistics/power.vue @@ -0,0 +1,516 @@ +<script setup name="power"> + import { ref, reactive, onMounted, computed } 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 powerTypes from '@/utils/const/const_powerType.js'; + import { + delBatt, + } from "@/api/station"; + + const userStore = useUserStore(); + const { uid, uname } = storeToRefs(userStore); + + + + import { + getDevList, + } from "@/api/station"; + + const { $loading, $message, $confirm } = useElement(); + + const headers = [ + { + prop: "provice", + label: "鐪�", + width: "80", + }, + { + prop: "city", + label: "甯�", + width: "80", + }, + { + prop: "country", + label: "鍖哄幙", + width: "80", + }, + { + prop: "stationName", + label: "鏈烘埧鍚嶇О", + width: "160", + }, + { + prop: "stationType", + label: "鐢靛帇绛夌骇", + width: "80", + }, + { + prop: "longitude", + label: "缁忓害", + width: "80", + }, + { + prop: "latitude", + label: "绾害", + width: "80", + }, + { + prop: "powerName", + label: "鐢垫簮鍚嶇О", + width: "80", + }, + { + prop: "powerTypeStr", + label: "鐢垫簮绫诲瀷", + width: "80", + }, + { + prop: "company", + label: "鐢垫簮鍝佺墝", + width: "80", + }, + { + prop: "powerModel", + label: "鐢垫簮鍨嬪彿", + width: "80", + }, + { + prop: "protocol", + label: "鐢垫簮鍗忚", + width: "80", + }, + { + prop: "powerIp", + label: "鐢垫簮IP", + width: "120", + }, + { + prop: "devName", + label: "璁惧鍚嶇О", + width: "120", + }, + { + prop: "devType", + label: "璁惧鍨嬪彿", + width: "120", + }, + { + prop: "devIp", + label: "璁惧IP", + width: "120", + }, + { + prop: "battgroupName", + label: "鐢垫睜缁勫悕绉�", + width: "120", + }, + { + prop: "moncount", + label: "鐢垫睜鍗曚綋涓暟", + width: "120", + }, + { + prop: "monvolstd", + label: "鐢垫睜鏍囩О鐢靛帇", + width: "120", + }, + { + prop: "moncapstd", + label: "鐢垫睜鏍囩О瀹归噺", + width: "120", + }, + { + prop: "monresstd", + label: "鐢垫睜鏍囩О鍐呴樆", + width: "120", + }, + { + prop: "product", + label: "鐢垫睜鍝佺墝", + width: "120", + }, + { + prop: "battModel", + label: "鐢垫睜鍨嬪彿", + width: "120", + }, + ]; + 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 datas = reactive({ + tableData: [], + rowData: {}, + }); + + // const tableData = reactive([]); + // const rowData = reactive({}); + + // const userStore = useUserStore(); + // const { uid, uname } = storeToRefs(userStore); + + function getList() { + let loading = $loading(); + let params = { + // city: "", + // country: "", + pageNum: pageCurr.value, + pageSize: pageSize.value, + // powerName: "", + // provice: "", + // stationName: "", + }; + + getDevList(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, + powerTypeStr: powerTypes[v.powerType], + // roleName: roles[v.role], + })); + _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 add() { + dialogTitle.value = "娣诲姞璁惧"; + datas.rowData = {}; + addEditVisible.value = true; + } + function edit(record) { + dialogTitle.value = "缂栬緫璁惧"; + addEditVisible.value = true; + console.log(record, '=======edit======'); + // if (record.ainfList.idPath) { + // ids = record.ainfList.idPath.split("_").map((v) => v * 1); + // } + // ids.push(record.areaId); + + datas.rowData = { ...record }; + } + + function addBatt(record) { + dialogTitle.value = "娣诲姞鐢垫睜缁�"; + datas.rowData = { ...record, addBattFlag: true }; + addEditVisible.value = true; + } + + function confirmRemove(record) { + $confirm("鍒犻櫎", () => { + let { stationId, powerId, battgroupId } = record; + remove(stationId, powerId, battgroupId||undefined); + }); + } + function remove(stationId, powerId, battgroupId) { + let loading = $loading(); + delBatt(stationId, powerId, battgroupId) + .then((res) => { + let { code, data } = res; + loading.close(); + if (code && data) { + $message.success("鎿嶄綔鎴愬姛"); + handleCurrentChange(1); + } else { + $message.success("鎿嶄綔澶辫触"); + } + }) + .catch((err) => { + loading.close(); + console.log(err); + }); + } + function onOk() { + addEditVisible.value = false; + handleCurrentChange(1); + } + function onCanel() { + addEditVisible.value = false; + } + + + onMounted(() => { + 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="table-row"> + <div class="table-cell text-right">鐪侊細</div> + <div class="table-cell"> + <el-select + v-model="provice" + size="small" + placeholder="璇烽�夋嫨鐪�" + > + <el-option + v-for="item in proviceList" + :key="'l0_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">甯傦細</div> + <div class="table-cell"> + <el-select + v-model="city" + size="small" + placeholder="璇烽�夋嫨甯�" + > + <el-option + v-for="item in cityList" + :key="'l1_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鍖哄幙:</div> + <div class="table-cell"> + <el-select + v-model="country" + size="small" + placeholder="璇烽�夋嫨鍖哄幙" + > + <el-option + v-for="item in countryList" + :key="'l2_' + item" + :label="item" + :value="item" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">绔欑偣:</div> + <div class="table-cell"> + <el-select + v-model="stationName" + 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 class="table-cell text-right">鍝佺墝:</div> + <div class="table-cell"> + <el-select + v-model="country" + size="small" + placeholder="璇烽�夋嫨鍝佺墝" + > + <el-option + v-for="item in countryList" + :key="item.value" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </div> + <div class="table-cell text-right">鐢靛帇绛夌骇:</div> + <div class="table-cell"> + <el-select + v-model="country" + size="small" + placeholder="璇烽�夋嫨鐢靛帇绛夌骇" + > + <el-option + v-for="item in countryList" + :key="item.value" + :label="item.label" + :value="item.value" + > + </el-option> + </el-select> + </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="primary" size="small" + @click="edit(scope.row)">缂栬緫</el-button> + <el-button type="danger" size="small" + @click="confirmRemove(scope.row)">鍒犻櫎</el-button> + <el-button type="primary" size="small" + @click="addBatt(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="add" :icon="Plus">娣诲姞</el-button> + <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"></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> + <add-edit v-if="addEditVisible" @success="onOk" :info="datas.rowData" @cancel="onCanel"></add-edit> + </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; + } + + .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> \ No newline at end of file diff --git a/src/views/statistics/station.vue b/src/views/statistics/station.vue new file mode 100644 index 0000000..034a153 --- /dev/null +++ b/src/views/statistics/station.vue @@ -0,0 +1,421 @@ +<script setup name="station"> + 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 { + delBatt, + } from "@/api/station"; + + const userStore = useUserStore(); + const { uid, uname } = storeToRefs(userStore); + + + import { + getVoltageLevel, + } from "@/api/station"; + + import { + getStationStatistic, + } from "@/api/statistic.js"; + + const { $loading, $message, $confirm } = useElement(); + + const headers = [ + { + prop: "provice", + label: "鐪�", + width: "80", + }, + { + prop: "city", + label: "甯�", + width: "80", + }, + { + prop: "country", + label: "鍖哄幙", + width: "80", + }, + { + prop: "stationName", + label: "鏈烘埧鍚嶇О", + width: "160", + }, + { + prop: "stationType", + label: "鐢靛帇绛夌骇", + width: "80", + }, + { + prop: "longitude", + label: "缁忓害", + width: "80", + }, + { + prop: "latitude", + label: "绾害", + width: "80", + }, + ]; + + const volLevels = ref([]); + const stationType = ref(''); + 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 datas = reactive({ + tableData: [], + rowData: {}, + }); + + // const tableData = reactive([]); + // const rowData = reactive({}); + + // const userStore = useUserStore(); + // const { uid, uname } = storeToRefs(userStore); + + // 鑾峰彇鐢靛帇绛夌骇 + function getVolLevels() { + console.log("鑾峰彇鐢靛帇绛夌骇"); + getVoltageLevel().then((res) => { + let { code, data, data2 } = res; + let list = []; + if (code && data) { + list = data2; + } + volLevels.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, + stationType: stationType.value || undefined, + pageNum: pageCurr.value, + pageSize: pageSize.value, + }; + + getStationStatistic(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, + pageFlag: Math.random(), + } + }); + } + + function goHis (row) { + router.push({ + path: '/datas/realtime', + query: { + id: row.battgroupId + } + }); + } + + function exportExcel() { + ExportFile(headers, datas.tableData, "绔欑偣缁熻"); + } + + onMounted(() => { + getVolLevels(); + 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="table-row"> + <div class="table-cell text-right">鐪侊細</div> + <div class="table-cell"> + <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 class="table-cell text-right">甯傦細</div> + <div class="table-cell"> + <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 class="table-cell text-right">鍖哄幙:</div> + <div class="table-cell"> + <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 class="table-cell text-right">绔欑偣:</div> + <div class="table-cell"> + <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 class="table-cell text-right">鐢靛帇绛夌骇:</div> + <div class="table-cell"> + <el-select + v-model="stationType" + size="small" + clearable + @change="filterChange" + placeholder="璇烽�夋嫨鐢靛帇绛夌骇" + > + <el-option + v-for="(item, idx) in volLevels" + :key="'list5_' + idx" + :label="item" + :value="item" + > + </el-option> + </el-select> + </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; + } + } +} +</style> \ No newline at end of file diff --git a/src/views/user/MyCard.vue b/src/views/user/MyCard.vue index cf03cb5..d671b19 100644 --- a/src/views/user/MyCard.vue +++ b/src/views/user/MyCard.vue @@ -1,8 +1,7 @@ <template> <div class="my-card"> <div class="my-card-header"> - <div class="card-title"> - <img src="@/assets/images/card-title.png" class="card-title-img"> + <div class="card-title title ys-title panel-title"> {{title}} </div> <div class="my-card-tools"> @@ -46,7 +45,7 @@ } .my-card-header { display: flex; - font-size: 16px; + font-size: 20px; margin: 8px; padding: 8px; } @@ -55,9 +54,9 @@ margin-right: 4px; } .card-title { - color: #00feff; - font-weight: bold; - line-height: 32px; + color: #fff; + font-weight: normal; + line-height: 26px; } .my-card-tools { flex: 1; diff --git a/src/views/user/baojiMager.vue b/src/views/user/baojiMager.vue index 96226f8..5ac22a1 100644 --- a/src/views/user/baojiMager.vue +++ b/src/views/user/baojiMager.vue @@ -550,12 +550,12 @@ <style scoped lang="less"> .page-wrapper { - padding: 10px; + padding: 10px 28px; } :deep(.flex-layout-body) { margin-left: 10px; - border: 1px solid #0ff; - border-radius: 6px; + border: 1px solid #1B4C79; + border-radius: 0; } :deep(.el-dialog__body .flex-layout-body) { margin-left: 0; @@ -701,10 +701,10 @@ } } .flex-page-content { - margin-left: 8px; - margin-right: 8px; + // margin-left: 8px; + // margin-right: 8px; height: 100%; - padding: 0 8px; + // padding: 0 8px; :deep(.el-tabs) { height: 100%; } diff --git a/src/views/user/index.vue b/src/views/user/index.vue index 47d6576..b8c6e2a 100644 --- a/src/views/user/index.vue +++ b/src/views/user/index.vue @@ -216,7 +216,7 @@ </script> <template> - <div class="page-wrapper"> + <div class="page-wrapper page-contain bg-footer"> <!-- <div class="page-header"> </div> --> <div class="page-content"> @@ -355,7 +355,7 @@ .page-wrapper { display: flex; flex-direction: row; - padding: 8px; + padding: 8px 32px 42px; height: 100%; .page-content { diff --git a/src/views/user/powerMager.vue b/src/views/user/powerMager.vue index 071f908..541bbbd 100644 --- a/src/views/user/powerMager.vue +++ b/src/views/user/powerMager.vue @@ -43,7 +43,7 @@ </my-card> </template> <div class="flex-page-content"> - <context-box title="鐢ㄦ埛-鏉冮檺鏍�"> + <context-box title="鐢ㄦ埛鏉冮檺鏍�"> <div class="power-user-tree"> <div class="power-content power-content-user"> <el-transfer @@ -870,7 +870,7 @@ <style scoped lang="less"> .page-wrapper { - padding: 10px; + padding: 10px 28px; :deep(.flex-layout-body) { margin-left: 10px; border: 1px solid #38628E; @@ -879,10 +879,12 @@ } // border-radius: 6px; .content-box-title { + font-family: 'YouSheBiaoTiHei'; background-color: #014886; margin: 0; border-radius: 0; color: #fff; + font-weight: normal; } } } -- Gitblit v1.9.1