| | |
| | | */ |
| | | // name: "", |
| | | // name: "cqdz", |
| | | name: "sxty", // 请查看alarmPopup是否开启,logo是否开启且为gjdw |
| | | // name: "sxty", // 请查看alarmPopup是否开启,logo是否开启且为gjdw |
| | | // name: "tydc", |
| | | // name: 'szdt', |
| | | name: 'szdt', |
| | | // name: 'njck', |
| | | // name: "ynkm", // 云南昆明定制了设备实时告警和设备历史告警名称 打包时注意设置为isChangeAlarm=true,其他设置为false |
| | | //value: false, |
| | |
| | | }, |
| | | series: [ |
| | | // 图片底色 |
| | | { |
| | | name: "", |
| | | type: "scatter", |
| | | coordinateSystem: "geo", |
| | | symbol: "circle", |
| | | symbolSize: [24, 24], |
| | | label: { |
| | | formatter: "{b}", |
| | | position: "inside", |
| | | show: true, |
| | | color: "#FFFFFF", |
| | | fontWeight: "bold", |
| | | }, |
| | | itemStyle: { |
| | | color(params) { |
| | | return params.data.color; |
| | | }, |
| | | }, |
| | | data: convertData(data), |
| | | z: 3, |
| | | }, |
| | | { |
| | | //图片 |
| | | name: "图片", |
| | | type: "scatter", |
| | | coordinateSystem: "geo", |
| | | symbol: function (value, params) { |
| | | let img; |
| | | let color = params.data.color; |
| | | // let color = "#ff6b6c"; |
| | | switch (color) { |
| | | case "#0081ff": // 浮充 |
| | | img = HomeChargeImage; |
| | | break; |
| | | case "#ff6b6c": // 放电 |
| | | img = HomeDischargeImage; |
| | | break; |
| | | case "#66f842": // 充电 |
| | | img = HomeNormalImage; |
| | | break; |
| | | case "#7668f9": // 停电 |
| | | img = HomeTingDianImage; |
| | | break; |
| | | default: |
| | | // img = HomeChargeImage; |
| | | img = HomeTransImage; |
| | | break; |
| | | } |
| | | return params.data.name ? "circle" : "image://" + img; |
| | | }, |
| | | symbolSize: [24, 24], |
| | | label: { |
| | | formatter: "{b}", |
| | | position: "inside", |
| | | show: true, |
| | | color: "#FFFFFF", |
| | | fontWeight: "bold", |
| | | }, |
| | | itemStyle: { |
| | | color(params) { |
| | | return params.data.color; |
| | | }, |
| | | }, |
| | | data: convertData(data), |
| | | showEffectOn: "render", |
| | | rippleEffect: { |
| | | brushType: "stroke", |
| | | }, |
| | | hoverAnimation: true, |
| | | // zlevel: 3 |
| | | z: 4, |
| | | }, |
| | | { |
| | | name: "波纹", |
| | | type: "effectScatter", |
| | | coordinateSystem: "geo", |
| | | rippleEffect: { |
| | | scale: 3, |
| | | }, |
| | | symbolSize: [18, 18], |
| | | data: convertData(data), |
| | | itemStyle: { |
| | | color(params) { |
| | | return params.data.color; |
| | | }, |
| | | }, |
| | | tooltip: { |
| | | show: true, |
| | | }, |
| | | // zlevel: 2 |
| | | z: 2, |
| | | }, |
| | | // { |
| | | // name: "", |
| | | // type: "scatter", |
| | | // coordinateSystem: "geo", |
| | | // symbol: "circle", |
| | | // symbolSize: [24, 24], |
| | | // label: { |
| | | // formatter: "{b}", |
| | | // position: "inside", |
| | | // show: true, |
| | | // color: "#FFFFFF", |
| | | // fontWeight: "bold", |
| | | // }, |
| | | // itemStyle: { |
| | | // color(params) { |
| | | // return params.data.color; |
| | | // }, |
| | | // }, |
| | | // data: convertData(data), |
| | | // z: 3, |
| | | // }, |
| | | // { |
| | | // //图片 |
| | | // name: "图片", |
| | | // type: "scatter", |
| | | // coordinateSystem: "geo", |
| | | // symbol: function (value, params) { |
| | | // let img; |
| | | // let color = params.data.color; |
| | | // // let color = "#ff6b6c"; |
| | | // switch (color) { |
| | | // case "#0081ff": // 浮充 |
| | | // img = HomeChargeImage; |
| | | // break; |
| | | // case "#ff6b6c": // 放电 |
| | | // img = HomeDischargeImage; |
| | | // break; |
| | | // case "#66f842": // 充电 |
| | | // img = HomeNormalImage; |
| | | // break; |
| | | // case "#7668f9": // 停电 |
| | | // img = HomeTingDianImage; |
| | | // break; |
| | | // default: |
| | | // // img = HomeChargeImage; |
| | | // img = HomeTransImage; |
| | | // break; |
| | | // } |
| | | // return params.data.name ? "circle" : "image://" + img; |
| | | // }, |
| | | // symbolSize: [24, 24], |
| | | // label: { |
| | | // formatter: "{b}", |
| | | // position: "inside", |
| | | // show: true, |
| | | // color: "#FFFFFF", |
| | | // fontWeight: "bold", |
| | | // }, |
| | | // itemStyle: { |
| | | // color(params) { |
| | | // return params.data.color; |
| | | // }, |
| | | // }, |
| | | // data: convertData(data), |
| | | // showEffectOn: "render", |
| | | // rippleEffect: { |
| | | // brushType: "stroke", |
| | | // }, |
| | | // hoverAnimation: true, |
| | | // // zlevel: 3 |
| | | // z: 4, |
| | | // }, |
| | | // { |
| | | // name: "波纹", |
| | | // type: "effectScatter", |
| | | // coordinateSystem: "geo", |
| | | // rippleEffect: { |
| | | // scale: 3, |
| | | // }, |
| | | // symbolSize: [18, 18], |
| | | // data: convertData(data), |
| | | // itemStyle: { |
| | | // color(params) { |
| | | // return params.data.color; |
| | | // }, |
| | | // }, |
| | | // tooltip: { |
| | | // show: true, |
| | | // }, |
| | | // // zlevel: 2 |
| | | // z: 2, |
| | | // }, |
| | | { |
| | | type: "map", |
| | | map: mapName, |
| | | show: false, |
| | | geoIndex: 0, |
| | | aspectScale: 0.75, //长宽比 |
| | | showLegendSymbol: false, // 存在legend时显示 |
| | |
| | | NProgress.configure({ showSpinner: false }) // NProgress Configuration |
| | | |
| | | // /frame-jy 为山西晋源的iframe 统计页面 |
| | | const whiteList = ['/login', '/frame-jy'] // no redirect whitelist |
| | | const whiteList = ['/login', '/frame-jy', '/test'] // no redirect whitelist |
| | | router.beforeEach(async (to, from, next) => { |
| | | // determine whether the user has logged in |
| | | let username = sessionStorage.getItem('username'); |
| | |
| | | path: "/redirect/:path*", |
| | | component: () => import("@/views/404/redirect"), |
| | | }, |
| | | { |
| | | path: '/test', |
| | | component: () => import('@/views/test.vue'), |
| | | }, |
| | | // 404 页面 |
| | | { |
| | | path: "*", |
New file |
| | |
| | | <template> |
| | | <div id="metroChart" ref="chart" style="height: 100%"></div> |
| | | </template> |
| | | |
| | | <script> |
| | | import echarts from "echarts"; |
| | | |
| | | let myChart; |
| | | export default { |
| | | props: { |
| | | lines: { |
| | | type: Array, |
| | | default() { |
| | | return [] |
| | | } |
| | | }, |
| | | status: { |
| | | type: Object, |
| | | default() { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | jsonData: {}, |
| | | } |
| | | }, |
| | | computed: { |
| | | lineList() { |
| | | // console.log('line', this.lines) |
| | | return this.lines.map(v => v + '号线'); |
| | | } |
| | | }, |
| | | watch: { |
| | | lines() { |
| | | // console.log('line', this.lines, '============='); |
| | | this.updateMap(); |
| | | }, |
| | | status() { |
| | | this.updateMap(); |
| | | } |
| | | }, |
| | | methods: { |
| | | async getJson() { |
| | | const dynamicPath = `mapJson/subway/suzhou1.json`; |
| | | try { |
| | | const response = await fetch(dynamicPath); |
| | | if (!response.ok) { |
| | | throw new Error(`HTTP error! status: ${response.status}`); |
| | | } |
| | | const data = await response.json(); |
| | | // console.log("data", data, "============="); |
| | | // this.defaultData = data.l; |
| | | return data; |
| | | } catch (error) { |
| | | console.error("加载 JSON 出错:", error); |
| | | } |
| | | }, |
| | | |
| | | async getSubwayJson() { |
| | | const { l } = this.jsonData; |
| | | let stationList = this.lineList; |
| | | const subwayList = l.filter((item) => { |
| | | return stationList.includes(item.ln); |
| | | }); |
| | | // 站点状态 |
| | | let statusList = this.status; |
| | | |
| | | const position = { |
| | | 0: "top", |
| | | 1: "topRight", |
| | | 2: "right", |
| | | 3: "bottomRight", |
| | | 4: "bottom", |
| | | 5: "bottomLeft", |
| | | 6: "left", |
| | | 7: "topLeft", |
| | | }; |
| | | const list = { |
| | | xPeak: { |
| | | min: 0, |
| | | max: 0, |
| | | }, |
| | | yPeak: { |
| | | min: 0, |
| | | max: 0, |
| | | }, |
| | | names: [], |
| | | x: [], |
| | | y: [], |
| | | nodes: [], |
| | | lines: [], |
| | | }; |
| | | for (let i = 0; i < subwayList.length; i++) { |
| | | const { cl, st, ln } = subwayList[i]; |
| | | let lineNum = ln.replace('号线', ''); |
| | | for (let k = 0; k < st.length; k++) { |
| | | const { n, p, lg } = st[k]; |
| | | const point = p.split(" "); |
| | | const x = Number(point[0]); |
| | | const y = Number(point[1]); |
| | | list.x.push(x); |
| | | list.y.push(y); |
| | | if (!list.names.includes(n)) { |
| | | list.names.push(n); |
| | | const names = n.split(""); |
| | | let p = ""; |
| | | let offset = [0, 0]; |
| | | if (position[lg] === "topLeft") { |
| | | p = "left"; |
| | | offset = [0, -8]; |
| | | } else if (position[lg] === "topRight") { |
| | | p = "right"; |
| | | offset = [0, -8]; |
| | | } else if (position[lg] === "bottomLeft") { |
| | | p = "left"; |
| | | offset = [0, 12]; |
| | | } else if (position[lg] === "bottomRight") { |
| | | p = "right"; |
| | | offset = [0, 12]; |
| | | } else { |
| | | p = position[lg]; |
| | | } |
| | | let stations = statusList[lineNum].filter(v => v.stationName8 == k + 1); |
| | | |
| | | let status = stations.length ? stations[0].note == 1 : false; |
| | | list.nodes.push({ |
| | | category: i, |
| | | name: n, |
| | | x, |
| | | status, |
| | | y, |
| | | color: "#" + cl, |
| | | p, |
| | | offset, |
| | | }); |
| | | } |
| | | if (k !== st.length - 1) { |
| | | list.lines.push({ |
| | | source: n, |
| | | target: st[k + 1].n, |
| | | lineStyle: { |
| | | normal: { |
| | | color: "#" + cl, |
| | | }, |
| | | }, |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | list.xPeak = { |
| | | min: Math.min(...list.x), |
| | | max: Math.max(...list.x), |
| | | }; |
| | | list.yPeak = { |
| | | min: Math.min(...list.y), |
| | | max: Math.max(...list.y), |
| | | }; |
| | | return list; |
| | | }, |
| | | async updateMap() { |
| | | let metroData = await this.getSubwayJson(); |
| | | const option = { |
| | | xAxis: { |
| | | show: false, |
| | | type: "value", |
| | | min: metroData.xPeak.min, |
| | | max: metroData.xPeak.max, |
| | | position: "top", |
| | | }, |
| | | yAxis: { |
| | | show: false, |
| | | type: "value", |
| | | min: metroData.yPeak.min, |
| | | max: metroData.yPeak.max, |
| | | }, |
| | | legend: [ |
| | | { |
| | | data: this.lineList, |
| | | textStyle: { |
| | | color: '#fff' |
| | | } |
| | | } |
| | | ], |
| | | series: [ |
| | | { |
| | | type: "graph", |
| | | layout: "none", |
| | | roam: true, |
| | | labelLayout: { |
| | | hideOverlap: true, |
| | | }, |
| | | categories: this.lineList.map(v=>({name: v})), |
| | | data: metroData.nodes.map((node) => ({ |
| | | name: node.name, |
| | | symbol: "circle", |
| | | symbolSize: 6, |
| | | category: node.category, |
| | | x: node.x, |
| | | y: node.y, |
| | | itemStyle: { |
| | | color: node.status ? '#0f0' : "#f00", |
| | | // borderColor: node.color, |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: node.p, |
| | | color: '#fff', |
| | | offset: node.offset, |
| | | }, |
| | | })), |
| | | links: metroData.lines, |
| | | }, |
| | | ], |
| | | }; |
| | | myChart.setOption(option); |
| | | |
| | | }, |
| | | }, |
| | | |
| | | async mounted() { |
| | | this.jsonData = await this.getJson(); |
| | | myChart = echarts.init(this.$refs.chart); |
| | | this.updateMap(); |
| | | |
| | | myChart.on('legendselectchanged', (param) => { |
| | | this.$emit('legend-change', param.selected); |
| | | }); |
| | | }, |
| | | }; |
| | | </script> |
New file |
| | |
| | | <template> |
| | | <div class="home-card"> |
| | | <div class="home-card-container"> |
| | | <div class="home-card-header"> |
| | | <span class="home-card-title" :class="{'red': isRedTitle}">{{ title }}</span> |
| | | <div class="tools"> |
| | | <slot name="tools"></slot> |
| | | </div> |
| | | </div> |
| | | <div :class="['home-card-body', contentClass]"> |
| | | <slot></slot> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "home_card", |
| | | props: { |
| | | title: { |
| | | type: String, |
| | | default: "" |
| | | }, |
| | | contentClass: { |
| | | type: [String, Array], |
| | | default() { |
| | | return [] |
| | | } |
| | | }, |
| | | isRedTitle: { |
| | | type: Boolean, |
| | | default: false |
| | | } |
| | | }, |
| | | data() { |
| | | return {}; |
| | | }, |
| | | methods: {} |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .home-card { |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | padding-bottom: 8px; |
| | | } |
| | | .home-card-container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | height: 100%; |
| | | /* background-color: #023752; */ |
| | | } |
| | | .home-card-header { |
| | | padding: 8px; |
| | | position: relative; |
| | | } |
| | | .tools { |
| | | position: absolute; |
| | | top: 8px; |
| | | right: 8px; |
| | | display: flex; |
| | | } |
| | | .home-card-header img { |
| | | height: 16px; |
| | | vertical-align: middle; |
| | | } |
| | | .home-card-title { |
| | | margin-left: 8px; |
| | | color: #00feff; |
| | | font-size: 20px; |
| | | font-weight: bold; |
| | | } |
| | | .home-card-title.red { |
| | | color: #ff0000; |
| | | } |
| | | .home-card-body { |
| | | flex: 1; |
| | | position: relative; |
| | | } |
| | | .home-card-title-sub { |
| | | font-size: 16px; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <vue-seamless-scroll :data="listData" :class-option="classOption" ref="seamlessScroll" class="my-outbox"> |
| | | <div class="my-inbox"> |
| | | <div v-for="(item,index) in listData" :key='index' ref='list' @click="clickItem(item)" class="my-list"> |
| | | <div v-if="!item.isEmpty" class="item"> |
| | | <div class="station-name" :title="item.stationName3">{{item.stationName3}}</div> <div class="alarm-time">{{item.almStartTime}}</div> <div class="alarm-name">{{item.almSignalIdName ||'未知'}}</div> |
| | | </div> |
| | | <div class="item empty" v-else :style="{'width':item.width+'px'}"></div> |
| | | </div> |
| | | </div> |
| | | <!-- <div class="my-inbox" slot="copy"> |
| | | <div v-for="(item,index) in listData" :key='index' ref='list' @click="clickItem(item)" class="my-list"> |
| | | <div v-if="!item.isEmpty"> |
| | | {{item.stationName}}在{{item.almStartTime}}出现了{{item.alarmName||'未知'}} |
| | | <img src="../../assets/images/new.png" class="img" v-if="item.isNew"> |
| | | </div> |
| | | <div v-else :style="{'width':item.width+'px'}"></div> |
| | | </div> |
| | | </div> --> |
| | | </vue-seamless-scroll> |
| | | </template> |
| | | |
| | | <script> |
| | | import vueSeamlessScroll from '@/layout/components/FooterScroll.vue'; |
| | | export default { |
| | | name: 'marquee-left', |
| | | components: { |
| | | vueSeamlessScroll |
| | | }, |
| | | props: { |
| | | sendVal: { |
| | | type: Array, |
| | | default() { |
| | | return []; |
| | | } |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | listData: [], |
| | | classOption: { |
| | | limitMoveNum: 0, |
| | | direction: 1, |
| | | step: 1, |
| | | }, |
| | | startDis: window.screen.width, |
| | | sstationObj: {}, |
| | | alarmId: "", |
| | | emptyIndex: null, |
| | | distanceWid: null, |
| | | // 每一个内容的宽度 |
| | | disArr: [], |
| | | } |
| | | }, |
| | | watch: { |
| | | 'sendVal': { |
| | | handler(val) { |
| | | this.$nextTick(() => { |
| | | this.listData = JSON.parse(JSON.stringify(val)) |
| | | var item = this.$refs.list |
| | | var arr = [] |
| | | // 因为设置的margin值一样,所以取第一个就行。 |
| | | var margin = 0 |
| | | if (item && item.length > 0) { |
| | | margin = this.getMargin(item[0]) |
| | | } |
| | | if (this.listData.length > 0) { |
| | | this.listData.map((jtem, i) => { |
| | | if (item && item.length > 0) { |
| | | arr.push(item[i]?.clientWidth + margin) // 把宽度和 margin 加起来就是每一个元素需要移动的距离 |
| | | } |
| | | }) |
| | | } |
| | | this.disArr = arr |
| | | // listData length无变化,仅仅是属性变更,手动调用下组件内部的reset方法 |
| | | this.$refs.seamlessScroll.reset() |
| | | }) |
| | | }, |
| | | immediate: true, |
| | | }, |
| | | }, |
| | | mounted() { |
| | | |
| | | }, |
| | | beforeDestroy() { |
| | | |
| | | }, |
| | | computed: { |
| | | search() { |
| | | let list = this.stationObj; |
| | | let id = this.alarmId; |
| | | return '?province=' + list.stationName1 + '&city=' + list.stationName2 + '&county=' + list.stationName5 + |
| | | '&home=' + list.stationName3 + '&alamId=' + id + "&stationName=" + list.stationName |
| | | }, |
| | | }, |
| | | methods: { |
| | | clickItem(val) { |
| | | this.stationObj = val.stationObj; |
| | | this.alarmId = val.almId; |
| | | let pageFlag = Math.random(); |
| | | if (val.alarmType == '1') { |
| | | //设备实时告警 |
| | | this.$router.push('/alarmMager/deviceTimequery' + this.search + '&fromType=fromIndex&'+"pageFlag="+pageFlag) |
| | | }else if(val.alarmType=='2') { |
| | | let strNum = RegExp('^1150'); |
| | | // 通信电源设备告警 |
| | | if(strNum.test(val.battGroupId)) { |
| | | this.$router.push('/alarmMager/powerBoxAlarm' + this.search + '&fromType=fromIndex&'+"pageFlag="+pageFlag) |
| | | }else { |
| | | //电源实时告警-国网页面 |
| | | this.$router.push('/alarmMager/powerRealtimeInfo' + this.search + '&fromType=fromIndex&'+"pageFlag="+pageFlag) |
| | | } |
| | | |
| | | } else { |
| | | //电池实时告警 |
| | | this.$router.push('/alarmMager/batteryrTimequery' + this.search + '&fromType=fromIndex&'+"pageFlag="+pageFlag) |
| | | } |
| | | }, |
| | | // 获取margin属性 |
| | | getMargin(obj) { |
| | | var marg = window.getComputedStyle(obj, null)['margin-right'] |
| | | marg = marg.replace('px', '') |
| | | return Number(marg) // 强制转化成数字 |
| | | }, |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .my-outbox { |
| | | /*color: #D7BC8D;*/ |
| | | overflow: hidden; |
| | | color: #ffffff; |
| | | /* height: 35px; */ |
| | | /*background: #422b02;*/ |
| | | } |
| | | |
| | | .my-inbox { |
| | | white-space: nowrap; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | } |
| | | |
| | | .my-list { |
| | | margin-right: 25px; |
| | | display: inline-block; |
| | | font-size: 0.6rem; |
| | | height: 40px; |
| | | line-height: 40px; |
| | | cursor: pointer; |
| | | position: relative; |
| | | } |
| | | |
| | | .my-list .img { |
| | | width: 32px; |
| | | height: 14px; |
| | | } |
| | | .item { |
| | | display: flex; |
| | | .station-name { |
| | | display: inline-block; |
| | | color: #fff; |
| | | max-width: 14em; |
| | | overflow: hidden; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | margin-right: 0.4em; |
| | | } |
| | | .alarm-time { |
| | | display: inline-block; |
| | | color: #ebf006; |
| | | margin-left: 0.4em; |
| | | margin-right: 0.4em; |
| | | } |
| | | .alarm-name { |
| | | display: inline-block; |
| | | color: #fc0303; |
| | | margin-left: 0.4em; |
| | | } |
| | | } |
| | | |
| | | .my-uname { |
| | | /*color: #FF8900;*/ |
| | | color: #ffffff; |
| | | } |
| | | </style> |
New file |
| | |
| | | <script> |
| | | import ECharts from 'echarts'; |
| | | import BaseChart from '@/components/myCharts/BaseChart.vue'; |
| | | |
| | | import imgSrc from '../images/batt.png'; |
| | | const colorList = ['#afa3f5', '#00d488', '#3feed4', '#3bafff', '#f1bb4c', '#1fed08', '#f04d0d']; |
| | | 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 sData = data; |
| | | |
| | | let width = this.$options.chart.getWidth(), |
| | | height = this.$options.chart.getHeight(); |
| | | let imgW = width > height ? height * .25 : width * .25; |
| | | |
| | | // console.log(this.$options.chart.getWidth(), this.$options.chart.getHeight(), '=====get', imgW); |
| | | return { |
| | | grid: { |
| | | bottom: 150, |
| | | left: 0, |
| | | // right: '10%' |
| | | right: 0 |
| | | }, |
| | | graphic: { |
| | | elements: [{ |
| | | type: "image", |
| | | z: 6, |
| | | // x: 0, |
| | | y: -100, |
| | | style: { |
| | | image: imgSrc, |
| | | width: imgW / 2, |
| | | // shadowBlur: 0, |
| | | // shadowColor: '#000', |
| | | // shadowOffsetX: '1', |
| | | // shadowOffsetY: '1', |
| | | }, |
| | | left: 'center', |
| | | // left: '48%', |
| | | // right: '52%', |
| | | top: "44%", |
| | | // top: 'middle' |
| | | }] |
| | | }, |
| | | legend: { |
| | | show: false, |
| | | orient: 'vertical', |
| | | top: "middle", |
| | | right: "5%", |
| | | textStyle: { |
| | | color: '#f2f2f2', |
| | | fontSize: 25, |
| | | |
| | | }, |
| | | icon: 'roundRect' |
| | | }, |
| | | |
| | | series: [ |
| | | // 主要展示层的 |
| | | { |
| | | radius: ['25%', '45%'], |
| | | center: ['50%', '50%'], |
| | | type: 'pie', |
| | | itemStyle: { |
| | | normal: { |
| | | color: function (params) { |
| | | return colorList[params.dataIndex % colorList.length] |
| | | }, |
| | | borderWidth: 0, |
| | | }, |
| | | }, |
| | | // data: [{ |
| | | // value:17, |
| | | // name:'体育技能', |
| | | // },] |
| | | data: sData.map((v, i) => { |
| | | v.label = { |
| | | color: colorList[i % colorList.length], |
| | | normal: { |
| | | formatter: '{nameStyle|{b}} \n {rate|{d}% ({c})}', |
| | | // padding: [0, -110], |
| | | // height: 165, |
| | | rich: { |
| | | nameStyle: { |
| | | fontSize: 12, |
| | | color: colorList[i % colorList.length], |
| | | align: 'left' |
| | | }, |
| | | rate: { |
| | | fontSize: 14, |
| | | color: colorList[i % colorList.length], |
| | | align: 'left' |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | return v; |
| | | }) |
| | | }, |
| | | // 边框的设置 |
| | | { |
| | | radius: ['43%', '45%'], |
| | | center: ['50%', '50%'], |
| | | type: 'pie', |
| | | label: { |
| | | normal: { |
| | | show: false |
| | | }, |
| | | emphasis: { |
| | | show: false |
| | | } |
| | | }, |
| | | labelLine: { |
| | | normal: { |
| | | show: false |
| | | }, |
| | | emphasis: { |
| | | show: false |
| | | } |
| | | }, |
| | | animation: false, |
| | | tooltip: { |
| | | show: false |
| | | }, |
| | | itemStyle: { |
| | | normal: { |
| | | color: 'rgba(250,250,250,0.5)' |
| | | } |
| | | }, |
| | | data: [{ |
| | | value: 1, |
| | | }], |
| | | } |
| | | ], |
| | | } |
| | | } |
| | | }, |
| | | computed: { |
| | | yName() { |
| | | let unit = this.unit; |
| | | return unit ? "Y(" + unit + ")" : "Y"; |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.setData([]); |
| | | } |
| | | } |
| | | </script> |
New file |
| | |
| | | <script > |
| | | export default { |
| | | props: { |
| | | offset: { |
| | | type: Array, |
| | | default: () => [0, 0], |
| | | }, |
| | | points: { |
| | | type: Array, |
| | | default: () => [ |
| | | [0, 0], |
| | | [10, 10], |
| | | ], |
| | | }, |
| | | name: { |
| | | type: String, |
| | | default: '', |
| | | }, |
| | | color: { |
| | | type: String, |
| | | default: "#804000", |
| | | }, |
| | | lineWidth: { |
| | | type: Number, |
| | | default: 4, |
| | | }, |
| | | currColor: { |
| | | type: String, |
| | | default: "#0f0", |
| | | }, |
| | | |
| | | }, |
| | | computed: { |
| | | path() { |
| | | |
| | | let points = this.points; |
| | | let path = `M ${points[0].join(",")} `; |
| | | for (let i = 1, len = points.length; i < len; i++) { |
| | | path += ` L ${points[i].join(",")} `; |
| | | } |
| | | return path; |
| | | } |
| | | }, |
| | | } |
| | | |
| | | </script> |
| | | |
| | | <template> |
| | | <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> |
| | | <path :d="path" ref="path" fill="none" :stroke-width="lineWidth" :stroke="color"></path> |
| | | <text :x="points[1][0] + 10" :y="points[1][1]+10" |
| | | font-family="Verdana" |
| | | fill="#fff" |
| | | |
| | | font-size="8"> |
| | | {{ name }} |
| | | </text> |
| | | </g> |
| | | </template> |
| | | |
| | | <style scoped lang="less"></style> |
New file |
| | |
| | | <script > |
| | | export default { |
| | | props: { |
| | | offset: { |
| | | type: Array, |
| | | default: () => [0, 0], |
| | | }, |
| | | points: { |
| | | type: Array, |
| | | default: () => [0, 0], |
| | | }, |
| | | r: { |
| | | type: [Number, String], |
| | | default: 12, |
| | | }, |
| | | name: { |
| | | type: String, |
| | | default: '', |
| | | }, |
| | | color: { |
| | | type: String, |
| | | default: "#804000", |
| | | }, |
| | | lineWidth: { |
| | | type: Number, |
| | | default: 2, |
| | | }, |
| | | currColor: { |
| | | type: String, |
| | | default: "#0f0", |
| | | }, |
| | | pos: { |
| | | type: [String, Number], |
| | | default: 0 |
| | | }, |
| | | }, |
| | | computed: { |
| | | x() { |
| | | return this.points[0] * 1; |
| | | }, |
| | | y() { |
| | | return this.points[1] * 1; |
| | | }, |
| | | dx() { |
| | | let res = 0; |
| | | switch(this.pos * 1) { |
| | | case 0: |
| | | case 4: |
| | | res = 0; |
| | | break; |
| | | case 1: |
| | | case 2: |
| | | case 3: |
| | | res = 16; |
| | | break; |
| | | case 5: |
| | | case 6: |
| | | case 7: |
| | | res = -16; |
| | | break; |
| | | default: |
| | | res = 0; |
| | | break; |
| | | } |
| | | return res; |
| | | }, |
| | | dy() { |
| | | let res = 0; |
| | | switch(this.pos * 1) { |
| | | case 2: |
| | | case 6: |
| | | res = 0; |
| | | break; |
| | | case 0: |
| | | case 1: |
| | | case 7: |
| | | res = -16; |
| | | break; |
| | | case 3: |
| | | case 4: |
| | | case 5: |
| | | res = 32; |
| | | break; |
| | | default: |
| | | res = 0; |
| | | break; |
| | | } |
| | | return res; |
| | | }, |
| | | textAnchor() { |
| | | let res = ''; |
| | | switch(this.pos * 1) { |
| | | case 0: |
| | | case 4: |
| | | res = 'middle'; |
| | | break; |
| | | case 1: |
| | | case 2: |
| | | case 3: |
| | | res = 'start'; |
| | | break; |
| | | case 5: |
| | | case 6: |
| | | case 7: |
| | | res = 'end'; |
| | | break; |
| | | default: |
| | | res = 'start'; |
| | | break; |
| | | } |
| | | return res; |
| | | }, |
| | | } |
| | | |
| | | } |
| | | |
| | | </script> |
| | | |
| | | <template> |
| | | <g ref="g" :transform="'translate(' + offset.join(',') + ')'"> |
| | | <circle :cx="x" :cy="y" :r="r" :stroke="color" fill="#aaa" /> |
| | | <text :x="x" :y="y" |
| | | :dx="dx" |
| | | :dy="dy" |
| | | font-family="Verdana" |
| | | fill="#fff" |
| | | :text-anchor="textAnchor" |
| | | font-size="34"> |
| | | {{ name }} |
| | | </text> |
| | | </g> |
| | | </template> |
| | | |
| | | <style scoped lang="less"></style> |
New file |
| | |
| | | <script > |
| | | import svgLine from './svgLine.vue'; |
| | | import svgStation from './svgStation.vue'; |
| | | |
| | | const colors = [ |
| | | '#0f0', |
| | | '#f00', |
| | | '#00f', |
| | | '#ff0', |
| | | '#0ff', |
| | | '#f0f', |
| | | '#018AE8', |
| | | '#FF713B', |
| | | '#0AE88E', |
| | | ]; |
| | | |
| | | export default { |
| | | components: { |
| | | svgLine, |
| | | svgStation, |
| | | }, |
| | | data() { |
| | | return { |
| | | colors, |
| | | svgWidth: 1400, |
| | | svgHeight: 712, |
| | | padding: 100, |
| | | minLat: Infinity, |
| | | minLng: Infinity, |
| | | maxLat: -Infinity, |
| | | maxLng: -Infinity, |
| | | lines: [], |
| | | allLines: [3, 5, 6, 7, 8], |
| | | disableList: [], |
| | | viewBox: [0, 0, 100, 100], |
| | | lineObjs: [], |
| | | defaultData: [], |
| | | |
| | | infoVisible: false, |
| | | info: { |
| | | name: '', |
| | | lineName: '', |
| | | status: 0, |
| | | }, |
| | | left: 0, |
| | | top: 0, |
| | | transLeft: false, |
| | | transTop: false, |
| | | |
| | | } |
| | | }, |
| | | computed: { |
| | | filterLines() { |
| | | |
| | | return this.allLines.filter(v => this.disableList.every(vv => vv != v)); |
| | | }, |
| | | resData() { |
| | | return this.defaultData.filter(v => this.filterLines.some(vv=>vv == v.ln.substr(0, 1))).map(v => { |
| | | return { |
| | | name: v.ln, |
| | | list: v.st.map(vv => ({ |
| | | name: vv.n, |
| | | // points: vv.sl.split(',') |
| | | points: vv.p.split(' '), |
| | | p: vv.lg |
| | | })) |
| | | } |
| | | }) |
| | | }, |
| | | subWays() { |
| | | return this.defaultData.filter(v => this.allLines.some(vv=>vv == v.ln.substr(0, 1))).map(v => v.ln) |
| | | }, |
| | | |
| | | viewBoxArr() { |
| | | if ( |
| | | this.minLat == Infinity |
| | | || this.maxLat == -Infinity |
| | | || this.minLng == Infinity |
| | | || this.maxLng == -Infinity |
| | | ) { |
| | | return [0, 0, this.svgWidth, this.svgHeight]; |
| | | } else { |
| | | return [this.minLng - this.padding, this.minLat - this.padding, this.maxLng - this.minLng + this.padding * 2, this.maxLat - this.minLat + this.padding * 2]; |
| | | } |
| | | }, |
| | | }, |
| | | methods: { |
| | | async getJson () { |
| | | |
| | | const dynamicPath = `mapJson/subway/suzhou1.json`; |
| | | try { |
| | | const response = await fetch(dynamicPath); |
| | | if (!response.ok) { |
| | | throw new Error(`HTTP error! status: ${response.status}`); |
| | | } |
| | | const data = await response.json(); |
| | | console.log('data', data, '============='); |
| | | this.defaultData = data.l; |
| | | } catch (error) { |
| | | console.error('加载 JSON 出错:', error); |
| | | } |
| | | }, |
| | | getSize(points) { |
| | | |
| | | points.forEach(point => { |
| | | let [lng, lat] = point; |
| | | lng *= 1; |
| | | lat *= 1; |
| | | if (lat < this.minLat) this.minLat = lat; |
| | | if (lat > this.maxLat) this.maxLat = lat; |
| | | if (lng < this.minLng) this.minLng = lng; |
| | | if (lng > this.maxLng) this.maxLng = lng; |
| | | }); |
| | | |
| | | }, |
| | | async getPoints() { |
| | | let gpsPoints = this.resData; |
| | | |
| | | let arr = []; |
| | | for (let i = 0, len = gpsPoints.length; i < len; i++) { |
| | | let item = gpsPoints[i]; |
| | | item.list.forEach(v => { |
| | | arr.push(v.points); |
| | | }) |
| | | } |
| | | |
| | | console.log('arr', arr, '============='); |
| | | |
| | | this.getSize(arr); |
| | | this.lines = gpsPoints.map((v, i) => ({ name: v.name, points: v.list.map(vv => vv.points) })); |
| | | this.lineObjs = gpsPoints.map((v, i) => ({ name: v.name, list: v.list.map(vv => ({ name: vv.name, points: vv.points, p: vv.p })) })); |
| | | }, |
| | | toggleLine(idx) { |
| | | let _idx = this.subWays[idx].substr(0,1); |
| | | let arr = this.disableList; |
| | | // 判断是否是不显示的 |
| | | let _i = arr.indexOf(_idx); |
| | | if(_i > -1) { |
| | | arr.splice(_i, 1); |
| | | } else { |
| | | arr.push(_idx); |
| | | } |
| | | this.disableList = arr; |
| | | // nextTick() |
| | | this.getPoints(); |
| | | }, |
| | | |
| | | showInfo(e, data, lineName) { |
| | | this.infoVisible = true; |
| | | console.log('e', e, data, '============='); |
| | | this.left = e.clientX + 'px'; |
| | | this.top = e.clientY + 'px'; |
| | | let w = window.innerWidth; |
| | | let h = window.innerHeight; |
| | | if (e.clientX > w / 2) { |
| | | this.transLeft = true; |
| | | } else { |
| | | this.transLeft = false; |
| | | } |
| | | if (e.clientY > h / 2) { |
| | | this.transTop = true; |
| | | } else { |
| | | this.transTop = false; |
| | | } |
| | | this.info.name = data.name; |
| | | this.info.lineName = lineName; |
| | | }, |
| | | |
| | | hideInfo () { |
| | | this.infoVisible = false; |
| | | }, |
| | | |
| | | |
| | | }, |
| | | async mounted() { |
| | | await this.getJson(); |
| | | this.getPoints(); |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div class="main"> |
| | | <div class="lines"> |
| | | <div :class="['item', `level${item.substr(0, 1)}`, {disabled: disableList.indexOf(item.substr(0, 1)) > -1}]" v-for="(item, idx) in subWays" :key="idx" @click="toggleLine(idx)"> |
| | | {{ item }} |
| | | </div> |
| | | </div> |
| | | <svg |
| | | class="map" |
| | | width="100%" |
| | | height="100%" |
| | | :viewBox="viewBoxArr.join(' ')" |
| | | xmlns="http://www.w3.org/2000/svg" |
| | | xmlns:xlink="http://www.w3.org/1999/xlink" |
| | | style="position: relative;" |
| | | :transform="'scale(' + [1, 1].join(',') + ')'" |
| | | ref="map" |
| | | > |
| | | <svg-line |
| | | v-for="(item, idx) in lines" |
| | | :key="idx" |
| | | :points="item.points" |
| | | :color="colors[item.name.substr(0,1)]" |
| | | :name="subWays[idx]" |
| | | |
| | | ></svg-line> |
| | | |
| | | <!-- 站点 --> |
| | | <template v-for="(item, i) in lineObjs"> |
| | | <svg-station |
| | | v-for="(point, idx) in item.list" |
| | | :key="'line_' + i + '_point' + idx" |
| | | :points="point.points" |
| | | :name="point.name" |
| | | :color="colors[item.name.substr(0,1)]" |
| | | :pos="point.p" |
| | | @mouseenter.capture="(e) => showInfo(e, point, item.name)" |
| | | ></svg-station> |
| | | </template> |
| | | </svg> |
| | | <teleport to='body' v-if="infoVisible"> |
| | | <div :class="['info', {'trans-left': transLeft, 'trans-top': transTop}]" v-if="infoVisible" :style="{ left, top }"> |
| | | <div class="info-item station-name"> |
| | | <div class="label">站名:</div> |
| | | <div class="value">{{ info.name }}</div> |
| | | </div> |
| | | <div class="info-item line-name"> |
| | | <div class="label">线路:</div> |
| | | <div class="value">{{ info.lineName }}</div> |
| | | </div> |
| | | <div class="info-item status"> |
| | | <div class="label">状态:</div> |
| | | <div class="value">{{ info.status ? '在线' : '离线' }}</div> |
| | | </div> |
| | | </div> |
| | | <div class="mask" @mouseenter="hideInfo"></div> |
| | | </teleport> |
| | | </div> |
| | | </template> |
| | | |
| | | <style scoped lang="less"> |
| | | .item { |
| | | background: #0ff; |
| | | border-radius: 4px; |
| | | color: #000; |
| | | padding: 8px; |
| | | &.level3 { |
| | | background: #ff0; |
| | | } |
| | | &.level5 { |
| | | background: #f0f; |
| | | } |
| | | &.level6 { |
| | | background: #018AE8; |
| | | } |
| | | &.level7 { |
| | | background: #FF713B; |
| | | } |
| | | &.level8 { |
| | | background: #0AE88E; |
| | | } |
| | | &.disabled { |
| | | background: #ccc; |
| | | } |
| | | } |
| | | .main { |
| | | background: #333; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .lines { |
| | | display: flex; |
| | | flex-direction: row; |
| | | |
| | | .item { |
| | | margin-right: 20px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | |
| | | .map { |
| | | flex: 1; |
| | | } |
| | | } |
| | | .info { |
| | | position: absolute; |
| | | background: #0ff; |
| | | z-index: 99; |
| | | color: #000; |
| | | padding: 12px; |
| | | border-radius: 8px; |
| | | white-space: nowrap; |
| | | &.trans-left { |
| | | transform: translateX(-100%); |
| | | } |
| | | &.trans-top { |
| | | transform: translateY(-100%); |
| | | } |
| | | &.trans-left.trans-top { |
| | | transform: translate(-100%, -100%); |
| | | } |
| | | &::after { |
| | | content: ''; |
| | | position: absolute; |
| | | left: -6px; |
| | | top: -6px; |
| | | right: -6px; |
| | | bottom: -6px; |
| | | z-index: -1; |
| | | } |
| | | } |
| | | .info-item { |
| | | display: flex; |
| | | .label { |
| | | margin-right: 0.4em; |
| | | } |
| | | } |
| | | .mask { |
| | | position: fixed; |
| | | left: 0; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: transparent; |
| | | z-index: 98; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="p-main"> |
| | | <div class="row"> |
| | | <card> |
| | | <big-screen-card title="告警统计"> |
| | | <template #tools> |
| | | <el-radio-group size="mini" v-model="alarmType" @input="alarmTypeChangede"> |
| | | <el-radio-button :label="0">告警类型</el-radio-button> |
| | | <el-radio-button :label="1">告警等级</el-radio-button> |
| | | </el-radio-group> |
| | | </template> |
| | | <div class="chart-wrap"> |
| | | <div class="inner"> |
| | | <bar-chart-alarm v-if="alarmType == 1" ref="chart_alarm"></bar-chart-alarm> |
| | | <pie-chart ref="alarmPieChart" :values="alarms" v-else></pie-chart> |
| | | </div> |
| | | </div> |
| | | </big-screen-card> |
| | | </card> |
| | | </div> |
| | | <div class="row"> |
| | | <card> |
| | | <big-screen-card title="设备工作状态"> |
| | | <div class="dev-wrap"> |
| | | <circle-box class="item" :type="0" :value="workState[0]" @click.native="goDevWorkState(4)"></circle-box> |
| | | <circle-box ref="devWorkState1" class="item" :type="1" :value="workState[1]" |
| | | @click.native="goDevWorkState(2)"></circle-box> |
| | | <circle-box ref="devWorkState2" class="item" :type="2" :value="workState[2]" |
| | | @click.native="goDevWorkState(0)"></circle-box> |
| | | <circle-box ref="devWorkState3" class="item" :type="3" :value="workState[3]" |
| | | @click.native="goDevAlarm"></circle-box> |
| | | </div> |
| | | </big-screen-card> |
| | | </card> |
| | | </div> |
| | | <div class="row"> |
| | | <card> |
| | | <big-screen-card title="整组容量"> |
| | | <div class="mon-box-container"> |
| | | <div class="mon-info-box"> |
| | | <div class="mon-info-title">大于95%比例:</div> |
| | | <div class="mon-info-value">{{ cap.level0 }}</div> |
| | | </div> |
| | | <div class="mon-info-box box2"> |
| | | <div class="mon-info-title">95%~85%比例:</div> |
| | | <div class="mon-info-value">{{ cap.level1 }}</div> |
| | | </div> |
| | | <div class="mon-info-box box3"> |
| | | <div class="mon-info-title">85%~60%比例:</div> |
| | | <div class="mon-info-value">{{ cap.level2 }}</div> |
| | | </div> |
| | | </div> |
| | | <div class="mon-box-container mgt16"> |
| | | <div class="mon-info-box box2"> |
| | | <div class="mon-info-title">60%~50%比例:</div> |
| | | <div class="mon-info-value">{{ cap.level3 }}</div> |
| | | </div> |
| | | <div class="mon-info-box box3"> |
| | | <div class="mon-info-title">小于50%:</div> |
| | | <div class="mon-info-value">{{ cap.level4 }}</div> |
| | | </div> |
| | | </div> |
| | | </big-screen-card> |
| | | </card> |
| | | <div class="p-side p-left"> |
| | | <div class="row"> |
| | | <home-card title="统计电池告警"> |
| | | <template #tools> |
| | | <el-select v-model="lineSelect0" size="mini" @change="testLevelChange(0)"> |
| | | <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item == 0 ? '全部' : item + '号线'" :value="item"></el-option> |
| | | </el-select> |
| | | </template> |
| | | <!-- <div class="chart-wrap"> |
| | | <div class="inner"> |
| | | <bar-chart-alarm v-if="alarmType == 1" ref="chart_alarm"></bar-chart-alarm> |
| | | <pie-chart ref="alarmPieChart" :values="alarms" v-else></pie-chart> |
| | | </div> |
| | | </div> --> |
| | | <bar3d ref="bar3d0"></bar3d> |
| | | </home-card> |
| | | </div> |
| | | <div class="row"> |
| | | <home-card title="故障类型统计"> |
| | | <template #tools> |
| | | <el-select v-model="lineSelect1" size="mini" @change="testLevelChange(1)"> |
| | | <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item == 0 ? '全部' : item + '号线'" :value="item"></el-option> |
| | | </el-select> |
| | | </template> |
| | | <pie-chart ref="pie"></pie-chart> |
| | | </home-card> |
| | | </div> |
| | | </div> |
| | | <div class="wraper"> |
| | | <div class="row row1"> |
| | | <card :miniCor="true"> |
| | | <div class="info"> |
| | | <div class="item" @click="goStations"> |
| | | <div class="name">站点</div> |
| | | <div class="name">机房个数</div> |
| | | <div class="num"> |
| | | <led-num color="#f00" :num="stationNum"></led-num> |
| | | {{ stationNum }} |
| | | </div> |
| | | </div> |
| | | <div class="item"> |
| | | <div class="name">设备</div> |
| | | <div class="name">设备个数</div> |
| | | <div class="num"> |
| | | <led-num color="#f00" :num="devCount"></led-num> |
| | | {{ devCount }} |
| | | </div> |
| | | </div> |
| | | <div class="item" @click="goBatt"> |
| | | <div class="name">电池节数</div> |
| | | <div class="num bits5"> |
| | | <led-num color="#f00" :bits='5' :num="battGroupMonCount"></led-num> |
| | | </div> |
| | | </div> |
| | | <div class="item" @click="goBatt"> |
| | | <div class="name">电池组</div> |
| | | <div class="name">电池组个数</div> |
| | | <div class="num"> |
| | | <led-num color="#f00" :num="battGroupCount"></led-num> |
| | | {{ battGroupCount }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </card> |
| | | </div> |
| | | <div class="row row2"> |
| | | <card :inside="false"> |
| | | <div class="flex-map-contain"> |
| | | <div class="inner"> |
| | | <map-chart ref="map" subway="suzhou"> |
| | | <map-mark-list slot="tools"></map-mark-list> |
| | | </map-chart> |
| | | <svg-subway :lines="lineList.filter(v=> v != 0)" :status="statusList" @legend-change="legendChange"></svg-subway> |
| | | </div> |
| | | </div> |
| | | </card> |
| | | </div> |
| | | </div> |
| | | <div class="row alarm"> |
| | | <card> |
| | | <big-screen-card title="实时告警信息"> |
| | | <div class="scroller-wrap"> |
| | | <div class="inner"> |
| | | <el-table ref="elTbl" stripe size="small" :data="tbl.data" height="100%" :row-class-name=" |
| | | (row) =>'cursor-pointer' |
| | | " @row-dblclick="goRealTime" class="tableCent"> |
| | | <el-table-column v-for="header in tbl.headers" :key="header.prop" :prop="header.prop" |
| | | :label="header.label" :width="header.width" :min-width="header.minWidth" :sortable="header.sortable" |
| | | align="center"></el-table-column> |
| | | <el-table-column label="操作" width="110" align="center"> |
| | | <template slot-scope="scope"> |
| | | <el-button type="primary" size="mini" @click="goRealTime(scope.row)">实时</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- <div class="empty-msg" v-else>最近一周无记录</div> --> |
| | | <div class="p-side p-right"> |
| | | <div class="row alarm"> |
| | | <home-card title="电池状态"> |
| | | <template #tools> |
| | | <el-select v-model="lineSelect2" size="mini" @change="testLevelChange(2)"> |
| | | <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item == 0 ? '全部' : item + '号线'" :value="item"></el-option> |
| | | </el-select> |
| | | </template> |
| | | <bar3d ref="bar3d1"></bar3d> |
| | | </home-card> |
| | | </div> |
| | | <div class="row test-info"> |
| | | <home-card title="实时电池告警滚动"> |
| | | <template #tools> |
| | | <el-select v-model="lineSelect3" size="mini" @change="testLevelChange(3)"> |
| | | <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item == 0 ? '全部' : item + '号线'" :value="item"></el-option> |
| | | </el-select> |
| | | </template> |
| | | <div class="scroller-wraper"> |
| | | <marquee-top :sendVal="newItems" v-if="showMarquee"></marquee-top> |
| | | <div class="no-warning-msg" v-else>最近24小时内无告警</div> |
| | | </div> |
| | | </div> |
| | | </big-screen-card> |
| | | </card> |
| | | </div> |
| | | <div class="row test-info"> |
| | | <card> |
| | | <big-screen-card title="线路告警"> |
| | | <template #tools> |
| | | <!-- :disabled="!chartData.test.length" --> |
| | | <!-- <el-radio-group |
| | | size="mini" |
| | | @input="testLevelChange" |
| | | v-model="testLevel" |
| | | > |
| | | <el-radio-button :label="0">总线路</el-radio-button> |
| | | <el-radio-button :label="1">1号线</el-radio-button> |
| | | <el-radio-button :label="2">2号线</el-radio-button> |
| | | </el-radio-group> --> |
| | | <el-select v-model="testLevel" size="small" @change="testLevelChange"> |
| | | <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item" :value="item"></el-option> |
| | | </el-select> |
| | | </template> |
| | | <bar3d ref="bar3d"></bar3d> |
| | | </big-screen-card> |
| | | </card> |
| | | </home-card> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import card from "./components/card-corner"; |
| | | import BigScreenCard from "@/components/bigScreenPage/big_screen_card.vue"; |
| | | import homeCard from "./components/home_card.vue"; |
| | | import BatteryPieChart from "@/components/myCharts/BatteryPieChart.vue"; |
| | | import MapChart from "@/components/myCharts/MapChart.vue"; |
| | | import MapMarkList from "@/components/mapMarkList.vue"; |
| | |
| | | import circleBox from "./components/circle.vue"; |
| | | import BarChart from "@/components/myCharts/BarChart.vue"; |
| | | import LedNum from "@/components/ledNum"; |
| | | import pieChart from "./components/pieCharts"; |
| | | // import pieChart from "./components/pieCharts"; |
| | | import pieChart from "./components/pie-chart1"; |
| | | import BarChartAlarm from "./components/batt-chart-alarm"; |
| | | import PowerPieChart from "@/components/myCharts/PieRoseChart.vue"; |
| | | import { const_alarm_level } from "@/assets/js/const"; |
| | | import { getLabelByValue } from "@/assets/js/tools"; |
| | | import getNowStamp from "@/assets/js/tools/getNowStamp"; |
| | | import marqueeTop from './components/marqueeTop.vue'; |
| | | |
| | | // import svgSubway from './components/test.vue'; |
| | | import svgSubway from './components/SubwayView.vue'; |
| | | |
| | | import createWs from "@/assets/js/websocket/plus"; |
| | | import { sethoubeiTime, formatSeconds } from "@/assets/js/tools"; |
| | | const WSMixin = createWs("screen_sz", 'battAlarmFoot'); |
| | | const WSMixin = createWs("screen_sz2", 'battAlarmFoot'); |
| | | |
| | | export default { |
| | | name: "", |
| | | mixins: [WSMixin], |
| | | data() { |
| | | return { |
| | | nums: {}, |
| | | selectFlag: false, |
| | | newItems: [], |
| | | lineSelect0: '', |
| | | lineSelect1: '', |
| | | lineSelect2: '', |
| | | lineSelect3: '', |
| | | lineList: [], |
| | | otherPwrProd: [], |
| | | testData: {}, |
| | | faultData: {}, |
| | | workState: {}, |
| | | alarmRt: {}, |
| | | statusList: {}, |
| | | alarmData: [[], [], []], |
| | | testLevel: '', |
| | | workState: [0, 0, 0, 0], |
| | | nxType: 0, |
| | | alarmType: 0, |
| | | alarms: [0, 0, 0], |
| | |
| | | label: "告警开始时间", |
| | | minWidth: 110, |
| | | }, |
| | | // { |
| | | // prop: "xuhang", |
| | | // label: "预估续航时长", |
| | | // minWidth: 110, |
| | | // }, |
| | | ], |
| | | data: [], |
| | | }, |
| | | }; |
| | | }, |
| | | components: { |
| | | card, |
| | | BigScreenCard, |
| | | homeCard, |
| | | BatteryPieChart, |
| | | MapChart, |
| | | MapMarkList, |
| | |
| | | BarChartAlarm, |
| | | bar3d, |
| | | PowerPieChart, |
| | | svgSubway, |
| | | marqueeTop, |
| | | }, |
| | | methods: { |
| | | alarmTypeChangede(value) { |
| | |
| | | res = JSON.parse(res.data); |
| | | // console.log(res, "=====111data"); |
| | | let { |
| | | devStates, |
| | | stationCount, |
| | | battGroupInfo, |
| | | alarmsLevelWithStationName5, |
| | | devCountMap, |
| | | resTestdataInfAnalysis, |
| | | groupCap, |
| | | alarmsLevel, |
| | | dischargingBattery, |
| | | res_inf, |
| | | res_battState, |
| | | res_battAlarm, |
| | | res_station, |
| | | } = res.data; |
| | | // 站点数量统计更新 |
| | | this.updateSiteDev(devCountMap); |
| | | // 更新设备工作状态 |
| | | this.updateWorkState(devStates); |
| | | // 更新整组容量 |
| | | this.updateGroupCap(groupCap); |
| | | this.updateSiteDev(res_inf); |
| | | // 测试信息 改为告警信息 |
| | | this.updateTestData(alarmsLevelWithStationName5); |
| | | // 更新地图 |
| | | this.updateMap(devCountMap); |
| | | // 更新告警统计 |
| | | this.updateAlarms(alarmsLevel); |
| | | // // 实时放电信息 |
| | | // this.updateDischargeInfo(dischargingBattery); |
| | | this.updateTestData(res_battAlarm); |
| | | // 更新电池状态 |
| | | this.updateWorkState(res_battState); |
| | | // // 更新地图 |
| | | this.updateMap(res_station); |
| | | }, |
| | | onWSOpen2() { |
| | | this.sendMessage2(); |
| | |
| | | |
| | | // this.updateFlag = Math.random(); |
| | | }, |
| | | legendChange(data) { |
| | | console.log('data, ', data, '============='); |
| | | this.selectFlag = true; |
| | | let stionNum = 0; |
| | | let battNum = 0; |
| | | let devNum = 0; |
| | | let nums = this.nums; |
| | | Object.keys(data).forEach(v => { |
| | | if (data[v]) { |
| | | stionNum += nums[v].stionNum; |
| | | devNum += nums[v].devNum; |
| | | battNum += nums[v].battNum; |
| | | } |
| | | }); |
| | | this.stationNum = stionNum; |
| | | this.devCount = devNum; |
| | | this.battGroupCount = battNum; |
| | | }, |
| | | updateSiteDev(data) { |
| | | const { devCount, stationNum, battGroupCount, battGroupMonCount } = data.data2; |
| | | this.devCount = devCount; |
| | | this.stationNum = stationNum; |
| | | this.battGroupCount = battGroupCount; |
| | | this.battGroupMonCount = battGroupMonCount; |
| | | const { devNum, stionNum, battNum } = data.data2?.allmap || {}; |
| | | if (!this.selectFlag) { |
| | | this.devCount = devNum || 0; |
| | | this.stationNum = stionNum || 0; |
| | | this.battGroupCount = battNum || 0; |
| | | } |
| | | |
| | | let _data = data.data2; |
| | | let res = {}; |
| | | Object.keys(_data).forEach(v => { |
| | | if (v != 'allmap') { |
| | | res[v + '号线'] = _data[v]; |
| | | } |
| | | }); |
| | | this.nums = res; |
| | | }, |
| | | updateWorkState(data) { |
| | | data = data.data2; |
| | | this.workState = [ |
| | | data["内阻测试数量"], |
| | | data["核容测试数量"], |
| | | data["直连充电数量"], |
| | | data["通讯故障数量"], |
| | | ]; |
| | | let workList = {}; |
| | | this.lineList.forEach(v => { |
| | | let item = v == 0 ? data['allmap'] : data[v]; |
| | | let xLabel = []; |
| | | let sData = []; |
| | | Object.keys(item).forEach(vv => { |
| | | xLabel.push(vv); |
| | | sData.push(item[vv]); |
| | | }); |
| | | workList[v] = {xLabel, sData}; |
| | | }); |
| | | this.workState = workList; |
| | | this.$refs.bar3d1.setData(this.workState[this.lineSelect2]); |
| | | }, |
| | | updateGroupCap(obj) { |
| | | const { code, data, data3 } = obj; |
| | |
| | | this.cap.level3 = level3; |
| | | this.cap.level4 = level4; |
| | | }, |
| | | // 电池统计 |
| | | updateBattInfo(obj) { |
| | | // let { code, data, data2 } = obj; |
| | | // let vol2 = 0, |
| | | // vol12 = 0, |
| | | // producer = [{ name: "电池品牌", value: 0 }]; |
| | | // if (code && data) { |
| | | // vol2 = data2.monVol["2.0"]; |
| | | // vol12 = data2.monVol["12.0"]; |
| | | // let arr = Object.keys(data2.producer) |
| | | // .map((v) => ({ name: v, value: data2.producer[v] })) |
| | | // .sort((a, b) => b.value - a.value); |
| | | // if (arr.length <= 5) { |
| | | // producer = arr; |
| | | // } else { |
| | | // let name = "其他"; |
| | | // let value = 0; |
| | | // arr.splice(4).forEach((v) => { |
| | | // value += v.value * 1; |
| | | // }); |
| | | // arr.push({ name, value }); |
| | | // producer = arr; |
| | | // } |
| | | // } |
| | | // this.$refs.batteryChart.setData(vol2, vol12, producer); |
| | | }, |
| | | |
| | | updateTestData(obj) { |
| | | let list_obj = obj.data2.data; |
| | | let list_obj = obj.data2.level; |
| | | let lineList = Object.keys(list_obj); |
| | | lineList.unshift(0); |
| | | if (!this.lineList.length) { |
| | | this.lineList = lineList; |
| | | this.testLevel = lineList[0]; |
| | | |
| | | this.lineSelect0 = 0; |
| | | this.lineSelect1 = 0; |
| | | this.lineSelect2 = 0; |
| | | this.lineSelect3 = 0; |
| | | } |
| | | |
| | | let test = {}; |
| | | lineList.forEach((item) => { |
| | | let _item = list_obj[item]; |
| | | let _item = item == 0 ? obj.data2.allLevel : list_obj[item]; |
| | | const { |
| | | level1, |
| | | level2, |
| | | level3, |
| | | level4, |
| | | 1: level1, |
| | | 2: level2, |
| | | 3: level3, |
| | | 4: level4, |
| | | } = _item; |
| | | |
| | | test[item] = { |
| | | xLabel: ["一级告警", "二级告警", "三级告警", "四级告警"], |
| | | sData: [ |
| | | level1.battAlarmCount + level1.powerAlarmCount + level1.deviceAlarmCount, |
| | | level2.battAlarmCount + level2.powerAlarmCount + level2.deviceAlarmCount, |
| | | level3.battAlarmCount + level3.powerAlarmCount + level3.deviceAlarmCount, |
| | | level4.battAlarmCount + level4.powerAlarmCount + level4.deviceAlarmCount |
| | | level1, |
| | | level2, |
| | | level3, |
| | | level4 |
| | | ], |
| | | }; |
| | | }); |
| | | this.testData = test; |
| | | this.$refs.bar3d.setData(test[this.testLevel]); |
| | | // 故障 |
| | | let fault = {}; |
| | | let _fault = obj.data2.type; |
| | | lineList.forEach(v => { |
| | | let _item = v == 0 ? obj.data2.allType : _fault[v]; |
| | | let arr = []; |
| | | Object.keys(_item).forEach(vv => { |
| | | arr.push({ |
| | | name: vv, |
| | | value: _item[vv] |
| | | }); |
| | | }); |
| | | fault[v] = arr; |
| | | }); |
| | | |
| | | this.faultData = fault; |
| | | |
| | | this.$refs.bar3d0.setData(test[this.lineSelect0]); |
| | | this.$refs.pie.setData(fault[this.lineSelect1]); |
| | | // 告警列表 |
| | | let alarmRt = {}; |
| | | let alarmList = obj.data2.list; |
| | | lineList.forEach(v => { |
| | | let _list = v == 0 ? alarmList['allList'] : alarmList[v]; |
| | | alarmRt[v] = _list; |
| | | }); |
| | | this.alarmRt = alarmRt; |
| | | this.newItems = alarmRt[this.lineSelect3]; |
| | | }, |
| | | testLevelChange(value) { |
| | | this.$refs.bar3d.setData(this.testData[value]); |
| | | // TODO |
| | | switch(value) { |
| | | case 0: |
| | | this.$refs.bar3d0.setData(this.testData[this.lineSelect0]); |
| | | break; |
| | | case 1: |
| | | this.$refs.pie.setData(this.faultData[this.lineSelect1]); |
| | | break; |
| | | case 2: |
| | | this.$refs.bar3d1.setData(this.workState[this.lineSelect2]); |
| | | break; |
| | | case 3: |
| | | this.newItems = this.alarmRt[this.lineSelect3]; |
| | | break; |
| | | } |
| | | }, |
| | | // 更新地图 |
| | | updateMap(obj) { |
| | | let data = obj.data2.stationInfList; |
| | | const getColor = (o) => { |
| | | let res = 0; |
| | | res = o.devWorkState <= 3 ? o.devWorkState : 0; |
| | | return ["#0081ff", "#66f842", "#ff6b6c", "#7668f9"][res]; |
| | | }; |
| | | this.$refs.map.setData( |
| | | data.map((v) => { |
| | | return { |
| | | ...v, |
| | | label: v.stationName3, |
| | | color: getColor(v), |
| | | points: [v.stationLongitude, v.stationLatitude], |
| | | // 无实际意义 |
| | | value: 100, |
| | | }; |
| | | }) |
| | | ); |
| | | }, |
| | | // 更新告警统计 |
| | | updateAlarms(obj) { |
| | | let { level1, level2, level3, level4 } = obj.data2.data; |
| | | this.alarms = [ |
| | | level1.powerAlarmCount, |
| | | level1.deviceAlarmCount, |
| | | level1.battAlarmCount, |
| | | ]; |
| | | this.alarmData = [ |
| | | [ |
| | | level1.powerAlarmCount, |
| | | level2.powerAlarmCount, |
| | | level3.powerAlarmCount, |
| | | level4.powerAlarmCount, |
| | | ], |
| | | [ |
| | | level1.deviceAlarmCount, |
| | | level2.deviceAlarmCount, |
| | | level3.deviceAlarmCount, |
| | | level4.deviceAlarmCount, |
| | | ], |
| | | [ |
| | | level1.battAlarmCount, |
| | | level2.battAlarmCount, |
| | | level3.battAlarmCount, |
| | | level4.battAlarmCount, |
| | | ], |
| | | ]; |
| | | if (this.$refs.alarmPieChart) { |
| | | this.$refs.alarmPieChart.update(); |
| | | } |
| | | |
| | | if (this.$refs.chart_alarm) { |
| | | this.$refs.chart_alarm.setData(this.alarmData); |
| | | } |
| | | this.statusList = obj.data2 || {}; |
| | | }, |
| | | goDevWorkState(num) { |
| | | let status = num; |
| | |
| | | }, |
| | | }); |
| | | }, |
| | | // updateDischargeInfo(obj) { |
| | | // const { code, data, data2, msg } = obj; |
| | | // let list = []; |
| | | // if (code && data) { |
| | | // let outTime = 2 * 60; //设备超时时间(2分钟) |
| | | // let nowTime = new Date(msg).getTime(); //当前时间 |
| | | // list = data2 |
| | | // .filter((v) => { |
| | | // // 判断是否超时 |
| | | // let record = new Date(v.battTestRecordtime).getTime(); |
| | | // return Math.abs(nowTime - record) / 1000 <= outTime; |
| | | // }) |
| | | // .map((v) => { |
| | | // // v.stationArea = |
| | | // // v.stationName1 + " " + v.stationName2 + " " + v.stationName5; |
| | | // v.battTestTimelong = formatSeconds(v.battTestTlong); |
| | | // let xuhang = v.loadCurr ? v.battRealCap / v.loadCurr : 0; |
| | | // v.xuhang = xuhang ? sethoubeiTime(xuhang) : "---"; |
| | | // return v; |
| | | // }); |
| | | // } |
| | | // this.tbl.data = list; |
| | | // }, |
| | | goDevAlarm() { |
| | | this.$router.push({ |
| | | path: "/alarmMager/deviceTimequery", |
| | |
| | | this.$router.push("/dataMager/battGroupMager"); |
| | | }, |
| | | initEvent() { |
| | | this.$refs.map.getChart().on("click", (e) => { |
| | | console.log('e', e, '=======123======'); |
| | | // this.$refs.map.getChart().on("click", (e) => { |
| | | // console.log('e', e, '=======123======'); |
| | | |
| | | }); |
| | | // }); |
| | | }, |
| | | }, |
| | | |
| | | computed: { |
| | | showMarquee() { |
| | | return typeof this.newItems == "undefined" || this.newItems.length == 0 |
| | | ? false |
| | | : true; |
| | | }, |
| | | }, |
| | | |
| | | mounted() { |
| | | if (this.$refs.alarmPieChart) { |
| | |
| | | <style scoped lang="less"> |
| | | .p-main { |
| | | height: 100%; |
| | | display: grid; |
| | | grid-auto-flow: column; |
| | | grid-template-rows: 1fr 1fr 1fr; |
| | | grid-template-columns: 1fr 1.5fr 1fr; |
| | | grid-gap: 8px; |
| | | // display: grid; |
| | | // grid-auto-flow: column; |
| | | // grid-template-rows: 1fr; |
| | | // grid-template-columns: 1fr 1.95fr 1fr; |
| | | // grid-gap: 8px; |
| | | display: flex; |
| | | |
| | | /deep/ .big-screen-card { |
| | | .p-side { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | padding-left: 36px; |
| | | padding-right: 58px; |
| | | position: relative; |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | top: 0; |
| | | bottom: 0; |
| | | background: url(./images/bg-side.png) left center / auto 100% no-repeat, |
| | | url(./images/bg-card.png) left center / 100% 100% no-repeat; |
| | | } |
| | | &.p-right { |
| | | padding-left: 68px; |
| | | padding-right: 36px; |
| | | &::before { |
| | | transform: scaleX(-1); |
| | | } |
| | | } |
| | | .row { |
| | | margin-top: 50px; |
| | | margin-bottom: 50px; |
| | | |
| | | } |
| | | .row~.row { |
| | | margin-top: 8px; |
| | | } |
| | | } |
| | | .row { |
| | | flex: 1; |
| | | :deep(.el-select) { |
| | | width: 8em; |
| | | } |
| | | } |
| | | |
| | | |
| | | /deep/ .home-card { |
| | | padding: 0; |
| | | } |
| | | |
| | | .wraper { |
| | | grid-row-start: span 2; |
| | | flex: 2.4; |
| | | // grid-row-start: span 2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | |
| | | .row2 { |
| | | flex: 1.8; |
| | | margin-top: 8px; |
| | | position: relative; |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | top: 0; |
| | | bottom: 0; |
| | | background: url(./images/bg-map-sz.jpg) center center / cover no-repeat; |
| | | opacity: 0.6; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .row.alarm { |
| | | grid-column-start: span 2; |
| | | // grid-column-start: span 2; |
| | | } |
| | | |
| | | .row.test-info { |
| | | grid-row-start: span 2; |
| | | // grid-row-start: span 2; |
| | | } |
| | | } |
| | | |
| | |
| | | .item { |
| | | cursor: pointer; |
| | | display: flex; |
| | | flex-direction: column; |
| | | // border-radius: 6px; |
| | | align-items: center; |
| | | justify-content: center; |
| | | min-width: 10em; |
| | | min-height: 4em; |
| | | background: url(./images/bg-info.png) center center / contain no-repeat; |
| | | |
| | | .name { |
| | | background: #0ff; |
| | | border-radius: 6px; |
| | | color: #333; |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | padding: 0 10px; |
| | | // background: #0ff; |
| | | // border-radius: 6px; |
| | | // color: #333; |
| | | // font-size: 18px; |
| | | // font-weight: bold; |
| | | // padding: 0 10px; |
| | | font-size: 14px; |
| | | margin-top: 10px; |
| | | color: #0ff; |
| | | &::after { |
| | | content: ':'; |
| | | } |
| | | } |
| | | |
| | | .num { |
| | | width: 3em; |
| | | height: 1.5em; |
| | | padding: 0 10px; |
| | | |
| | | &.bits5 { |
| | | width: 5em; |
| | | } |
| | | // width: 3em; |
| | | // height: 1.5em; |
| | | // padding: 0 10px; |
| | | color: #fbfc0d; |
| | | font-weight: bold; |
| | | font-size: 22px; |
| | | } |
| | | } |
| | | } |
| | |
| | | bottom: 0; |
| | | } |
| | | } |
| | | .scroller-wraper { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 30px; |
| | | right: 0; |
| | | bottom: 30px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /deep/ .mark-list-container { |
| | | bottom: 0.4rem; |
| | |
| | | <template> |
| | | <div class=""> |
| | | <svg-dyhr style="background: gray;"></svg-dyhr> |
| | | <div class="test"> |
| | | <test ></test> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import SvgDyhr from '@/views/home/components/svg/svgDyhr.vue'; |
| | | import test from '@/views/home/home-szdt.vue'; |
| | | export default { |
| | | name: '', |
| | | |
| | |
| | | } |
| | | }, |
| | | components: { |
| | | SvgDyhr |
| | | test |
| | | }, |
| | | methods: { |
| | | |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | .test { |
| | | height: 100%; |
| | | } |
| | | </style> |