Commit 546380c8ad577105b84a4b118d5c716b4a495484

Authored by 徐烜
1 parent 01a31e3e

临港公交电子站牌项目

1、新建lggj/chart目录,将组件eBusStop-line-chart及相关文件移动到此目录中
2、新建lggj/list目录,创建组件eBusStop-line-chart-list及相关文件
front-end/h5/src/components/core/plugins/bsth/lggj/css/eBusStop-line-chart.css renamed to front-end/h5/src/components/core/plugins/bsth/lggj/chart/css/eBusStop-line-chart.css
... ... @@ -39,7 +39,7 @@ svg.eBusStop-line-chart path.station_link {
39 39  
40 40 svg.eBusStop-line-chart circle.station_circle {
41 41 fill: #5e96d2;
42   - r: 5.5;
  42 + /*r: 5.5;*/
43 43 stroke: rgb(253, 253, 253);
44 44 stroke-width: 3;
45 45 Pointer-events: none;
... ...
front-end/h5/src/components/core/plugins/bsth/lggj/eBusStop-line-chart.js renamed to front-end/h5/src/components/core/plugins/bsth/lggj/chart/eBusStop-line-chart.js
... ... @@ -4,10 +4,12 @@
4 4 import PropTypes from '@luban-h5/plugin-common-props'
5 5  
6 6 import Utils from 'core/plugins/bsth/bsth-utils'
7   -import EBusStopData from 'core/plugins/bsth/lggj/models/eBusStopData'
  7 +import { EBusStopData } from 'core/plugins/bsth/lggj/chart/models/eBusStopData'
8 8  
9 9 import './css/eBusStop-line-chart.css'
10 10  
  11 +import moment from 'moment'
  12 +
11 13 export default {
12 14 extra: {
13 15 defaultStyle: { // 默认属性
... ... @@ -68,6 +70,64 @@ export default {
68 70 eBusStopData: null // 电子站牌数据(EBusStopData类型)
69 71 }
70 72 },
  73 + computed: {
  74 + arriveTime1 () {
  75 + // TODO:要使用后台返回的系统时间
  76 + // TODO:添加报站功能
  77 + let _time = this.eBusStopData.arriveTime1
  78 + if (_time === '') {
  79 + return _time
  80 + }
  81 + try {
  82 + // 1、获取到达时间的hours,minutes
  83 + let _hours = parseInt(_time.split(':')[0])
  84 + let _minutes = parseInt(_time.split(':')[1])
  85 + // 2、使用hours,minutes创建一个到达时间
  86 + let _arriveMomentTime = moment().startOf('day').add(_hours, 'hours').add(_minutes, 'minutes')
  87 + // 3、计算到达时间和当前时间差值(分钟)返回
  88 + let _diffMinutes = _arriveMomentTime.diff(moment(), 'minutes')
  89 +
  90 + if (_diffMinutes === 1) {
  91 + return '车辆即将到站'
  92 + } else if (_diffMinutes === 0) {
  93 + return '车辆进站'
  94 + } else {
  95 + return _diffMinutes + '分钟'
  96 + }
  97 + } catch (err) {
  98 + console.log(` 转换到达时间1失败(格式必须为:HH:mm),状态:${err.status},错误:${err.statusText}`, 1)
  99 + return _time;
  100 + }
  101 + },
  102 + arriveTime2 () {
  103 + // TODO:要使用后台返回的系统时间
  104 + // TODO:添加报站功能
  105 + let _time = this.eBusStopData.arriveTime2
  106 + if (_time === '') {
  107 + return _time
  108 + }
  109 + try {
  110 + // 1、获取到达时间的hours,minutes
  111 + let _hours = parseInt(_time.split(':')[0])
  112 + let _minutes = parseInt(_time.split(':')[1])
  113 + // 2、使用hours,minutes创建一个到达时间
  114 + let _arriveMomentTime = moment().startOf('day').add(_hours, 'hours').add(_minutes, 'minutes')
  115 + // 3、计算到达时间和当前时间差值(分钟)返回
  116 + let _diffMinutes = _arriveMomentTime.diff(moment(), 'minutes')
  117 +
  118 + if (_diffMinutes === 1) {
  119 + return '车辆即将到站'
  120 + } else if (_diffMinutes === 0) {
  121 + return '车辆进站'
  122 + } else {
  123 + return _diffMinutes + '分钟'
  124 + }
  125 + } catch (err) {
  126 + console.log(` 转换到达时间1失败(格式必须为:HH:mm),状态:${err.status},错误:${err.statusText}`, 1)
  127 + return _time;
  128 + }
  129 + }
  130 + },
71 131 props: {
72 132 useMode: PropTypes.string({ // 自定义使用模式,alone:(单独使用),child:(子组件)
73 133 defaultValue: 'alone',
... ... @@ -98,7 +158,6 @@ export default {
98 158  
99 159 // 数据属性
100 160 _flag_1_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="数据属性" class="bsth-line-item-divider"></hr>) } }),
101   -
102 161 // 图外层css
103 162 _flag_2_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图外层css属性" class="bsth-line-item-divider"></hr>) } }),
104 163 margin_left: PropTypes.number({ label: '图左边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
... ... @@ -122,7 +181,7 @@ export default {
122 181 arrive_info_fix_text_top_padding: PropTypes.number({ label: '固定文字距离上边', defaultValue: 2, layout: { prefixCls: 'bsth-line' } }),
123 182 arrive_info_stop_text_font_size: PropTypes.number({ label: '开往站点名字体大小', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
124 183 arrive_info_stop_text_font_color: PropTypes.color({ label: '开往站点名字体颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
125   - arrive_info_text_font_size: PropTypes.number({ label: '到达信息字体大小', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  184 + arrive_info_text_font_size: PropTypes.number({ label: '到达信息字体大小', defaultValue: 18, layout: { prefixCls: 'bsth-line' } }),
126 185 arrive_info_text_font_color: PropTypes.color({ label: '到达信息字体颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
127 186 _flag_4_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层上部分矩形css属性" class="bsth-line-item-divider"></hr>) } }),
128 187 svg_background: PropTypes.color({ label: '线路图背景颜色', defaultValue: '#9EE0DF', layout: { prefixCls: 'bsth-line' } }),
... ... @@ -138,12 +197,18 @@ export default {
138 197 chart_top_padding: PropTypes.number({ label: '内部线路图距离上边', defaultValue: 13, layout: { prefixCls: 'bsth-line' } }),
139 198 chart_up_line_path_s_width: PropTypes.number({ label: '上部分线宽度', defaultValue: 5, layout: { prefixCls: 'bsth-line' } }),
140 199 chart_up_line_path_s_color: PropTypes.color({ label: '上部分线颜色', defaultValue: '#008000', layout: { prefixCls: 'bsth-line' } }),
141   - chart_up_line_circle_f_color: PropTypes.color({ label: '线圆圈填充色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  200 + chart_up_line_circle_f_color_current: PropTypes.color({ label: '线圆圈填充色-当前站点', defaultValue: '#CB0808', layout: { prefixCls: 'bsth-line' } }),
  201 + chart_up_line_circle_f_color_before: PropTypes.color({ label: '线圆圈填充色-前面站点', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  202 + chart_up_line_circle_f_color_after: PropTypes.color({ label: '线圆圈填充色-后面站点', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
142 203 chart_up_line_circle_r: PropTypes.number({ label: '线圆圈大小', defaultValue: 8, layout: { prefixCls: 'bsth-line' } }),
143 204 chart_station_text_top_padding: PropTypes.number({ label: '站点文字距离上边', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
144   - chart_station_text_font_size: PropTypes.number({ label: '站名字体大小', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  205 + chart_station_text_font_size_current: PropTypes.number({ label: '站名字体大小-当前站点', defaultValue: 25, layout: { prefixCls: 'bsth-line' } }),
  206 + chart_station_text_font_size_before: PropTypes.number({ label: '站名字体大小-前面站点', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  207 + chart_station_text_font_size_after: PropTypes.number({ label: '站名字体大小-后面站点', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
145 208 chart_station_text_length: PropTypes.number({ label: '站名长度', defaultValue: 100, layout: { prefixCls: 'bsth-line' } }),
146   - chart_up_station_text_font_f_color: PropTypes.color({ label: '站名颜色', defaultValue: '#4556b6', layout: { prefixCls: 'bsth-line' } }),
  209 + chart_up_station_text_font_f_color_current: PropTypes.color({ label: '站名颜色-当前站点', defaultValue: '#060D37', layout: { prefixCls: 'bsth-line' } }),
  210 + chart_up_station_text_font_f_color_before: PropTypes.color({ label: '站名颜色-前面站点', defaultValue: '#9398B4', layout: { prefixCls: 'bsth-line' } }),
  211 + chart_up_station_text_font_f_color_after: PropTypes.color({ label: '站名颜色-后面站点', defaultValue: '#4556b6', layout: { prefixCls: 'bsth-line' } }),
147 212 _flag_6_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层下部分线css属性" class="bsth-line-item-divider"></hr>) } }),
148 213 down_line_left_padding: PropTypes.number({ label: '线距离左边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
149 214 down_line_right_padding: PropTypes.number({ label: '线距离右边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
... ... @@ -263,11 +328,11 @@ export default {
263 328 </div>
264 329 <div style={arriveInfoStyle}>
265 330 <span style={arriveInfoFixTextStyle}>预计本次班车:</span>
266   - <span style={arriveInfoTextStyle}>{this.eBusStopData.arriveTime1}</span>
  331 + <span style={arriveInfoTextStyle}>{this.arriveTime1}</span>
267 332 </div>
268 333 <div style={arriveInfoStyle}>
269 334 <span style={arriveInfoFixTextStyle}>预计下次班车:</span>
270   - <span style={arriveInfoTextStyle}>{this.eBusStopData.arriveTime2}</span>
  335 + <span style={arriveInfoTextStyle}>{this.arriveTime2}</span>
271 336 </div>
272 337 </div>
273 338 </div>
... ... @@ -280,10 +345,10 @@ export default {
280 345 width={this.up_rect_width + 'px'}
281 346 height={this.up_rect_height + 'px'}
282 347 rx={this.up_rect_r + 'px'}
283   - style={{'stroke-width': '0px', 'fill': this.up_rect_b_color}}></rect>
  348 + style={{ 'stroke-width': '0px', 'fill': this.up_rect_b_color }}></rect>
284 349 </g>
285 350 <g class="arrow-wrap">
286   - <path d={downLinePathD} style={{'fill': this.down_line_s_color}}></path>
  351 + <path d={downLinePathD} style={{ 'fill': this.down_line_s_color }}></path>
287 352 </g>
288 353 </svg>
289 354 </div>
... ... @@ -369,13 +434,13 @@ export default {
369 434 line_chart_outer_div_width: function (val) {
370 435 let self = this
371 436 if (self.useMode === 'child') {
372   - self.line_width = val - self.margin_left - self.margin_right
  437 + self.component_width = val - self.margin_left - self.margin_right
373 438 }
374 439 },
375 440 line_chart_outer_div_height: function (val) {
376 441 let self = this
377 442 if (self.useMode === 'child') {
378   - self.line_height = val - self.margin_top - self.margin_bottom
  443 + self.component_height = val - self.margin_top - self.margin_bottom
379 444 }
380 445 },
381 446 eBusStopData_child: function (val) {
... ... @@ -422,19 +487,19 @@ export default {
422 487 // ----------- 图外层css 监控 ----------- //
423 488 margin_left () {
424 489 let self = this
425   - self.line_width = self.line_width - self.margin_left - self.margin_right
  490 + self.component_width = self.component_width - self.margin_left - self.margin_right
426 491 },
427 492 margin_right () {
428 493 let self = this
429   - self.line_width = self.line_width - self.margin_left - self.margin_right
  494 + self.component_width = self.component_width - self.margin_left - self.margin_right
430 495 },
431 496 margin_top () {
432 497 let self = this
433   - self.line_height = self.line_height - self.margin_top - self.margin_bottom
  498 + self.component_height = self.component_height - self.margin_top - self.margin_bottom
434 499 },
435 500 margin_bottom () {
436 501 let self = this
437   - self.line_height = self.line_height - self.margin_top - self.margin_bottom
  502 + self.component_height = self.component_height - self.margin_top - self.margin_bottom
438 503 },
439 504 border_size () {
440 505 this.text_info_width = this.component_width - this.border_size * 2
... ... @@ -477,22 +542,42 @@ export default {
477 542 svg.selectAll('g.item path.station_link:not(.down)')
478 543 .style('stroke', val)
479 544 },
480   - chart_up_line_circle_f_color: function (val) {
  545 + chart_up_line_circle_f_color_current: function (val) {
481 546 let svg = this.private_svg
482   - svg.selectAll('g.item circle.station_circle:not(.down')
  547 + svg.selectAll('g.item circle.station_circle.current')
  548 + .style('fill', val)
  549 + },
  550 + chart_up_line_circle_f_color_before: function (val) {
  551 + let svg = this.private_svg
  552 + svg.selectAll('g.item circle.station_circle.before')
  553 + .style('fill', val)
  554 + },
  555 + chart_up_line_circle_f_color_after: function (val) {
  556 + let svg = this.private_svg
  557 + svg.selectAll('g.item circle.station_circle.after')
483 558 .style('fill', val)
484 559 },
485 560 chart_up_line_circle_r: function (val) {
486 561 let svg = this.private_svg
487   - svg.selectAll('g.item circle.station_circle:not(.down')
  562 + svg.selectAll('g.item circle.station_circle')
488 563 .style('r', val)
489 564 },
490 565 chart_station_text_top_padding: function (val) {
491 566 this.refreshLineSvg()
492 567 },
493   - chart_station_text_font_size: function (val) {
  568 + chart_station_text_font_size_current: function (val) {
494 569 let svg = this.private_svg
495   - svg.selectAll('g.item text')
  570 + svg.selectAll('g.item text.station_text.up.current')
  571 + .style('font-size', val)
  572 + },
  573 + chart_station_text_font_size_before: function (val) {
  574 + let svg = this.private_svg
  575 + svg.selectAll('g.item text.station_text.up.before')
  576 + .style('font-size', val)
  577 + },
  578 + chart_station_text_font_size_after: function (val) {
  579 + let svg = this.private_svg
  580 + svg.selectAll('g.item text.station_text.up.after')
496 581 .style('font-size', val)
497 582 },
498 583 chart_station_text_length: function (val) {
... ... @@ -500,9 +585,19 @@ export default {
500 585 svg.selectAll('g.item text')
501 586 .attr('textLength', val)
502 587 },
503   - chart_up_station_text_font_f_color: function (val) {
  588 + chart_up_station_text_font_f_color_current: function (val) {
  589 + let svg = this.private_svg
  590 + svg.selectAll('g.item text.station_text.up.current')
  591 + .style('stroke', val)
  592 + },
  593 + chart_up_station_text_font_f_color_before: function (val) {
504 594 let svg = this.private_svg
505   - svg.selectAll('g.item text.station_text.up')
  595 + svg.selectAll('g.item text.station_text.up.before')
  596 + .style('stroke', val)
  597 + },
  598 + chart_up_station_text_font_f_color_after: function (val) {
  599 + let svg = this.private_svg
  600 + svg.selectAll('g.item text.station_text.up.after')
506 601 .style('stroke', val)
507 602 },
508 603 // ----------- _flag_6_属性
... ... @@ -662,7 +757,24 @@ export default {
662 757 return d.type !== 1 ? this : null
663 758 }).append('circle')
664 759 .classed('station_circle', true)
665   - .style('fill', self.chart_up_line_circle_f_color)
  760 + .classed('current', function (d, i) {
  761 + return self.eBusStopData.currentStopStationIndex === i
  762 + })
  763 + .classed('before', function (d, i) {
  764 + return i < self.eBusStopData.currentStopStationIndex
  765 + })
  766 + .classed('after', function (d, i) {
  767 + return i > self.eBusStopData.currentStopStationIndex
  768 + })
  769 + .style('fill', function (d, i) {
  770 + if (i === self.eBusStopData.currentStopStationIndex) {
  771 + return self.chart_up_line_circle_f_color_current
  772 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  773 + return self.chart_up_line_circle_f_color_before
  774 + } else {
  775 + return self.chart_up_line_circle_f_color_after
  776 + }
  777 + })
666 778 .style('stroke-width', 0) // 暂时外部的stroke设置为0,不参与属性设置
667 779 .attr('r', self.chart_up_line_circle_r) // css也设置了,但是有些游览器不支持(如 android5.1的内置游览器),所以直接定义成属性
668 780 .attr('cx', function (d, i) {
... ... @@ -686,8 +798,33 @@ export default {
686 798 itemsEnter.append('text')
687 799 .classed('station_text', true)
688 800 .classed('up', true)
689   - .style('font-size', self.chart_station_text_font_size + 'px')
690   - .style('stroke', self.chart_up_station_text_font_f_color)
  801 + .classed('current', function (d, i) {
  802 + return self.eBusStopData.currentStopStationIndex === i
  803 + })
  804 + .classed('before', function (d, i) {
  805 + return i < self.eBusStopData.currentStopStationIndex
  806 + })
  807 + .classed('after', function (d, i) {
  808 + return i > self.eBusStopData.currentStopStationIndex
  809 + })
  810 + .style('font-size', function (d, i) {
  811 + if (i === self.eBusStopData.currentStopStationIndex) {
  812 + return self.chart_station_text_font_size_current + 'px'
  813 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  814 + return self.chart_station_text_font_size_before + 'px'
  815 + } else {
  816 + return self.chart_station_text_font_size_after + 'px'
  817 + }
  818 + })
  819 + .style('stroke', function (d, i) {
  820 + if (i === self.eBusStopData.currentStopStationIndex) {
  821 + return self.chart_up_station_text_font_f_color_current
  822 + } else if (i < self.eBusStopData.currentStopStationIndex) {
  823 + return self.chart_up_station_text_font_f_color_before
  824 + } else {
  825 + return self.chart_up_station_text_font_f_color_after
  826 + }
  827 + })
691 828 .attr('textLength', self.chart_station_text_length)
692 829 .text(function (d) {
693 830 if (!d.name) {
... ...
front-end/h5/src/components/core/plugins/bsth/lggj/models/eBusStopData.js renamed to front-end/h5/src/components/core/plugins/bsth/lggj/chart/models/eBusStopData.js
... ... @@ -58,6 +58,19 @@ class EBusStopData {
58 58 }
59 59  
60 60 /**
  61 + * 设置到达时间
  62 + * @param times 到达时间数组
  63 + */
  64 + set arriveTimes (times) {
  65 + this._arriveTimes.splice(0, this._arriveTimes.length)
  66 + if (times && times.length) {
  67 + times.map(time => {
  68 + this._arriveTimes.push(time)
  69 + })
  70 + }
  71 + }
  72 +
  73 + /**
61 74 * 获取线路名称。
62 75 * @return {*}
63 76 */
... ... @@ -147,12 +160,21 @@ class EBusStopData {
147 160 let s6 = new StationData('站点6', '6')
148 161 let stationDataList = [s1, s2, s3, s4, s5, s6]
149 162 // 2、路由信息
150   - let routeData = new RouteData(2, stationDataList)
  163 + let routeData = new RouteData(2, stationDataList)
151 164 // 3、电子站牌信息
152   - let eBusStopData = new EBusStopData('线路1', '1', routeData, ['10:00', '10:20'])
  165 + return new EBusStopData('线路1', '1', routeData, ['23:58', '23:59'])
  166 + }
153 167  
154   - return eBusStopData
  168 + /**
  169 + * 产生空测试数据。
  170 + */
  171 + static generateEmptyTestData () {
  172 + return new EBusStopData('', '', new RouteData(0, []), [])
155 173 }
156 174 }
157 175  
158   -export default EBusStopData
  176 +export {
  177 + StationData,
  178 + RouteData,
  179 + EBusStopData
  180 +}
... ...
front-end/h5/src/components/core/plugins/bsth/lggj/list/css/eBusStop-line-chart-list.css 0 → 100644
  1 +/*
  2 + 内部使用的是border-box
  3 + 注意:
  4 + 1、这个设置很重要,因为内部计算width是减去两侧border的
  5 + 2、在编辑器模式下,外层的.ant-layout会给内层所有元素设置border-box,此时你不设置无所谓
  6 + 3、但是在打包预览模式下,是没有外层.ant-layout定义的,此时如果组件内部不定义,则会使用content-box,会和内部计算宽度产生偏差
  7 +*/
  8 +.eBusStop-line-chart-list-outer-div, .eBusStop-line-chart-list-outer-div * {
  9 + box-sizing: border-box;
  10 +}
  11 +
  12 +/**
  13 + 这里使用float布局,当多个线路模拟图排列的时候
  14 + 1、如果最外层div使用position: relative或不指定position,
  15 + 最外层的div位置会有偏差,滚动列表是会造成距离偏差
  16 + 2、如果使用position:absolute,需要指定top,可以算出的,但是麻烦
  17 + 3、直接使用float:left,不会有问题,因为宽度是死的,高度是活的,排列时没有偏差
  18 + */
  19 +.eBusStop-line-chart-list-outer-div .eBusStop-line-chart-outer-div {
  20 + float: left;
  21 +}
... ...
front-end/h5/src/components/core/plugins/bsth/lggj/list/eBusStop-line-chart-list-scrollPage.js 0 → 100644
  1 +/**
  2 + * 自定义线路模拟图组件列表滚动Page
  3 + * 注意:此组件不单独使用,只用在 eBusStop-line-chart-list 组件内部)
  4 + */
  5 +
  6 +import { jsonp } from 'vue-jsonp'
  7 +import { ScrollPageInnerData } from 'core/plugins/bsth/lggj/list/models/eBusStop-line-chart-list-scrollPage-innerData'
  8 +
  9 +export default {
  10 + props: {
  11 + // ---------------- 父组件传递的属性 ---------------- //
  12 + // 编辑模式
  13 + editorMode: { type: String, required: true },
  14 + // 每页大小
  15 + page_size: { type: Number, required: true },
  16 + // 列表宽度
  17 + list_width: { type: Number, required: true },
  18 + // 列表高度
  19 + list_height: { type: Number, required: true },
  20 + // 滚动时间间隔(秒)
  21 + scroll_seconds: { type: Number, required: true },
  22 + // 滚动速度(像素/秒)
  23 + scroll_speed: { type: Number, required: true },
  24 +
  25 + // 获取远端数据url
  26 + remote_data_url: { type: String, required: true },
  27 + // 获取远端数据url参数:站牌设备id
  28 + remote_data_url_param_device_id: { type: String, required: true },
  29 + // 获取远端数据间隔(秒)
  30 + remote_data_refresh_seconds: { type: Number, required: true }
  31 + },
  32 + computed: {
  33 + remoteUrl () {
  34 + return this.remote_data_url + '?deviceId=' + this.remote_data_url_param_device_id
  35 + }
  36 + },
  37 +
  38 + data () {
  39 + return {
  40 + // --------------- lazy加载slot --------------- //
  41 + lazySlot: true,
  42 +
  43 + // --------------- 滚动翻页数据对象 --------------//
  44 + scrollPageInnerData: null,
  45 + initLoading: true,
  46 + initLoadingText: '',
  47 +
  48 + // ---------------- 内部的定时timer --------------- //
  49 + scrollTimer: { // 滚动间隔timer
  50 + timer: undefined,
  51 + count: 0
  52 + },
  53 + remoteDataTimer: { // 远程数据刷新间隔timer
  54 + timer: undefined,
  55 + count: 0
  56 + }
  57 + }
  58 + },
  59 + mounted () {
  60 + // 1、初始化数据
  61 + // 1.1、edit模式下,使用测试数据
  62 + if (this.editorMode === 'edit') {
  63 + this.initLoading = true
  64 + this.initLoadingText = '初始化数据...'
  65 + this.scrollPageInnerData = ScrollPageInnerData.generateDataListByTest(
  66 + this.page_size, this.list_width, this.list_height)
  67 + // 发送bindData事件,父组件绑定该事件
  68 + this.$emit('bindData', this.scrollPageInnerData.scrollDataItemList)
  69 + this.initLoading = false
  70 + this.lazySlot = false
  71 + }
  72 + // 1.2、preview模式下,使用远程数据
  73 + if (this.editorMode === 'preview') {
  74 + this.initDataByRemoteApi()
  75 + }
  76 + },
  77 + destroyed () {
  78 + // 重置滚动间隔timer
  79 + let scrollTimer = this.scrollTimer.timer
  80 + if (scrollTimer) {
  81 + try {
  82 + clearTimeout(scrollTimer)
  83 + } catch (err) {}
  84 + }
  85 + this.scrollTimer.timer = undefined
  86 +
  87 + // 重置远程数据刷新间隔timer
  88 + let remoteDataTimer = this.remoteDataTimer.timer
  89 + if (remoteDataTimer) {
  90 + try {
  91 + clearTimeout(remoteDataTimer)
  92 + } catch (err) {}
  93 + }
  94 + this.remoteDataTimer.timer = undefined
  95 +
  96 + // 重置滚动翻页数据对象
  97 + if (this.scrollPageInnerData) {
  98 + this.scrollPageInnerData.resetData()
  99 + }
  100 + },
  101 + watch: {
  102 + 'scrollTimer.count' () {
  103 + let timer = this.scrollTimer.timer
  104 + if (timer) {
  105 + try {
  106 + clearTimeout(timer)
  107 + } catch (err) {}
  108 + this.scrollTimer.timer = undefined
  109 + }
  110 + let self = this
  111 + this.scrollTimer.timer = setTimeout(function () {
  112 + self.startScroll()
  113 + // self.scrollTimer.count++ // 滚动完成再触发,this.scrollListInnerData.scrollUp触发
  114 + }, this.scroll_seconds * 1000)
  115 + },
  116 + 'remoteDataTimer.count' () {
  117 + let timer = this.remoteDataTimer.timer
  118 + if (timer) {
  119 + try {
  120 + clearTimeout(timer)
  121 + } catch (err) {}
  122 + }
  123 + let self = this
  124 + this.remoteDataTimer.timer = setTimeout(function () {
  125 + self.refreshDataByRemoteApi()
  126 + // self.gpsTimer.count++ // refreshGpsDataOfApi触发
  127 + }, this.remote_data_refresh_seconds * 1000)
  128 + },
  129 + // -------------------- 监控父组件传递的属性 --------------- //
  130 + page_size (val) {
  131 + // 只在edit模式下监控,preview模式下不监控
  132 + if (this.editorMode === 'edit') { // 使用测试数据
  133 + this.scrollPageInnerData.pageSize = val
  134 + }
  135 + },
  136 + list_width (val) {
  137 + if (this.editorMode === 'edit') {
  138 + this.scrollPageInnerData.width = val
  139 + } else {
  140 + // TODO:
  141 + }
  142 + },
  143 + list_height (val) {
  144 + if (this.editorMode === 'edit') {
  145 + this.scrollPageInnerData.height = val
  146 + } else {
  147 + // TODO:
  148 + }
  149 + }
  150 + },
  151 + render () {
  152 + // TODO:暂时是没有内容显示的,只处理内部数据,后面再根据不同的错误显示内容
  153 + return (
  154 + <a-spin tip={this.initLoadingText} spinning={this.initLoading} size="large">
  155 + {
  156 + !this.lazySlot ? this.$slots.default : ''
  157 + }
  158 + </a-spin>
  159 + )
  160 + },
  161 + methods: {
  162 + startScroll () {
  163 + this.scrollPageInnerData.scrollUp(this)
  164 + },
  165 + initDataByRemoteApi () { // 使用后台api初始化数据
  166 + this.initLoading = true
  167 + this.initLoadingText = '初始化数据...'
  168 + jsonp(this.remoteUrl).then(remoteDataList => {
  169 + if (!remoteDataList || !remoteDataList.length) {
  170 + this.initLoadingText = `远端数据为空,等待${this.remote_data_refresh_seconds}秒后重新获取,请稍后...`
  171 + this.remoteDataTimer.count++
  172 + } else {
  173 + this.scrollPageInnerData = ScrollPageInnerData.generateDataListByRemoteData(
  174 + this.page_size, this.list_width, this.list_height, remoteDataList)
  175 + // 发送bindData事件,父组件绑定该事件
  176 + this.$emit('bindData', this.scrollPageInnerData.scrollDataItemList)
  177 + this.initLoading = false
  178 + this.lazySlot = false
  179 + // 启动滚动分页,后台数据刷新
  180 + this.scrollTimer.count++
  181 + this.remoteDataTimer.count++
  182 + }
  183 + }).catch(err => {
  184 + console.log(err)
  185 + this.$message.error(`获取远端数据失败,状态:${err.status},错误:${err.statusText}`, 1)
  186 + this.initLoadingText = `获取远端数据失败,等待${this.remote_data_refresh_seconds}秒后重新获取,请稍后...`
  187 + this.remoteDataTimer.count++
  188 + })
  189 + },
  190 + refreshDataByRemoteApi () { // 使用后台api刷新数据
  191 + console.log('refreshDataByRemoteApi')
  192 + // this.scrollPageInnerData.scrollDataItemList[0]._eBusStopData.arriveTimes = ['12:08']
  193 + // length===0说明初始化失败,或者后台无数据,重新刷新
  194 + if (!this.scrollPageInnerData || !this.scrollPageInnerData.scrollDataItemList.length) {
  195 + this.initDataByRemoteApi()
  196 + } else {
  197 + jsonp(this.remoteUrl).then(remoteDataList => {
  198 + this.scrollPageInnerData.refreshDataWithRemoteData(remoteDataList)
  199 + }).catch(err => {
  200 + console.log(err)
  201 + this.$message.error(` 获取数据失败,状态:${err.status},错误:${err.statusText}`, 1)
  202 + })
  203 + this.remoteDataTimer.count++
  204 + }
  205 + }
  206 + }
  207 +}
... ...
front-end/h5/src/components/core/plugins/bsth/lggj/list/eBusStop-line-chart-list.js 0 → 100644
  1 +/**
  2 + * 自定义线路模拟图组件列表(内部使用 eBusStop-line-chart 组件)
  3 + */
  4 +
  5 +import PropTypes from '@luban-h5/plugin-common-props'
  6 +
  7 +import scrollPage from 'core/plugins/bsth/lggj/list/eBusStop-line-chart-list-scrollPage'
  8 +
  9 +import './css/eBusStop-line-chart-list.css'
  10 +
  11 +export default {
  12 + extra: {
  13 + defaultStyle: { // 默认属性
  14 + top: 0,
  15 + left: 0,
  16 + width: 700,
  17 + height: 800
  18 + }
  19 + },
  20 + name: 'lggj-eBusStop-line-chart-list',
  21 + data () {
  22 + // eslint-disable-next-line
  23 + this.private_jQuery = jQuery.noConflict() // jquery引用
  24 + return {
  25 + /**
  26 + * 监控外层元素的宽度高度变化
  27 + * 1、由于编辑器缩放,自定义组件无法监控,所以需要定义一个定时器监控最外层元素的大小变化
  28 + * 2、建议所有自定义组件,最外层都定义一个div包在自定义组件最外层,不要关联任何自定义的属性,样式对应编辑器的通用样式
  29 + */
  30 + watchWidthHeightTimer: {
  31 + timer: undefined,
  32 + count: 0,
  33 + millisecond: 1000
  34 + },
  35 + list_width: 350, // 列表组件宽度
  36 + list_height: 300, // 列表组件高度
  37 + line_chart_outer_div_width: 0, // 线路图外层div宽度
  38 + line_chart_outer_div_height: 0, // 线路图外层div高度
  39 + internalDataSet: [], // 内部数据(ScrollPageInnerDataItem类型数组,由数据组件生成)
  40 + scrollTop: 0 // 控制垂直滚动 top
  41 + }
  42 + },
  43 + props: {
  44 + editorMode: PropTypes.string({ // 编辑模式会由编辑器自动注入(值:edit, preview)
  45 + defaultValue: 'preview',
  46 + label: '模式',
  47 + visible: false
  48 + }),
  49 + // --------------- 数据属性 -------------- //
  50 + _flag_1_: PropTypes.string({ label: '', component: null, extra (h) { return (<hr data-label='数据属性' class='bsth-line-item-divider'/>) } }),
  51 + page_size: PropTypes.number({ label: '每页显示线路图数量', defaultValue: 3, layout: { prefixCls: 'bsth-line' } }),
  52 + scroll_seconds: PropTypes.number({ label: '滚动时间间隔(秒)', defaultValue: 3, layout: { prefixCls: 'bsth-line' } }),
  53 + scroll_speed: PropTypes.number({ label: '滚动速度(像素/秒)', defaultValue: 1000, layout: { prefixCls: 'bsth-line' } }),
  54 + remote_data_refresh_seconds: PropTypes.number({ label: '数据刷新间隔(秒)', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  55 + remote_data_url: PropTypes.string({ label: '远端数据url', component: 'a-textarea', defaultValue: 'http://27.115.69.123:19102/General_Interface/getArriveVO', layout: { prefixCls: 'bsth-line' } }),
  56 + device_id: PropTypes.string({ label: '站牌设备Id', defaultValue: 'L55C0001', layout: { prefixCls: 'bsth-line' } }),
  57 + // --------------- 外层css属性 --------------- //
  58 + _flag_2_: PropTypes.string({ label: '', component: null, extra (h) { return (<hr data-label='外层css属性' class='bsth-line-item-divider'/>) } }),
  59 + margin_left: PropTypes.number({ label: '图左边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  60 + margin_right: PropTypes.number({ label: '图右边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  61 + margin_top: PropTypes.number({ label: '图上边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  62 + margin_bottom: PropTypes.number({ label: '图底部margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  63 + border_size: PropTypes.number({ label: '图边框宽度', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  64 + background_color: PropTypes.color({ label: '背景颜色', defaultValue: '#9EE0DF', layout: { prefixCls: 'bsth-line' } }),
  65 + // --------------- 内部线路模拟图外层css属性 --------------- //
  66 + _flag_3_: PropTypes.string({ label: '', component: null, extra (h) { return (<hr data-label='内部线路模拟图外层css属性' class='bsth-line-item-divider'></hr>) } }),
  67 + line_chart_margin_left: PropTypes.number({ label: '图左边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  68 + line_chart_margin_right: PropTypes.number({ label: '图右边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  69 + line_chart_margin_top: PropTypes.number({ label: '图上边margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  70 + line_chart_margin_bottom: PropTypes.number({ label: '图底部margin', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  71 + line_chart_border_size: PropTypes.number({ label: '图边框宽度', defaultValue: 0, layout: { prefixCls: 'bsth-line' } }),
  72 + line_chart_background_color: PropTypes.color({ label: '背景颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  73 + // 图内层css
  74 + _flag_4_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层线路到达信息css属性" class="bsth-line-item-divider"></hr>) } }),
  75 + text_info_background: PropTypes.color({ label: '信息背景颜色', defaultValue: '#238A94', layout: { prefixCls: 'bsth-line' } }),
  76 + line_info_height: PropTypes.number({ label: '线路信息高度', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  77 + line_info_name_font_size: PropTypes.number({ label: '线路名称字体大小', defaultValue: 22, layout: { prefixCls: 'bsth-line' } }),
  78 + line_info_name_font_color: PropTypes.color({ label: '线路名称字体颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  79 + line_info_name_left_padding: PropTypes.number({ label: '线路名称距离左边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  80 + line_info_name_top_padding: PropTypes.number({ label: '线路名称距离上边', defaultValue: 2, layout: { prefixCls: 'bsth-line' } }),
  81 + arrive_info_height: PropTypes.number({ label: '到达信息高度', defaultValue: 35, layout: { prefixCls: 'bsth-line' } }),
  82 + arrive_info_fix_text_font_size: PropTypes.number({ label: '固定文字字体大小', defaultValue: 18, layout: { prefixCls: 'bsth-line' } }),
  83 + arrive_info_fix_text_font_color: PropTypes.color({ label: '固定文字字体颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  84 + arrive_info_fix_text_left_padding: PropTypes.number({ label: '固定文字距离左边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  85 + arrive_info_fix_text_top_padding: PropTypes.number({ label: '固定文字距离上边', defaultValue: 2, layout: { prefixCls: 'bsth-line' } }),
  86 + arrive_info_stop_text_font_size: PropTypes.number({ label: '开往站点名字体大小', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  87 + arrive_info_stop_text_font_color: PropTypes.color({ label: '开往站点名字体颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  88 + arrive_info_text_font_size: PropTypes.number({ label: '到达信息字体大小', defaultValue: 18, layout: { prefixCls: 'bsth-line' } }),
  89 + arrive_info_text_font_color: PropTypes.color({ label: '到达信息字体颜色', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  90 + _flag_5_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层上部分矩形css属性" class="bsth-line-item-divider"></hr>) } }),
  91 + svg_background: PropTypes.color({ label: '线路图背景颜色', defaultValue: '#9EE0DF', layout: { prefixCls: 'bsth-line' } }),
  92 + up_rect_left_padding: PropTypes.number({ label: '矩形距离左边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  93 + up_rect_right_padding: PropTypes.number({ label: '矩形距离右边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  94 + up_rect_top_padding: PropTypes.number({ label: '矩形距离上边', defaultValue: 3, layout: { prefixCls: 'bsth-line' } }),
  95 + up_rect_height: PropTypes.number({ label: '矩形高度', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  96 + up_rect_r: PropTypes.number({ label: '矩形圆边大小', defaultValue: 10, layout: { prefixCls: 'bsth-line' } }),
  97 + up_rect_b_color: PropTypes.color({ label: '矩形背景颜色', defaultValue: '#9FA067', layout: { prefixCls: 'bsth-line' } }),
  98 + _flag_6_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层线路图css属性" class="bsth-line-item-divider"></hr>) } }),
  99 + chart_left_padding: PropTypes.number({ label: '内部线路图距离左边', defaultValue: 50, layout: { prefixCls: 'bsth-line' } }),
  100 + chart_right_padding: PropTypes.number({ label: '内部线路图距离右边', defaultValue: 50, layout: { prefixCls: 'bsth-line' } }),
  101 + chart_top_padding: PropTypes.number({ label: '内部线路图距离上边', defaultValue: 13, layout: { prefixCls: 'bsth-line' } }),
  102 + chart_up_line_path_s_width: PropTypes.number({ label: '上部分线宽度', defaultValue: 7, layout: { prefixCls: 'bsth-line' } }),
  103 + chart_up_line_path_s_color: PropTypes.color({ label: '上部分线颜色', defaultValue: '#008000', layout: { prefixCls: 'bsth-line' } }),
  104 + chart_up_line_circle_f_color_current: PropTypes.color({ label: '线圆圈填充色-当前站点', defaultValue: '#CB0808', layout: { prefixCls: 'bsth-line' } }),
  105 + chart_up_line_circle_f_color_before: PropTypes.color({ label: '线圆圈填充色-前面站点', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  106 + chart_up_line_circle_f_color_after: PropTypes.color({ label: '线圆圈填充色-后面站点', defaultValue: '#FFFFFF', layout: { prefixCls: 'bsth-line' } }),
  107 + chart_up_line_circle_r: PropTypes.number({ label: '线圆圈大小', defaultValue: 8, layout: { prefixCls: 'bsth-line' } }),
  108 + chart_station_text_top_padding: PropTypes.number({ label: '站点文字距离上边', defaultValue: 30, layout: { prefixCls: 'bsth-line' } }),
  109 + chart_station_text_font_size_current: PropTypes.number({ label: '站名字体大小-当前站点', defaultValue: 25, layout: { prefixCls: 'bsth-line' } }),
  110 + chart_station_text_font_size_before: PropTypes.number({ label: '站名字体大小-前面站点', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  111 + chart_station_text_font_size_after: PropTypes.number({ label: '站名字体大小-后面站点', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  112 + chart_station_text_length: PropTypes.number({ label: '站名长度', defaultValue: 130, layout: { prefixCls: 'bsth-line' } }),
  113 + chart_up_station_text_font_f_color_current: PropTypes.color({ label: '站名颜色-当前站点', defaultValue: '#060D37', layout: { prefixCls: 'bsth-line' } }),
  114 + chart_up_station_text_font_f_color_before: PropTypes.color({ label: '站名颜色-前面站点', defaultValue: '#9398B4', layout: { prefixCls: 'bsth-line' } }),
  115 + chart_up_station_text_font_f_color_after: PropTypes.color({ label: '站名颜色-后面站点', defaultValue: '#4556b6', layout: { prefixCls: 'bsth-line' } }),
  116 + _flag_7_: PropTypes.string({ label: '', component: null, extra: function (h) { return (<hr data-label="图内层下部分线css属性" class="bsth-line-item-divider"></hr>) } }),
  117 + down_line_left_padding: PropTypes.number({ label: '线距离左边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  118 + down_line_right_padding: PropTypes.number({ label: '线距离右边', defaultValue: 20, layout: { prefixCls: 'bsth-line' } }),
  119 + down_line_bottom_padding: PropTypes.number({ label: '线距离下边', defaultValue: 6, layout: { prefixCls: 'bsth-line' } }),
  120 + down_line_s_width: PropTypes.number({ label: '线宽度', defaultValue: 5, layout: { prefixCls: 'bsth-line' } }),
  121 + down_line_s_color: PropTypes.color({ label: '线颜色', defaultValue: '#277461', layout: { prefixCls: 'bsth-line' } }),
  122 + down_line_arrow_width: PropTypes.number({ label: '箭头宽度', defaultValue: 55, layout: { prefixCls: 'bsth-line' } }),
  123 + down_line_arrow_height: PropTypes.number({ label: '箭头高度', defaultValue: 15, layout: { prefixCls: 'bsth-line' } })
  124 + },
  125 + render () {
  126 + /* 最外层div对应编辑器的通用样式 */
  127 + return (
  128 + <div class="eBusStop-line-chart-list-outer-div">
  129 + {
  130 + this.renderScrollPage()
  131 + }
  132 + </div>
  133 + )
  134 + },
  135 + mounted () {
  136 + // 使用外部元素的框架定义图的长宽
  137 + let $jQuery = this.private_jQuery
  138 + this.list_width = $jQuery(this.$el).width() - this.margin_left - this.margin_right
  139 + this.list_height = $jQuery(this.$el).height() - this.margin_top - this.margin_bottom
  140 + // 开启外部元素长宽监控计数
  141 + /**
  142 + * 开启外部元素长宽监控逻辑
  143 + * 1、必须在编辑模式下启效果,否则无效
  144 + */
  145 + if (this.editorMode === 'edit') {
  146 + this.watchWidthHeightTimer.count++
  147 + }
  148 + },
  149 + destroyed () {
  150 + // 消耗 watchWidthHeightTimer 定时器
  151 + let timer1 = this.watchWidthHeightTimer.timer
  152 + if (timer1) {
  153 + try {
  154 + clearTimeout(timer1)
  155 + } catch (e) {}
  156 + this.watchWidthHeightTimer.timer = undefined
  157 + }
  158 + },
  159 + watch: {
  160 + 'watchWidthHeightTimer.count' () { // 长宽定时器监控
  161 + let timer = this.watchWidthHeightTimer.timer
  162 + if (timer) {
  163 + clearTimeout(timer)
  164 + this.watchWidthHeightTimer.timer = null
  165 + }
  166 +
  167 + let self = this
  168 + let $jQuery = this.private_jQuery
  169 + self.watchWidthHeightTimer.timer = setTimeout(function () {
  170 + // 处理逻辑
  171 + let width = $jQuery(self.$el).width()
  172 + let height = $jQuery(self.$el).height()
  173 +
  174 + if (width !== self.list_width) {
  175 + self.list_width = width - self.margin_left - self.margin_right
  176 + }
  177 + if (height !== self.list_height) {
  178 + self.list_height = height - self.margin_top - self.margin_bottom
  179 + }
  180 +
  181 + self.watchWidthHeightTimer.count++
  182 + }, self.watchWidthHeightTimer.millisecond)
  183 + },
  184 + // ----------------- 数据属性 ---------------- //
  185 + page_size () {
  186 + this.line_chart_outer_div_height = Math.floor(this.list_height / this.page_size)
  187 + },
  188 + // ----------------- 本身宽高 监控 ---------------- //
  189 + list_width () {
  190 + this.line_chart_outer_div_width = this.list_width - this.border_size * 2
  191 + },
  192 + list_height () {
  193 + this.line_chart_outer_div_height = Math.floor((this.list_height - this.border_size * 2) / this.page_size)
  194 + },
  195 + // ----------------- 外层css属性 监控 ----------------- //
  196 + margin_left () {
  197 + this.list_width = this.list_width - this.margin_left - this.margin_right
  198 + },
  199 + margin_right () {
  200 + this.list_width = this.list_width - this.margin_left - this.margin_right
  201 + },
  202 + margin_top () {
  203 + this.list_height = this.list_height - this.margin_top - this.margin_bottom
  204 + },
  205 + margin_bottom () {
  206 + this.list_height = this.list_height - this.margin_top - this.margin_bottom
  207 + },
  208 + border_size () {
  209 + this.line_chart_outer_div_width = this.list_width - this.border_size * 2
  210 + this.line_chart_outer_div_height = Math.floor((this.list_height - this.border_size * 2) / this.page_size)
  211 + }
  212 + },
  213 + methods: {
  214 + /**
  215 + * scrollPage组件的scrollTop事件处理函数。
  216 + * @param val 视口距离内部page的距离
  217 + */
  218 + onScrollTop (val) {
  219 + // 注意:默认向上滚动,scrollPage组件内部的view视口是向下移动的,top是大于等于0的
  220 + // 但是,使用scrollPage的组件外部view视口div是固定的,只能移动内部的div,所以top要变成负值
  221 + if (val === 0) {
  222 + this.scrollTop = 0
  223 + } else {
  224 + this.scrollTop = -val
  225 + }
  226 + },
  227 + /**
  228 + * scrollPage组件的bindData事件处理函数。
  229 + * @param dataSet
  230 + */
  231 + onBindData (dataSet) {
  232 + // 初始化的时候绑定一次数据,之后所有数据的变化都在ScrollPage内部变化
  233 + this.internalDataSet = dataSet
  234 + },
  235 +
  236 + /**
  237 + * 绘制scrollPage组件(内部组件,只能在本组件中使用,index.js中未注册)。
  238 + * @return {*}
  239 + */
  240 + renderScrollPage () {
  241 + const innerDivStyle = {
  242 + 'width': this.list_width + 'px',
  243 + 'height': this.list_height + 'px',
  244 + 'border': this.border_size + 'px solid black',
  245 + 'margin-left': this.margin_left + 'px',
  246 + 'margin-right': this.margin_right + 'px',
  247 + 'margin-top': this.margin_top + 'px',
  248 + 'margin-bottom': this.margin_bottom + 'px',
  249 + 'background': this.background_color,
  250 + 'position': 'relative',
  251 + 'overflow': 'hidden' // 隐藏超出的模拟图
  252 + }
  253 +
  254 + // 包含所有的线路模拟图,滚动时设置top值,总高度等于所有图高度和
  255 + const wrapperDivStyle = {
  256 + 'top': this.scrollTop + 'px',
  257 + 'position': 'absolute',
  258 + 'width': this.list_width + 'px',
  259 + 'height': this.line_chart_outer_div_height * this.internalDataSet.length + 'px'
  260 + }
  261 +
  262 + return (
  263 + <scrollPage
  264 + editorMode={this.editorMode}
  265 + page_size={this.page_size}
  266 + list_width={this.list_width}
  267 + list_height={this.list_height}
  268 + scroll_seconds={this.scroll_seconds}
  269 + scroll_speed={this.scroll_speed}
  270 + remote_data_url={this.remote_data_url}
  271 + remote_data_url_param_device_id={this.device_id}
  272 + remote_data_refresh_seconds={this.remote_data_refresh_seconds}
  273 + onBindData={this.onBindData}
  274 + onScrollTop={this.onScrollTop}>
  275 + <div style={innerDivStyle}>
  276 + <div style={wrapperDivStyle}>
  277 + {
  278 + this.internalDataSet.map(dataItem => (
  279 + this.renderLineChart(dataItem._eBusStopData)
  280 + ))
  281 + }
  282 + </div>
  283 + </div>
  284 + </scrollPage>
  285 + )
  286 + },
  287 + /**
  288 + * 绘制eBusStop-line-chart组件(index.js中已经注册过,不需要import)。
  289 + * @param eBusStopData EBusStopData类型
  290 + * @return {*}
  291 + */
  292 + renderLineChart (eBusStopData) {
  293 + return (
  294 + <eBusStop-line-chart
  295 + useMode='child'
  296 + editorMode={this.editorMode}
  297 + line_chart_outer_div_width={this.line_chart_outer_div_width}
  298 + line_chart_outer_div_height={this.line_chart_outer_div_height}
  299 + eBusStopData_child={eBusStopData}
  300 + // 内部线路模拟图外层css属性
  301 + margin_left={this.line_chart_margin_left}
  302 + margin_right={this.line_chart_margin_right}
  303 + margin_top={this.line_chart_margin_top}
  304 + margin_bottom={this.line_chart_margin_bottom}
  305 + border_size={this.line_chart_border_size}
  306 + background_color={this.line_chart_background_color}
  307 + // 内部线路模拟图内层css属性
  308 + text_info_background={this.text_info_background}
  309 + line_info_height={this.line_info_height}
  310 + line_info_name_font_size={this.line_info_name_font_size}
  311 + line_info_name_font_color={this.line_info_name_font_color}
  312 + line_info_name_left_padding={this.line_info_name_left_padding}
  313 + line_info_name_top_padding={this.line_info_name_top_padding}
  314 + arrive_info_height={this.arrive_info_height}
  315 + arrive_info_fix_text_font_size={this.arrive_info_fix_text_font_size}
  316 + arrive_info_fix_text_font_color={this.arrive_info_fix_text_font_color}
  317 + arrive_info_fix_text_left_padding={this.arrive_info_fix_text_left_padding}
  318 + arrive_info_fix_text_top_padding={this.arrive_info_fix_text_top_padding}
  319 + arrive_info_stop_text_font_size={this.arrive_info_stop_text_font_size}
  320 + arrive_info_stop_text_font_color={this.arrive_info_stop_text_font_color}
  321 + arrive_info_text_font_size={this.arrive_info_text_font_size}
  322 + arrive_info_text_font_color={this.arrive_info_text_font_color}
  323 + svg_background={this.svg_background}
  324 + up_rect_left_padding={this.up_rect_left_padding}
  325 + up_rect_right_padding={this.up_rect_right_padding}
  326 + up_rect_top_padding={this.up_rect_top_padding}
  327 + up_rect_height={this.up_rect_height}
  328 + up_rect_r={this.up_rect_r}
  329 + up_rect_b_color={this.up_rect_b_color}
  330 + chart_left_padding={this.chart_left_padding}
  331 + chart_right_padding={this.chart_right_padding}
  332 + chart_top_padding={this.chart_top_padding}
  333 + chart_up_line_path_s_width={this.chart_up_line_path_s_width}
  334 + chart_up_line_path_s_color={this.chart_up_line_path_s_color}
  335 + chart_up_line_circle_f_color_current={this.chart_up_line_circle_f_color_current}
  336 + chart_up_line_circle_f_color_before={this.chart_up_line_circle_f_color_before}
  337 + chart_up_line_circle_f_color_after={this.chart_up_line_circle_f_color_after}
  338 + chart_up_line_circle_r={this.chart_up_line_circle_r}
  339 + chart_station_text_top_padding={this.chart_station_text_top_padding}
  340 + chart_station_text_font_size_current={this.chart_station_text_font_size_current}
  341 + chart_station_text_font_size_before={this.chart_station_text_font_size_before}
  342 + chart_station_text_font_size_after={this.chart_station_text_font_size_after}
  343 + chart_station_text_length={this.chart_station_text_length}
  344 + chart_up_station_text_font_f_color_current={this.chart_up_station_text_font_f_color_current}
  345 + chart_up_station_text_font_f_color_before={this.chart_up_station_text_font_f_color_before}
  346 + chart_up_station_text_font_f_color_after={this.chart_up_station_text_font_f_color_after}
  347 + down_line_left_padding={this.down_line_left_padding}
  348 + down_line_right_padding={this.down_line_right_padding}
  349 + down_line_bottom_padding={this.down_line_bottom_padding}
  350 + down_line_s_width={this.down_line_s_width}
  351 + down_line_s_color={this.down_line_s_color}
  352 + down_line_arrow_width={this.down_line_arrow_width}
  353 + down_line_arrow_height={this.down_line_arrow_height}
  354 + />
  355 + )
  356 + }
  357 + }
  358 +}
... ...
front-end/h5/src/components/core/plugins/bsth/lggj/list/models/eBusStop-line-chart-list-scrollPage-innerData.js 0 → 100644
  1 +/**
  2 + * eBusStop-line-chart-list-scrollPage.js 内部使用数据对象
  3 + */
  4 +
  5 +import Utils from 'core/plugins/bsth/bsth-utils'
  6 +import { StationData, RouteData, EBusStopData } from 'core/plugins/bsth/lggj/chart/models/eBusStopData'
  7 +
  8 +class EBusStopLineChartListScrollPageInnerDataItem {
  9 + /**
  10 + * 构造函数。
  11 + * @param width int 对应eBusStop-line-chart组件宽度
  12 + * @param height int 对应eBusStop-line-chart组件高度
  13 + * @param cssTop int 对应eBusStop-line-chart组件距离顶部css top值
  14 + * @param itemIndex int 每页中的item下标(从0开始)
  15 + * @param pageIndex int 第几页下标(从0开始)
  16 + * @param eBusStopData EBusStopData 对应eBusStop-line-chart组件使用的数据对象
  17 + */
  18 + constructor (width = 0, height = 0, cssTop, itemIndex, pageIndex, eBusStopData) {
  19 + // 数据对象
  20 + this._eBusStopData = eBusStopData
  21 +
  22 + // ------------- 滚动列表用的数据 ------------ //
  23 + this._width = width
  24 + this._height = height
  25 + this._cssTop = cssTop
  26 + this._itemIndex = itemIndex
  27 + this._pageIndex = pageIndex
  28 + }
  29 +
  30 + get width () {
  31 + return this._width
  32 + }
  33 + get height () {
  34 + return this._height
  35 + }
  36 +
  37 + /**
  38 + * 使用类本身对象创建。
  39 + * @param dataItem EBusStopLineChartListScrollPageInnerDataItem
  40 + * @return EBusStopLineChartListScrollPageInnerDataItem
  41 + */
  42 + static createByDataItem (dataItem) {
  43 + return new EBusStopLineChartListScrollPageInnerDataItem(
  44 + 0, 0,
  45 + dataItem._cssTop,
  46 + dataItem._itemIndex,
  47 + dataItem._pageIndex,
  48 + dataItem._eBusStopData
  49 + )
  50 + }
  51 +
  52 + // TODO:
  53 +}
  54 +
  55 +class EBusStopLineChartListScrollPageInnerData {
  56 + /**
  57 + * 构造函数。
  58 + * @param pageSize 每页大小
  59 + * @param width 列表宽度
  60 + * @param height 列表高度
  61 + */
  62 + constructor (pageSize, width, height) {
  63 + this._pageSize = pageSize
  64 + this._width = width
  65 + this._height = height
  66 +
  67 + // --------------- 内部数据对象 ---------------- //
  68 + // EBusStopLineChartListScrollPageInnerDataItem 类型数组
  69 + this._innerDataItemList = []
  70 + this._pageCount = 0 // 一共多少页
  71 +
  72 + // --------------- 内部滚动数据对象 --------------- //
  73 + // 滚动用的 EBusStopLineChartListScrollPageInnerDataItem 类型数组(根据不同的滚动策略会和_innerDataItemList不一致)
  74 + this._scrollDataItemList = []
  75 + this._currentScrollIndex = 0 // 当前滚动项index
  76 + this._nextScrollIndex = 1 // 下一个滚动项index
  77 + this._scrollAnimateTimer = { // 滚动动画效果timer
  78 + timer: undefined,
  79 + count: 0,
  80 + millisecond: 1
  81 + }
  82 + }
  83 +
  84 + // ---------------- get/set方法 -------------- //
  85 + set pageSize (val) { // 设置每页大小
  86 + this._pageSize = val
  87 + this._pageCount = Math.ceil(this._innerDataItemList.length / this._pageSize)
  88 + // 重新计算_scrollDataItemList
  89 + _private_refreshScrollData.call(this)
  90 + }
  91 +
  92 + get scrollDataItemList () { // 返回滚动数据集
  93 + return this._scrollDataItemList
  94 + }
  95 +
  96 + set width (val) {
  97 + this._width = val
  98 + // 刷新滚动数据中 宽,高,top
  99 + _private_refreshScrollDataSizeProperty.call(this)
  100 + }
  101 +
  102 + set height (val) {
  103 + this._height = val
  104 + // 刷新滚动数据中 宽,高,top
  105 + _private_refreshScrollDataSizeProperty.call(this)
  106 + }
  107 +
  108 + // --------------------- 分页移动方法 --------------------- //
  109 + /**
  110 + * eBusStop-line-chart-list-scrollPage组件联动,向上滚动翻页
  111 + * 主要分页逻辑:每次向上移动一个chart,第一个chart接到最后一个chart组成一个环滚动翻
  112 + * @param scrollListComponent eBusStop-line-chart-list-scrollPage组件
  113 + */
  114 + scrollUp (scrollListComponent) {
  115 + if (this._scrollDataItemList.length <= this._pageSize) { // 总数据小于页大小,不滚动
  116 + return
  117 + }
  118 +
  119 + if (this._scrollAnimateTimer.timer) {
  120 + try {
  121 + clearInterval(this._scrollAnimateTimer.timer)
  122 + } catch (err) {
  123 + }
  124 + this._scrollAnimateTimer.timer = undefined
  125 + }
  126 +
  127 + // 往上滚动,相当于视口view向下移动
  128 + let viewTopFrom = this._scrollDataItemList[this._currentScrollIndex].top
  129 + let viewTopTo = this._scrollDataItemList[this._nextScrollIndex].top
  130 + let speed = scrollListComponent.scroll_speed // 每秒移动像素数
  131 + let step = speed / 1000 // 每毫秒移动像素数
  132 + // let step = (topTo - topFrom) / 20 // 每毫秒移动距离差的5分之一
  133 + let self = this
  134 + self._scrollAnimateTimer.timer = setInterval(function () {
  135 + self._scrollAnimateTimer.count++
  136 + let currentViewTop = viewTopFrom + self._scrollAnimateTimer.count * step
  137 + // console.log(currentViewTop)
  138 + if (currentViewTop > viewTopTo || (viewTopTo - currentViewTop) < step) {
  139 + scrollListComponent.$emit('scrollTop', viewTopTo)
  140 + self._scrollAnimateTimer.count = 0
  141 +
  142 + // console.log(self._pageCount)
  143 + // console.log(self._scrollDataItemList[self._nextScrollIndex].pageIndex)
  144 + if (self._scrollDataItemList[self._nextScrollIndex].pageIndex === self._pageCount) {
  145 + scrollListComponent.$emit('scrollTop', self._scrollDataItemList[0].top)
  146 + self._currentScrollIndex = 0
  147 + self._nextScrollIndex = 1
  148 + } else {
  149 + self._currentScrollIndex = self._nextScrollIndex
  150 + self._nextScrollIndex++
  151 + }
  152 +
  153 + if (self._scrollAnimateTimer.timer) {
  154 + try {
  155 + clearInterval(self._scrollAnimateTimer.timer)
  156 + } catch (err) {
  157 + }
  158 + self._scrollAnimateTimer.timer = null
  159 + }
  160 +
  161 + scrollListComponent.scrollTimer.count++
  162 +
  163 + } else {
  164 + scrollListComponent.$emit('scrollTop', currentViewTop)
  165 + }
  166 +
  167 + }, 1)
  168 + }
  169 +
  170 + // ----------------------- 数据方法 --------------------- //
  171 + /**
  172 + * 重置内部数据
  173 + */
  174 + resetData () {
  175 + // ------------ 重置内部数据对象 ------------ //
  176 + this._innerDataItemList.splice(0, this._innerDataItemList.length) // 直接删除数据内部数据,而不是 = []
  177 + this._pageCount = 0
  178 +
  179 + // ------------ 重置内部滚动数据对象 ---------- //
  180 + this._scrollDataItemList.splice(0, this._scrollDataItemList.length)
  181 + this._currentScrollIndex = 0
  182 + this._nextScrollIndex = 1
  183 + if (this._scrollAnimateTimer.timer) {
  184 + try {
  185 + clearInterval(this._scrollAnimateTimer.timer)
  186 + } catch (err) {
  187 + }
  188 + }
  189 + this._scrollAnimateTimer.timer = undefined
  190 + this._scrollAnimateTimer.count = 0
  191 + }
  192 +
  193 + /**
  194 + * 使用远程数据刷新内部数据。
  195 + * @param remoteDataList Object
  196 + */
  197 + refreshDataWithRemoteData (remoteDataList) {
  198 + // 远程数据格式参考 http://27.115.69.123:19102/General_Interface/getArriveVO?deviceId=L55C0001
  199 + if (!remoteDataList || !remoteDataList.length) {
  200 + return
  201 + }
  202 +
  203 + // 1、按照线路名字_线路编码分组数据
  204 + let dataGroupByLineNameCode = Utils.listGroupBy(remoteDataList, function (d) {
  205 + return d.lineName + '_' + d.lineCode
  206 + })
  207 + // 2、处理数据,循环计算每条线路的数据 TODO:
  208 + for (let internalData of this._innerDataItemList) {
  209 + let key = internalData._eBusStopData.lineName + '_' + internalData._eBusStopData.lineCode
  210 + if (dataGroupByLineNameCode[key]) {
  211 + // 构造到达时间数组
  212 + let arriveTimes = []
  213 + let info = dataGroupByLineNameCode[key][0]
  214 + if (info['arrive'] && info['arrive'].length) {
  215 + info['arrive'].map(arrive => {
  216 + arriveTimes.push(arrive.timeFormat || '')
  217 + })
  218 + }
  219 + // 设置arriveTimes
  220 + console.log(arriveTimes)
  221 + internalData._eBusStopData.arriveTimes = arriveTimes
  222 + }
  223 + }
  224 +
  225 + }
  226 +
  227 + // --------------------------- static构建方法 ------------------------- //
  228 + /**
  229 + * 使用远程数据生成对象。
  230 + * @param pageSize 每页大小
  231 + * @param width 列表宽度
  232 + * @param height 列表高度
  233 + * @param remoteDataList Object
  234 + * @return EBusStopLineChartListScrollPageInnerData
  235 + */
  236 + static generateDataListByRemoteData (pageSize, width, height, remoteDataList) {
  237 + let rtnData = new EBusStopLineChartListScrollPageInnerData(
  238 + pageSize, width, height
  239 + )
  240 +
  241 + // 1、重置内部数据
  242 + rtnData.resetData()
  243 + // 1-1、如果远端数据为空,直接返回
  244 + if (!remoteDataList || !remoteDataList.length) {
  245 + return rtnData
  246 + }
  247 +
  248 + // 2、计算内部数据对象
  249 + rtnData._innerDataItemList.splice(0, rtnData._innerDataItemList.length)
  250 +
  251 + // 2-1、使用远端数据构造内部数据
  252 + // 远程数据格式参考 http://27.115.69.123:19102/General_Interface/getArriveVO?deviceId=L55C0001
  253 + let eBusStopDataList = []
  254 + remoteDataList.map(info => {
  255 + let lineName = info.lineName || ''
  256 + let lineCode = info.lineCode || ''
  257 + let startTime = info.startTime || ''
  258 + let endTime = info.endTime || ''
  259 + let arriveTimes = []
  260 + if (info['arrive'] && info['arrive'].length) {
  261 + info['arrive'].map(arrive => {
  262 + arriveTimes.push(arrive.timeFormat || '')
  263 + })
  264 + }
  265 + let stationDataList = []
  266 + if (info['lineRoute'] && info['lineRoute'].length) {
  267 + info['lineRoute'].map(station => {
  268 + let stationData = new StationData(
  269 + station.stationName || '',
  270 + station.stationCode || '',
  271 + )
  272 + stationDataList.push(stationData)
  273 + })
  274 + }
  275 + // TODO:当前站点索引后面再算,目前默认0
  276 + let routeData = new RouteData(0, stationDataList)
  277 + eBusStopDataList.push(new EBusStopData(
  278 + lineName, lineCode, routeData, arriveTimes))
  279 + })
  280 + eBusStopDataList.map(stopData => {
  281 + rtnData._innerDataItemList.push(new EBusStopLineChartListScrollPageInnerDataItem(
  282 + 0, 0, 0, 0, 0, stopData
  283 + ))
  284 + })
  285 + // 2.2、一共有多少页
  286 + rtnData._pageCount = Math.ceil(rtnData._innerDataItemList.length / rtnData._pageSize)
  287 +
  288 + // 3、计算内部滚动数据对象
  289 + _private_refreshScrollData.call(rtnData)
  290 +
  291 + return rtnData
  292 + }
  293 +
  294 + /**
  295 + * static方法,使用测试数据生成对象。
  296 + * @param pageSize 每页大小
  297 + * @param width 列表宽度
  298 + * @param height 列表高度
  299 + * @return EBusStopLineChartListScrollPageInnerData
  300 + */
  301 + static generateDataListByTest (pageSize, width, height) {
  302 + let rtnData = new EBusStopLineChartListScrollPageInnerData(
  303 + pageSize, width, height
  304 + )
  305 +
  306 + // 1、重置内部数据
  307 + rtnData.resetData()
  308 +
  309 + // 2、计算内部数据对象
  310 + rtnData._innerDataItemList.splice(0, rtnData._innerDataItemList.length)
  311 + // 2-1、测试数据
  312 + let eBusStopData1 = EBusStopData.generateTestData()
  313 + let eBusStopData2 = EBusStopData.generateTestData()
  314 + let eBusStopData3 = EBusStopData.generateEmptyTestData()
  315 + let eBusStopDataList = [eBusStopData1, eBusStopData2, eBusStopData3]
  316 + eBusStopDataList.map(stopData => {
  317 + rtnData._innerDataItemList.push(new EBusStopLineChartListScrollPageInnerDataItem(
  318 + 0, 0, 0, 0, 0, stopData
  319 + ))
  320 + })
  321 + // 2.2、一共有多少页
  322 + rtnData._pageCount = Math.ceil(rtnData._innerDataItemList.length / rtnData._pageSize)
  323 +
  324 + // 3、计算内部滚动数据对象
  325 + _private_refreshScrollData.call(rtnData)
  326 +
  327 + return rtnData
  328 + }
  329 +}
  330 +
  331 +// ---------------- private私有方法 -----------------//
  332 +/**
  333 + * 计算内部滚动数据。
  334 + */
  335 +function _private_refreshScrollData () {
  336 + this._scrollDataItemList.splice(0, this._scrollDataItemList.length)
  337 +
  338 + // 3.1、拷贝属性赋值
  339 + for (let dataItem of this._innerDataItemList) {
  340 + // 注意这里直接拷贝_innerDataItemList元素属性,然后new新的ScrollListInnerDataItem对象
  341 + this._scrollDataItemList.push(
  342 + EBusStopLineChartListScrollPageInnerDataItem.createByDataItem(dataItem)
  343 + )
  344 + }
  345 + // 3.2、如果总数据小于页大小,不用计算其他滚动数据,返回
  346 + if (this._innerDataItemList.length <= this._pageSize) {
  347 + return
  348 + }
  349 + // 3.3、计算每条数据的 itemIndex pageIndex 属性
  350 + for (let i = 0; i < this._pageCount; i++) { // 计算itemIndex pageIndex
  351 + for (let j = 0; j < this._pageSize; j++) {
  352 + let index = i * this._pageSize + j
  353 + if (index === this._scrollDataItemList.length) { // 超出记录退出
  354 + break
  355 + }
  356 + let innerDataItem = this._scrollDataItemList[i * this._pageSize + j]
  357 + innerDataItem.itemIndex = j
  358 + innerDataItem.pageIndex = i
  359 + }
  360 + }
  361 + // 3.4、在最后添加第一页的数据(为了无缝滚动需要),同时pageIndex要加1
  362 + // 注意:添加的一页不计算进this.pageCount中
  363 + for (let i = 0; i < this._pageSize; i++) {
  364 + let InnerDataItem = EBusStopLineChartListScrollPageInnerDataItem.createByDataItem(this._innerDataItemList[i])
  365 + InnerDataItem.pageIndex = this._pageCount
  366 + this._scrollDataItemList.push(InnerDataItem)
  367 + }
  368 + // 3.5、计算每个元素的宽,高,top
  369 + _private_refreshScrollDataSizeProperty.call(this)
  370 +}
  371 +
  372 +/**
  373 + * 刷新滚动数据中 宽,高,top
  374 + */
  375 +function _private_refreshScrollDataSizeProperty () {
  376 + // TODO:先直接除假设每个item高度相同,后面再改
  377 + let scrollHeight = Math.floor(this._height / this._pageSize)
  378 + for (let i = 0; i < this._scrollDataItemList.length; i++) {
  379 + let innerDataItem = this._scrollDataItemList[i]
  380 + innerDataItem._width = this._width
  381 + innerDataItem._height = scrollHeight
  382 + innerDataItem._cssTop = i * scrollHeight
  383 + }
  384 +}
  385 +
  386 +export {
  387 + EBusStopLineChartListScrollPageInnerData as ScrollPageInnerData,
  388 + EBusStopLineChartListScrollPageInnerDataItem as ScrollPageInnerDataItem
  389 +}
... ...
front-end/h5/src/components/core/plugins/index.js
... ... @@ -27,7 +27,8 @@ import BsthSlide from &#39;core/plugins/bsth/bsth-slide&#39;
27 27 import BsthWeatherRealtime from 'core/plugins/bsth/bsth-weather-realtime'
28 28 import BsthDatetime from 'core/plugins/bsth/bsth-datetime'
29 29  
30   -import EBusStopLineChart from 'core/plugins/bsth/lggj/eBusStop-line-chart'
  30 +import EBusStopLineChart from 'core/plugins/bsth/lggj/chart/eBusStop-line-chart'
  31 +import EBusStopLineChartList from 'core/plugins/bsth/lggj/list/eBusStop-line-chart-list'
31 32  
32 33 export const pluginsList = [
33 34 // {
... ... @@ -327,6 +328,18 @@ export const pluginsList = [
327 328 name: EBusStopLineChart.name
328 329 },
329 330  
  331 + {
  332 + i18nTitle: {
  333 + 'en-US': 'EBusStopLineChartList',
  334 + 'zh-CN': '电子站牌单线路模拟图列表'
  335 + },
  336 + title: '电子站牌单线路模拟图列表',
  337 + icon: 'list',
  338 + component: EBusStopLineChartList,
  339 + visible: true,
  340 + name: EBusStopLineChartList.name
  341 + },
  342 +
330 343 // {
331 344 // i18nTitle: {
332 345 // 'en-US': 'LineChart',
... ...