15个文件已修改
1个文件已删除
25个文件已添加
| | |
| | | "vue": "^2.7.5", |
| | | "vue-layer": "^1.2.0", |
| | | "vue-router": "3.0.2", |
| | | "echarts": "^4.8.0", |
| | | "vuex": "3.1.0" |
| | | }, |
| | | "devDependencies": { |
| | |
| | | core-js: |
| | | specifier: ^3.8.3 |
| | | version: registry.npmmirror.com/core-js@3.33.3 |
| | | echarts: |
| | | specifier: ^4.8.0 |
| | | version: registry.npmmirror.com/echarts@4.9.0 |
| | | element-ui: |
| | | specifier: ^2.15.14 |
| | | version: registry.npmmirror.com/element-ui@2.15.14(vue@2.7.15) |
| | |
| | | version: 1.0.1 |
| | | engines: {node: '>=6.0.0'} |
| | | dev: true |
| | | |
| | | registry.npmmirror.com/echarts@4.9.0: |
| | | resolution: {integrity: sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==, tarball: https://registry.npmmirror.com/echarts/-/echarts-4.9.0.tgz} |
| | | name: echarts |
| | | version: 4.9.0 |
| | | dependencies: |
| | | zrender: registry.npmmirror.com/zrender@4.3.2 |
| | | dev: false |
| | | |
| | | registry.npmmirror.com/ee-first@1.0.3: |
| | | resolution: {integrity: sha512-1q/3kz+ZwmrrWpJcCCrBZ3JnBzB1BMA5EVW9nxnIP1LxDZ16Cqs9VdolqLWlExet1vU+bar3WSkAa4/YrA9bIw==, tarball: https://registry.npmmirror.com/ee-first/-/ee-first-1.0.3.tgz} |
| | |
| | | normalize-path: registry.npmmirror.com/normalize-path@1.0.0 |
| | | strip-indent: registry.npmmirror.com/strip-indent@2.0.0 |
| | | dev: true |
| | | |
| | | registry.npmmirror.com/zrender@4.3.2: |
| | | resolution: {integrity: sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g==, tarball: https://registry.npmmirror.com/zrender/-/zrender-4.3.2.tgz} |
| | | name: zrender |
| | | version: 4.3.2 |
| | | dev: false |
| | |
| | | <style> |
| | | #app { |
| | | height: 100vh; |
| | | background: #011F39; |
| | | } |
| | | </style> |
| | |
| | | |
| | | if (process.env.NODE_ENV == 'development') { |
| | | // 跨域请求 |
| | | axios.defaults.baseURL = 'http://localhost:8094/fdk/'; |
| | | axios.defaults.baseURL = 'http://localhost:8095/ms/'; |
| | | axios.defaults.withCredentials = true; // 保持请求头 |
| | | } |
| | | |
| | |
| | | function getWebUrl() { |
| | | let url = ''; |
| | | if (process.env.NODE_ENV == 'development') { |
| | | url = "http://localhost:8094/fdk/" |
| | | url = "http://localhost:8095/ms/" |
| | | } else { |
| | | url = location.protocol + "//" + location.host + "/fdk/"; |
| | | url = location.protocol + "//" + location.host + "/ms/"; |
| | | } |
| | | return url; |
| | | } |
| | |
| | | <template> |
| | | <div style="padding: 0 15px;" @click="toggleClick"> |
| | | <div style="padding: 6px 15px;" @click="toggleClick"> |
| | | <svg |
| | | :class="{'is-active':isActive}" |
| | | class="hamburger" |
| | |
| | | width="64" |
| | | height="64" |
| | | > |
| | | <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" /> |
| | | <path fill="#fff" d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" /> |
| | | </svg> |
| | | </div> |
| | | </template> |
New file |
| | |
| | | <template> |
| | | <div class="alarm-card"> |
| | | <div class="name">{{ name }}</div> |
| | | <div |
| | | :class="[ |
| | | 'state', |
| | | { level1: 1 == level, level2: 2 == level, level3: 3 == level }, |
| | | ]" |
| | | ></div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | name: { |
| | | type: String, |
| | | required: true, |
| | | }, |
| | | level: { |
| | | type: Number, |
| | | default: 0, |
| | | validator(value) { |
| | | return [0, 1, 2, 3].some((v) => v == value); |
| | | }, |
| | | }, |
| | | }, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | components: {}, |
| | | methods: {}, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .alarm-card { |
| | | background: #0C4D77; |
| | | border: 1px solid #78eef8; |
| | | border-radius: 4px; |
| | | // width: 320px; |
| | | width: 100%; |
| | | height: 38px; |
| | | display: flex; |
| | | padding: 6px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | .state { |
| | | width: 60px; |
| | | background: #78eef8; |
| | | border-radius: 4px; |
| | | align-self: stretch; |
| | | &.level1 { |
| | | background: #4871E3; |
| | | } |
| | | &.level2 { |
| | | background: #F69F40; |
| | | } |
| | | &.level3 { |
| | | background: #FF3801; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="alarm-legend"> |
| | | <div class="item" v-for="(item, idx) in list" :key="'legend_' + idx"> |
| | | <div |
| | | :class="[ |
| | | 'state', |
| | | { level1: 1 == item.level, level2: 2 == item.level, level3: 3 == item.level }, |
| | | ]" |
| | | ></div> |
| | | <div class="name">{{ item.name }}</div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | data() { |
| | | return { |
| | | list: [ |
| | | { |
| | | name: "正常", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "一般", |
| | | level: 1, |
| | | }, |
| | | { |
| | | name: "重大", |
| | | level: 2, |
| | | }, |
| | | { |
| | | name: "紧急", |
| | | level: 3, |
| | | }, |
| | | ], |
| | | }; |
| | | }, |
| | | components: {}, |
| | | methods: {}, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .alarm-legend { |
| | | display: flex; |
| | | padding: 6px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | .item { |
| | | display: flex; |
| | | } |
| | | .state { |
| | | margin-right: 4px; |
| | | width: 20px; |
| | | height: 20px; |
| | | background: #78eef8; |
| | | border-radius: 50%; |
| | | &.level1 { |
| | | background: #4871e3; |
| | | } |
| | | &.level2 { |
| | | background: #f69f40; |
| | | } |
| | | &.level3 { |
| | | background: #ff3801; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <script> |
| | | import ECharts from "echarts"; |
| | | import BaseChart from "@/components/echarts/BaseChart"; |
| | | |
| | | export default { |
| | | extends: BaseChart, |
| | | props: { |
| | | name: { |
| | | type: String, |
| | | default: "", |
| | | }, |
| | | unit: { |
| | | type: String, |
| | | default: "", |
| | | }, |
| | | }, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | methods: { |
| | | fullScreen() { |
| | | return false; |
| | | }, |
| | | |
| | | setData(data) { |
| | | let option = this.getOption(data); |
| | | this.setOption(option); |
| | | }, |
| | | |
| | | getOption(data) { |
| | | let xLabel = data.xLabel; |
| | | let sData = data.sData; |
| | | // let sName = this.name; |
| | | |
| | | // let maxD = Math.max(...sData); |
| | | // if (maxD <= 0) { |
| | | // maxD = 1; |
| | | // } else { |
| | | // maxD = Math.round(maxD * 1.2 * 100) / 100; |
| | | // } |
| | | |
| | | // let fillData = sData.map(() => maxD); |
| | | |
| | | // let min = 0; |
| | | // let max = |
| | | // sData.length == 0 |
| | | // ? 0 |
| | | // : function (data) { |
| | | // let max = data.max; |
| | | // if (max == -Infinity) { |
| | | // max = 1; |
| | | // } |
| | | // // max = Math.max(Math.round((max + max * 0.2) * 100) / 100); |
| | | // return max; |
| | | // }; |
| | | |
| | | // let data = [ |
| | | // [30, 50, 120], |
| | | // ["A相", "B相", "C相"], |
| | | // ]; |
| | | |
| | | var getmydzd = []; |
| | | |
| | | let big = 0; |
| | | sData.forEach((el) => { |
| | | if (!(el === undefined || el === "")) { |
| | | if (big < Number(el)) { |
| | | big = Number(el); |
| | | } |
| | | } |
| | | }); |
| | | for (let i = 0; i < sData.length; i++) { |
| | | getmydzd.push(big * 4); |
| | | } |
| | | //计算最大值 |
| | | function calMax(arr) { |
| | | let max = 0; |
| | | arr.forEach((el) => { |
| | | el.forEach((el1) => { |
| | | if (!(el1 === undefined || el1 === "")) { |
| | | if (max < Number(el1)) { |
| | | max = Number(el1); |
| | | } |
| | | } |
| | | }); |
| | | }); |
| | | let maxint = Math.ceil(max / 9.5); |
| | | //不让最高的值超过最上面的刻度 |
| | | let maxval = maxint * 10; |
| | | //让显示的刻度是整数 |
| | | return maxval; |
| | | } |
| | | |
| | | var max = Math.ceil(calMax([sData]) / 10) * 10; |
| | | return { |
| | | grid: { |
| | | left: "3%", |
| | | right: "13%", |
| | | bottom: "10%", |
| | | top: "10%", |
| | | containLabel: true, |
| | | }, |
| | | tooltip: { |
| | | formatter: (params) => { |
| | | if (params.name !== "") { |
| | | return params.name + " : " + sData[params.dataIndex]; |
| | | } |
| | | }, |
| | | textStyle: { |
| | | align: "left", |
| | | }, |
| | | }, |
| | | xAxis: [ |
| | | { |
| | | type: "value", |
| | | axisLabel: { |
| | | margin: 5, |
| | | color: "#fff", |
| | | formatter: function (val) { |
| | | return val + ""; |
| | | }, |
| | | textStyle: { |
| | | fontSize: "13", |
| | | }, |
| | | }, |
| | | min: 0, |
| | | max: max, // 计算最大值 |
| | | interval: max / 5, // 平均分为5份 |
| | | splitNumber: 5, |
| | | splitLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: "#fff", |
| | | }, |
| | | }, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: "#fff", |
| | | width: 1, |
| | | opacity: 0.3, |
| | | }, |
| | | }, |
| | | axisTick: { |
| | | show: false, |
| | | }, |
| | | axisLabel: { |
| | | show: false, |
| | | }, |
| | | }, |
| | | { |
| | | type: "value", |
| | | axisLabel: { |
| | | show: false, |
| | | }, |
| | | min: 0, |
| | | max: max, // 计算最大值 |
| | | interval: max / 10, // 平均分为5份 |
| | | splitNumber: 10, |
| | | splitLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | type: "dashed", |
| | | color: "#D8D8D8", |
| | | }, |
| | | }, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: "#fff", |
| | | }, |
| | | }, |
| | | axisTick: { |
| | | show: false, |
| | | }, |
| | | }, |
| | | ], |
| | | yAxis: [ |
| | | { |
| | | type: "category", |
| | | inverse: true, |
| | | // boundaryGap:true, |
| | | axisLabel: { |
| | | formatter: (value, index) => { |
| | | if (value.length >= 12) { |
| | | value = value.slice(0, 12) + `\n` + value.slice(12); |
| | | } |
| | | if (value.length >= 26) { |
| | | value = value.slice(0, 26) + `\n` + value.slice(26); |
| | | } |
| | | return value; |
| | | }, |
| | | textStyle: { |
| | | color: "rgba(255,255,255,0.8)", |
| | | fontSize: "12", |
| | | align: "right", |
| | | lineHeight: 18, |
| | | }, |
| | | }, |
| | | splitLine: { |
| | | show: false, |
| | | }, |
| | | axisTick: { |
| | | show: false, |
| | | }, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: "#fff", |
| | | width: 1, |
| | | opacity: 0.3, |
| | | }, |
| | | }, |
| | | data: xLabel, |
| | | }, |
| | | |
| | | { |
| | | type: "category", |
| | | inverse: true, |
| | | axisTick: "none", |
| | | axisLine: "none", |
| | | show: true, |
| | | axisLabel: { |
| | | textStyle: { |
| | | color: "#ff0000", |
| | | fontSize: "12", |
| | | }, |
| | | formatter: function (value) { |
| | | return "{a|" + value + "}"; |
| | | }, |
| | | rich: { |
| | | a: { |
| | | backgroundColor: "#0C4D77", |
| | | fontSize: 14, |
| | | // lineHeight: 24, |
| | | verticalAlign: 'middle', |
| | | width: 50, |
| | | color: "#78EEF8", |
| | | // padding: [4, 0, 0, 1], |
| | | padding: [4, 4 ], |
| | | borderColor: "#78EEF8", |
| | | borderRadius: 3, |
| | | borderWidth: 1, |
| | | }, |
| | | }, |
| | | }, |
| | | data: (function () { |
| | | let arr = []; |
| | | sData.forEach((item) => { |
| | | let data = item + "V"; |
| | | arr.push(data); |
| | | }); |
| | | return arr; |
| | | })(), |
| | | }, |
| | | ], |
| | | dataZoom: [ |
| | | { |
| | | type: "inside", |
| | | show: true, |
| | | height: 15, |
| | | start: 1, |
| | | end: 100, |
| | | orient: "vertical", |
| | | zlevel: 66, |
| | | }, |
| | | ], |
| | | series: [ |
| | | { |
| | | name: "值", |
| | | type: "bar", |
| | | // zlevel: 1, |
| | | xAxisIndex: 0, |
| | | itemStyle: { |
| | | normal: { |
| | | // barBorderRadius: [0, 5, 5, 0], |
| | | color: function (params) { |
| | | let colorList = ["#4AFD88", "#F69F40", "#FF3801"]; |
| | | return colorList[params.dataIndex]; |
| | | }, |
| | | }, |
| | | }, |
| | | barWidth: 25, |
| | | data: sData, |
| | | z: 0, |
| | | }, |
| | | { |
| | | // 分隔 |
| | | type: "pictorialBar", |
| | | itemStyle: { |
| | | normal: { |
| | | color: "#022539", |
| | | }, |
| | | }, |
| | | symbolRepeat: "fixed", |
| | | symbolMargin: 4, |
| | | symbol: "rect", |
| | | symbolClip: true, |
| | | symbolSize: [2, 25], |
| | | symbolPosition: "start", |
| | | symbolOffset: [-1, 0], |
| | | data: getmydzd, |
| | | z: 66, |
| | | animationEasing: "elasticOut", |
| | | }, |
| | | { |
| | | name: "背景", |
| | | type: "bar", |
| | | barWidth: 25, |
| | | barGap: "-100%", |
| | | xAxisIndex: 1, |
| | | data: getmydzd, |
| | | itemStyle: { |
| | | normal: { |
| | | // color: '#52768C' |
| | | color: { |
| | | colorStops: [ |
| | | { |
| | | offset: 0, |
| | | color: "rgba(24,144,255,0.3)", // 0% 处的颜色 |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: "rgba(99,180,255,0.3)", // 100% 处的颜色 |
| | | }, |
| | | ], |
| | | }, |
| | | }, |
| | | }, |
| | | z: 0, |
| | | }, |
| | | // { |
| | | // name: "背景", |
| | | // type: "bar", |
| | | // barMaxWidth: "40%", |
| | | // barGap: "-100%", |
| | | // label: { |
| | | // show: true, |
| | | // position: "right", |
| | | // formatter: function (params) { |
| | | // let value = params.value; |
| | | // return "{a|" + value + "V" + "}"; |
| | | // }, |
| | | // rich: { |
| | | // a: { |
| | | // backgroundColor: "#2c5875", |
| | | // fontSize: 14, |
| | | // color: "#fdf100", |
| | | // padding: 8, |
| | | // borderColor: "#00FEFF", |
| | | // borderWidth: 1, |
| | | // }, |
| | | // }, |
| | | // }, |
| | | // tooltip: { |
| | | // show: false, |
| | | // }, |
| | | // data: sData.map(() => max), |
| | | // }, |
| | | ], |
| | | }; |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.setData({ |
| | | xLabel: ["A相", "B相", "C相"], |
| | | sData: [30, 50, 120], |
| | | }); |
| | | }, |
| | | }; |
| | | </script> |
New file |
| | |
| | | <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> |
| | | |
| | | <script> |
| | | // 引入 ECharts 主模块 |
| | | import ECharts from "echarts"; |
| | | // 引入自定义主题 |
| | | import "./transparent"; |
| | | export default { |
| | | name: "BaseChart", |
| | | chart: "", |
| | | exportChart: "", |
| | | data() { |
| | | return { |
| | | fullScreenFlag: false, |
| | | }; |
| | | }, |
| | | methods: { |
| | | /** |
| | | * 设置echarts图表的配置项 |
| | | * @param option echarts标准的配置项 |
| | | */ |
| | | setOption(option) { |
| | | let chart = this.$options.chart; |
| | | if (chart) { |
| | | chart.setOption(option); |
| | | } |
| | | }, |
| | | /** |
| | | * 全屏 |
| | | */ |
| | | fullScreen() { |
| | | this.fullScreenFlag = this.fullScreenFlag?false:true; |
| | | this.$nextTick(()=>{ |
| | | this.resize(); |
| | | }); |
| | | }, |
| | | /** |
| | | * 导出echarts600*400的图片 |
| | | * @returns {Base64} 图片的base64字符串 |
| | | */ |
| | | getDataURL() { |
| | | let chart = this.$options.chart; |
| | | let exportChart = this.$options.exportChart; |
| | | let base64 = ""; |
| | | |
| | | if(exportChart) { |
| | | let option = chart.getOption(); |
| | | // x轴样式 |
| | | option.xAxis[0].axisLine.lineStyle = { |
| | | color: "#000" |
| | | }; |
| | | option.xAxis[0].axisLabel.textStyle.color = "#000"; |
| | | |
| | | // y轴样式 |
| | | option.yAxis[0].axisLine.lineStyle = { |
| | | color: "#000" |
| | | }; |
| | | option.yAxis[0].axisLabel.textStyle.color = "#000"; |
| | | |
| | | exportChart.setOption(option); |
| | | |
| | | base64 = exportChart.getDataURL({ |
| | | pixelRatio: 1, |
| | | backgroundColor: '#fff' |
| | | }); |
| | | } |
| | | return base64; |
| | | }, |
| | | /** |
| | | * 对echarts进行缩放 |
| | | */ |
| | | resize() { |
| | | let chart = this.$options.chart; |
| | | // console.log("resize"); |
| | | if (chart) { |
| | | chart.resize(); |
| | | } |
| | | }, |
| | | /** |
| | | * 销毁echarts实例释放内存 |
| | | * @return {[type]} [return description] |
| | | */ |
| | | dispose() { |
| | | // 销毁chart |
| | | let chart = this.$options.chart; |
| | | this.disposeChart(chart); |
| | | |
| | | // 销毁chart |
| | | let exportChart = this.$options.exportChart; |
| | | this.disposeChart(exportChart); |
| | | }, |
| | | /** |
| | | * 销毁echarts实例释放内存 |
| | | * @param chart echarts实例 |
| | | */ |
| | | disposeChart(chart) { |
| | | if (chart) { |
| | | chart.dispose(); // 销毁实例 |
| | | this.$options.chart = ""; |
| | | } |
| | | }, |
| | | getChart() { |
| | | return this.$options.chart; |
| | | }, |
| | | handleClick() { |
| | | this.$emit('click', true); |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.$options.chart = ECharts.init(this.$refs.chart, "transparent"); |
| | | this.$options.exportChart = ECharts.init(this.$refs.exportChart, "transparent"); |
| | | // 监听windows窗口的缩放,绑定resize事件 |
| | | window.addEventListener("resize", this.resize); |
| | | this.$nextTick(() => { |
| | | this.resize(); |
| | | }); |
| | | }, |
| | | beforeDestroy() { |
| | | // 销毁resize事件 |
| | | window.removeEventListener("resize", this.resize); |
| | | this.dispose(); |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <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> |
New file |
| | |
| | | |
| | | /* |
| | | * Licensed to the Apache Software Foundation (ASF) under one |
| | | * or more contributor license agreements. See the NOTICE file |
| | | * distributed with this work for additional information |
| | | * regarding copyright ownership. The ASF licenses this file |
| | | * to you under the Apache License, Version 2.0 (the |
| | | * "License"); you may not use this file except in compliance |
| | | * with the License. You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, |
| | | * software distributed under the License is distributed on an |
| | | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| | | * KIND, either express or implied. See the License for the |
| | | * specific language governing permissions and limitations |
| | | * under the License. |
| | | */ |
| | | |
| | | /* |
| | | * Licensed to the Apache Software Foundation (ASF) under one |
| | | * or more contributor license agreements. See the NOTICE file |
| | | * distributed with this work for additional information |
| | | * regarding copyright ownership. The ASF licenses this file |
| | | * to you under the Apache License, Version 2.0 (the |
| | | * "License"); you may not use this file except in compliance |
| | | * with the License. You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, |
| | | * software distributed under the License is distributed on an |
| | | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| | | * KIND, either express or implied. See the License for the |
| | | * specific language governing permissions and limitations |
| | | * under the License. |
| | | */ |
| | | // 引入 ECharts 主模块 |
| | | import ECharts from "echarts/lib/echarts"; |
| | | |
| | | var contrastColor = '#00feff'; |
| | | |
| | | var axisCommon = function () { |
| | | return { |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: contrastColor |
| | | } |
| | | }, |
| | | axisTick: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: contrastColor |
| | | } |
| | | }, |
| | | axisLabel: { |
| | | show: true, |
| | | textStyle: { |
| | | color: contrastColor |
| | | } |
| | | }, |
| | | splitLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | type: 'solid', |
| | | color: '#0b388a' |
| | | } |
| | | }, |
| | | splitArea: { |
| | | areaStyle: { |
| | | color: contrastColor |
| | | } |
| | | } |
| | | }; |
| | | }; |
| | | |
| | | var colorPalette = ['#15E3F3', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53', '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42']; |
| | | var theme = { |
| | | color: colorPalette, |
| | | backgroundColor: '', |
| | | tooltip: { |
| | | axisPointer: { |
| | | lineStyle: { |
| | | color: contrastColor |
| | | }, |
| | | crossStyle: { |
| | | color: contrastColor |
| | | }, |
| | | label: { |
| | | color: '#000' |
| | | } |
| | | } |
| | | }, |
| | | legend: { |
| | | textStyle: { |
| | | color: contrastColor |
| | | } |
| | | }, |
| | | textStyle: { |
| | | color: contrastColor |
| | | }, |
| | | title: { |
| | | textStyle: { |
| | | color: contrastColor |
| | | } |
| | | }, |
| | | toolbox: { |
| | | show: false, |
| | | iconStyle: { |
| | | normal: { |
| | | borderColor: contrastColor |
| | | } |
| | | } |
| | | }, |
| | | dataZoom: { |
| | | textStyle: { |
| | | color: contrastColor |
| | | } |
| | | }, |
| | | visualMap: { |
| | | textStyle: { |
| | | color: contrastColor |
| | | } |
| | | }, |
| | | timeline: { |
| | | lineStyle: { |
| | | color: contrastColor |
| | | }, |
| | | itemStyle: { |
| | | normal: { |
| | | color: colorPalette[1] |
| | | } |
| | | }, |
| | | label: { |
| | | normal: { |
| | | textStyle: { |
| | | color: contrastColor |
| | | } |
| | | } |
| | | }, |
| | | controlStyle: { |
| | | normal: { |
| | | color: contrastColor, |
| | | borderColor: contrastColor |
| | | } |
| | | } |
| | | }, |
| | | timeAxis: axisCommon(), |
| | | logAxis: axisCommon(), |
| | | valueAxis: axisCommon(), |
| | | categoryAxis: axisCommon(), |
| | | line: { |
| | | symbol: 'circle' |
| | | }, |
| | | graph: { |
| | | color: colorPalette |
| | | }, |
| | | gauge: { |
| | | title: { |
| | | textStyle: { |
| | | color: contrastColor |
| | | } |
| | | } |
| | | }, |
| | | candlestick: { |
| | | itemStyle: { |
| | | normal: { |
| | | color: '#FD1050', |
| | | color0: '#0CF49B', |
| | | borderColor: '#FD1050', |
| | | borderColor0: '#0CF49B' |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | ECharts.registerTheme('transparent', theme); |
New file |
| | |
| | | <script> |
| | | import ECharts from "echarts"; |
| | | import BaseChart from "@/components/echarts/BaseChart"; |
| | | |
| | | var highlight = "#03b7c9"; |
| | | |
| | | var demoData = [ |
| | | { |
| | | name: "电压", |
| | | value: 220, |
| | | unit: "V", |
| | | pos: ["16.6%", "40%"], |
| | | range: [0, 400], |
| | | }, |
| | | { name: "电流", value: 32, unit: "A", pos: ["49.8%", "40%"], range: [0, 60] }, |
| | | { |
| | | name: "功率因数", |
| | | value: 0.9, |
| | | pos: ["83%", "40%"], |
| | | range: [0.1, 1.0], |
| | | splitNum: 9, |
| | | }, |
| | | // { |
| | | // name: "有功功率", |
| | | // value: 6.34, |
| | | // unit: "kW", |
| | | // pos: ["16.6%", "75%"], |
| | | // range: [0, 50], |
| | | // }, |
| | | // { |
| | | // name: "有功电能", |
| | | // value: 6.28, |
| | | // unit: "kWh", |
| | | // pos: ["49.8%", "75%"], |
| | | // range: [0, 50], |
| | | // }, |
| | | // { |
| | | // name: "电网频率", |
| | | // value: 50, |
| | | // unit: "Hz", |
| | | // pos: ["83%", "75%"], |
| | | // range: [0, 100], |
| | | // }, |
| | | ]; |
| | | |
| | | |
| | | export default { |
| | | extends: BaseChart, |
| | | props: { |
| | | name: { |
| | | type: String, |
| | | default: "", |
| | | }, |
| | | unit: { |
| | | type: String, |
| | | default: "", |
| | | }, |
| | | r: { |
| | | type: [String, Number], |
| | | required: true, |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | // r: '33.3%', |
| | | }; |
| | | }, |
| | | computed: { |
| | | }, |
| | | watch: { |
| | | r() { |
| | | this.$nextTick(() => { |
| | | |
| | | this.resize(); |
| | | }); |
| | | } |
| | | }, |
| | | methods: { |
| | | fullScreen() { |
| | | return false; |
| | | }, |
| | | setData(data) { |
| | | let option = this.getOption(data); |
| | | this.setOption(option); |
| | | }, |
| | | |
| | | getOption(data) { |
| | | let xLabel = data.xLabel; |
| | | let sData = data.sData; |
| | | let sName = this.name; |
| | | |
| | | let maxD = Math.max(...sData); |
| | | if (maxD <= 0) { |
| | | maxD = 1; |
| | | } else { |
| | | maxD = Math.round(maxD * 1.2 * 100) / 100; |
| | | } |
| | | |
| | | let fillData = sData.map(() => maxD); |
| | | |
| | | let min = 0; |
| | | let max = |
| | | sData.length == 0 |
| | | ? 0 |
| | | : function (data) { |
| | | let max = data.max; |
| | | if (max == -Infinity) { |
| | | max = 1; |
| | | } |
| | | // max = Math.max(Math.round((max + max * 0.2) * 100) / 100); |
| | | return max; |
| | | }; |
| | | |
| | | let self = this; |
| | | return { |
| | | grid: { |
| | | left: "1%", |
| | | right: "1%", |
| | | bottom: "2%", |
| | | top: "2%", |
| | | containLabel: true, |
| | | }, |
| | | series: (function () { |
| | | var result = []; |
| | | |
| | | demoData.forEach(function (item) { |
| | | result.push( |
| | | // 外围刻度 |
| | | { |
| | | type: "gauge", |
| | | center: item.pos, |
| | | // radius: "33.33%", // 1行3个 |
| | | radius: self.r, |
| | | |
| | | splitNumber: item.splitNum || 10, |
| | | min: item.range[0], |
| | | max: item.range[1], |
| | | startAngle: 225, |
| | | endAngle: -45, |
| | | axisLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | width: 2, |
| | | shadowBlur: 0, |
| | | color: [[1, highlight]], |
| | | }, |
| | | }, |
| | | axisTick: { |
| | | show: true, |
| | | lineStyle: { |
| | | color: highlight, |
| | | width: 1, |
| | | }, |
| | | // length: -5, |
| | | splitNumber: 10, |
| | | }, |
| | | splitLine: { |
| | | // show: true, |
| | | show: false, |
| | | // length: -14, |
| | | lineStyle: { |
| | | color: highlight, |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | distance: -20, |
| | | // textStyle: { |
| | | // color: highlight, |
| | | // fontSize: "14", |
| | | // fontWeight: "bold", |
| | | // }, |
| | | }, |
| | | pointer: { |
| | | show: 0, |
| | | }, |
| | | detail: { |
| | | show: 0, |
| | | }, |
| | | }, |
| | | |
| | | // 内侧指针、数值显示 |
| | | { |
| | | name: item.name, |
| | | type: "gauge", |
| | | center: item.pos, |
| | | radius: "30.33%", |
| | | startAngle: 225, |
| | | endAngle: -45, |
| | | min: item.range[0], |
| | | max: item.range[1], |
| | | axisLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | width: 16, |
| | | color: [[1, "rgba(255,255,255,.1)"]], |
| | | }, |
| | | }, |
| | | axisTick: { |
| | | show: 0, |
| | | }, |
| | | splitLine: { |
| | | show: 0, |
| | | }, |
| | | axisLabel: { |
| | | show: 0, |
| | | }, |
| | | pointer: { |
| | | show: true, |
| | | length: "105%", |
| | | }, |
| | | detail: { |
| | | show: true, |
| | | offsetCenter: [0, "200%"], |
| | | textStyle: { |
| | | fontSize: 20, |
| | | color: "#fff", |
| | | }, |
| | | formatter: [ |
| | | "{value} " + (item.unit || ""), |
| | | "{name|" + item.name + "}", |
| | | ].join("\n"), |
| | | rich: { |
| | | name: { |
| | | fontSize: 14, |
| | | lineHeight: 30, |
| | | color: "#ddd", |
| | | }, |
| | | }, |
| | | }, |
| | | itemStyle: { |
| | | normal: { |
| | | color: highlight, |
| | | }, |
| | | }, |
| | | data: [ |
| | | { |
| | | value: item.value, |
| | | }, |
| | | ], |
| | | } |
| | | ); |
| | | }); |
| | | |
| | | return result; |
| | | })(), |
| | | }; |
| | | }, |
| | | }, |
| | | mounted() { |
| | | |
| | | this.setData({ |
| | | xLabel: [], |
| | | sData: [], |
| | | }); |
| | | |
| | | }, |
| | | }; |
| | | </script> |
New file |
| | |
| | | <template> |
| | | <div class="list-card"> |
| | | <div class="column" v-for="(item, idx) in list" :key="'column_' + idx"> |
| | | <div |
| | | class="list-item" |
| | | v-for="(iitem, iidx) in item" |
| | | :key="'item_' + iidx" |
| | | > |
| | | <template v-if="iitem"> |
| | | {{ iitem.label }}: {{ valueObj[iitem.key] || "" }} |
| | | </template> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | valueObj: { |
| | | type: Object, |
| | | default() { |
| | | return {}; |
| | | }, |
| | | }, |
| | | datas: { |
| | | type: Array, |
| | | required: true, |
| | | }, |
| | | emptyIdxs: { |
| | | type: Array, |
| | | default() { |
| | | return []; |
| | | }, |
| | | }, |
| | | rows: { |
| | | type: Number, |
| | | default: 3, |
| | | }, |
| | | cols: { |
| | | type: Number, |
| | | default: 2, |
| | | }, |
| | | }, |
| | | computed: { |
| | | // 添加空行 并转为二维数组 |
| | | list() { |
| | | let { datas: list, emptyIdxs } = this; |
| | | emptyIdxs.sort((a, b) => a - b); |
| | | for (let i = 0, j = emptyIdxs.length; i < j; i++) { |
| | | list.splice(emptyIdxs[i], 0, null); |
| | | } |
| | | list = this.chunkArray(list, this.rows, this.cols); |
| | | return list; |
| | | }, |
| | | }, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | components: {}, |
| | | methods: { |
| | | chunkArray(array, chunkSize, len) { |
| | | let chunks = []; |
| | | for (let i = 0; i < array.length; i += chunkSize) { |
| | | chunks.push(array.slice(i, i + chunkSize)); |
| | | } |
| | | // 只有最后一个子元素可能不够长度补null 或子元素个数不够 差的组 全部补null |
| | | let realLen = chunks.length; |
| | | let lastItem = chunks[realLen - 1]; |
| | | if (lastItem.length < chunkSize) { |
| | | lastItem.push(...new Array(chunkSize - lastItem.length)); |
| | | } |
| | | if (realLen < len) { |
| | | let arr = new Array(chunkSize); |
| | | for (let m = len - realLen; m > 0; m--) { |
| | | chunks.push(arr); |
| | | } |
| | | } |
| | | return chunks; |
| | | }, |
| | | }, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .list-card { |
| | | // background: #011f39; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: row; |
| | | .column { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | & + .column { |
| | | margin-left: 6px; |
| | | } |
| | | .list-item { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | padding-left: 10px; |
| | | // height: 20px; |
| | | // line-height: 20px; |
| | | background: #153952; |
| | | &:nth-child(2n) { |
| | | background: rgba(21, 57, 82, 0.6); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="panel"> |
| | | <div class="inner"> |
| | | <!-- 标题 --> |
| | | <div class="title">{{ title }}</div> |
| | | <!-- 内容 --> |
| | | <div class="content"> |
| | | <slot></slot> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | title: { |
| | | type: String, |
| | | }, |
| | | }, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | components: {}, |
| | | methods: {}, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .panel { |
| | | padding: 4px; |
| | | position: relative; |
| | | &::after { |
| | | pointer-events: none; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | content: ""; |
| | | background: radial-gradient( |
| | | circle farthest-side at 0% 100%, |
| | | transparent 70%, |
| | | rgba(0, 255, 255, 0.3) 70%, |
| | | rgba(0, 255, 255, 3) 71%, |
| | | rgba(0, 255, 255, 3) 95%, |
| | | rgba(0, 255, 255, 0.3) 96%, |
| | | transparent 96%, |
| | | transparent |
| | | ) |
| | | calc(100% - 2px) 2px, |
| | | linear-gradient( |
| | | 0deg, |
| | | transparent 50%, |
| | | rgba(0, 255, 255, 0.3) 50%, |
| | | rgba(100, 255, 255, 3) 51%, |
| | | rgba(100, 255, 255, 3) |
| | | ) |
| | | calc(100% - 16px) 3px, |
| | | linear-gradient( |
| | | 90deg, |
| | | transparent 50%, |
| | | rgba(0, 255, 255, 0.3) 50%, |
| | | rgba(100, 255, 255, 3) 51%, |
| | | rgba(100, 255, 255, 3) |
| | | ) |
| | | calc(100% - 3px) 16px, |
| | | radial-gradient( |
| | | circle farthest-side at 100% 0, |
| | | transparent 70%, |
| | | rgba(0, 255, 255, 0.3) 70%, |
| | | rgba(0, 255, 255, 3) 71%, |
| | | rgba(0, 255, 255, 3) 95%, |
| | | rgba(0, 255, 255, 0.3) 96%, |
| | | transparent 96%, |
| | | transparent |
| | | ) |
| | | 2px calc(100% - 2px), |
| | | linear-gradient( |
| | | -90deg, |
| | | transparent 50%, |
| | | rgba(0, 255, 255, 0.3) 50%, |
| | | rgba(100, 255, 255, 3) 51%, |
| | | rgba(100, 255, 255, 3) |
| | | ) |
| | | 3px calc(100% - 16px), |
| | | linear-gradient( |
| | | 180deg, |
| | | transparent 50%, |
| | | rgba(0, 255, 255, 0.3) 50%, |
| | | rgba(100, 255, 255, 3) 51%, |
| | | rgba(100, 255, 255, 3) |
| | | ) |
| | | 16px calc(100% - 3px), |
| | | radial-gradient( |
| | | circle farthest-side at 100% 100%, |
| | | transparent 70%, |
| | | rgba(0, 255, 255, 0.3) 70%, |
| | | rgba(0, 255, 255, 3) 71%, |
| | | rgba(0, 255, 255, 3) 95%, |
| | | rgba(0, 255, 255, 0.3) 96%, |
| | | transparent 96%, |
| | | transparent |
| | | ) |
| | | 2px 2px, |
| | | linear-gradient( |
| | | 0deg, |
| | | transparent 50%, |
| | | rgba(0, 255, 255, 0.3) 50%, |
| | | rgba(100, 255, 255, 3) 51%, |
| | | rgba(100, 255, 255, 3) |
| | | ) |
| | | 16px 3px, |
| | | linear-gradient( |
| | | -90deg, |
| | | transparent 50%, |
| | | rgba(0, 255, 255, 0.3) 50%, |
| | | rgba(100, 255, 255, 3) 51%, |
| | | rgba(100, 255, 255, 3) |
| | | ) |
| | | 3px 16px, |
| | | radial-gradient( |
| | | circle farthest-side at 0 0, |
| | | transparent 70%, |
| | | rgba(0, 255, 255, 0.3) 70%, |
| | | rgba(0, 255, 255, 3) 71%, |
| | | rgba(0, 255, 255, 3) 95%, |
| | | rgba(0, 255, 255, 0.3) 96%, |
| | | transparent 96%, |
| | | transparent |
| | | ) |
| | | calc(100% - 2px) calc(100% - 2px), |
| | | linear-gradient( |
| | | 180deg, |
| | | transparent 50%, |
| | | rgba(0, 255, 255, 0.3) 50%, |
| | | rgba(100, 255, 255, 3) 51%, |
| | | rgba(100, 255, 255, 3) |
| | | ) |
| | | calc(100% - 16px) calc(100% - 3px), |
| | | linear-gradient( |
| | | 90deg, |
| | | transparent 50%, |
| | | rgba(0, 255, 255, 0.3) 50%, |
| | | rgba(100, 255, 255, 3) 51%, |
| | | rgba(100, 255, 255, 3) |
| | | ) |
| | | calc(100% - 3px) calc(100% - 16px); |
| | | background-size: 14px 14px, 6px 6px, 6px 6px; |
| | | background-repeat: no-repeat; |
| | | } |
| | | // background: gray; |
| | | .inner { |
| | | height: 100%; |
| | | border: 1px #0d8191 solid; |
| | | border-radius: 10px; |
| | | background: radial-gradient(rgba(01, 31, 57, 0.25) 63%, #77eef7 280%); |
| | | display: flex; |
| | | flex-direction: column; |
| | | .title { |
| | | height: 42px; |
| | | text-align: center; |
| | | color: #00f7f8; |
| | | font-size: 20px; |
| | | line-height: 42px; |
| | | background: url("images/panel-title.png") 50% 50% / auto 100% no-repeat; |
| | | } |
| | | .content { |
| | | flex: 1; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="navbar"> |
| | | <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> |
| | | <!-- <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> --> |
| | | <div class="title">通信电源监控主站测控系统</div> |
| | | <div class="info"> |
| | | <!-- 左边 --> |
| | | <div class="left"> |
| | | <div class="box"> |
| | | 分闸开关 |
| | | <div class="num">12</div> |
| | | </div> |
| | | <div class="box">合闸开关<div class="num">22</div></div> |
| | | </div> |
| | | <!-- 右边 --> |
| | | <div class="right"> |
| | | <div class="box"> |
| | | 开关告警数 |
| | | <div class="num">4</div> |
| | | </div> |
| | | <div class="box"> |
| | | 跳闸开关 |
| | | <div class="num">12</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="right-menu"> |
| | | <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover"> |
| | | <el-dropdown |
| | | class="avatar-container right-menu-item hover-effect" |
| | | trigger="hover" |
| | | > |
| | | <div class="avatar-wrapper"> |
| | | <span class="user-name">{{ name }}</span> |
| | | <i class="el-icon-caret-bottom" /> |
| | | </div> |
| | | <el-dropdown-menu slot="dropdown"> |
| | | <el-dropdown-item @click.native="changePwd"> |
| | | <span style="display:block;">修改密码</span> |
| | | <span style="display: block">修改密码</span> |
| | | </el-dropdown-item> |
| | | <el-dropdown-item @click.native="logout"> |
| | | <span style="display:block;">退出登录</span> |
| | | <span style="display: block">退出登录</span> |
| | | </el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </el-dropdown> |
| | | </div> |
| | | <!-- 密码修改 --> |
| | | <el-dialog |
| | | <!-- 密码修改 --> |
| | | <el-dialog |
| | | title="密码修改" |
| | | width="400px" |
| | | :visible.sync="changePwdVisible" |
| | |
| | | class="dialog-center" |
| | | :modal-append-to-body="false" |
| | | > |
| | | <pwd-change v-if="changePwdVisible" :visible.sync="changePwdVisible"></pwd-change> |
| | | </el-dialog> |
| | | <pwd-change |
| | | v-if="changePwdVisible" |
| | | :visible.sync="changePwdVisible" |
| | | ></pwd-change> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapGetters } from 'vuex' |
| | | import Hamburger from '@/components/Hamburger' |
| | | import { mapGetters } from "vuex"; |
| | | // import Hamburger from '@/components/Hamburger' |
| | | import PwdChange from "./PwdChange"; |
| | | export default { |
| | | components: { |
| | | Hamburger, |
| | | // Hamburger, |
| | | PwdChange, |
| | | }, |
| | | computed: { |
| | | ...mapGetters([ |
| | | 'sidebar', |
| | | 'avatar', |
| | | 'device', |
| | | 'name', |
| | | ]) |
| | | ...mapGetters(["sidebar", "avatar", "device", "name"]), |
| | | }, |
| | | data() { |
| | | return { |
| | | changePwdVisible: false, |
| | | } |
| | | }; |
| | | }, |
| | | methods: { |
| | | changePwd() { |
| | | this.changePwdVisible = true; |
| | | }, |
| | | toggleSideBar() { |
| | | this.$store.dispatch('app/toggleSideBar') |
| | | this.$store.dispatch("app/toggleSideBar"); |
| | | }, |
| | | async logout() { |
| | | await this.$store.dispatch('user/logout') |
| | | this.$router.push(`/login?redirect=${this.$route.fullPath}`) |
| | | } |
| | | } |
| | | } |
| | | await this.$store.dispatch("user/logout"); |
| | | this.$router.push(`/login?redirect=${this.$route.fullPath}`); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .navbar { |
| | | height: 50px; |
| | | height: 104px; |
| | | overflow: hidden; |
| | | position: relative; |
| | | background: #fff; |
| | | box-shadow: 0 1px 4px rgba(0,21,41,.08); |
| | | |
| | | color: #fff; |
| | | background: #011f39 url("images/header-bg.png") 50% 50% / auto 100% no-repeat; |
| | | box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); |
| | | .title { |
| | | font-size: 34px; |
| | | font-weight: bold; |
| | | text-align: center; |
| | | line-height: 76px; |
| | | letter-spacing: 6px; |
| | | } |
| | | .info { |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | top: 30px; |
| | | bottom: 0; |
| | | display: flex; |
| | | .left, |
| | | .right { |
| | | width: 50%; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | .left { |
| | | // padding-right: 380px; |
| | | padding-right: 264px; |
| | | } |
| | | .right { |
| | | padding-left: 264px; |
| | | } |
| | | .box { |
| | | display: inline-block; |
| | | width: 160px; |
| | | height: 40px; |
| | | line-height: 38px; |
| | | font-size: 16px; |
| | | border: 1px #5ec7d4 solid; |
| | | border-radius: 10px; |
| | | text-align: center; |
| | | .num { |
| | | display: inline-block; |
| | | height: 36px; |
| | | min-width: 36px; |
| | | padding: 6px; |
| | | background: #78eef8; |
| | | margin-top: 1px; |
| | | line-height: 24px; |
| | | border-radius: 18px; |
| | | color: #011f39; |
| | | margin-left: 1.2em; |
| | | } |
| | | & + .box { |
| | | margin-left: 10px; |
| | | } |
| | | } |
| | | } |
| | | .hamburger-container { |
| | | line-height: 46px; |
| | | height: 100%; |
| | | float: left; |
| | | cursor: pointer; |
| | | transition: background .3s; |
| | | -webkit-tap-highlight-color:transparent; |
| | | transition: background 0.3s; |
| | | -webkit-tap-highlight-color: transparent; |
| | | |
| | | &:hover { |
| | | background: rgba(0, 0, 0, .025) |
| | | background: rgba(0, 0, 0, 0.025); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | .right-menu { |
| | | float: right; |
| | | position: absolute; |
| | | right: 0; |
| | | top: 0; |
| | | height: 100%; |
| | | line-height: 50px; |
| | | |
| | | padding-top: 40px; |
| | | &:focus { |
| | | outline: none; |
| | | } |
| | |
| | | padding: 0 8px; |
| | | height: 100%; |
| | | font-size: 18px; |
| | | color: #5a5e66; |
| | | color: #fff; |
| | | vertical-align: text-bottom; |
| | | |
| | | &.hover-effect { |
| | | cursor: pointer; |
| | | transition: background .3s; |
| | | transition: background 0.3s; |
| | | |
| | | &:hover { |
| | | background: rgba(0, 0, 0, .025) |
| | | background: rgba(0, 0, 0, 0.025); |
| | | } |
| | | } |
| | | } |
| | |
| | | <template> |
| | | <div v-if="!item.hidden"> |
| | | <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> |
| | | <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> |
| | | <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)" @click.native="closeMenu"> |
| | | <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> |
| | | <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> |
| | | </el-menu-item> |
| | |
| | | return {} |
| | | }, |
| | | methods: { |
| | | closeMenu() { |
| | | this.$store.dispatch("app/closeSideBar", { withoutAnimation: false }); |
| | | }, |
| | | hasOneShowingChild(children = [], parent) { |
| | | const showingChildren = children.filter(item => { |
| | | if (item.hidden) { |
| | |
| | | <template> |
| | | <div class="side-menu-wrapper"> |
| | | <logo :collapse="isCollapse" /> |
| | | <!-- <logo :collapse="isCollapse" /> --> |
| | | <div class="side-menu-content"> |
| | | <el-menu |
| | | :default-active="activeMenu" |
| | |
| | | <template> |
| | | <div id="tags-view-container" class="tags-view-container"> |
| | | <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll"> |
| | | <router-link |
| | | v-for="tag in visitedViews" |
| | | ref="tag" |
| | | :key="tag.path" |
| | | :class="isActive(tag)?'active':''" |
| | | :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" |
| | | tag="span" |
| | | class="tags-view-item" |
| | | @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''" |
| | | @contextmenu.prevent.native="openMenu(tag,$event)"> |
| | | {{ tag.title }} |
| | | <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> |
| | | </router-link> |
| | | </scroll-pane> |
| | | <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"> |
| | | <hamburger |
| | | id="hamburger-container" |
| | | :is-active="sidebar.opened" |
| | | class="hamburger-container" |
| | | @toggleClick="toggleSideBar" |
| | | /> |
| | | <div class="tags-inner"> |
| | | <scroll-pane |
| | | ref="scrollPane" |
| | | class="tags-view-wrapper" |
| | | @scroll="handleScroll" |
| | | > |
| | | <router-link |
| | | v-for="tag in visitedViews" |
| | | ref="tag" |
| | | :key="tag.path" |
| | | :class="isActive(tag) ? 'active' : ''" |
| | | :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" |
| | | tag="span" |
| | | class="tags-view-item" |
| | | @click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''" |
| | | @contextmenu.prevent.native="openMenu(tag, $event)" |
| | | > |
| | | {{ tag.title }} |
| | | <span |
| | | v-if="!isAffix(tag)" |
| | | class="el-icon-close" |
| | | @click.prevent.stop="closeSelectedTag(tag)" |
| | | /> |
| | | </router-link> |
| | | </scroll-pane> |
| | | </div> |
| | | <ul |
| | | v-show="visible" |
| | | :style="{ left: left + 'px', top: top + 'px' }" |
| | | class="contextmenu" |
| | | > |
| | | <li @click="refreshSelectedTag(selectedTag)">Refresh</li> |
| | | <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li> |
| | | <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"> |
| | | Close |
| | | </li> |
| | | <li @click="closeOthersTags">Close Others</li> |
| | | <li @click="closeAllTags(selectedTag)">Close All</li> |
| | | </ul> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import path from "path-browserify" |
| | | import path from "path-browserify"; |
| | | import scrollPane from "@/layout/components/TagsView/ScrollPane.vue"; |
| | | import Hamburger from "@/components/Hamburger"; |
| | | import routes from "@/router/routes"; |
| | | import { mapGetters } from 'vuex'; |
| | | export default { |
| | | components: { |
| | | scrollPane |
| | | }, |
| | | components: { |
| | | scrollPane, |
| | | Hamburger, |
| | | }, |
| | | data() { |
| | | return { |
| | | visible: false, |
| | |
| | | left: 0, |
| | | selectedTag: {}, |
| | | affixTags: [], |
| | | routes: routes, |
| | | } |
| | | routes: routes, |
| | | }; |
| | | }, |
| | | computed: { |
| | | ...mapGetters([ |
| | | 'sidebar', |
| | | ]), |
| | | visitedViews() { |
| | | return this.$store.state.tagsView.visitedViews |
| | | } |
| | | return this.$store.state.tagsView.visitedViews; |
| | | }, |
| | | }, |
| | | watch: { |
| | | $route() { |
| | | this.addTags() |
| | | this.moveToCurrentTag() |
| | | this.addTags(); |
| | | this.moveToCurrentTag(); |
| | | }, |
| | | visible(value) { |
| | | if (value) { |
| | | document.body.addEventListener('click', this.closeMenu) |
| | | document.body.addEventListener("click", this.closeMenu); |
| | | } else { |
| | | document.body.removeEventListener('click', this.closeMenu) |
| | | document.body.removeEventListener("click", this.closeMenu); |
| | | } |
| | | } |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.initTags() |
| | | this.addTags() |
| | | this.initTags(); |
| | | this.addTags(); |
| | | }, |
| | | methods: { |
| | | isActive(route) { |
| | | return route.path === this.$route.path |
| | | return route.path === this.$route.path; |
| | | }, |
| | | isAffix(tag) { |
| | | return tag.meta && tag.meta.affix |
| | | return tag.meta && tag.meta.affix; |
| | | }, |
| | | filterAffixTags(routes, basePath = '/') { |
| | | let tags = [] |
| | | routes.forEach(route => { |
| | | filterAffixTags(routes, basePath = "/") { |
| | | let tags = []; |
| | | routes.forEach((route) => { |
| | | if (route.meta && route.meta.affix) { |
| | | const tagPath = path.resolve(basePath, route.path) |
| | | const tagPath = path.resolve(basePath, route.path); |
| | | tags.push({ |
| | | fullPath: tagPath, |
| | | path: tagPath, |
| | | name: route.name, |
| | | meta: { ...route.meta } |
| | | }) |
| | | meta: { ...route.meta }, |
| | | }); |
| | | } |
| | | if (route.children) { |
| | | const tempTags = this.filterAffixTags(route.children, route.path) |
| | | const tempTags = this.filterAffixTags(route.children, route.path); |
| | | if (tempTags.length >= 1) { |
| | | tags = [...tags, ...tempTags] |
| | | tags = [...tags, ...tempTags]; |
| | | } |
| | | } |
| | | }) |
| | | return tags |
| | | }); |
| | | return tags; |
| | | }, |
| | | initTags() { |
| | | const affixTags = this.affixTags = this.filterAffixTags(this.routes) |
| | | const affixTags = (this.affixTags = this.filterAffixTags(this.routes)); |
| | | for (const tag of affixTags) { |
| | | // Must have tag name |
| | | if (tag.name) { |
| | | this.$store.dispatch('tagsView/addVisitedView', tag) |
| | | this.$store.dispatch("tagsView/addVisitedView", tag); |
| | | } |
| | | } |
| | | }, |
| | | addTags() { |
| | | const { name } = this.$route |
| | | const { name } = this.$route; |
| | | if (name) { |
| | | this.$store.dispatch('tagsView/addView', this.$route) |
| | | this.$store.dispatch("tagsView/addView", this.$route); |
| | | } |
| | | return false |
| | | return false; |
| | | }, |
| | | moveToCurrentTag() { |
| | | const tags = this.$refs.tag |
| | | const tags = this.$refs.tag; |
| | | this.$nextTick(() => { |
| | | for (const tag of tags) { |
| | | if (tag.to.path === this.$route.path) { |
| | | this.$refs.scrollPane.moveToTarget(tag) |
| | | this.$refs.scrollPane.moveToTarget(tag); |
| | | // when query is different then update |
| | | if (tag.to.fullPath !== this.$route.fullPath) { |
| | | this.$store.dispatch('tagsView/updateVisitedView', this.$route) |
| | | this.$store.dispatch("tagsView/updateVisitedView", this.$route); |
| | | } |
| | | break |
| | | break; |
| | | } |
| | | } |
| | | }) |
| | | }); |
| | | }, |
| | | refreshSelectedTag(view) { |
| | | this.$store.dispatch('tagsView/delCachedView', view).then(() => { |
| | | const { fullPath } = view |
| | | this.$store.dispatch("tagsView/delCachedView", view).then(() => { |
| | | const { fullPath } = view; |
| | | this.$nextTick(() => { |
| | | this.$router.replace({ |
| | | path: '/redirect' + fullPath |
| | | }) |
| | | }) |
| | | }) |
| | | path: "/redirect" + fullPath, |
| | | }); |
| | | }); |
| | | }); |
| | | }, |
| | | closeSelectedTag(view) { |
| | | this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => { |
| | | if (this.isActive(view)) { |
| | | this.toLastView(visitedViews, view) |
| | | } |
| | | }) |
| | | this.$store |
| | | .dispatch("tagsView/delView", view) |
| | | .then(({ visitedViews }) => { |
| | | if (this.isActive(view)) { |
| | | this.toLastView(visitedViews, view); |
| | | } |
| | | }); |
| | | }, |
| | | closeOthersTags() { |
| | | this.$router.push(this.selectedTag) |
| | | this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => { |
| | | this.moveToCurrentTag() |
| | | }) |
| | | this.$router.push(this.selectedTag); |
| | | this.$store |
| | | .dispatch("tagsView/delOthersViews", this.selectedTag) |
| | | .then(() => { |
| | | this.moveToCurrentTag(); |
| | | }); |
| | | }, |
| | | closeAllTags(view) { |
| | | this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => { |
| | | if (this.affixTags.some(tag => tag.path === view.path)) { |
| | | return |
| | | this.$store.dispatch("tagsView/delAllViews").then(({ visitedViews }) => { |
| | | if (this.affixTags.some((tag) => tag.path === view.path)) { |
| | | return; |
| | | } |
| | | this.toLastView(visitedViews, view) |
| | | }) |
| | | this.toLastView(visitedViews, view); |
| | | }); |
| | | }, |
| | | toLastView(visitedViews, view) { |
| | | const latestView = visitedViews.slice(-1)[0] |
| | | const latestView = visitedViews.slice(-1)[0]; |
| | | if (latestView) { |
| | | this.$router.push(latestView.fullPath) |
| | | this.$router.push(latestView.fullPath); |
| | | } else { |
| | | // now the default is to redirect to the home page if there is no tags-view, |
| | | // you can adjust it according to your needs. |
| | | if (view.name === 'Dashboard') { |
| | | if (view.name === "Dashboard") { |
| | | // to reload home page |
| | | this.$router.replace({ path: '/redirect' + view.fullPath }) |
| | | this.$router.replace({ path: "/redirect" + view.fullPath }); |
| | | } else { |
| | | this.$router.push('/') |
| | | this.$router.push("/"); |
| | | } |
| | | } |
| | | }, |
| | | openMenu(tag, e) { |
| | | const menuMinWidth = 105 |
| | | const offsetLeft = this.$el.getBoundingClientRect().left // container margin left |
| | | const offsetWidth = this.$el.offsetWidth // container width |
| | | const maxLeft = offsetWidth - menuMinWidth // left boundary |
| | | const left = e.clientX - offsetLeft + 15 // 15: margin right |
| | | const menuMinWidth = 105; |
| | | const offsetLeft = this.$el.getBoundingClientRect().left; // container margin left |
| | | const offsetWidth = this.$el.offsetWidth; // container width |
| | | const maxLeft = offsetWidth - menuMinWidth; // left boundary |
| | | const left = e.clientX - offsetLeft + 15; // 15: margin right |
| | | |
| | | if (left > maxLeft) { |
| | | this.left = maxLeft |
| | | this.left = maxLeft; |
| | | } else { |
| | | this.left = left |
| | | this.left = left; |
| | | } |
| | | |
| | | this.top = e.clientY |
| | | this.visible = true |
| | | this.selectedTag = tag |
| | | this.top = e.clientY; |
| | | this.visible = true; |
| | | this.selectedTag = tag; |
| | | }, |
| | | closeMenu() { |
| | | this.visible = false |
| | | this.visible = false; |
| | | }, |
| | | handleScroll() { |
| | | this.closeMenu() |
| | | } |
| | | } |
| | | } |
| | | this.closeMenu(); |
| | | }, |
| | | toggleSideBar() { |
| | | this.$store.dispatch('app/toggleSideBar') |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .tags-view-container { |
| | | height: 34px; |
| | | width: 100%; |
| | | background: #fff; |
| | | border-bottom: 1px solid #d8dce5; |
| | | box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04); |
| | | // width: 100%; |
| | | margin: 0 10px; |
| | | background: #0F8090; |
| | | display: flex; |
| | | .tags-inner { |
| | | flex: 1; |
| | | } |
| | | .tags-view-wrapper { |
| | | .tags-view-item { |
| | | display: inline-block; |
| | |
| | | margin-right: 15px; |
| | | } |
| | | &.active { |
| | | background-color: #42b983; |
| | | color: #fff; |
| | | border-color: #42b983; |
| | | // background-color: #42b983; |
| | | background-color: #78EEF8; |
| | | color: #000; |
| | | border-color: #78EEF8; |
| | | &::before { |
| | | content: ''; |
| | | content: ""; |
| | | background: #fff; |
| | | display: inline-block; |
| | | width: 8px; |
| | |
| | | font-size: 12px; |
| | | font-weight: 400; |
| | | color: #333; |
| | | box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); |
| | | box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3); |
| | | li { |
| | | margin: 0; |
| | | padding: 7px 16px; |
| | |
| | | vertical-align: 2px; |
| | | border-radius: 50%; |
| | | text-align: center; |
| | | transition: all .3s cubic-bezier(.645, .045, .355, 1); |
| | | transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); |
| | | transform-origin: 100% 50%; |
| | | &:before { |
| | | transform: scale(.6); |
| | | // transform: scale(0.6); |
| | | transform: scale(1.6); |
| | | display: inline-block; |
| | | vertical-align: -3px; |
| | | } |
| | |
| | | <template> |
| | | <div :class="classObj" class="app-wrapper"> |
| | | <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> |
| | | <!-- <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> --> |
| | | <div v-if="sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> |
| | | <sidebar class="sidebar-container" /> |
| | | <div class="main-container"> |
| | | <div class="inner"> |
| | | <div class="inner"> |
| | | <div class="main-container-wrapper"> |
| | | <div class="main-container-header"> |
| | | <navbar /> |
| | | <tags-view /> |
| | | </div> |
| | | <div class="main-container-content"> |
| | | <app-main /> |
| | | </div> |
| | | <div class="main-container-header"> |
| | | <navbar /> |
| | | <tags-view /> |
| | | </div> |
| | | <div class="main-container-content"> |
| | | <app-main /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components' |
| | | import ResizeMixin from './mixin/ResizeHandler' |
| | | import { mapState } from 'vuex' |
| | | import { AppMain, Navbar, Settings, Sidebar, TagsView } from "./components"; |
| | | import ResizeMixin from "./mixin/ResizeHandler"; |
| | | import { mapState } from "vuex"; |
| | | |
| | | import createWs from '@/assets/js/websocket/plus'; |
| | | const WSMixin = createWs('loginCheck'); |
| | | import createWs from "@/assets/js/websocket/plus"; |
| | | const WSMixin = createWs("loginCheck"); |
| | | |
| | | export default { |
| | | name: 'Layout', |
| | | name: "Layout", |
| | | components: { |
| | | AppMain, |
| | | Navbar, |
| | | Settings, |
| | | Sidebar, |
| | | TagsView |
| | | TagsView, |
| | | }, |
| | | mixins: [ResizeMixin, WSMixin], |
| | | mixins: [ResizeMixin |
| | | // , WSMixin |
| | | ], |
| | | computed: { |
| | | ...mapState({ |
| | | sidebar: state => state.app.sidebar, |
| | | device: state => state.app.device, |
| | | sidebar: (state) => state.app.sidebar, |
| | | device: (state) => state.app.device, |
| | | }), |
| | | classObj() { |
| | | return { |
| | | hideSidebar: !this.sidebar.opened, |
| | | openSidebar: this.sidebar.opened, |
| | | withoutAnimation: this.sidebar.withoutAnimation, |
| | | mobile: this.device === 'mobile' |
| | | } |
| | | } |
| | | classObj() { |
| | | return { |
| | | hideSidebar: !this.sidebar.opened, |
| | | openSidebar: this.sidebar.opened, |
| | | withoutAnimation: this.sidebar.withoutAnimation, |
| | | mobile: this.device === "mobile", |
| | | }; |
| | | }, |
| | | }, |
| | | methods: { |
| | | handleClickOutside() { |
| | | this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
| | | this.$store.dispatch("app/closeSideBar", { withoutAnimation: false }); |
| | | }, |
| | | onWSMessage1: function(res) { |
| | | onWSMessage1: function (res) { |
| | | //console.log(res) |
| | | let resData = JSON.parse(res.data); |
| | | if (!resData.data.checkLogin.data) { |
| | | this.$layer.msg(resData.data.checkLogin.msg); |
| | | this.$store.dispatch('user/logout'); |
| | | this.$store.dispatch("user/logout"); |
| | | setTimeout(() => { |
| | | this.$router.push("/login"); |
| | | location.reload(); |
| | | }, 2000); |
| | | } |
| | | }, |
| | | onWSOpen1: function() { |
| | | onWSOpen1: function () { |
| | | console.log("通讯成功"); |
| | | }, |
| | | } |
| | | } |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .app-wrapper { |
| | | display: flex; |
| | | height: 100%; |
| | | .main-container { |
| | | flex: 1; |
| | | display: flex; |
| | | height: 100%; |
| | | .drawer-bg { |
| | | position: fixed; |
| | | top: 0; |
| | | bottom: 0; |
| | | right: 0; |
| | | left: 0; |
| | | z-index: 999998; |
| | | } |
| | | &.hideSidebar .sidebar-container { |
| | | transform: translate(-100%, 0); |
| | | } |
| | | .sidebar-container { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | bottom: 0; |
| | | z-index: 999999; |
| | | } |
| | | .main-container { |
| | | flex: 1; |
| | | position: relative; |
| | | .inner { |
| | | position: absolute; |
| | |
| | | right: 0; |
| | | bottom: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .main-container-wrapper { |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | .main-container-content { |
| | | flex: 1; |
| | | overflow-y: auto; |
| | | } |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | .main-container-content { |
| | | flex: 1; |
| | | overflow-y: auto; |
| | | margin: 0 10px; |
| | | background: #122C43; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | ] |
| | | }, |
| | | { |
| | | path: "/realtime", |
| | | component: Layout, |
| | | meta: { title: "实时监控", icon: 'dashboard'}, |
| | | name: "realtime", |
| | | children: [ |
| | | { |
| | | path: '', |
| | | component: () => import('@/views/realTime'), |
| | | name: 'realtime', |
| | | meta: {title: '实时监控', icon: 'dashboard'} |
| | | }, |
| | | ] |
| | | }, |
| | | { |
| | | path: "/user", |
| | | component: Layout, |
| | | redirect: '/user/list', |
New file |
| | |
| | | <template> |
| | | <g :transform="'translate(' + offset.join(',') + ')'"> |
| | | <defs> |
| | | <linearGradient id="color" x1="0%" y1="0%" x2="0%" y2="100%"> |
| | | <stop offset="0%" style="stop-color: #377add; stop-opacity: 1" /> |
| | | <stop offset="100%" style="stop-color: #4ec1fb; stop-opacity: 1" /> |
| | | </linearGradient> |
| | | </defs> |
| | | <!-- 圆角矩形 --> |
| | | <path |
| | | :d="createRoundRectPath(92, 80, 10)" |
| | | stroke="none" |
| | | fill="url(#color)" |
| | | /> |
| | | |
| | | <!-- 绘制标题 --> |
| | | <text x="46" y="18" text-anchor="middle" fill="#fff" font-size="16"> |
| | | 防雷保护器 |
| | | </text> |
| | | |
| | | <!-- 绘制图片 --> |
| | | <image x="13" y="22" width="66" height="48" :xlink:href="img" /> |
| | | </g> |
| | | </template> |
| | | |
| | | <script> |
| | | import img from "../images/bhq.png"; |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | offset: { |
| | | type: Array, |
| | | default() { |
| | | return [0, 0]; |
| | | }, |
| | | }, |
| | | }, |
| | | computed: {}, |
| | | data() { |
| | | return { |
| | | img, |
| | | }; |
| | | }, |
| | | methods: { |
| | | createRoundRectPath(w, h, r = 5, x = 0, y = 0) { |
| | | let p0 = [x, y]; |
| | | let p1 = [x + w, y]; |
| | | let p2 = [x + w, y + h]; |
| | | let p3 = [x, y + h]; |
| | | |
| | | let cp0 = [x + r, y]; |
| | | let cp1 = [x + w - r, y]; |
| | | let cp2 = [x + w, y + r]; |
| | | let cp3 = [x + w, y + h - r]; |
| | | let cp4 = [x + w - r, y + h]; |
| | | let cp5 = [x + r, y + h]; |
| | | let cp6 = [x, y + h - r]; |
| | | let cp7 = [x, y + r]; |
| | | |
| | | return `M${cp0[0]},${cp0[1]} |
| | | L ${cp1[0]} ${cp1[1]} |
| | | C ${cp1[0]} ${cp1[1]}, ${p1[0]} ${p1[1]}, ${cp2[0]} ${cp2[1]} |
| | | L ${cp3[0]} ${cp3[1]} |
| | | C ${cp3[0]} ${cp3[1]}, ${p2[0]} ${p2[1]}, ${cp4[0]} ${cp4[1]} |
| | | L ${cp5[0]} ${cp5[1]} |
| | | C ${cp5[0]} ${cp5[1]}, ${p3[0]} ${p3[1]}, ${cp6[0]} ${cp6[1]} |
| | | L ${cp7[0]} ${cp7[1]} |
| | | C ${cp7[0]} ${cp7[1]}, ${p0[0]} ${p0[1]}, ${cp0[0]} ${cp0[1]} |
| | | Z`; |
| | | }, |
| | | }, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <g :transform="'translate(' + offset.join(',') + ')'"> |
| | | <!-- 圆角矩形 --> |
| | | <path :d="createLinePath()" stroke="#fff" fill="none" stroke-width="2" /> |
| | | </g> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | offset: { |
| | | type: Array, |
| | | default() { |
| | | return [0, 0]; |
| | | }, |
| | | }, |
| | | radius: { |
| | | type: Number, |
| | | default: 0, |
| | | }, |
| | | points: { |
| | | type: Array, |
| | | required: true, |
| | | default() { |
| | | return [ |
| | | [0, 0], |
| | | [10, 10], |
| | | ]; |
| | | }, |
| | | }, |
| | | }, |
| | | computed: {}, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | methods: { |
| | | // 获取线段上离终点指定距离的点的坐标 |
| | | getPointForLine(p0, p1, dis) { |
| | | let dir = [p1[0] - p0[0], p1[1] - p0[1]]; |
| | | let dirlen = Math.sqrt(dir[0] * dir[0] + dir[1] * dir[1]); |
| | | let dir_normal = [dir[0] / dirlen, dir[1] / dirlen]; |
| | | let dis_v = [dir_normal[0] * dis, dir_normal[1] * dis]; |
| | | return [p1[0] - dis_v[0], p1[1] - dis_v[1]]; |
| | | }, |
| | | createLinePath() { |
| | | let { radius, points } = this; |
| | | let path = ""; |
| | | let len = points.length; |
| | | points.forEach((v, i) => { |
| | | let isCentral = i > 0 && i < len - 1; |
| | | let p_last = i > 0 ? points[i - 1] : []; |
| | | let p_next = i < len - 1 ? points[i + 1] : []; |
| | | if (0 == i) { |
| | | path += `M${v[0]},${v[1]}`; |
| | | } else if (i == len - 1) { |
| | | path += ` L ${v[0]} ${v[1]}`; |
| | | } else { |
| | | if (radius > 0) { |
| | | let c_last = this.getPointForLine(p_last, v, radius); |
| | | let c_next = this.getPointForLine(p_next, v, radius); |
| | | p_last; |
| | | path += ` L ${c_last[0]} ${c_last[1]} C ${c_last[0]} ${c_last[1]}, ${v[0]} ${v[1]}, ${c_next[0]} ${c_next[1]}`; |
| | | } else { |
| | | path += ` L ${v[0]} ${v[1]}`; |
| | | } |
| | | } |
| | | }); |
| | | |
| | | return path; |
| | | }, |
| | | }, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <g class="pointer" :transform="'translate(' + offset.join(',') + ')'"> |
| | | <!-- 圆角矩形 --> |
| | | <path |
| | | :d="createRoundRectPath(small ? 64 : 84, 68, 10)" |
| | | stroke="#07D0C8" |
| | | :fill="alarm ? '#FF3801' : '#0C4D77'" |
| | | /> |
| | | |
| | | <!-- 绘制标题 --> |
| | | <text |
| | | x="16" |
| | | y="44" |
| | | text-anchor="middle" |
| | | fill="rgb(200,200,200)" |
| | | font-size="20" |
| | | > |
| | | {{ type + "P" }} |
| | | </text> |
| | | |
| | | <!-- 绘制图片 --> |
| | | <image :x="small ? 36 : 40" y="6" :width="imgW" height="60" :xlink:href="url" /> |
| | | </g> |
| | | </template> |
| | | |
| | | <script> |
| | | import SP1 from "../images/s-1p.png"; |
| | | import SP2 from "../images/s-2p.png"; |
| | | import SP3 from "../images/s-3p.png"; |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | type: { |
| | | type: Number, |
| | | default: 1, |
| | | }, |
| | | small: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | alarm: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | offset: { |
| | | type: Array, |
| | | default() { |
| | | return [0, 0]; |
| | | }, |
| | | }, |
| | | }, |
| | | computed: { |
| | | url() { |
| | | let res = ""; |
| | | switch (this.type) { |
| | | case 1: |
| | | res = SP1; |
| | | break; |
| | | |
| | | case 2: |
| | | res = SP2; |
| | | break; |
| | | case 3: |
| | | res = SP3; |
| | | break; |
| | | } |
| | | return res; |
| | | }, |
| | | imgW() { |
| | | let res = ""; |
| | | switch (this.type) { |
| | | case 1: |
| | | res = 20; |
| | | break; |
| | | |
| | | case 2: |
| | | res = 26; |
| | | break; |
| | | case 3: |
| | | res = 32; |
| | | break; |
| | | } |
| | | return res; |
| | | }, |
| | | }, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | methods: { |
| | | createRoundRectPath(w, h, r = 5, x = 0, y = 0) { |
| | | let p0 = [x, y]; |
| | | let p1 = [x + w, y]; |
| | | let p2 = [x + w, y + h]; |
| | | let p3 = [x, y + h]; |
| | | |
| | | let cp0 = [x + r, y]; |
| | | let cp1 = [x + w - r, y]; |
| | | let cp2 = [x + w, y + r]; |
| | | let cp3 = [x + w, y + h - r]; |
| | | let cp4 = [x + w - r, y + h]; |
| | | let cp5 = [x + r, y + h]; |
| | | let cp6 = [x, y + h - r]; |
| | | let cp7 = [x, y + r]; |
| | | |
| | | return `M${cp0[0]},${cp0[1]} |
| | | L ${cp1[0]} ${cp1[1]} |
| | | C ${cp1[0]} ${cp1[1]}, ${p1[0]} ${p1[1]}, ${cp2[0]} ${cp2[1]} |
| | | L ${cp3[0]} ${cp3[1]} |
| | | C ${cp3[0]} ${cp3[1]}, ${p2[0]} ${p2[1]}, ${cp4[0]} ${cp4[1]} |
| | | L ${cp5[0]} ${cp5[1]} |
| | | C ${cp5[0]} ${cp5[1]}, ${p3[0]} ${p3[1]}, ${cp6[0]} ${cp6[1]} |
| | | L ${cp7[0]} ${cp7[1]} |
| | | C ${cp7[0]} ${cp7[1]}, ${p0[0]} ${p0[1]}, ${cp0[0]} ${cp0[1]} |
| | | Z`; |
| | | }, |
| | | }, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .pointer { |
| | | cursor: pointer; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div> |
| | | <svg width="100%" height="100%" viewBox="0 0 800 600"> |
| | | <switch-box :type="3" :offset="[60, 40]"></switch-box> |
| | | <switch-box :type="3" :offset="[180, 40]"></switch-box> |
| | | <switch-box :type="3" :offset="[300, 40]"></switch-box> |
| | | <switch-box :type="1" :offset="[20, 180]"></switch-box> |
| | | <switch-box :type="1" :offset="[120, 180]"></switch-box> |
| | | <switch-box :type="1" :offset="[220, 180]"></switch-box> |
| | | <switch-box :type="1" :offset="[320, 180]"></switch-box> |
| | | </svg> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import img from "../images/hr.png"; |
| | | import SwitchBox from './switchBox'; |
| | | export default { |
| | | name: "", |
| | | |
| | | data() { |
| | | return { |
| | | img, |
| | | }; |
| | | }, |
| | | components: { |
| | | SwitchBox, |
| | | }, |
| | | methods: {}, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <g :transform="'translate(' + offset.join(',') + ')'"> |
| | | <!-- 圆角矩形 --> |
| | | <path |
| | | :d="createRoundRectPath(84, 30, 6)" |
| | | stroke="none" |
| | | fill="#F69F40" |
| | | /> |
| | | |
| | | <!-- 绘制标题 --> |
| | | <text x="42" y="20" text-anchor="middle" fill="#011F39" font-size="18"> |
| | | 电操开关 |
| | | </text> |
| | | </g> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "", |
| | | props: { |
| | | offset: { |
| | | type: Array, |
| | | default() { |
| | | return [0, 0]; |
| | | }, |
| | | }, |
| | | }, |
| | | computed: {}, |
| | | data() { |
| | | return { |
| | | }; |
| | | }, |
| | | methods: { |
| | | createRoundRectPath(w, h, r = 5, x = 0, y = 0) { |
| | | let p0 = [x, y]; |
| | | let p1 = [x + w, y]; |
| | | let p2 = [x + w, y + h]; |
| | | let p3 = [x, y + h]; |
| | | |
| | | let cp0 = [x + r, y]; |
| | | let cp1 = [x + w - r, y]; |
| | | let cp2 = [x + w, y + r]; |
| | | let cp3 = [x + w, y + h - r]; |
| | | let cp4 = [x + w - r, y + h]; |
| | | let cp5 = [x + r, y + h]; |
| | | let cp6 = [x, y + h - r]; |
| | | let cp7 = [x, y + r]; |
| | | |
| | | return `M${cp0[0]},${cp0[1]} |
| | | L ${cp1[0]} ${cp1[1]} |
| | | C ${cp1[0]} ${cp1[1]}, ${p1[0]} ${p1[1]}, ${cp2[0]} ${cp2[1]} |
| | | L ${cp3[0]} ${cp3[1]} |
| | | C ${cp3[0]} ${cp3[1]}, ${p2[0]} ${p2[1]}, ${cp4[0]} ${cp4[1]} |
| | | L ${cp5[0]} ${cp5[1]} |
| | | C ${cp5[0]} ${cp5[1]}, ${p3[0]} ${p3[1]}, ${cp6[0]} ${cp6[1]} |
| | | L ${cp7[0]} ${cp7[1]} |
| | | C ${cp7[0]} ${cp7[1]}, ${p0[0]} ${p0[1]}, ${cp0[0]} ${cp0[1]} |
| | | Z`; |
| | | }, |
| | | }, |
| | | |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | </style> |
| | |
| | | <script> |
| | | import { mapState } from "vuex"; |
| | | import { updateDfu, readFileList, getDevFileName, stopDfu } from "./api"; |
| | | import propConfig from "./js/props"; |
| | | import SwitchBox from "./components/switchBox"; |
| | | import ProtectorBox from "./components/protectorBox"; |
| | | import TextBox from "./components/textBox"; |
| | | import SvgLine from "./components/svgline"; |
| | | |
| | | import FileProcess from "./fileProcess"; |
| | | import getWebUrl from "@/assets/js/getWebUrl"; |
| | | import Panel from "@/components/panel.vue"; |
| | | import pdgImg from "./images/pdg.png"; |
| | | import kggImg from "./images/kgg.png"; |
| | | import hrImg from "./images/hr.png"; |
| | | |
| | | import createWs from "@/assets/js/websocket/plus"; |
| | | const WSMixin = createWs("dev", "dfu"); |
| | | |
| | | const WORKSTATE = ["通信故障", "通信正常", "远程升级中", "文件下载中"]; |
| | | const { PDG, KGG, HR } = propConfig; |
| | | export default { |
| | | name: "home", |
| | | mixins: [WSMixin], |
| | | // mixins: [WSMixin], |
| | | components: { |
| | | FileProcess, |
| | | Panel, |
| | | SwitchBox, |
| | | ProtectorBox, |
| | | TextBox, |
| | | SvgLine, |
| | | }, |
| | | data() { |
| | | const baseURL = getWebUrl(); |
| | | return { |
| | | updatePercent: 0, |
| | | baseURL, |
| | | fileListVisible: false, |
| | | updateVisible: false, |
| | | battListVisible: false, |
| | | tableData: [], |
| | | headers: [ |
| | | { |
| | | prop: "devIp", |
| | | label: "设备Ip", |
| | | width: "180", |
| | | }, |
| | | { |
| | | prop: "devVersion", |
| | | label: "设备版本号", |
| | | width: "240", |
| | | }, |
| | | { |
| | | prop: "devId", |
| | | label: "设备ID", |
| | | width: "180", |
| | | }, |
| | | { |
| | | prop: "recordDatetime", |
| | | label: "更新时间", |
| | | width: "180", |
| | | }, |
| | | { |
| | | prop: "devEachgroupBattsum", |
| | | label: "电池组数", |
| | | width: "120", |
| | | }, |
| | | { |
| | | prop: "devState", |
| | | label: "设备工作状态", |
| | | width: "120", |
| | | }, |
| | | { |
| | | prop: "devCommcount", |
| | | label: "设备通信计数", |
| | | width: "120", |
| | | }, |
| | | { |
| | | prop: "devErrcommcount", |
| | | label: "设备通信错误计数", |
| | | width: "150", |
| | | }, |
| | | ], |
| | | tableBattsData: [], |
| | | battsHeaders: [ |
| | | { |
| | | prop: "battName", |
| | | label: "电池组名称", |
| | | width: "240", |
| | | }, |
| | | ], |
| | | fileList: [], |
| | | currDevId: 0, |
| | | transferFiles: {}, |
| | | pcFileListVisible: false, |
| | | pcFileList: [], |
| | | multipleSelection: [], |
| | | PDG, |
| | | KGG, |
| | | HR, |
| | | pdgImg, |
| | | kggImg, |
| | | hrImg, |
| | | }; |
| | | }, |
| | | methods: { |
| | | onWSMessage1(res) { |
| | | res = JSON.parse(res.data); |
| | | |
| | | let sys_time = new Date(res.data3).getTime(); |
| | | let data = res.data2.map((v) => { |
| | | v.isTimeout = |
| | | Math.abs(new Date(v.recordDatetime).getTime() - sys_time) > 1000 * 60; |
| | | v.devState = v.isTimeout ? "连接超时" : WORKSTATE[v.devWorkstate]; |
| | | v.batts = v.battnamelist.split(","); |
| | | return v; |
| | | }); |
| | | // console.log(data, "=====data", sys_time); |
| | | this.tableData = data; |
| | | }, |
| | | onWSMessage2(res) { |
| | | res = JSON.parse(res.data); |
| | | let { dfuDataBlocklen, dfuDataBlocknum } = res.data2; |
| | | if (!dfuDataBlocklen) { |
| | | this.updatePercent = 0; |
| | | return false; |
| | | } |
| | | this.updatePercent = |
| | | Math.round((dfuDataBlocknum / dfuDataBlocklen) * 10000) / 100; |
| | | }, |
| | | sendMessage2() { |
| | | if (!this.isWSOpen2) { |
| | | setTimeout(this.sendMessage2, 500); |
| | | return false; |
| | | } |
| | | this.SOCKET2.send(JSON.stringify(this.currDevId)); |
| | | }, |
| | | canUpdate(record) { |
| | | let { isTimeout, devWorkstate } = record; |
| | | return !isTimeout && (devWorkstate == 1 || devWorkstate == 2); |
| | | }, |
| | | canRead(record) { |
| | | let { isTimeout, devWorkstate } = record; |
| | | return !isTimeout && (devWorkstate == 1 || devWorkstate == 3); |
| | | }, |
| | | showBatts(record) { |
| | | this.currDevId = record.devId; |
| | | this.tableBattsData = record.batts.map((v, i) => ({ |
| | | battName: v, |
| | | idx: i, |
| | | })); |
| | | this.battListVisible = true; |
| | | }, |
| | | update(record) { |
| | | this.currDevId = record.devId; |
| | | this.fileList = []; |
| | | this.updateVisible = true; |
| | | this.sendMessage2(); |
| | | }, |
| | | fileChange(file, fileList) { |
| | | // console.log(file, fileList, "change"); |
| | | this.fileList = [file]; |
| | | }, |
| | | fileRemove(file, fileList) { |
| | | this.fileList = fileList; |
| | | }, |
| | | stopUpdate() { |
| | | let loading = this.$layer.loading(); |
| | | stopDfu(this.currDevId) |
| | | .then((res) => { |
| | | let { code, data } = res.data; |
| | | if (code && data) { |
| | | this.$message.success("操作成功"); |
| | | } else { |
| | | this.$message.error("操作失败"); |
| | | } |
| | | this.$layer.close(loading); |
| | | }) |
| | | .catch((err) => { |
| | | this.$layer.close(loading); |
| | | console.log(err); |
| | | }); |
| | | }, |
| | | upload() { |
| | | let formData = new FormData(); |
| | | formData.append("file", this.fileList[0].raw); |
| | | formData.append("devId", this.currDevId); |
| | | let loading = this.$layer.loading(); |
| | | updateDfu(formData) |
| | | .then((res) => { |
| | | let { code, data, msg } = res.data; |
| | | if (code && data) { |
| | | this.$message.success(msg); |
| | | } else { |
| | | this.$message.error(msg); |
| | | } |
| | | this.$layer.close(loading); |
| | | }) |
| | | .catch((err) => { |
| | | this.$layer.close(loading); |
| | | console.log(err); |
| | | }); |
| | | }, |
| | | showFiles(record) { |
| | | // 如果是下载中 则不请求数据 进组件 查websocket |
| | | if (this.isTransfering) { |
| | | this.fileListVisible = true; |
| | | this.transferFiles = {}; |
| | | return; |
| | | } |
| | | |
| | | let battIndex = record.idx; |
| | | let devId = this.currDevId; |
| | | let fileIndex = 0; |
| | | let loading = this.$layer.loading(); |
| | | readFileList(battIndex, devId, fileIndex) |
| | | .then((res) => { |
| | | let { code, data, data2, msg } = res.data; |
| | | if (code && data) { |
| | | this.$message.success(msg); |
| | | this.fileListVisible = true; |
| | | this.transferFiles = data2; |
| | | } else { |
| | | this.$message.error(msg); |
| | | this.transferFiles = {}; |
| | | } |
| | | this.$layer.close(loading); |
| | | }) |
| | | .catch((err) => { |
| | | this.$layer.close(loading); |
| | | console.log(err); |
| | | }); |
| | | }, |
| | | showPCFiles(record) { |
| | | let battName = record.battName; |
| | | let devId = this.currDevId; |
| | | let loading = this.$layer.loading(); |
| | | getDevFileName(battName, devId) |
| | | .then((res) => { |
| | | let { code, data, data2 } = res.data; |
| | | let list = []; |
| | | if (code && data) { |
| | | // console.log(data); |
| | | list = data2.map((v) => { |
| | | let url = v; |
| | | let fileName = url.split("\\").pop(); |
| | | return { |
| | | url, |
| | | fileName, |
| | | }; |
| | | }); |
| | | } |
| | | this.$layer.close(loading); |
| | | this.pcFileList = list; |
| | | this.pcFileListVisible = true; |
| | | }) |
| | | .catch((err) => { |
| | | this.$layer.close(loading); |
| | | console.log(err); |
| | | }); |
| | | }, |
| | | handleSelectionChange(val) { |
| | | // console.log(val, "selection"); |
| | | this.multipleSelection = val; |
| | | }, |
| | | downloadFile(url) { |
| | | // const fileName = url.split("\\").pop(); |
| | | // let link = document.createElement("a"); |
| | | // link.style.display = "none"; |
| | | // link.href = this.baseURL + url; |
| | | // link.download = fileName; |
| | | // document.body.appendChild(link); |
| | | // link.click(); |
| | | // document.body.removeChild(link); |
| | | const iframe = document.createElement("iframe"); |
| | | iframe.style.display = "none"; |
| | | iframe.src = this.baseURL + url; |
| | | document.body.appendChild(iframe); |
| | | setTimeout(() => { |
| | | iframe.remove(); |
| | | }, 10 * 1000); |
| | | }, |
| | | downloadFiles() { |
| | | // console.log(this.multipleSelection, "??z"); |
| | | this.multipleSelection.forEach((v, i) => { |
| | | this.downloadFile(v.url); |
| | | }); |
| | | }, |
| | | hover() { |
| | | console.log('hhhh'); |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapState({ |
| | | cachedViews: (state) => state.tagsView.cachedViews, |
| | | }), |
| | | isTransfering() { |
| | | if (!this.currDevId) { |
| | | return false; |
| | | } |
| | | let obj = this.tableData.filter((v) => v.devId == this.currDevId)[0]; |
| | | let { isTimeout, devWorkstate } = obj; |
| | | // console.log("是否下载中", !isTimeout && devWorkstate == 3); |
| | | return !isTimeout && devWorkstate == 3; |
| | | }, |
| | | isUpdateing() { |
| | | if (!this.currDevId) { |
| | | return false; |
| | | } |
| | | let obj = this.tableData.filter((v) => v.devId == this.currDevId)[0]; |
| | | let { isTimeout, devWorkstate } = obj; |
| | | return !isTimeout && devWorkstate == 2; |
| | | }, |
| | | readingBattName() { |
| | | if (!this.currDevId) { |
| | | return false; |
| | | } |
| | | let obj = this.tableData.filter((v) => v.devId == this.currDevId)[0]; |
| | | return obj.nowDownloadBatt; |
| | | }, |
| | | progressColor() { |
| | | if (this.updatePercent < 30) { |
| | | return "#ff0000"; |
| | | } |
| | | if (this.updatePercent < 60) { |
| | | return "#AA40F0"; |
| | | } |
| | | if (this.updatePercent == 100) { |
| | | return "#009900"; |
| | | } else { |
| | | return "#4840F0"; |
| | | } |
| | | }, |
| | | progressTextColor() { |
| | | if (this.updatePercent < 8) { |
| | | return "#00f7f9"; |
| | | } |
| | | return "#ffffff"; |
| | | }, |
| | | }, |
| | | mounted() {}, |
| | | }; |
| | |
| | | |
| | | <template> |
| | | <div class="p-container" ref="root"> |
| | | <div class="p-title">设备列表</div> |
| | | <el-table |
| | | ref="table" |
| | | :data="tableData" |
| | | border |
| | | height="100%" |
| | | style="width: 100%" |
| | | tooltip-effect="light" |
| | | > |
| | | <el-table-column type="index" label="序号" width="80"></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" |
| | | show-overflow-tooltip |
| | | ></el-table-column> |
| | | <el-table-column label="操作" fixed="right" width="180" align="center"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | type="primary" |
| | | size="mini" |
| | | :disabled="!canRead(scope.row)" |
| | | @click="showBatts(scope.row)" |
| | | >电池组列表</el-button |
| | | > |
| | | <el-button |
| | | type="danger" |
| | | :disabled="!canUpdate(scope.row)" |
| | | size="mini" |
| | | @click="update(scope.row)" |
| | | >升级</el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- 升级弹窗 --> |
| | | <el-dialog |
| | | title="电池组列表" |
| | | :visible.sync="updateVisible" |
| | | top="0" |
| | | :close-on-click-modal="false" |
| | | class="dialog-center" |
| | | width="700px" |
| | | center |
| | | > |
| | | <el-upload |
| | | v-if="!isUpdateing" |
| | | class="upload-demo" |
| | | ref="upload" |
| | | action="" |
| | | :multiple="false" |
| | | :on-remove="fileRemove" |
| | | :on-change="fileChange" |
| | | :file-list="fileList" |
| | | accept=".sm5" |
| | | :auto-upload="false" |
| | | > |
| | | <el-button slot="trigger" size="small" type="primary" |
| | | >选取文件</el-button |
| | | > |
| | | </el-upload> |
| | | <template v-else> |
| | | <div class="s-title">升级中</div> |
| | | <el-progress |
| | | :text-inside="true" |
| | | :stroke-width="24" |
| | | :percentage="updatePercent" |
| | | :color="progressColor" |
| | | :text-color="progressTextColor" |
| | | ></el-progress> |
| | | </template> |
| | | <span slot="footer" class="dialog-footer"> |
| | | <el-button @click="updateVisible = false">关闭</el-button> |
| | | <el-button |
| | | v-if="!isUpdateing" |
| | | type="primary" |
| | | :disabled="!fileList.length" |
| | | @click="upload" |
| | | >上传并升级</el-button |
| | | > |
| | | <el-button v-else type="primary" @click="stopUpdate" |
| | | >终止升级</el-button |
| | | > |
| | | </span> |
| | | </el-dialog> |
| | | <!-- 弹窗 --> |
| | | <el-dialog |
| | | title="电池组列表" |
| | | :visible.sync="battListVisible" |
| | | top="0" |
| | | :close-on-click-modal="false" |
| | | class="dialog-center" |
| | | width="700px" |
| | | center |
| | | > |
| | | <el-table |
| | | ref="table" |
| | | :data="tableBattsData" |
| | | border |
| | | max-height="300" |
| | | style="width: 100%" |
| | | tooltip-effect="light" |
| | | > |
| | | <el-table-column type="index" label="序号" width="80"></el-table-column> |
| | | <el-table-column |
| | | v-for="header in battsHeaders" |
| | | :key="header.prop" |
| | | :prop="header.prop" |
| | | :label="header.label" |
| | | :min-width="header.width" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | ></el-table-column> |
| | | <el-table-column label="操作" fixed="right" width="260" align="center"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | type="primary" |
| | | size="mini" |
| | | :disabled=" |
| | | isTransfering && |
| | | !!readingBattName && |
| | | readingBattName != scope.row.battName |
| | | " |
| | | @click="showFiles(scope.row)" |
| | | >读取文件列表</el-button |
| | | > |
| | | <el-button |
| | | type="primary" |
| | | size="mini" |
| | | @click="showPCFiles(scope.row)" |
| | | >已导入文件列表</el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | <!-- 服务器文件列表 --> |
| | | <el-dialog |
| | | title="已导入文件列表" |
| | | :visible.sync="pcFileListVisible" |
| | | top="0" |
| | | :close-on-click-modal="false" |
| | | class="dialog-center" |
| | | width="700px" |
| | | center |
| | | > |
| | | <div class="btn-grp"> |
| | | <el-button |
| | | type="primary" |
| | | size="mini" |
| | | @click="downloadFiles" |
| | | :disabled="!multipleSelection.length" |
| | | >下载选中项</el-button |
| | | > |
| | | <panel class="panel left" title="通信电源柜、核容主机状态"> |
| | | <div class="content"> |
| | | <div class="info info1"> |
| | | <div class="side"> |
| | | <div class="info-title">交直流配电柜</div> |
| | | <div class="img"> |
| | | <el-image :src="pdgImg" fit="fill"></el-image> |
| | | </div> |
| | | <div class="state"> |
| | | <div class="s-row"> |
| | | 运行: |
| | | <div class="i"></div> |
| | | </div> |
| | | <div class="s-row"> |
| | | 通信: |
| | | <div class="i danger"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="main"> |
| | | <div class="list"> |
| | | <div class="row-item" v-for="idx in 9" :key="'pdg_' + idx"> |
| | | {{ idx - 1 }}{{ PDG[idx - 1].label }}: |
| | | </div> |
| | | </div> |
| | | <div class="list"> |
| | | <div class="row-item" v-for="idx of 9" :key="'pdg2_' + idx"> |
| | | <template v-if="PDG[idx + 8]" |
| | | >{{ idx + 8 }}{{ PDG[idx + 8].label }}:</template |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="info info2"> |
| | | <div class="side"> |
| | | <div class="info-title">高频开关柜</div> |
| | | <div class="img"> |
| | | <el-image :src="kggImg" fit="fill"></el-image> |
| | | </div> |
| | | <div class="state"> |
| | | <div class="s-row"> |
| | | 运行: |
| | | <div class="i"></div> |
| | | </div> |
| | | <div class="s-row"> |
| | | 通信: |
| | | <div class="i danger"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="main"> |
| | | <div class="list"> |
| | | <div class="row-item" v-for="idx in 6" :key="'kgg_' + idx"> |
| | | {{ idx - 1 }}{{ KGG[idx - 1].label }}: |
| | | </div> |
| | | </div> |
| | | <div class="list"> |
| | | <div class="row-item" v-for="idx of 6" :key="'kgg2_' + idx"> |
| | | <template v-if="KGG[idx + 5]" |
| | | >{{ idx + 5 }}{{ KGG[idx + 5].label }}:</template |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="info info3"> |
| | | <div class="side"> |
| | | <div class="info-title">核容装置</div> |
| | | <div class="img img3"> |
| | | <el-image :src="hrImg" fit="fill"></el-image> |
| | | </div> |
| | | <div class="state"> |
| | | <div class="s-row"> |
| | | 运行: |
| | | <div class="i"></div> |
| | | </div> |
| | | <div class="s-row"> |
| | | 通信: |
| | | <div class="i danger"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="main"> |
| | | <div class="list"> |
| | | <div class="row-item" v-for="idx in 4" :key="'hr_' + idx"> |
| | | <template v-if="idx < 4" |
| | | >{{ idx - 1 }}{{ HR[idx - 1].label }}:</template |
| | | > |
| | | </div> |
| | | </div> |
| | | <div class="list"> |
| | | <div class="row-item" v-for="idx of 4" :key="'hr2_' + idx"> |
| | | <template v-if="idx < 4 && HR[idx + 2]" |
| | | >{{ idx + 2 }}{{ HR[idx + 2].label }}:</template |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <el-table |
| | | ref="table" |
| | | :data="pcFileList" |
| | | border |
| | | max-height="300" |
| | | style="width: 100%" |
| | | @selection-change="handleSelectionChange" |
| | | tooltip-effect="light" |
| | | > |
| | | <el-table-column type="selection" width="55"> </el-table-column> |
| | | <el-table-column type="index" label="序号" width="80"></el-table-column> |
| | | <el-table-column |
| | | prop="fileName" |
| | | label="文件名称" |
| | | align="center" |
| | | show-overflow-tooltip |
| | | ></el-table-column> |
| | | <el-table-column label="操作" fixed="right" width="160" align="center"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | type="primary" |
| | | size="mini" |
| | | @click="downloadFile(scope.row.url)" |
| | | >下载</el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | <!-- 传输进度弹窗 --> |
| | | <el-dialog |
| | | title="电池组文件列表" |
| | | :visible.sync="fileListVisible" |
| | | top="0" |
| | | :close-on-click-modal="false" |
| | | class="dialog-center" |
| | | width="700px" |
| | | center |
| | | > |
| | | <file-process |
| | | v-if="fileListVisible" |
| | | :dev-id="currDevId" |
| | | :transfer="isTransfering" |
| | | :infos="transferFiles" |
| | | ></file-process> |
| | | </el-dialog> |
| | | </panel> |
| | | <panel class="panel right" title="交流/直流微断路器状态"> |
| | | <div class="content"> |
| | | <!-- --> |
| | | <div class="yc-row row1"> |
| | | <div class="yc-panel"> |
| | | <div class="yc-title">交流进线1</div> |
| | | <div class="yc-content"> |
| | | <div class="svg-contain"> |
| | | <div class="pos-full"> |
| | | <svg width="100%" height="100%" viewBox="0 0 500 340"> |
| | | <text-box :offset="[220, 10]"></text-box> |
| | | <protector-box :offset="[36, 10]"></protector-box> |
| | | <switch-box :type="3" :offset="[36, 134]"></switch-box> |
| | | <switch-box :type="3" :offset="[220, 134]"></switch-box> |
| | | <switch-box :type="3" :offset="[390, 134]"></switch-box> |
| | | <switch-box :type="1" :offset="[36, 252]"></switch-box> |
| | | <switch-box :type="1" :offset="[150, 252]"></switch-box> |
| | | <switch-box :type="1" :offset="[274, 252]"></switch-box> |
| | | <switch-box :type="1" :offset="[390, 252]"></switch-box> |
| | | <svg-line |
| | | :points="[ |
| | | [262, 40], |
| | | [262, 134], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [128, 70], |
| | | [262, 70], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :radius="10" |
| | | :points="[ |
| | | [78, 134], |
| | | [78, 110], |
| | | [432, 110], |
| | | [432, 134], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [98, 202], |
| | | [98, 228], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [262, 202], |
| | | [262, 228], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [412, 202], |
| | | [412, 228], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [192, 228], |
| | | [192, 252], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [316, 228], |
| | | [316, 252], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :radius="10" |
| | | :points="[ |
| | | [78, 252], |
| | | [78, 228], |
| | | [432, 228], |
| | | [432, 252], |
| | | ]" |
| | | ></svg-line> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="yc-panel-footer"> |
| | | <div class="state">防雷保护器空开跳闸</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="yc-panel"> |
| | | <div class="yc-title">交流进线2</div> |
| | | <div class="yc-content"> |
| | | <div class="svg-contain"> |
| | | <div class="pos-full"> |
| | | <svg width="100%" height="100%" viewBox="0 0 500 340"> |
| | | <text-box :offset="[220, 10]"></text-box> |
| | | <protector-box :offset="[390, 10]"></protector-box> |
| | | <switch-box :type="3" :offset="[36, 134]"></switch-box> |
| | | <switch-box :type="3" :offset="[220, 134]"></switch-box> |
| | | <switch-box :type="3" :offset="[390, 134]"></switch-box> |
| | | <switch-box :type="1" :offset="[36, 252]"></switch-box> |
| | | <switch-box :type="1" :offset="[150, 252]"></switch-box> |
| | | <switch-box :type="1" :offset="[274, 252]"></switch-box> |
| | | <switch-box :type="1" :offset="[390, 252]"></switch-box> |
| | | <svg-line |
| | | :points="[ |
| | | [262, 40], |
| | | [262, 134], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [390, 70], |
| | | [262, 70], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :radius="10" |
| | | :points="[ |
| | | [78, 134], |
| | | [78, 110], |
| | | [432, 110], |
| | | [432, 134], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [98, 202], |
| | | [98, 228], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [262, 202], |
| | | [262, 228], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [412, 202], |
| | | [412, 228], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [192, 228], |
| | | [192, 252], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [316, 228], |
| | | [316, 252], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :radius="10" |
| | | :points="[ |
| | | [78, 252], |
| | | [78, 228], |
| | | [432, 228], |
| | | [432, 252], |
| | | ]" |
| | | ></svg-line> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="yc-panel-footer"> |
| | | <div class="state"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="yc-row"> |
| | | <div class="yc-panel"> |
| | | <div class="yc-title">直流进线1</div> |
| | | <div class="yc-content"> |
| | | <div class="svg-contain"> |
| | | <div class="pos-full"> |
| | | <svg width="100%" height="100%" viewBox="0 0 622 240"> |
| | | <switch-box @click.native="hover" :type="2" :offset="[269, 14]"></switch-box> |
| | | <switch-box @click.native="hover" small :offset="[20, 160]"></switch-box> |
| | | <switch-box small :offset="[94, 160]"></switch-box> |
| | | <switch-box small :offset="[168, 160]"></switch-box> |
| | | <switch-box alarm small :offset="[242, 160]"></switch-box> |
| | | <switch-box small :offset="[316, 160]"></switch-box> |
| | | <switch-box small :offset="[390, 160]"></switch-box> |
| | | <switch-box small :offset="[464, 160]"></switch-box> |
| | | <switch-box small :offset="[538, 160]"></switch-box> |
| | | <svg-line |
| | | :points="[ |
| | | [311, 82], |
| | | [311, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :radius="10" |
| | | :points="[ |
| | | [52, 160], |
| | | [52, 116], |
| | | [570, 116], |
| | | [570, 160], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [126, 160], |
| | | [126, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [200, 160], |
| | | [200, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [274, 160], |
| | | [274, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [348, 160], |
| | | [348, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [422, 160], |
| | | [422, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [496, 160], |
| | | [496, 116], |
| | | ]" |
| | | ></svg-line> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="yc-panel-footer"> |
| | | <div class="state"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="yc-panel"> |
| | | <div class="yc-title">直流进线2</div> |
| | | <div class="yc-content"> |
| | | <div class="svg-contain"> |
| | | <div class="pos-full"> |
| | | <svg width="100%" height="100%" viewBox="0 0 622 240"> |
| | | <switch-box :type="2" :offset="[269, 14]"></switch-box> |
| | | <switch-box small :offset="[20, 160]"></switch-box> |
| | | <switch-box small :offset="[94, 160]"></switch-box> |
| | | <switch-box small :offset="[168, 160]"></switch-box> |
| | | <switch-box small :offset="[242, 160]"></switch-box> |
| | | <switch-box small :offset="[316, 160]"></switch-box> |
| | | <switch-box small :offset="[390, 160]"></switch-box> |
| | | <switch-box small :offset="[464, 160]"></switch-box> |
| | | <switch-box small :offset="[538, 160]"></switch-box> |
| | | <svg-line |
| | | :points="[ |
| | | [311, 82], |
| | | [311, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :radius="10" |
| | | :points="[ |
| | | [52, 160], |
| | | [52, 116], |
| | | [570, 116], |
| | | [570, 160], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [126, 160], |
| | | [126, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [200, 160], |
| | | [200, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [274, 160], |
| | | [274, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [348, 160], |
| | | [348, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [422, 160], |
| | | [422, 116], |
| | | ]" |
| | | ></svg-line> |
| | | <svg-line |
| | | :points="[ |
| | | [496, 160], |
| | | [496, 116], |
| | | ]" |
| | | ></svg-line> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | <div class="yc-panel-footer"> |
| | | <div class="state"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </panel> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | .p-container { |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | flex-direction: row; |
| | | padding: 10px; |
| | | } |
| | | .p-title { |
| | | font-size: 20px; |
| | |
| | | font-weight: bolder; |
| | | padding-bottom: 10px; |
| | | } |
| | | .panel { |
| | | color: #fff; |
| | | // height: 100%; |
| | | flex: 1; |
| | | &.right { |
| | | margin-left: 10px; |
| | | flex: 1.44; |
| | | } |
| | | &.left .content { |
| | | height: 100%; |
| | | padding: 10px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | .info { |
| | | border: 1px #02b4c0 solid; |
| | | border-radius: 4px; |
| | | display: flex; |
| | | flex-direction: row; |
| | | background: #011f39; |
| | | overflow: hidden; |
| | | .side { |
| | | width: 160px; |
| | | background: #0c4d77; |
| | | padding: 0 4px 10px; |
| | | border-right: 1px #02b4c0 solid; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | .img { |
| | | width: 80px; |
| | | height: 120px; |
| | | } |
| | | .img3 { |
| | | width: 120px; |
| | | height: 50px; |
| | | } |
| | | .info-title { |
| | | font-size: 18px; |
| | | padding-top: 10px; |
| | | letter-spacing: 2px; |
| | | text-align: center; |
| | | } |
| | | .state { |
| | | background: #f69f41; |
| | | border-radius: 4px; |
| | | font-weight: bold; |
| | | align-self: stretch; |
| | | color: #1b2d3a; |
| | | .s-row { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | .i { |
| | | margin-left: 20px; |
| | | display: inline-block; |
| | | width: 20px; |
| | | height: 20px; |
| | | border-radius: 50%; |
| | | background: radial-gradient( |
| | | circle farthest-side at 50% 50%, |
| | | rgba(1, 31, 57, 0.5) 50%, |
| | | rgba(74, 253, 136, 0.5) 100% |
| | | ); |
| | | text-align: center; |
| | | position: relative; |
| | | &::after { |
| | | content: ""; |
| | | display: inline-block; |
| | | position: absolute; |
| | | border-radius: 50%; |
| | | top: 4px; |
| | | right: 4px; |
| | | bottom: 4px; |
| | | left: 4px; |
| | | background: #4afd88; |
| | | } |
| | | &.danger { |
| | | background: radial-gradient( |
| | | circle farthest-side at 50% 50%, |
| | | rgba(1, 31, 57, 0.5) 50%, |
| | | rgba(255, 56, 1, 0.5) 100% |
| | | ); |
| | | &::after { |
| | | background: #ff3801; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .main { |
| | | flex: 1; |
| | | display: flex; |
| | | padding: 0 6px; |
| | | .list { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | padding: 10px 0; |
| | | & + .list { |
| | | margin-left: 6px; |
| | | } |
| | | .row-item { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | padding-left: 10px; |
| | | // height: 20px; |
| | | // line-height: 20px; |
| | | background: #153952; |
| | | &:nth-child(2n) { |
| | | background: rgba(21, 57, 82, 0.6); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | &.info1 { |
| | | flex: 10; |
| | | } |
| | | &.info2 { |
| | | flex: 7; |
| | | } |
| | | &.info3 { |
| | | flex: 5; |
| | | } |
| | | & + .info { |
| | | margin-top: 10px; |
| | | } |
| | | } |
| | | } |
| | | &.right .content { |
| | | height: 100%; |
| | | padding: 10px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .yc-row { |
| | | flex: 3; |
| | | display: flex; |
| | | &.row1 { |
| | | flex: 4; |
| | | } |
| | | & + .yc-row { |
| | | margin-top: 10px; |
| | | } |
| | | .yc-panel { |
| | | flex: 1; |
| | | border: 1px solid #4da2b1; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | display: flex; |
| | | flex-direction: column; |
| | | & + .yc-panel { |
| | | margin-left: 10px; |
| | | } |
| | | .yc-title { |
| | | text-align: center; |
| | | font-size: 18px; |
| | | height: 36px; |
| | | line-height: 36px; |
| | | background: #0c4d77; |
| | | } |
| | | .yc-content { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | background: #011f39; |
| | | .svg-contain { |
| | | flex: 1; |
| | | position: relative; |
| | | .pos-full { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | } |
| | | } |
| | | .yc-panel-footer { |
| | | padding: 0 20px 10px; |
| | | .state { |
| | | background: #78eef8; |
| | | height: 36px; |
| | | line-height: 36px; |
| | | color: #011f39; |
| | | font-weight: bold; |
| | | border-radius: 4px; |
| | | padding-left: 0.8em; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | const PDG = [ |
| | | { |
| | | label: '1路交流输入A相电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '1路交流输入B相电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '1路交流输入C相电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '1路交流输入A相电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '1路交流输入B相电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '1路交流输入C相电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '直流电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '电池组电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '机柜温度(℃)', |
| | | key: '', |
| | | }, |
| | | |
| | | { |
| | | label: '2路交流输入A相电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '2路交流输入B相电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '2路交流输入C相电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '2路交流输入A相电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '2路交流输入B相电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '2路交流输入C相电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '直流电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '电池组电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '故障报警', |
| | | key: '', |
| | | }, |
| | | ]; |
| | | |
| | | const KGG = [ |
| | | { |
| | | label: '交流输入电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '交流输入电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '电池电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '负载电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '开关状态', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '故障报警', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '直流输出电压(V)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '直流输出电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '电池(充电)电流(A)', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '直流熔丝状态', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '机柜温度(℃)', |
| | | key: '', |
| | | }, |
| | | ]; |
| | | |
| | | const HR = [ |
| | | { |
| | | label: '系统工作状态', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '电池组电流', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '最高单体电压', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '电池组电压', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '在线端电压', |
| | | key: '', |
| | | }, |
| | | { |
| | | label: '最低单体电压', |
| | | key: '', |
| | | }, |
| | | ]; |
| | | |
| | | export default { |
| | | PDG, |
| | | KGG, |
| | | HR |
| | | } |
| | |
| | | <script> |
| | | import { validUsername } from "@/utils/validate"; |
| | | import { login } from "./api"; |
| | | import { mapMutations } from 'vuex'; |
| | | import { mapMutations } from "vuex"; |
| | | export default { |
| | | name: "loginPage", |
| | | data() { |
| | |
| | | } |
| | | }; |
| | | const validatePassword = (rule, value, callback) => { |
| | | if (value.trim() == '') { |
| | | if (value.trim() == "") { |
| | | callback(new Error("密码不能为空")); |
| | | } else { |
| | | callback(); |
| | |
| | | }; |
| | | return { |
| | | loginForm: { |
| | | // username: "hw", |
| | | // password: "123456", |
| | | username: "", |
| | | password: "", |
| | | username: "hw", |
| | | password: "123456", |
| | | // username: "", |
| | | // password: "", |
| | | }, |
| | | loginRules: { |
| | | username: [ |
| | |
| | | }; |
| | | }, |
| | | methods: { |
| | | ...mapMutations('user', ['SETUSER', 'SETDOWNLOAD', 'SETUID']), |
| | | ...mapMutations("user", ["SETUSER", "SETDOWNLOAD", "SETUID"]), |
| | | checkCapslock(e) { |
| | | const { key } = e; |
| | | this.capsTooltip = key && key.length === 1 && key >= "A" && key <= "Z"; |
| | |
| | | let { code, data, data2 } = res.data; |
| | | if (code && data) { |
| | | // console.log(data); |
| | | this.$message.success('登录成功'); |
| | | this.$message.success("登录成功"); |
| | | this.SETUSER(data2.uname); |
| | | this.SETDOWNLOAD(data2.udownloadRole); |
| | | this.SETUID(data2.uid); |
| | | this.$router.push('/'); |
| | | this.$router.push("/"); |
| | | } else { |
| | | this.$message.error(msg); |
| | | } |
| | |
| | | |
| | | <template> |
| | | <div class="login-container"> |
| | | <el-form |
| | | ref="loginForm" |
| | | :model="loginForm" |
| | | :rules="loginRules" |
| | | class="login-form" |
| | | autocomplete="on" |
| | | label-position="left" |
| | | > |
| | | <div class="title-container"> |
| | | <h3 class="title">登录</h3> |
| | | </div> |
| | | |
| | | <el-form-item prop="username"> |
| | | <span class="svg-container"> |
| | | <svg-icon icon-class="user" /> |
| | | </span> |
| | | <el-input |
| | | ref="username" |
| | | v-model="loginForm.username" |
| | | placeholder="Username" |
| | | name="username" |
| | | type="text" |
| | | tabindex="1" |
| | | autocomplete="on" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-tooltip |
| | | v-model="capsTooltip" |
| | | content="输入了大写字母" |
| | | placement="right" |
| | | manual |
| | | <div class="page-title">通信电源监控主站测控系统</div> |
| | | <div class="login-wrap"> |
| | | <el-form |
| | | ref="loginForm" |
| | | :model="loginForm" |
| | | :rules="loginRules" |
| | | class="login-form" |
| | | autocomplete="on" |
| | | label-position="left" |
| | | > |
| | | <el-form-item prop="password"> |
| | | <div class="title-container"> |
| | | <h3 class="title">用户登录</h3> |
| | | </div> |
| | | <el-form-item prop="username"> |
| | | <span class="svg-container"> |
| | | <svg-icon icon-class="password" /> |
| | | <svg-icon icon-class="user" /> |
| | | </span> |
| | | <el-input |
| | | :key="passwordType" |
| | | ref="password" |
| | | v-model="loginForm.password" |
| | | :type="passwordType" |
| | | placeholder="Password" |
| | | name="password" |
| | | tabindex="2" |
| | | ref="username" |
| | | v-model="loginForm.username" |
| | | placeholder="请输入用户名" |
| | | name="username" |
| | | type="text" |
| | | tabindex="1" |
| | | autocomplete="on" |
| | | @keyup.native="checkCapslock" |
| | | @blur="capsTooltip = false" |
| | | @keyup.enter.native="handleLogin" |
| | | /> |
| | | <span class="show-pwd" @click="showPwd"> |
| | | <svg-icon |
| | | :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" |
| | | /> |
| | | </span> |
| | | </el-form-item> |
| | | </el-tooltip> |
| | | <el-button |
| | | :loading="loading" |
| | | type="primary" |
| | | style="width: 100%; margin-bottom: 30px" |
| | | @click.native.prevent="handleLogin" |
| | | >Login</el-button |
| | | > |
| | | </el-form> |
| | | <el-tooltip |
| | | v-model="capsTooltip" |
| | | content="输入了大写字母" |
| | | placement="right" |
| | | manual |
| | | > |
| | | <el-form-item prop="password"> |
| | | <span class="svg-container"> |
| | | <svg-icon icon-class="password" /> |
| | | </span> |
| | | <el-input |
| | | :key="passwordType" |
| | | ref="password" |
| | | v-model="loginForm.password" |
| | | :type="passwordType" |
| | | placeholder="请输入密码" |
| | | name="password" |
| | | tabindex="2" |
| | | autocomplete="on" |
| | | @keyup.native="checkCapslock" |
| | | @blur="capsTooltip = false" |
| | | @keyup.enter.native="handleLogin" |
| | | /> |
| | | <span class="show-pwd" @click="showPwd"> |
| | | <svg-icon |
| | | :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" |
| | | /> |
| | | </span> |
| | | </el-form-item> |
| | | </el-tooltip> |
| | | <div class="btn-grp"> |
| | | <el-button |
| | | class="btn-login" |
| | | :loading="loading" |
| | | @click.native.prevent="handleLogin" |
| | | >登录</el-button |
| | | > |
| | | </div> |
| | | </el-form> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | -webkit-appearance: none; |
| | | border-radius: 0; |
| | | padding: 12px 5px 12px 15px; |
| | | color: #ffffff; |
| | | color: #192e41; |
| | | height: 47px; |
| | | caret-color: #283443; |
| | | |
| | |
| | | } |
| | | |
| | | .el-form-item { |
| | | border: 1px solid rgba(255, 255, 255, 0.1); |
| | | background: rgba(0, 0, 0, 0.1); |
| | | border: 2px solid #e4e4e4; |
| | | background: transparent; |
| | | border-radius: 5px; |
| | | color: #454545; |
| | | } |
| | |
| | | .login-container { |
| | | min-height: 100%; |
| | | width: 100%; |
| | | background-color: #2d3a4b; |
| | | // background: url('images/bg.jpg') center center / 100% 100% no-repeat; |
| | | background: url("images/bg.jpg") center center / cover no-repeat; |
| | | // background-color: #2d3a4b; |
| | | overflow: hidden; |
| | | |
| | | .login-form { |
| | | position: relative; |
| | | width: 520px; |
| | | max-width: 100%; |
| | | padding: 160px 35px 0; |
| | | margin: 0 auto; |
| | | overflow: hidden; |
| | | .page-title { |
| | | font-weight: bolder; |
| | | font-size: 50px; |
| | | color: #fff; |
| | | padding-top: 80px; |
| | | padding-left: 80px; |
| | | } |
| | | .login-wrap { |
| | | position: absolute; |
| | | top: 50%; |
| | | right: 0; |
| | | width: 460px; |
| | | transform: translate(-44%, -50%); |
| | | .login-form { |
| | | background: #fff; |
| | | // max-width: 100%; |
| | | padding: 50px 35px 30px; |
| | | border-radius: 12px; |
| | | letter-spacing: 2px; |
| | | // margin: 0 auto; |
| | | // overflow: hidden; |
| | | z-index: 0; |
| | | } |
| | | |
| | | &::before, |
| | | &::after { |
| | | position: absolute; |
| | | content: ""; |
| | | left: -20px; |
| | | right: -20px; |
| | | top: 36px; |
| | | bottom: 36px; |
| | | background: rgba(255, 255, 255, 0.2); |
| | | border-radius: 10px; |
| | | z-index: -1; |
| | | } |
| | | &::after { |
| | | top: 72px; |
| | | bottom: 72px; |
| | | left: -40px; |
| | | right: -40px; |
| | | } |
| | | } |
| | | |
| | | .tips { |
| | |
| | | |
| | | .svg-container { |
| | | padding: 6px 5px 6px 15px; |
| | | color: #889aa4; |
| | | color: #505050; |
| | | vertical-align: middle; |
| | | width: 30px; |
| | | width: 38px; |
| | | display: inline-block; |
| | | position: relative; |
| | | } |
| | | .svg-container::after { |
| | | content: ""; |
| | | position: absolute; |
| | | top: 50%; |
| | | right: 0; |
| | | width: 1px; |
| | | height: 42%; |
| | | transform: translate(5px, -50%); |
| | | background: #e4e4e4; |
| | | } |
| | | .btn-grp { |
| | | width: 100%; |
| | | padding: 120px 20px 60px; |
| | | } |
| | | .btn-login { |
| | | // display: block; |
| | | width: 100%; |
| | | letter-spacing: 6px; |
| | | line-height: 28px; |
| | | color: #f0f0f0; |
| | | border: 0 none; |
| | | border-radius: 6px; |
| | | font-size: 16px; |
| | | background: linear-gradient(to right, #059fab 0, #09335b 100%); |
| | | box-shadow: 10px 10px 20px -10px #000; |
| | | } |
| | | // /deep/ .el-form-item__content { |
| | | // background: transparent; |
| | | // border: 1px solid #000; |
| | | // border-radius: 4px; |
| | | // } |
| | | |
| | | .title-container { |
| | | position: relative; |
| | | |
| | | .title { |
| | | font-size: 26px; |
| | | color: #eee; |
| | | color: #1d3748; |
| | | margin: 0 auto 40px auto; |
| | | text-align: center; |
| | | font-weight: bold; |
New file |
| | |
| | | <template> |
| | | <div class="p-main"> |
| | | <el-tabs class="tab" type="border-card" @tab-click="tabClick"> |
| | | <el-tab-pane label="交流/直流配电柜"> |
| | | <div class="tab-content content1 flex-r"> |
| | | <panel class="panel left" title="交流/直流配电柜遥测量"> |
| | | <div class="content"> |
| | | <div class="row row1"> |
| | | <div class="card has-title"> |
| | | <div class="card-title">第1路交流三相输入电压(V)</div> |
| | | <div class="card-content"> |
| | | <bar1 ref="bar1"></bar1> |
| | | </div> |
| | | </div> |
| | | <div class="card has-title"> |
| | | <div class="card-title">第2路交流三相输入电压(V)</div> |
| | | <div class="card-content"> |
| | | <bar1 ref="bar2"></bar1> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="card row2"> |
| | | <list-card :datas="props1" :rows="4"></list-card> |
| | | </div> |
| | | <div class="row row3"> |
| | | <div class="card has-title"> |
| | | <div class="card-title">第1路交流三相输入电流(A)</div> |
| | | <div class="card-content"> |
| | | <instrument-board |
| | | ref="board1" |
| | | :r="boardR" |
| | | ></instrument-board> |
| | | </div> |
| | | </div> |
| | | <div class="card has-title"> |
| | | <div class="card-title">第2路交流三相输入电流(A)</div> |
| | | </div> |
| | | </div> |
| | | <div class="card card2 row4"> |
| | | <list-card :datas="props2" :rows="3"></list-card> |
| | | </div> |
| | | </div> |
| | | </panel> |
| | | <panel class="panel right" title="交流/直流配电柜遥信量"> |
| | | <div class="content"> |
| | | <alarm-legend class="legend"></alarm-legend> |
| | | <div class="state-row"> |
| | | <el-row :gutter="30"> |
| | | <el-col |
| | | :span="8" |
| | | v-for="(item, idx) in alarmList1" |
| | | :key="'alarm1_' + idx" |
| | | > |
| | | <alarm-card |
| | | class="state-item" |
| | | :level="item.level" |
| | | :name="item.name" |
| | | ></alarm-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <div class="state-row"> |
| | | <el-row :gutter="30"> |
| | | <el-col |
| | | :span="8" |
| | | v-for="(item, idx) in alarmList2" |
| | | :key="'alarm2_' + idx" |
| | | > |
| | | <alarm-card |
| | | :level="item.level" |
| | | :name="item.name" |
| | | ></alarm-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </div> |
| | | </panel> |
| | | </div> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="高频开关整流柜"> |
| | | <div class="tab-content content1 flex-r"> |
| | | <panel class="panel left" title="高频开关整流柜遥测量"> |
| | | <div class="content"> |
| | | <div class="row row1"> |
| | | <div class="card has-title"> |
| | | <div class="card-title">第1路交流三相输入电压(V)</div> |
| | | <div class="card-content"> |
| | | <bar1 ref="bar3"></bar1> |
| | | </div> |
| | | </div> |
| | | <div class="card has-title"> |
| | | <div class="card-title">三相交流输出电压(V)</div> |
| | | <div class="card-content"> |
| | | <bar1 ref="bar4"></bar1> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="card row2"> |
| | | <list-card :datas="props3" :rows="4"></list-card> |
| | | </div> |
| | | <div class="row row3"> |
| | | <div class="card has-title"> |
| | | <div class="card-title">第2路交流三相输入电压(V)</div> |
| | | <div class="card-content"> |
| | | <instrument-board |
| | | ref="board2" |
| | | :r="boardR" |
| | | ></instrument-board> |
| | | </div> |
| | | </div> |
| | | <div class="card has-title"> |
| | | <div class="card-title">三相交流输出电流(A)</div> |
| | | </div> |
| | | </div> |
| | | <div class="card card2 row4"> |
| | | <list-card :datas="props4" :rows="3"></list-card> |
| | | </div> |
| | | </div> |
| | | </panel> |
| | | <panel class="panel right" title="高频开关整流柜遥信量"> |
| | | <div class="content"> |
| | | <alarm-legend class="legend"></alarm-legend> |
| | | <div class="state-row"> |
| | | <el-row :gutter="30"> |
| | | <el-col |
| | | :span="8" |
| | | v-for="(item, idx) in alarmList3" |
| | | :key="'alarm1_' + idx" |
| | | > |
| | | <alarm-card |
| | | class="state-item" |
| | | :level="item.level" |
| | | :name="item.name" |
| | | ></alarm-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </div> |
| | | </panel> |
| | | </div> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="核容装置"> </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapState } from "vuex"; |
| | | import Panel from "@/components/panel.vue"; |
| | | import ListCard from "@/components/listCard.vue"; |
| | | import AlarmCard from "@/components/alarmCard.vue"; |
| | | import AlarmLegend from "@/components/alarmLegend.vue"; |
| | | import InstrumentBoard from "@/components/instrumentBoard"; |
| | | import bar1 from "@/components/bar1"; |
| | | |
| | | export default { |
| | | name: "Details", |
| | | components: { |
| | | Panel, |
| | | ListCard, |
| | | AlarmCard, |
| | | AlarmLegend, |
| | | InstrumentBoard, |
| | | bar1, |
| | | }, |
| | | data() { |
| | | const props1 = [ |
| | | { |
| | | label: "交流配电柜温度(℃)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "交流电压告警阀值下限(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "第1路直流输入电压(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "1段直流母线输出电压(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "2段直流母线输出电流(A)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "直流配电柜温度(℃)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "直流电压告警阀值下限(V)", |
| | | key: "", |
| | | }, |
| | | ]; |
| | | const props2 = [ |
| | | { |
| | | label: "交流电压告警阀值上限(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "第二路直流输入电压(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "2段直流母线输出电压(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "2段直流母线输出电流(A)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "直流电压告警阀值上限(V)", |
| | | key: "", |
| | | }, |
| | | ]; |
| | | const props3 = [ |
| | | { |
| | | label: "直流输出电压(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "蓄电池组充电电流(A)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "均充电压(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "电池N端电压(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "模块N输出电流(A)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "交流电压告警阀值下限(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "直流电压告警阀值下限(V)", |
| | | key: "", |
| | | }, |
| | | ]; |
| | | const props4 = [ |
| | | { |
| | | label: "负载电流(A)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "电池充电限流值(A)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "浮充电压(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "高频开关电源柜温度(℃)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "交流电压告警阀值上限(V)", |
| | | key: "", |
| | | }, |
| | | { |
| | | label: "直流电压告警阀值上限(V)", |
| | | key: "", |
| | | }, |
| | | ]; |
| | | const alarmList1 = [ |
| | | { |
| | | name: "交流输入1停电", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "交流输入2停电", |
| | | level: 1, |
| | | }, |
| | | { |
| | | name: "交流输入1防雷器故障", |
| | | level: 2, |
| | | }, |
| | | { |
| | | name: "交流输入2防雷器故障", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流输入开关跳闸", |
| | | level: 3, |
| | | }, |
| | | { |
| | | name: "第2路交流输入开关跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流A相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流A相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流B相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流B相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流C相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流C相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流A相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流A相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流B相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流B相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流C相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流C相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流A相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流B相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流C相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流A相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流B相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流C相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "交流监控单元故障", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "1段交流母线输出开关1~N跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "2段交流母线输出开关1~N跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "交流配电柜总告警", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "交流配电柜温度告警", |
| | | level: 0, |
| | | }, |
| | | ]; |
| | | const alarmList2 = [ |
| | | { |
| | | name: "第1路直流过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路直流欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路直流过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路直流欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路输入开关跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路输入开关跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "1段直流第N路开关跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "2段直流第N路开关跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "温度告警", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "监控单元故障", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "直流配电柜总告警", |
| | | level: 0, |
| | | }, |
| | | ]; |
| | | const alarmList3 = [ |
| | | { |
| | | name: "交流输入1停电", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "交流输入2停电", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "交流输入1防雷器故障", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "交流输入2防雷器故障", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流输入开关跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流输入开关跳闸", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流A相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流A相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流B相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流B相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流C相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流C相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流A相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流A相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流B相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流B相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流C相过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流C相欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流A相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流B相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第1路交流C相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流A相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流B相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "第2路交流C相缺相", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "交流监控单元故障", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "模块N故障", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "高频开关电源柜总告警", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "直流输出过压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "直流输出欠压", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "电池组下电保护告警", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "电池组N熔丝告警", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "负载熔丝状态", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "均浮充状态", |
| | | level: 0, |
| | | }, |
| | | { |
| | | name: "在用交流输入路数", |
| | | level: 0, |
| | | }, |
| | | ]; |
| | | return { |
| | | boardR: "33.3%", |
| | | props1, |
| | | props2, |
| | | props3, |
| | | props4, |
| | | alarmList1, |
| | | alarmList2, |
| | | alarmList3, |
| | | }; |
| | | }, |
| | | mounted() { |
| | | // this.$nextTick(() => { |
| | | // this.getRadius(); |
| | | // }); |
| | | // window.addEventListener("resize", this.getRadius); |
| | | }, |
| | | methods: { |
| | | getRadius() { |
| | | this.boardR = this.$refs.board.$el.clientWidth / 6; |
| | | console.log(this.boardR, "?????"); |
| | | this.$refs.board1.setData({ xLabel: [], sData: [] }); |
| | | }, |
| | | tabClick() { |
| | | this.$nextTick(() => { |
| | | this.$refs.bar1.resize(); |
| | | this.$refs.bar2.resize(); |
| | | this.$refs.bar3.resize(); |
| | | this.$refs.bar4.resize(); |
| | | this.$refs.board1.resize(); |
| | | this.$refs.board2.resize(); |
| | | |
| | | }); |
| | | }, |
| | | }, |
| | | beforeDestroy() { |
| | | // 销毁resize事件 |
| | | // window.removeEventListener("resize", this.getRadius); |
| | | }, |
| | | computed: { |
| | | ...mapState({ |
| | | cachedViews: (state) => state.tagsView.cachedViews, |
| | | }), |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .p-main { |
| | | height: 100%; |
| | | .tab { |
| | | height: 100%; |
| | | background: transparent; |
| | | border: 0 none; |
| | | box-shadow: none; |
| | | display: flex; |
| | | flex-direction: column; |
| | | /deep/ .el-tabs__header { |
| | | border: 0 none; |
| | | background-color: transparent; |
| | | } |
| | | /deep/ .el-tabs__content { |
| | | flex: 1; |
| | | padding: 4px; |
| | | .el-tab-pane { |
| | | height: 100%; |
| | | } |
| | | } |
| | | .flex-c { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .flex-r { |
| | | display: flex; |
| | | flex-direction: row; |
| | | } |
| | | .tab-content { |
| | | height: 100%; |
| | | } |
| | | /deep/ .el-tabs__header .el-tabs__item { |
| | | background: #78eef8; |
| | | color: #000; |
| | | border-radius: 4px; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | border: 0 none; |
| | | & + .el-tabs__item { |
| | | margin-left: 6px; |
| | | } |
| | | &.is-active { |
| | | color: #fff; |
| | | background-color: #0081ff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .panel { |
| | | color: #fff; |
| | | // height: 100%; |
| | | flex: 1; |
| | | &.right { |
| | | margin-left: 10px; |
| | | flex: 1.44; |
| | | .content { |
| | | height: 100%; |
| | | padding: 10px 30px; |
| | | position: relative; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | .legend { |
| | | position: absolute; |
| | | bottom: 100%; |
| | | right: 6px; |
| | | width: 286px; |
| | | } |
| | | .state-row { |
| | | /deep/ .el-col:nth-child(n + 4) { |
| | | // /deep/ .el-col:nth-child(3) ~ .el-col { |
| | | margin-top: 10px; |
| | | } |
| | | .state-item { |
| | | } |
| | | } |
| | | } |
| | | } |
| | | &.left .content { |
| | | height: 100%; |
| | | padding: 10px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | & > div:not(:first-child) { |
| | | margin-top: 10px; |
| | | } |
| | | .row { |
| | | flex: 2.5; |
| | | display: flex; |
| | | } |
| | | .row2 { |
| | | flex: 1.66; |
| | | } |
| | | .row4 { |
| | | flex: 1.3; |
| | | } |
| | | } |
| | | } |
| | | .card { |
| | | border-radius: 6px; |
| | | border: 1px #4392a2 solid; |
| | | padding: 10px; |
| | | background: #011f39; |
| | | overflow: hidden; |
| | | &.has-title { |
| | | padding: 0; |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | & + .has-title { |
| | | margin-left: 10px; |
| | | } |
| | | .card-title { |
| | | background: #0c4d77; |
| | | line-height: 38px; |
| | | height: 38px; |
| | | font-size: 20px; |
| | | text-align: center; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .card-content { |
| | | flex: 1; |
| | | } |
| | | </style> |
| | |
| | | protocolImports: true, |
| | | }), |
| | | ], |
| | | server: { |
| | | host: '0.0.0.0', |
| | | port: 8080 |
| | | }, |
| | | base: "./", |
| | | resolve: { |
| | | extensions: [".js", ".vue"], |