xm-time-compare.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. <template>
  2. <div id="fullChart" :class="[$style.box, $style.chartswrap]" bordered>
  3. <div :class="$style.opt">
  4. <a-radio-group
  5. v-model="radioVal"
  6. button-style="solid"
  7. :class="$style.radio"
  8. @change="getdata(radioVal)"
  9. >
  10. <a-radio-button value="1">当天</a-radio-button>
  11. <a-radio-button value="3">近三天</a-radio-button>
  12. <a-radio-button value="5">近五天</a-radio-button>
  13. <a-radio-button value="7">近一周</a-radio-button>
  14. </a-radio-group>
  15. <div :class="$style.echartclass">
  16. <div ref="echart" :options="line" autoresize :class="$style.echart"> </div>
  17. </div>
  18. </div>
  19. </div>
  20. </template>
  21. <script>
  22. import echarts from 'echarts'
  23. import components from './_import-components/xm-time-compare-import'
  24. import 'echarts/lib/chart/bar'
  25. import 'echarts/lib/component/legend'
  26. import 'echarts/lib/component/tooltip'
  27. import 'echarts/lib/component/toolbox'
  28. import 'echarts/lib/component/dataZoom'
  29. import TrackService from './track-service'
  30. const fontFamily = `-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'`
  31. let _this
  32. const line = {
  33. title: {
  34. text: '关键用户打开时长对比',
  35. textStyle: {
  36. color: 'white',
  37. fontSize: '20',
  38. fontFamily: fontFamily,
  39. fontWeight: 200,
  40. },
  41. left: 'left',
  42. padding: [10, 0, 0, 15],
  43. show: true,
  44. textAlign: 'left',
  45. textVerticalAlign: 'left',
  46. },
  47. backgroundColor: '#0B3787',
  48. grid: { left: '10%', top: '30%', right: '10%', bottom: '15%' },
  49. tooltip: {
  50. trigger: 'axis',
  51. axisPointer: {
  52. type: 'shadow',
  53. },
  54. padding: [10, 10, 10, 10],
  55. backgroundColor: 'rgba(255,255,255,0.9)',
  56. textStyle: {
  57. color: 'black',
  58. },
  59. formatter(params) {
  60. const val0 = params[0].data[1]
  61. const val1 = params[1].data[1]
  62. const val2 = params[2].data[1]
  63. const color = ['#5DBDEF', '#DC9F69', '#CB03FF']
  64. const circle = `<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;left:5px;background-color:`
  65. const data0 = `${circle}${color[0]}"></span> ${params[0].seriesName}: ${val0}s`
  66. const data1 = `${circle}${color[1]}"></span> ${params[1].seriesName}: ${val1}s`
  67. const data2 = `${circle}${color[2]}"></span> ${params[2].seriesName}: ${val2}s`
  68. return `${params[0].axisValueLabel}<br/>${data0}<br/>${data1}<br/>${data2}<br/>`
  69. },
  70. },
  71. toolbox: {
  72. show: true,
  73. top: '40',
  74. iconStyle: {
  75. borderColor: '#fff',
  76. },
  77. emphasis: {
  78. iconStyle: {
  79. borderColor: '#fff',
  80. },
  81. },
  82. itemSize: 18,
  83. feature: {
  84. myReload: {
  85. show: true,
  86. title: ' ',
  87. icon:
  88. 'path://M81.92 634.88h194.56c12.288 0 20.48 8.192 20.48 20.48s-8.192 20.48-20.48 20.48h-161.792c69.632 155.648 225.28 260.096 401.408 260.096 184.32 0 348.16-114.688 411.648-284.672 4.096-10.24 16.384-16.384 26.624-12.288 10.24 4.096 16.384 16.384 12.288 26.624-69.632 186.368-247.808 311.296-450.56 311.296-180.224 0-342.016-100.352-423.936-253.952v135.168c0 12.288-8.192 20.48-20.48 20.48s-20.48-8.192-20.48-20.48v-204.8c0-6.144 2.048-10.24 6.144-14.336s8.192-6.144 14.336-6.144h10.24z m860.16-245.76h-194.56c-12.288 0-20.48-8.192-20.48-20.48s8.192-20.48 20.48-20.48h161.792c-69.632-155.648-225.28-260.096-401.408-260.096-184.32 0-348.16 114.688-411.648 284.672-4.096 10.24-16.384 16.384-26.624 12.288-10.24-4.096-16.384-16.384-12.288-26.624 69.632-186.368 247.808-311.296 450.56-311.296 180.224 0 342.016 100.352 423.936 253.952v-135.168c0-12.288 8.192-20.48 20.48-20.48s20.48 8.192 20.48 20.48v204.8c0 6.144-2.048 10.24-6.144 14.336s-8.192 6.144-14.336 6.144h-10.24z',
  89. onclick: function() {
  90. _this.initData()
  91. },
  92. },
  93. saveAsImage: { show: true, title: ' ' },
  94. myTool: {
  95. show: true,
  96. title: ' ',
  97. icon:
  98. 'path://M119.579981 119.560026l185.746448 0c16.074094 0 29.283953-13.134135 29.283953-29.322839 0-16.303314-13.113669-29.321816-29.283953-29.321816l-215.107149 0c-8.037047 0-15.34857 3.282766-20.655436 8.590656-5.383614 5.307889-8.629541 12.619412-8.629541 20.694321L60.934303 305.306474c0 16.074094 13.134135 29.283953 29.321816 29.283953 16.303314 0 29.322839-13.114692 29.322839-29.283953L119.578957 119.560026zM901.51076 119.560026 715.764312 119.560026c-16.093537 0-29.283953-13.134135-29.283953-29.322839 0-16.303314 13.114692-29.321816 29.283953-29.321816l215.107149 0c8.037047 0 15.34857 3.282766 20.655436 8.590656 5.384637 5.307889 8.629541 12.619412 8.629541 20.694321L960.156438 305.306474c0 16.074094-13.134135 29.283953-29.321816 29.283953-16.303314 0-29.322839-13.114692-29.322839-29.283953L901.511783 119.560026zM119.579981 901.489782l185.746448 0c16.074094 0 29.283953 13.133112 29.283953 29.321816 0 16.303314-13.113669 29.321816-29.283953 29.321816l-215.107149 0c-8.037047 0-15.34857-3.28379-20.655436-8.590656-5.383614-5.306866-8.629541-12.619412-8.629541-20.694321L60.934303 715.744357c0-16.075117 13.134135-29.286 29.321816-29.286 16.303314 0 29.322839 13.114692 29.322839 29.286L119.578957 901.489782zM901.51076 901.489782 715.764312 901.489782c-16.093537 0-29.283953 13.133112-29.283953 29.321816 0 16.303314 13.114692 29.321816 29.283953 29.321816l215.107149 0c8.037047 0 15.34857-3.28379 20.655436-8.590656 5.384637-5.306866 8.629541-12.619412 8.629541-20.694321L960.156438 715.744357c0-16.075117-13.134135-29.286-29.321816-29.286-16.303314 0-29.322839 13.114692-29.322839 29.286L901.511783 901.489782z',
  99. onclick: function() {
  100. if (_this.isfull === false) {
  101. _this.full = true
  102. _this.timer = null
  103. _this.$emit('fullcompare', true)
  104. } else {
  105. _this.full = false
  106. _this.$emit('fullcompare', false)
  107. }
  108. },
  109. },
  110. },
  111. },
  112. legend: {
  113. orient: 'vertical',
  114. x: 'right',
  115. y: 'center',
  116. padding: [10, 0, 20, 10],
  117. itemGap: 40,
  118. textStyle: {
  119. color: 'rgba(255,255,255,0.7)',
  120. },
  121. },
  122. dataZoom: [
  123. {
  124. type: 'slider',
  125. startValue: 0,
  126. endValue: 5,
  127. borderColor: '#134690',
  128. backgroundColor: '#0B3787',
  129. fillerColor: '#1465BB',
  130. height: '4%',
  131. bottom: '2%',
  132. handleSize: 0,
  133. showDetail: false, // 不显示拖动条的文字
  134. },
  135. ],
  136. xAxis: [
  137. {
  138. type: 'category',
  139. axisLine: {
  140. show: false,
  141. lineStyle: {
  142. color: '#fff',
  143. width: 1,
  144. type: 'solid',
  145. },
  146. },
  147. axisTick: {
  148. show: false,
  149. },
  150. axisLabel: {
  151. show: true,
  152. fontSize: 13,
  153. color: 'rgba(255,255,255,0.7)',
  154. interval: 0,
  155. formatter: function(value) {
  156. if (value.length > 7) {
  157. return `${value.slice(0, 4)}...`
  158. }
  159. return value
  160. },
  161. },
  162. },
  163. ],
  164. yAxis: [
  165. {
  166. type: 'value',
  167. axisLabel: {
  168. show: true,
  169. color: 'rgba(255,255,255,0.7)',
  170. fontSize: 13,
  171. formatter: '{value} s',
  172. },
  173. axisLine: {
  174. show: false,
  175. },
  176. axisTick: {
  177. show: false,
  178. },
  179. splitLine: {
  180. show: true,
  181. lineStyle: {
  182. color: 'rgba(255,255,255,0.2)',
  183. width: 1,
  184. type: 'solid',
  185. },
  186. },
  187. scale: true,
  188. },
  189. ],
  190. series: [
  191. {
  192. name: '平均',
  193. type: 'bar',
  194. barWidth: 20,
  195. barGap: 0,
  196. emphasis: {
  197. focus: 'series',
  198. },
  199. itemStyle: {
  200. color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
  201. { offset: 0, color: 'rgba(38,178,244,.2)' },
  202. { offset: 0.5, color: 'rgb(0,204,255)' },
  203. { offset: 1, color: 'rgb(0,204,255)' },
  204. ]),
  205. },
  206. data: [],
  207. },
  208. {
  209. name: '90%',
  210. type: 'bar',
  211. barWidth: 20,
  212. itemStyle: {
  213. color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
  214. { offset: 0, color: 'rgba(255,117,61,.2)' },
  215. { offset: 1, color: 'rgb(255,219,128)' },
  216. ]),
  217. },
  218. data: [],
  219. },
  220. {
  221. name: '最大',
  222. type: 'bar',
  223. barWidth: 20,
  224. itemStyle: {
  225. color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
  226. { offset: 0, color: 'rgba(182,0,241,.2)' },
  227. { offset: 1, color: 'rgb(255,60,235)' },
  228. ]),
  229. },
  230. data: [],
  231. },
  232. ],
  233. }
  234. export default {
  235. name: 'XmTimeCompare',
  236. metaInfo: {
  237. title: 'TimeCompare',
  238. },
  239. components,
  240. props: {
  241. isfull: {
  242. type: Boolean,
  243. },
  244. fullradio: {
  245. type: Number,
  246. default: null,
  247. },
  248. },
  249. data() {
  250. return {
  251. min: [],
  252. avg: [],
  253. max: [],
  254. timer: null,
  255. timerfull: null,
  256. chart: null,
  257. show: false,
  258. radioVal: '1',
  259. full: false,
  260. line: line,
  261. }
  262. },
  263. mounted() {
  264. this.initData()
  265. this.automove()
  266. },
  267. created() {
  268. _this = this
  269. clearInterval(this.timer)
  270. clearInterval(this.timerfull)
  271. },
  272. beforeDestroy() {
  273. clearInterval(this.timer)
  274. clearInterval(this.timerfull)
  275. },
  276. methods: {
  277. initData() {
  278. let params
  279. if (this.fullradio !== null) {
  280. params = {
  281. days: this.fullradio,
  282. }
  283. } else {
  284. params = {
  285. days: 1,
  286. }
  287. }
  288. TrackService.getOpenTime(params)
  289. .then((res) => {
  290. let avglist = []
  291. let minlist = []
  292. let maxlist = []
  293. avglist = res.data.avg.map((item, index) => {
  294. return ([index] = [item.name, item.val / 1000])
  295. })
  296. minlist = res.data.min.map((item, index) => {
  297. return ([index] = [item.name, item.val / 1000])
  298. })
  299. maxlist = res.data.max.map((item, index) => {
  300. return ([index] = [item.name, item.val / 1000])
  301. })
  302. this.line.series[0].data = avglist
  303. this.line.series[1].data = minlist
  304. this.line.series[2].data = maxlist
  305. this.initChart()
  306. this.listenhover()
  307. })
  308. .catch((e) => {})
  309. },
  310. listenhover() {
  311. this.chart.on('mouseover', 'datazoom', function(params) {
  312. if (!this.timer == null) {
  313. clearInterval(this.timer)
  314. } else if (!this.timerfull == null) {
  315. clearInterval(this.timer)
  316. }
  317. this.line.dataZoom[0].endValue = this.chart.getModel().option.dataZoom[0].endValue
  318. this.line.dataZoom[0].startValue = this.chart.getModel().option.dataZoom[0].startValue
  319. this.chart.setOption(this.line)
  320. this.automove()
  321. })
  322. this.chart.getZr().on('mouseover', this.stop)
  323. this.chart.getZr().on('mouseout', this.goMove)
  324. },
  325. getdata(days) {
  326. this.$emit('radiochange', parseInt(days))
  327. const params = {
  328. days: days,
  329. }
  330. TrackService.getOpenTime(params)
  331. .then((res) => {
  332. let avglist = []
  333. let minlist = []
  334. let maxlist = []
  335. avglist = res.data.avg.map((item, index) => {
  336. return ([index] = [item.name, (item.val / 1000).toFixed(1)])
  337. })
  338. minlist = res.data.min.map((item, index) => {
  339. return ([index] = [item.name, (item.val / 1000).toFixed(1)])
  340. })
  341. maxlist = res.data.max.map((item, index) => {
  342. return ([index] = [item.name, (item.val / 1000).toFixed(1)])
  343. })
  344. this.line.series[0].data = avglist
  345. this.line.series[1].data = minlist
  346. this.line.series[2].data = maxlist
  347. if (this.timer) {
  348. clearInterval(this.timer)
  349. this.line.dataZoom[0].endValue = 5
  350. this.line.dataZoom[0].startValue = 0
  351. this.chart.setOption(this.line)
  352. // this.automove()
  353. }
  354. })
  355. .catch((e) => {})
  356. },
  357. initChart(line) {
  358. this.$refs.echart.style.width = '100%'
  359. this.$refs.echart.style.height = '100%'
  360. this.chart = echarts.init(this.$refs.echart)
  361. this.chart.setOption(this.line)
  362. },
  363. automove() {
  364. // 两个定时器
  365. if (this.full === false) {
  366. this.timer = setInterval(() => {
  367. // 每次向后滚动一个,最后一个从头开始。
  368. if (this.line.dataZoom[0].endValue === this.line.series[0].data.length - 1) {
  369. this.line.dataZoom[0].endValue = 5
  370. this.line.dataZoom[0].startValue = 0
  371. } else {
  372. this.line.dataZoom[0].endValue = this.chart.getModel().option.dataZoom[0].endValue + 1
  373. this.line.dataZoom[0].startValue =
  374. this.chart.getModel().option.dataZoom[0].startValue + 1
  375. }
  376. this.chart.setOption(this.line)
  377. }, 2000)
  378. } else {
  379. this.timerfull = setInterval(() => {
  380. if (this.line.dataZoom[0].endValue === this.line.series[0].data.length - 1) {
  381. this.line.dataZoom[0].endValue = 5
  382. this.line.dataZoom[0].startValue = 0
  383. } else {
  384. this.line.dataZoom[0].endValue = this.chart.getModel().option.dataZoom[0].endValue + 1
  385. this.line.dataZoom[0].startValue =
  386. this.chart.getModel().option.dataZoom[0].startValue + 1
  387. }
  388. this.chart.setOption(this.line)
  389. }, 2000)
  390. }
  391. },
  392. stop() {
  393. if (this.timer) {
  394. clearInterval(this.timer)
  395. } else {
  396. clearInterval(this.timerfull)
  397. }
  398. },
  399. goMove() {
  400. this.stop()
  401. this.automove()
  402. },
  403. },
  404. }
  405. </script>
  406. <style module lang="scss">
  407. @use '@/common/design' as *;
  408. .chartswrap {
  409. margin-right: 10px;
  410. }
  411. .box {
  412. position: absolute;
  413. width: 100%;
  414. height: 100%;
  415. color: $card-background;
  416. background: #0b3787;
  417. .opt {
  418. position: relative;
  419. flex-wrap: wrap;
  420. height: 100%;
  421. p {
  422. flex-basis: 100%;
  423. padding: 10px 0 5px 15px;
  424. margin-bottom: 0;
  425. font-size: $switch-height;
  426. }
  427. }
  428. .radio {
  429. position: absolute;
  430. z-index: 99;
  431. padding-top: 4px;
  432. margin: 40px 0 0 15px;
  433. }
  434. .picker {
  435. min-width: 100px;
  436. max-width: 100px;
  437. margin-left: 20px;
  438. :global(.ant-select) {
  439. width: 100%;
  440. }
  441. }
  442. }
  443. .echartclass {
  444. position: relative;
  445. width: 100%;
  446. height: 100%;
  447. .echart {
  448. position: absolute;
  449. bottom: 0;
  450. left: 50%;
  451. z-index: 0;
  452. width: 100%;
  453. height: 100%;
  454. padding-top: 5px;
  455. padding-right: 20px;
  456. overflow: hidden;
  457. transform: translate(-50%, 0%);
  458. }
  459. }
  460. </style>