
element-ui、vue2
<template><div class="change_record"><div class="title-box"><span class="title">设备状态变更情况</span><div><span class="show-style">显示</span><el-radio-group v-model="showKey" @change="changeRadio" style="margin-right: 24px;"><el-radio label="sn">SN</el-radio><el-radio label="eid">EID</el-radio><el-radio label="iccid">ICCID</el-radio></el-radio-group><el-button plain class="down-excel" @click="exportExcel">{{$t('common.导出记录')}}</el-button></div></div><div class="change-box"><div class="change-content"><el-row class="change-item" v-for="(item, index) in tableData" :key="index"><div class="timeline" :id="'timeline_'+index">{{item.eid}}</div><div class="explain"><span class="huibiao" style="background-color: #DF001F;"></span><span>{{item.offline_format}}</span><span class="huibiao" style="background-color: #FFDD00;"></span><span>{{item.unstable_format}}</span><span class="huibiao" style="background-color: #AAE252;"></span><span>{{item.online_format}}</span><span class="change-count">变化:{{item.state_change_time}}次</span></div></el-row></div><WhiteSpace heightProps="20px" /><el-paginationclass="page"layout="prev, pager, next, sizes, jumper"@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-size="pageSize":page-sizes="[10, 20, 30, 40]":total="amount"></el-pagination><WhiteSpace heightProps="12px" /></div></div></template><script>import XLSX from "xlsx";import lodash from 'lodash';import moment from 'moment';import * as echarts from 'echarts';export default {components: {},data() {return {showKey: 'eid',currentPage: 1,pageSize: 10,tableData: [],types: [{name: '在线',value: 'online',color: '#73D500',}, {name: '不稳定',value: 'unstable',color: '#FFDD00',}, {name: '离线',value: 'offline',color: '#DF001F',}, {name: '未知',value: 'unknown',color: '#DF001F',}, {name: '中控电量低',value: 'noPower',color: '#FFDD00',}],option: {tooltip: {position: function(point, params, dom, rect, size) {if (params.value[7]) {return ['10%', '-240%'];} else {return ['10%', '10%'];}},formatter: function(params) {let str = `<p><span>${params.marker} ${params.name}</span><p>UCT ${params.value[4]} 至 ${params.value[5]}</p><span>时长:${params.value[6]}</span></p>`;return str;}},title: {text: '',left: 'start',// right: 'center',top: 'center',bottom: 'center',},grid: {left: 0,right: 0,},xAxis: {type: 'time',scale: true,// position: 'top',// type: 'time',// splitNumber: 10,// boundaryGap: ["0", "100%"],// splitLine: {// show: false// },// axisLine: {// show: true// }},yAxis: {data: null,type: 'category',// offset: 100,// axisLine: {// show: false// },// splitLine: {// show: true,// },},series: [{type: 'custom',itemStyle: {opacity: 0.8},encode: {x: [1, 2],y: 0},data: null,renderItem: function(params, api) {var categoryIndex = api.value(0);var start = api.coord([api.value(1), categoryIndex]);var end = api.coord([api.value(2), categoryIndex]);var height = api.size([0, 1])[1] * 0.3;var rectShape = echarts.graphic.clipRectByRect({x: start[0],y: start[1] - height / 2,width: end[0] - start[0],height: height}, {x: params.coordSys.x,y: params.coordSys.y,width: params.coordSys.width,height: params.coordSys.height});return rectShape && {type: 'rect',shape: rectShape,style: api.style()};}}]},};},props: {dataSource: {type: Array,default () {return []}},amount: {type: Number,default: 100,},controlPrams: {type: Object,default: () => {return {};},},},computed: {},watch: {dataSource(newval) {this.dataFormat(newval)},},filters: {timeformat(val) {if (!val) return '';return moment(val).local().format('YYYY.MM.DD HH:mm:ss');},},methods: {exportExcel() {function sheet2blob(sheet, sheetName) {sheetName = sheetName || 'sheet1';var workbook = {SheetNames: [sheetName],Sheets: {}};workbook.Sheets[sheetName] = sheet;var wopts = {bookType: 'xlsx',bookSST: false,type: 'binary'};var wbout = XLSX.write(workbook, wopts);var blob = new Blob([s2ab(wbout)], {type: "application/octet-stream"});function s2ab(s) {var buf = new ArrayBuffer(s.length);var view = new Uint8Array(buf);for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;return buf;}return blob;}function openDownloadDialog(url, saveName) {if (typeof url == 'object' && url instanceof Blob) {url = URL.createObjectURL(url);}var aLink = document.createElement('a');aLink.href = url;aLink.download = saveName || '';var event;if (window.MouseEvent) event = new MouseEvent('click');else {event = document.createEvent('MouseEvents');event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);}aLink.dispatchEvent(event);}const aoa = [];const sheetTitle = [this.showKey.toUpperCase(),'离线','不稳定','在线','变化','开始时间','结束时间',];aoa.push(sheetTitle);let selectTime = this.controlPrams.selectTime;let begin = 'UTC ' + moment(selectTime[0]).utc().format('YYYY.MM.DD HH:mm:ss');let end = 'UTC ' + moment(selectTime[1]).utc().format('YYYY.MM.DD HH:mm:ss');for (let i in this.tableData) {let item = []item.push(this.tableData[i][this.showKey]);item.push(this.tableData[i].offline_format);item.push(this.tableData[i].unstable_format);item.push(this.tableData[i].online_format);item.push(this.tableData[i].state_change_time);item.push(begin);item.push(end);aoa.push(item);}const sheet = XLSX.utils.aoa_to_sheet(aoa);sheet["!cols"] = [{wch: 26,}, {wch: 26,}, {wch: 26,}, {wch: 26,}, {wch: 9,}, {wch: 23,}, {wch: 23,}];openDownloadDialog(sheet2blob(sheet), '设备状态变更情况.xlsx');},handleSizeChange(val) {this.pageSize = val;this.$emit('record-change', {pageSize: this.pageSize,currentPage: this.currentPage,showKey: this.showKey,})},handleCurrentChange(val) {this.currentPage = val;this.$emit('record-change', {pageSize: this.pageSize,currentPage: this.currentPage,showKey: this.showKey,})},changeRadio(val) {this.showKey = val;this.$emit('record-change', {pageSize: this.pageSize,currentPage: this.currentPage,showKey: this.showKey,})},formatPercentageNew(num, total) {let rate = (num / total * 100).toFixed(2) + '%';return rate;},formatTime2DurationNew(count) {let time = '';let second = count % 60;let minute = parseInt(parseInt(count) / 60) % 60;time = second + "秒";if (minute >= 1) {time = minute + "分" + second + "秒";}let hour = parseInt(parseInt(count / 60) / 60) % 24;if (hour >= 1) {time = hour + "小时" + minute + "分" + second + "秒";}var day = parseInt(parseInt(parseInt(count / 60) / 60) / 24);if (day >= 1) {time = day + "天" + hour + "小时" + minute + "分" + second + "秒";}return time;},dataFormat(data) {if (data && data.length > 0) {let len = data.length;data.map((item, index) => {let {offline_duration = 0,online_duration = 0,unstable_duration = 0} = item;let total_duration = offline_duration + online_duration + unstable_duration;let offline_duration_format = this.formatTime2DurationNew(offline_duration);let online_duration_format = this.formatTime2DurationNew(online_duration);let unstable_duration_format = this.formatTime2DurationNew(unstable_duration);let offline_duration_rate = this.formatPercentageNew(offline_duration, total_duration);let online_duration_rate = this.formatPercentageNew(online_duration, total_duration);let unstable_duration_rate = this.formatPercentageNew(unstable_duration, total_duration);item.offline_format = `离线(${offline_duration_format},${offline_duration_rate})`;item.online_format = `在线(${online_duration_format},${online_duration_rate})`;item.unstable_format = `不稳定(${unstable_duration_format},${unstable_duration_rate})`;setTimeout(() => {let flag = (len - index) <= 3;this.initChart(item, index, flag);}, 500)})this.tableData = data;}},initChart(item, index, flag) {let state = item.state || [];let data = [];for (let i = 0; i < state.length; i++) {let tmp = state[i];let typeItem = lodash.find(this.types, {'value': tmp.state})let begin = moment(tmp.start_time).valueOf();let end = moment(tmp.end_time).valueOf();let diff = (end - begin) / 1000;let duration = this.formatTime2DurationNew(diff) || '0s';let begin_format = moment(tmp.start_time).utc().format('YYYY.MM.DD HH:mm:ss');let end_format = moment(tmp.end_time).utc().format('YYYY.MM.DD HH:mm:ss');data.push({name: tmp[this.showKey],value: [i, begin, end, tmp.state_duration, begin_format, end_format, duration, flag],itemStyle: {normal: {color: typeItem.color}}});}// 修改optionthis.option.series[0].data = data;this.option.yAxis.data = [item[this.showKey]];this.option.title.text = item[this.showKey];// 获取图表idlet chartDom = document.getElementById(`timeline_${index}`);chartDom.style.height = 26 + 'px';chartDom.style.width = '800px';// 初始化图表let myChart = echarts.init(chartDom);myChart.resize();myChart.clear();myChart.setOption(this.option);},},created() {},mounted() {}}</script><style lang="scss" scoped>.change_record {width: 100%;box-sizing: border-box;border-radius: 4px;box-shadow: 0px 8px 16px rgba(55, 70, 95, 0.070171);background-color: #FFFFFF;.title-box {padding: 0 36px;width: 100%;height: 66px;background-color: #FAFBFB;display: flex;align-items: center;justify-content: space-between;box-sizing: border-box;.title {font-weight: 500;font-size: 12px;color: #828D99;}.show-style {margin-right: 12px;font-weight: 600;font-size: 12px;color: #828D99;}.down-excel {padding: 6px 10px;font-weight: 400;font-size: 14px;color: #304156;}}.change-box {width: 100%;.change-content {width: 100%;overflow-x: scroll;// overflow-y: hidden;overflow-y: visible;border: 1px solid #F0F1F2;.change-item {display: flex;flex-direction: row;}.change-item:first-child {.timeline,.explain {border-top: 0px;}}.timeline {min-width: 800px;width: 800px;height: 26px;// background: green;border-top: 1px solid #F0F1F2;border-right: 1px solid #F0F1F2;box-sizing: border-box;}.explain {flex: 1;display: flex;flex-direction: row;align-items: center;font-weight: 400;font-size: 12px;color: #304156;white-space: nowrap;border-top: 1px solid #F0F1F2;box-sizing: border-box;.huibiao {margin: 0 4px 0 6px;width: 6px;height: 12px;}.change-count {margin: 0 12px 0 8px;}}}.page {text-align: center;}}}</style>

