| | |
| | | // import echarts from 'echarts' |
| | | import * as echarts from 'echarts' |
| | | require('echarts/theme/macarons') // echarts theme |
| | | import resize from './mixins/resize' |
| | | // import resize from './mixins/resize' |
| | | |
| | | export default { |
| | | mixins: [resize], |
| | | // mixins: [resize], |
| | | props: { |
| | | className: { |
| | | type: String, |
| | | default: 'chart', |
| | | default: 'chart' |
| | | }, |
| | | width: { |
| | | type: String, |
| | | default: '100%', |
| | | default: '100%' |
| | | }, |
| | | height: { |
| | | type: String, |
| | | default: '350px', |
| | | default: '350px' |
| | | }, |
| | | autoResize: { |
| | | type: Boolean, |
| | | default: true, |
| | | default: true |
| | | }, |
| | | isMouse: { |
| | | type: Boolean, |
| | | default: false, |
| | | default: false |
| | | }, |
| | | chartData: { |
| | | type: Object, |
| | | required: true, |
| | | required: true |
| | | }, |
| | | interval: { |
| | | type: Number, |
| | | default: 1, |
| | | }, |
| | | default: 1 |
| | | } |
| | | // xdata: { |
| | | // type: Array, |
| | | // required: true |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | chart: null, |
| | | chart: null |
| | | } |
| | | }, |
| | | watch: { |
| | |
| | | deep: true, |
| | | handler(val) { |
| | | this.setOptions(val) |
| | | }, |
| | | }, |
| | | } |
| | | } |
| | | // xdata: { |
| | | // deep: true, |
| | | // handler(val) { |
| | |
| | | }, |
| | | setOptions(val) { |
| | | function fontSize(res) { |
| | | let clientWidth = |
| | | const clientWidth = |
| | | window.innerWidth || |
| | | document.documentElement.clientWidth || |
| | | document.body.clientWidth |
| | | if (!clientWidth) return |
| | | let fontSize = 100 * (clientWidth / 1920) |
| | | const fontSize = 100 * (clientWidth / 1920) |
| | | return res * fontSize |
| | | } |
| | | let that = this |
| | | const that = this |
| | | if (this.isMouse) { |
| | | this.chart.on('mouseover', function (params) { |
| | | that.chart.setOption({ |
| | |
| | | title: { |
| | | text: val.text, |
| | | textStyle: { |
| | | color: '#000000', |
| | | }, |
| | | color: '#000000' |
| | | } |
| | | }, |
| | | xAxis: { |
| | | data: val.xAxis, |
| | | boundaryGap: false, |
| | | axisTick: { |
| | | show: true, |
| | | }, |
| | | show: true |
| | | } |
| | | }, |
| | | grid: { |
| | | left: '5%', |
| | | right: '5%', |
| | | top: '5%', |
| | | containLabel: true, |
| | | height: fontSize(4.3), |
| | | height: fontSize(4.3) |
| | | }, |
| | | toolbox: { |
| | | feature: { |
| | | dataZoom: { |
| | | yAxisIndex: 'none', |
| | | yAxisIndex: 'none' |
| | | }, |
| | | restore: {}, |
| | | saveAsImage: {}, |
| | | }, |
| | | saveAsImage: {} |
| | | } |
| | | }, |
| | | tooltip: { |
| | | backgroundColor: 'rgba(50,50,50,0.5)', |
| | | borderWidth: '0', |
| | | trigger: 'axis', |
| | | formatter: function (a) { |
| | | let list = [] |
| | | const list = [] |
| | | let listItem = '' |
| | | for (var i = 0; i < a.length; i++) { |
| | | list.push( |
| | |
| | | }, |
| | | position: function (point, params, dom, rect, size) { |
| | | //其中point为当前鼠标的位置,size中有两个属性:viewSize和contentSize,分别为外层div和tooltip提示框的大小 |
| | | let x = point[0];// |
| | | let y = point[1]; |
| | | let viewWidth = size.viewSize[0]; |
| | | let viewHeight = size.viewSize[1]; |
| | | let boxWidth = size.contentSize[0]; |
| | | let boxHeight = size.contentSize[1]; |
| | | let posX = 0;//x坐标位置 |
| | | let posY = 0;//y坐标位置 |
| | | const x = point[0]// |
| | | const y = point[1] |
| | | const viewWidth = size.viewSize[0] |
| | | const viewHeight = size.viewSize[1] |
| | | const boxWidth = size.contentSize[0] |
| | | const boxHeight = size.contentSize[1] |
| | | let posX = 0// x坐标位置 |
| | | let posY = 0// y坐标位置 |
| | | |
| | | if (x < boxWidth) {//左边放不开 |
| | | posX = 5; |
| | | posX = 5 |
| | | } else {//左边放的下 |
| | | posX = x - boxWidth; |
| | | posX = x - boxWidth |
| | | } |
| | | |
| | | if (y < boxHeight) {//上边放不开 |
| | | posY = 5; |
| | | posY = 5 |
| | | } else {//上边放得下 |
| | | posY = y - boxHeight; |
| | | posY = y - boxHeight |
| | | } |
| | | if (params && params.length > 20) { |
| | | posX = point[1], |
| | | posY = '-10%'; |
| | | posY = '-10%' |
| | | } |
| | | return [posX, posY]; |
| | | |
| | | return [posX, posY] |
| | | }, |
| | | axisPointer: { |
| | | type: 'cross', |
| | |
| | | |
| | | yAxis: { |
| | | axisTick: { |
| | | show: true, // 轴线刻度 |
| | | show: true // 轴线刻度 |
| | | }, |
| | | axisLine: { |
| | | show: true, //不显示坐标轴线 |
| | | show: true // 不显示坐标轴线 |
| | | }, |
| | | axisLabel: { |
| | | show: true, //不显示坐标轴上的文字 |
| | | show: true // 不显示坐标轴上的文字 |
| | | } |
| | | // axisLine: { |
| | | // lineStyle: { |
| | |
| | | legend: { |
| | | data: val.title, |
| | | tooltip: { |
| | | show: true, |
| | | show: true |
| | | }, |
| | | textStyle: { |
| | | fontSize: fontSize(0.15), |
| | | fontSize: fontSize(0.15) |
| | | }, |
| | | widht: 'auto', |
| | | height: 'auto', |
| | | top: fontSize(5.5), |
| | | top: fontSize(5.5) |
| | | }, |
| | | dataZoom: [ |
| | | { |
| | | type: 'inside', |
| | | start: 0, |
| | | end: 100, |
| | | end: 100 |
| | | }, |
| | | { |
| | | start: 0, |
| | | end: 20, |
| | | top: fontSize(4.8), |
| | | height: fontSize(0.5), |
| | | }, |
| | | height: fontSize(0.5) |
| | | } |
| | | ], |
| | | series: val.series, |
| | | series: val.series |
| | | }, |
| | | true |
| | | ) |
| | | window.onresize = this.chart.resize |
| | | }, |
| | | }, |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | |
| | | <template> |
| | | <div style="width: 100%; height: 100%"> |
| | | <div id="chartTableContent" style="width: 100%; height: 100%"> |
| | | <div class="topSelect"> |
| | | <!-- <el-cascader v-model="newMac" :options="options" clearable change-on-select :props="{ checkStrictly: true }" placeholder="选择设备" /> --> |
| | | <el-cascader v-model="newMac" :options="options" :props="props" collapse-tags clearable placeholder="选择设备" |
| | | style="width: 354px" /> |
| | | <el-cascader |
| | | v-model="newMac" |
| | | :options="options" |
| | | :props="props" |
| | | collapse-tags |
| | | clearable |
| | | placeholder="选择设备" |
| | | style="width: 354px" |
| | | /> |
| | | <!-- <div> --> |
| | | <el-select v-model="value" placeholder="选择因子" style="margin-left: 20px"> |
| | | <el-option v-for="(item, index) in newSensor" :key="index" :label="item.label" :value="item.value" /> |
| | |
| | | <el-radio-button label="自定义" /> |
| | | </el-radio-group> --> |
| | | <el-select v-model="select1" placeholder="请选择" style="margin-left: 20px; width: 200px"> |
| | | <el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> |
| | | </el-option> |
| | | <el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | <component :is="dataType" style="padding-left: 0; margin-left: 20px; width: 160px" |
| | | @sendPickerChild="showPickerChild" class="select11" /> |
| | | <component |
| | | :is="dataType" |
| | | style="padding-left: 0; margin-left: 20px; width: 160px" |
| | | class="select11" |
| | | @sendPickerChild="showPickerChild" |
| | | /> |
| | | <!--查询按钮--> |
| | | <el-button @click="selectData" class="btn1">查询</el-button> |
| | | <el-button class="btn1" @click="selectData">查询</el-button> |
| | | </div> |
| | | <div class="topTitle"> |
| | | <div style="position: absolute">{{ selectyz }}</div> |
| | | <!-- <div style="text-align: center;width: 100%;">{{ newData }}·{{ newMac?newMac[0]:'' }}·{{ newMac?newMac[newMac.length - 1][0]:'' }}·{{ value |sensorFilter }}·趋势图</div> --> |
| | | </div> |
| | | <LineChart :chart-data="lineChartData" style="height: 45rem" /> |
| | | <LineChart :chart-data="lineChartData" style="height: 40rem" /> |
| | | <div style="padding: 0px 10px;margin-bottom: 50px;"> |
| | | <el-table v-if="searchData.length>0" :data="tableData" border size="mini" style="width: 100%" max-height="250" tooltip-effect> |
| | | <el-table-column prop="rankingTitle" label="日期" width="150" align="center"> |
| | | <el-table-column |
| | | prop="rankingTitle" |
| | | label="高值" |
| | | align="center" |
| | | width="150" |
| | | /> |
| | | </el-table-column> |
| | | <template v-for="(th, thIndex) in thArr"> |
| | | <el-table-column :key="thIndex" align="center" :label="th.label" :prop="th.prop" /> |
| | | </template> |
| | | </el-table> |
| | | </div> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import CustomPicker1 from '@/components/Form/CustomPicker1' |
| | | import TimePicker1 from '@/components/Form/TimePicker1' |
| | | import json from '@/assets/json/sensor.json' |
| | | import _ from 'lodash' |
| | | |
| | | const lineChartData = { |
| | | newVisitis: { |
| | | expectedData: [100, 120, 161, 134, 105, 160, 165], |
| | | actualData: [120, 82, 91, 154, 162, 140, 145], |
| | | actualData: [120, 82, 91, 154, 162, 140, 145] |
| | | }, |
| | | messages: { |
| | | expectedData: [200, 192, 120, 144, 160, 130, 140], |
| | | actualData: [180, 160, 151, 106, 145, 150, 130], |
| | | actualData: [180, 160, 151, 106, 145, 150, 130] |
| | | }, |
| | | purchases: { |
| | | expectedData: [80, 100, 121, 104, 105, 90, 100], |
| | | actualData: [120, 90, 100, 138, 142, 130, 130], |
| | | actualData: [120, 90, 100, 138, 142, 130, 130] |
| | | }, |
| | | shoppings: { |
| | | expectedData: [130, 140, 141, 142, 145, 150, 160], |
| | | actualData: [120, 82, 91, 154, 162, 140, 130], |
| | | }, |
| | | actualData: [120, 82, 91, 154, 162, 140, 130] |
| | | } |
| | | } |
| | | export default { |
| | | // import 引入的组件需要注入到对象中才能使用 |
| | |
| | | CustomPicker, |
| | | CustomPicker1, |
| | | TimePicker1, |
| | | HourPicker1, |
| | | HourPicker1 |
| | | }, |
| | | filters: { |
| | | sensorFilter: function (value) { |
| | | if (!value) return '' |
| | | return json[value] |
| | | }, |
| | | } |
| | | }, |
| | | props: { |
| | | // defaultData: Array |
| | |
| | | newLineChartData: { |
| | | series: [], |
| | | xAxis: [], |
| | | title: '', |
| | | title: '' |
| | | }, |
| | | newData: '', |
| | | defaultData: [], |
| | |
| | | options1: [ |
| | | { |
| | | label: '五分钟报', |
| | | value: '五分钟报', |
| | | value: '五分钟报' |
| | | }, |
| | | { |
| | | label: '小时报', |
| | | value: '小时报', |
| | | value: '小时报' |
| | | }, |
| | | { |
| | | label: '日报', |
| | | value: '日报', |
| | | value: '日报' |
| | | }, |
| | | { |
| | | label: '月报', |
| | | value: '月报', |
| | | }, |
| | | value: '月报' |
| | | } |
| | | ], |
| | | searchData: [] |
| | | } |
| | | }, |
| | | // 计算属性 类似于data概念 |
| | | computed: {}, |
| | | computed: { |
| | | thArr() { |
| | | const data = [] |
| | | if (this.searchData.length > 0) { |
| | | this.searchData.forEach((item, index) => { |
| | | data.push({ |
| | | label: item.time, |
| | | name: item.time, |
| | | prop: 'souceData' + index |
| | | }) |
| | | }) |
| | | console.log(data) |
| | | } |
| | | return data |
| | | }, |
| | | tableData() { |
| | | const data = [] |
| | | const souceData = [] |
| | | const firstData = [] |
| | | const fobj = {} |
| | | const sobj = {} |
| | | if (this.searchData.length > 0) { |
| | | this.searchData.forEach((item, index) => { |
| | | fobj['souceData' + index] = this.sortFind(item.deviceData)[0].name |
| | | sobj['souceData' + index] = this.sortFind(item.deviceData)[1].name |
| | | }) |
| | | } |
| | | const a = [...firstData] |
| | | data.push({ ...fobj, rankingTitle: '第一高值' }, { ...sobj, rankingTitle: '第二高值' }) |
| | | console.log('firstData', fobj) |
| | | console.log('souceData', sobj) |
| | | console.log('datadatadata', data) |
| | | return data |
| | | } |
| | | }, |
| | | // 监控data中的数据变化 |
| | | watch: { |
| | | // 监听设备的数据更新 |
| | |
| | | ) { |
| | | this.selectyz = '(单位:ppm)' |
| | | } |
| | | }, |
| | | } |
| | | }, |
| | | // 生命周期 - 创建完成(可以访问当前 this 实例) |
| | | created() { |
| | |
| | | activated() { }, |
| | | // 方法集合 |
| | | methods: { |
| | | sortFind(data) { |
| | | let arr = [] |
| | | let a = '' |
| | | let b = '' |
| | | // const duplicateValue = _.orderBy(this.refrain(data), ['sensorValue'], ['desc']) // 重复值排序 |
| | | // console.log('duplicateValue', duplicateValue) |
| | | const originalValue = _.orderBy(data, ['sensorValue'], ['desc']) |
| | | const firstIndex = [] |
| | | const fiestDateList = [] |
| | | const secondeIndex = [] |
| | | const secondeDateList = [] |
| | | console.log('originalValue', originalValue) |
| | | if ((Number(originalValue[0].sensorValue) === Number(0))) { |
| | | return [{ name: '/' }, { name: '/' }] |
| | | } |
| | | originalValue.forEach((value, inx) => { |
| | | if ((Number(originalValue[0].sensorValue) === Number(value.sensorValue))) { |
| | | firstIndex.push(inx) |
| | | } |
| | | }) |
| | | |
| | | if (firstIndex.length > 1) { |
| | | firstIndex.forEach(item => { |
| | | a += (originalValue[item].name).replace(/\s+/g, '') + '(' + originalValue[item].sensorValue + ')' + ',' |
| | | }) |
| | | fiestDateList.push({ |
| | | name: a |
| | | }) |
| | | // 第二高值 |
| | | const secondInd = firstIndex[firstIndex.length - 1] |
| | | originalValue.forEach((value, inx) => { |
| | | if ((Number(originalValue[secondInd].sensorValue) === Number(value.sensorValue))) { |
| | | secondeIndex.push(inx) |
| | | } |
| | | }) |
| | | secondeIndex.forEach(item => { |
| | | b += (originalValue[item].name).replace(/\s+/g, '') + '(' + originalValue[item].sensorValue + ')' + ',' |
| | | }) |
| | | secondeDateList.push({ |
| | | name: b |
| | | }) |
| | | } else if (firstIndex.length <= 1) { |
| | | fiestDateList.push({ |
| | | name: (originalValue[0].name).replace(/\s+/g, '') + '(' + originalValue[0].sensorValue + ')' |
| | | }) |
| | | if (originalValue.length > 1) { |
| | | originalValue.forEach((value, inx) => { |
| | | if ((Number(originalValue[1].sensorValue) === Number(value.sensorValue))) { |
| | | secondeIndex.push(inx) |
| | | } |
| | | }) |
| | | secondeIndex.forEach(item => { |
| | | b += (originalValue[item].name).replace(/\s+/g, '') + '(' + originalValue[item].sensorValue + ')' + ',' |
| | | }) |
| | | secondeDateList.push({ |
| | | name: b |
| | | }) |
| | | } |
| | | } |
| | | console.log('fiestDateList', fiestDateList) |
| | | console.log('secondeDateList', secondeDateList) |
| | | arr = fiestDateList.concat(secondeDateList) |
| | | console.log('arr', arr) |
| | | return arr |
| | | // console.log('refrainrefrainrefrain', this.refrain(data)) |
| | | // const arr = [] |
| | | // const duplicates = data.filter(item => data.indexOf(item) !== data.lastIndexOf(item)) |
| | | // unUnit.forEach(item => { |
| | | // _.find(data, function(o) { return Number(item.sensorValue) === Number(o.sensorValue) }) |
| | | // arr.push() |
| | | // }) |
| | | }, |
| | | // 查询数据 |
| | | selectData() { |
| | | console.log(this.newData) |
| | | var newLineChartData = { |
| | | series: [], |
| | | xAxis: [], |
| | | title: [], |
| | | title: [] |
| | | } |
| | | this.newXData = [] |
| | | this.$request({ |
| | |
| | | sensorCode: this.value, |
| | | type: this.unit, |
| | | // times: data instanceof Array ? data : [data] |
| | | times: this.newData instanceof Array ? this.newData : [this.newData], |
| | | }, |
| | | times: this.newData instanceof Array ? this.newData : [this.newData] |
| | | } |
| | | }) |
| | | .then((res) => { |
| | | // console.log('获得时间对应因子数据') |
| | | const data = res.data |
| | | let lockLength = 0 |
| | | this.searchData = _.cloneDeep(res.data) |
| | | const data = _.cloneDeep(res.data) |
| | | console.log('this.se', this.searchData) |
| | | const lockLength = 0 |
| | | for (let i = 0; i < data.length; i++) { |
| | | for (let j = 0; j < data[i].deviceData.length; j++) { |
| | | if (res.data[0].deviceData.length === 1) { |
| | |
| | | type: 'line', |
| | | label: { |
| | | show: true, |
| | | position: 'top', |
| | | }, |
| | | position: 'top' |
| | | } |
| | | }) |
| | | } |
| | | } else { |
| | |
| | | name: '', |
| | | triggerLineEvent: true, |
| | | emphasis: { focus: 'series' }, |
| | | type: 'line', |
| | | type: 'line' |
| | | }) |
| | | } |
| | | newLineChartData.series[j].name = data[i].deviceData[j].name |
| | |
| | | url: '/monitorPoint/queryMonitorPoints', |
| | | method: 'get', |
| | | params: { |
| | | organizationId: this.$store.state.orgId, |
| | | }, |
| | | organizationId: this.$store.state.orgId |
| | | } |
| | | }) |
| | | .then((res) => { |
| | | // console.log('这是index页面左侧设备数据') |
| | |
| | | for (let i = 0; i < this.defaultData.length; i++) { |
| | | this.options.push({ |
| | | value: this.defaultData[i].name, |
| | | label: this.defaultData[i].name, |
| | | label: this.defaultData[i].name |
| | | }) |
| | | this.options[i].children = [] |
| | | for (let j = 0; j < this.defaultData[i].devices.length; j++) { |
| | | this.options[i].children.push({ |
| | | value: [ |
| | | this.defaultData[i].devices[j].name, |
| | | this.defaultData[i].devices[j].mac, |
| | | this.defaultData[i].devices[j].mac |
| | | ], |
| | | label: this.defaultData[i].devices[j].name, |
| | | label: this.defaultData[i].devices[j].name |
| | | }) |
| | | } |
| | | } |
| | |
| | | url: '/deviceInfo/getMacSensors', |
| | | method: 'post', |
| | | data: { |
| | | macs: this.newMac1, |
| | | }, |
| | | macs: this.newMac1 |
| | | } |
| | | }) |
| | | .then((result) => { |
| | | // console.log(result) |
| | |
| | | // 获得子组件时间选择器传递的数据 |
| | | showPickerChild(data) { |
| | | this.newData = data |
| | | }, |
| | | }, // 如果页面有keep-alive缓存功能,这个函数会触发 |
| | | } |
| | | } // 如果页面有keep-alive缓存功能,这个函数会触发 |
| | | } |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | #chartTableContent{ |
| | | overflow-y: scroll; |
| | | overflow-x: hidden; |
| | | } |
| | | .topSelect { |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | |
| | | /deep/.el-date-editor .el-range-separator { |
| | | width: 11%; |
| | | } |
| | | /*::v-deep 这里主要的作用就是用来强制修改element默认的样式*/ |
| | | ::v-deep .el-table thead.is-group th { |
| | | background: none; |
| | | padding: 0px; |
| | | } |
| | | |
| | | ::v-deep .el-table thead.is-group tr:first-of-type th:first-of-type { |
| | | border-bottom: none; /*中间的横线去掉*/ |
| | | } |
| | | |
| | | ::v-deep .el-table thead.is-group tr:first-of-type th:first-of-type div.cell { |
| | | text-align: right; /*上边文字靠右*/ |
| | | } |
| | | |
| | | ::v-deep .el-table thead.is-group tr:last-of-type th:first-of-type div.cell { |
| | | text-align: left; /*下边文字靠左*/ |
| | | } |
| | | /*核心代码*/ |
| | | ::v-deep .el-table thead.is-group tr:first-of-type th:first-of-type:before { |
| | | content: ""; |
| | | position: absolute; |
| | | width: 1px; |
| | | height: 100px; /*斜线的长度*/ |
| | | top: 0; |
| | | left: 0; |
| | | background-color: grey; |
| | | opacity: 0.2; |
| | | display: block; |
| | | transform: rotate(-43deg); /*调整斜线的角度*/ |
| | | transform: rotate(-70deg); /*调整斜线的角度*/ |
| | | -webkit-transform-origin: top; |
| | | transform-origin: top; |
| | | } |
| | | |
| | | ::v-deep .el-table thead.is-group tr:last-of-type th:first-of-type:before { |
| | | content: ""; |
| | | position: absolute; |
| | | width: 1px; |
| | | height: 100px; /*斜线的长度*/ |
| | | bottom: 0; |
| | | right: 0; |
| | | background-color: grey; |
| | | opacity: 0.2; |
| | | display: block; |
| | | transform: rotate(-45deg); /*调整斜线的角度*/ |
| | | transform: rotate(-70deg); /*调整斜线的角度*/ |
| | | -webkit-transform-origin: bottom; |
| | | transform-origin: bottom; |
| | | } |
| | | ::v-deep .el-table thead.is-group th { |
| | | height: 27.4px; |
| | | } |
| | | |
| | | </style> |
| | |
| | | // console.log(newVal) |
| | | // defaultData是站点名,包含设备 |
| | | const copyData = _.cloneDeep(this.defaultDataMiddle) |
| | | this.defaultData = copyData |
| | | this.openeds = [] |
| | | const arr = [] |
| | | let ke = 1 |