image.png

    element-ui、vue2

    1. <template>
    2. <div class="change_record">
    3. <div class="title-box">
    4. <span class="title">设备状态变更情况</span>
    5. <div>
    6. <span class="show-style">显示</span>
    7. <el-radio-group v-model="showKey" @change="changeRadio" style="margin-right: 24px;">
    8. <el-radio label="sn">SN</el-radio>
    9. <el-radio label="eid">EID</el-radio>
    10. <el-radio label="iccid">ICCID</el-radio>
    11. </el-radio-group>
    12. <el-button plain class="down-excel" @click="exportExcel">{{$t('common.导出记录')}}</el-button>
    13. </div>
    14. </div>
    15. <div class="change-box">
    16. <div class="change-content">
    17. <el-row class="change-item" v-for="(item, index) in tableData" :key="index">
    18. <div class="timeline" :id="'timeline_'+index">{{item.eid}}</div>
    19. <div class="explain">
    20. <span class="huibiao" style="background-color: #DF001F;"></span>
    21. <span>{{item.offline_format}}</span>
    22. <span class="huibiao" style="background-color: #FFDD00;"></span>
    23. <span>{{item.unstable_format}}</span>
    24. <span class="huibiao" style="background-color: #AAE252;"></span>
    25. <span>{{item.online_format}}</span>
    26. <span class="change-count">变化:{{item.state_change_time}}次</span>
    27. </div>
    28. </el-row>
    29. </div>
    30. <WhiteSpace heightProps="20px" />
    31. <el-pagination
    32. class="page"
    33. layout="prev, pager, next, sizes, jumper"
    34. @size-change="handleSizeChange"
    35. @current-change="handleCurrentChange"
    36. :current-page="currentPage"
    37. :page-size="pageSize"
    38. :page-sizes="[10, 20, 30, 40]"
    39. :total="amount">
    40. </el-pagination>
    41. <WhiteSpace heightProps="12px" />
    42. </div>
    43. </div>
    44. </template>
    45. <script>
    46. import XLSX from "xlsx";
    47. import lodash from 'lodash';
    48. import moment from 'moment';
    49. import * as echarts from 'echarts';
    50. export default {
    51. components: {},
    52. data() {
    53. return {
    54. showKey: 'eid',
    55. currentPage: 1,
    56. pageSize: 10,
    57. tableData: [],
    58. types: [{
    59. name: '在线',
    60. value: 'online',
    61. color: '#73D500',
    62. }, {
    63. name: '不稳定',
    64. value: 'unstable',
    65. color: '#FFDD00',
    66. }, {
    67. name: '离线',
    68. value: 'offline',
    69. color: '#DF001F',
    70. }, {
    71. name: '未知',
    72. value: 'unknown',
    73. color: '#DF001F',
    74. }, {
    75. name: '中控电量低',
    76. value: 'noPower',
    77. color: '#FFDD00',
    78. }],
    79. option: {
    80. tooltip: {
    81. position: function(point, params, dom, rect, size) {
    82. if (params.value[7]) {
    83. return ['10%', '-240%'];
    84. } else {
    85. return ['10%', '10%'];
    86. }
    87. },
    88. formatter: function(params) {
    89. let str = `<p>
    90. <span>${params.marker} ${params.name}</span>
    91. <p>UCT ${params.value[4]} ${params.value[5]}</p>
    92. <span>时长:${params.value[6]}</span>
    93. </p>`;
    94. return str;
    95. }
    96. },
    97. title: {
    98. text: '',
    99. left: 'start',
    100. // right: 'center',
    101. top: 'center',
    102. bottom: 'center',
    103. },
    104. grid: {
    105. left: 0,
    106. right: 0,
    107. },
    108. xAxis: {
    109. type: 'time',
    110. scale: true,
    111. // position: 'top',
    112. // type: 'time',
    113. // splitNumber: 10,
    114. // boundaryGap: ["0", "100%"],
    115. // splitLine: {
    116. // show: false
    117. // },
    118. // axisLine: {
    119. // show: true
    120. // }
    121. },
    122. yAxis: {
    123. data: null,
    124. type: 'category',
    125. // offset: 100,
    126. // axisLine: {
    127. // show: false
    128. // },
    129. // splitLine: {
    130. // show: true,
    131. // },
    132. },
    133. series: [{
    134. type: 'custom',
    135. itemStyle: {
    136. opacity: 0.8
    137. },
    138. encode: {
    139. x: [1, 2],
    140. y: 0
    141. },
    142. data: null,
    143. renderItem: function(params, api) {
    144. var categoryIndex = api.value(0);
    145. var start = api.coord([api.value(1), categoryIndex]);
    146. var end = api.coord([api.value(2), categoryIndex]);
    147. var height = api.size([0, 1])[1] * 0.3;
    148. var rectShape = echarts.graphic.clipRectByRect({
    149. x: start[0],
    150. y: start[1] - height / 2,
    151. width: end[0] - start[0],
    152. height: height
    153. }, {
    154. x: params.coordSys.x,
    155. y: params.coordSys.y,
    156. width: params.coordSys.width,
    157. height: params.coordSys.height
    158. });
    159. return rectShape && {
    160. type: 'rect',
    161. shape: rectShape,
    162. style: api.style()
    163. };
    164. }
    165. }]
    166. },
    167. };
    168. },
    169. props: {
    170. dataSource: {
    171. type: Array,
    172. default () {
    173. return []
    174. }
    175. },
    176. amount: {
    177. type: Number,
    178. default: 100,
    179. },
    180. controlPrams: {
    181. type: Object,
    182. default: () => {
    183. return {};
    184. },
    185. },
    186. },
    187. computed: {},
    188. watch: {
    189. dataSource(newval) {
    190. this.dataFormat(newval)
    191. },
    192. },
    193. filters: {
    194. timeformat(val) {
    195. if (!val) return '';
    196. return moment(val).local().format('YYYY.MM.DD HH:mm:ss');
    197. },
    198. },
    199. methods: {
    200. exportExcel() {
    201. function sheet2blob(sheet, sheetName) {
    202. sheetName = sheetName || 'sheet1';
    203. var workbook = {
    204. SheetNames: [sheetName],
    205. Sheets: {}
    206. };
    207. workbook.Sheets[sheetName] = sheet;
    208. var wopts = {
    209. bookType: 'xlsx',
    210. bookSST: false,
    211. type: 'binary'
    212. };
    213. var wbout = XLSX.write(workbook, wopts);
    214. var blob = new Blob([s2ab(wbout)], {
    215. type: "application/octet-stream"
    216. });
    217. function s2ab(s) {
    218. var buf = new ArrayBuffer(s.length);
    219. var view = new Uint8Array(buf);
    220. for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
    221. return buf;
    222. }
    223. return blob;
    224. }
    225. function openDownloadDialog(url, saveName) {
    226. if (typeof url == 'object' && url instanceof Blob) {
    227. url = URL.createObjectURL(url);
    228. }
    229. var aLink = document.createElement('a');
    230. aLink.href = url;
    231. aLink.download = saveName || '';
    232. var event;
    233. if (window.MouseEvent) event = new MouseEvent('click');
    234. else {
    235. event = document.createEvent('MouseEvents');
    236. event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    237. }
    238. aLink.dispatchEvent(event);
    239. }
    240. const aoa = [];
    241. const sheetTitle = [
    242. this.showKey.toUpperCase(),
    243. '离线',
    244. '不稳定',
    245. '在线',
    246. '变化',
    247. '开始时间',
    248. '结束时间',
    249. ];
    250. aoa.push(sheetTitle);
    251. let selectTime = this.controlPrams.selectTime;
    252. let begin = 'UTC ' + moment(selectTime[0]).utc().format('YYYY.MM.DD HH:mm:ss');
    253. let end = 'UTC ' + moment(selectTime[1]).utc().format('YYYY.MM.DD HH:mm:ss');
    254. for (let i in this.tableData) {
    255. let item = []
    256. item.push(this.tableData[i][this.showKey]);
    257. item.push(this.tableData[i].offline_format);
    258. item.push(this.tableData[i].unstable_format);
    259. item.push(this.tableData[i].online_format);
    260. item.push(this.tableData[i].state_change_time);
    261. item.push(begin);
    262. item.push(end);
    263. aoa.push(item);
    264. }
    265. const sheet = XLSX.utils.aoa_to_sheet(aoa);
    266. sheet["!cols"] = [{
    267. wch: 26,
    268. }, {
    269. wch: 26,
    270. }, {
    271. wch: 26,
    272. }, {
    273. wch: 26,
    274. }, {
    275. wch: 9,
    276. }, {
    277. wch: 23,
    278. }, {
    279. wch: 23,
    280. }];
    281. openDownloadDialog(sheet2blob(sheet), '设备状态变更情况.xlsx');
    282. },
    283. handleSizeChange(val) {
    284. this.pageSize = val;
    285. this.$emit('record-change', {
    286. pageSize: this.pageSize,
    287. currentPage: this.currentPage,
    288. showKey: this.showKey,
    289. })
    290. },
    291. handleCurrentChange(val) {
    292. this.currentPage = val;
    293. this.$emit('record-change', {
    294. pageSize: this.pageSize,
    295. currentPage: this.currentPage,
    296. showKey: this.showKey,
    297. })
    298. },
    299. changeRadio(val) {
    300. this.showKey = val;
    301. this.$emit('record-change', {
    302. pageSize: this.pageSize,
    303. currentPage: this.currentPage,
    304. showKey: this.showKey,
    305. })
    306. },
    307. formatPercentageNew(num, total) {
    308. let rate = (num / total * 100).toFixed(2) + '%';
    309. return rate;
    310. },
    311. formatTime2DurationNew(count) {
    312. let time = '';
    313. let second = count % 60;
    314. let minute = parseInt(parseInt(count) / 60) % 60;
    315. time = second + "秒";
    316. if (minute >= 1) {
    317. time = minute + "分" + second + "秒";
    318. }
    319. let hour = parseInt(parseInt(count / 60) / 60) % 24;
    320. if (hour >= 1) {
    321. time = hour + "小时" + minute + "分" + second + "秒";
    322. }
    323. var day = parseInt(parseInt(parseInt(count / 60) / 60) / 24);
    324. if (day >= 1) {
    325. time = day + "天" + hour + "小时" + minute + "分" + second + "秒";
    326. }
    327. return time;
    328. },
    329. dataFormat(data) {
    330. if (data && data.length > 0) {
    331. let len = data.length;
    332. data.map((item, index) => {
    333. let {
    334. offline_duration = 0,
    335. online_duration = 0,
    336. unstable_duration = 0
    337. } = item;
    338. let total_duration = offline_duration + online_duration + unstable_duration;
    339. let offline_duration_format = this.formatTime2DurationNew(offline_duration);
    340. let online_duration_format = this.formatTime2DurationNew(online_duration);
    341. let unstable_duration_format = this.formatTime2DurationNew(unstable_duration);
    342. let offline_duration_rate = this.formatPercentageNew(offline_duration, total_duration);
    343. let online_duration_rate = this.formatPercentageNew(online_duration, total_duration);
    344. let unstable_duration_rate = this.formatPercentageNew(unstable_duration, total_duration);
    345. item.offline_format = `离线(${offline_duration_format},${offline_duration_rate})`;
    346. item.online_format = `在线(${online_duration_format},${online_duration_rate})`;
    347. item.unstable_format = `不稳定(${unstable_duration_format},${unstable_duration_rate})`;
    348. setTimeout(() => {
    349. let flag = (len - index) <= 3;
    350. this.initChart(item, index, flag);
    351. }, 500)
    352. })
    353. this.tableData = data;
    354. }
    355. },
    356. initChart(item, index, flag) {
    357. let state = item.state || [];
    358. let data = [];
    359. for (let i = 0; i < state.length; i++) {
    360. let tmp = state[i];
    361. let typeItem = lodash.find(this.types, {
    362. 'value': tmp.state
    363. })
    364. let begin = moment(tmp.start_time).valueOf();
    365. let end = moment(tmp.end_time).valueOf();
    366. let diff = (end - begin) / 1000;
    367. let duration = this.formatTime2DurationNew(diff) || '0s';
    368. let begin_format = moment(tmp.start_time).utc().format('YYYY.MM.DD HH:mm:ss');
    369. let end_format = moment(tmp.end_time).utc().format('YYYY.MM.DD HH:mm:ss');
    370. data.push({
    371. name: tmp[this.showKey],
    372. value: [i, begin, end, tmp.state_duration, begin_format, end_format, duration, flag],
    373. itemStyle: {
    374. normal: {
    375. color: typeItem.color
    376. }
    377. }
    378. });
    379. }
    380. // 修改option
    381. this.option.series[0].data = data;
    382. this.option.yAxis.data = [item[this.showKey]];
    383. this.option.title.text = item[this.showKey];
    384. // 获取图表id
    385. let chartDom = document.getElementById(`timeline_${index}`);
    386. chartDom.style.height = 26 + 'px';
    387. chartDom.style.width = '800px';
    388. // 初始化图表
    389. let myChart = echarts.init(chartDom);
    390. myChart.resize();
    391. myChart.clear();
    392. myChart.setOption(this.option);
    393. },
    394. },
    395. created() {},
    396. mounted() {}
    397. }
    398. </script>
    399. <style lang="scss" scoped>
    400. .change_record {
    401. width: 100%;
    402. box-sizing: border-box;
    403. border-radius: 4px;
    404. box-shadow: 0px 8px 16px rgba(55, 70, 95, 0.070171);
    405. background-color: #FFFFFF;
    406. .title-box {
    407. padding: 0 36px;
    408. width: 100%;
    409. height: 66px;
    410. background-color: #FAFBFB;
    411. display: flex;
    412. align-items: center;
    413. justify-content: space-between;
    414. box-sizing: border-box;
    415. .title {
    416. font-weight: 500;
    417. font-size: 12px;
    418. color: #828D99;
    419. }
    420. .show-style {
    421. margin-right: 12px;
    422. font-weight: 600;
    423. font-size: 12px;
    424. color: #828D99;
    425. }
    426. .down-excel {
    427. padding: 6px 10px;
    428. font-weight: 400;
    429. font-size: 14px;
    430. color: #304156;
    431. }
    432. }
    433. .change-box {
    434. width: 100%;
    435. .change-content {
    436. width: 100%;
    437. overflow-x: scroll;
    438. // overflow-y: hidden;
    439. overflow-y: visible;
    440. border: 1px solid #F0F1F2;
    441. .change-item {
    442. display: flex;
    443. flex-direction: row;
    444. }
    445. .change-item:first-child {
    446. .timeline,
    447. .explain {
    448. border-top: 0px;
    449. }
    450. }
    451. .timeline {
    452. min-width: 800px;
    453. width: 800px;
    454. height: 26px;
    455. // background: green;
    456. border-top: 1px solid #F0F1F2;
    457. border-right: 1px solid #F0F1F2;
    458. box-sizing: border-box;
    459. }
    460. .explain {
    461. flex: 1;
    462. display: flex;
    463. flex-direction: row;
    464. align-items: center;
    465. font-weight: 400;
    466. font-size: 12px;
    467. color: #304156;
    468. white-space: nowrap;
    469. border-top: 1px solid #F0F1F2;
    470. box-sizing: border-box;
    471. .huibiao {
    472. margin: 0 4px 0 6px;
    473. width: 6px;
    474. height: 12px;
    475. }
    476. .change-count {
    477. margin: 0 12px 0 8px;
    478. }
    479. }
    480. }
    481. .page {
    482. text-align: center;
    483. }
    484. }
    485. }
    486. </style>

    image.png