index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <template>
  2. <Card :title="title" :subTitle="subTitle" :icon="icon" class="online-pay-day">
  3. <div class="info margin-r-20" v-if="showInfo">
  4. <div class="text">
  5. <p class="p1">线上缴费</p>
  6. <p class="p2 margin-tg-20">日热度统计</p>
  7. <p class="p3">(近12月日平均)</p>
  8. </div>
  9. <div class="legend">
  10. <p class="legend1">
  11. <span class="legend1-color"></span>
  12. <span>时段缴费</span>
  13. </p>
  14. <p class="legend2 margin-tg-20">
  15. <span class="legend2-color"></span>
  16. <span>时段占比</span>
  17. </p>
  18. <p class="legend3">
  19. <span class="legend3-color"><b class="inner"></b></span>
  20. <span>时段比例</span>
  21. </p>
  22. </div>
  23. </div>
  24. <div ref="onlinePayDayBar" class="online-pay-day-bar flex-1"></div>
  25. </Card>
  26. </template>
  27. <script>
  28. import * as echarts from 'echarts'
  29. import { huiJiaApi } from '@/api'
  30. // import { getBigNumberWithUint } from '@/libs/tools.js'
  31. import Card from '@/views/hui-jia/components/card'
  32. import icon from './images/icon-title.png'
  33. export default {
  34. name: 'OnlinePayDay',
  35. components: {
  36. Card
  37. },
  38. props: {
  39. showMarkPoint: {
  40. type: Boolean,
  41. default: () => true
  42. },
  43. showInfo: {
  44. type: Boolean,
  45. default: () => true
  46. }
  47. },
  48. data () {
  49. return {
  50. onlinePayDayBarInstance: null,
  51. xAxisData: ['01:00', '04:00', '07:00', '10:00', '13:00', '16:00', '19:00', '22:00'],
  52. seriesData: [0, 0, 0, 0, 0, 0, 0, 0],
  53. title: '线上缴费日热度',
  54. subTitle: '近12个月',
  55. icon: icon
  56. }
  57. },
  58. mounted () {
  59. this.initChart()
  60. this.getOnlinePayDay()
  61. window.addEventListener("resize", this.handleResize)
  62. },
  63. beforeDestroy() {
  64. if (this.onlinePayDayBarInstance) {
  65. this.onlinePayDayBarInstance.dispose()
  66. }
  67. window.removeEventListener("resize", this.handleResize)
  68. },
  69. methods: {
  70. getOnlinePayDay () {
  71. huiJiaApi.getOnlinePayDay().then(res => {
  72. this.xAxisData = (res.data.data.list || []).map(item => item.statData)
  73. this.seriesData = (res.data.data.list || []).map(item => item.payAmount)
  74. this.initChart()
  75. })
  76. },
  77. /**
  78. * 获取一个和max最接近的能被5整除的无零头整数
  79. */
  80. getMax (max) {
  81. if (max <= 10) return 10
  82. let pow = max.toString().length - 2
  83. pow = Math.pow(10, pow)
  84. max = Math.ceil(max / pow / 10) * 10 * pow
  85. return max
  86. },
  87. initChart () {
  88. this.onlinePayDayBarInstance = echarts.init(this.$refs.onlinePayDayBar)
  89. const xAxisData = this.xAxisData
  90. const seriesData = this.seriesData
  91. let all = seriesData.reduce((total, num) => {
  92. return Number(total) + Number(num)
  93. }, 0)
  94. let markPointData = []
  95. seriesData.forEach((item, i) => {
  96. const value = (all > 0 ? (Number(item) / all) * 100 : 0).toFixed(1) + '%'
  97. markPointData.push({
  98. value,
  99. xAxis: i,
  100. yAxis: item,
  101. itemStyle: {
  102. opacity: xAxisData[i].indexOf('hide') !== -1 ? 0 : 1
  103. }
  104. })
  105. })
  106. let lineData = []
  107. let min = seriesData.reduce((min, num) => {
  108. return Math.min(Number(min), Number(num))
  109. }, 0)
  110. let max = seriesData.reduce((min, num) => {
  111. return Math.max(Number(min), Number(num))
  112. }, 0)
  113. seriesData.forEach((item, i) => {
  114. lineData.push(Number(item) - min * 0.5)
  115. }, 0)
  116. const textSize = (text, fontSize) => {
  117. var span = document.createElement('span')
  118. var result = {
  119. 'width': span.offsetWidth,
  120. 'height': span.offsetHeight
  121. }
  122. span.style.visibility = 'hidden'
  123. span.style.fontSize = fontSize || '14px'
  124. document.body.appendChild(span)
  125. if (typeof span.textContent !== 'undefined') { span.textContent = text || '国' } else span.innerText = text || '国'
  126. result.width = span.offsetWidth - result.width
  127. result.height = span.offsetHeight - result.height
  128. span.parentNode.removeChild(span)
  129. return result
  130. }
  131. const option = {
  132. tooltip: {},
  133. legend: {
  134. show: false
  135. },
  136. grid: {
  137. top: this.showMarkPoint ? '10%' : '6%',
  138. bottom: '0px',
  139. left: '0px',
  140. right: '0px',
  141. containLabel: true
  142. },
  143. xAxis: {
  144. axisLabel: {
  145. color: '#fff',
  146. margin: 15,
  147. fontSize: 12,
  148. formatter: function (val, idx) {
  149. let value = xAxisData[idx]
  150. return value
  151. }
  152. },
  153. axisLine: {
  154. show: true,
  155. lineStyle: {
  156. color: '#666',
  157. opacity: 1,
  158. cap: 'round'
  159. }
  160. },
  161. boundaryGap: true,
  162. axisTick: {
  163. alignWithLabel: true,
  164. length: 7,
  165. lineStyle: {
  166. width: 3,
  167. color: '#fff',
  168. opacity: 0.5
  169. }
  170. },
  171. splitLine: {
  172. show: true,
  173. lineStyle: {
  174. color: '#fff',
  175. opacity: 0.3,
  176. cap: 'round',
  177. type: [5, 10]
  178. }
  179. },
  180. max: function (value) { // x轴左侧留白
  181. return value.max + 0.3
  182. },
  183. min: function (value) { // x轴左侧留白
  184. return -0.3
  185. },
  186. data: xAxisData
  187. },
  188. yAxis: [
  189. {
  190. axisLabel: {
  191. color: 'rgba(160, 179, 214, 0.7)',
  192. fontSize: 11,
  193. margin: 12
  194. },
  195. axisLine: {
  196. show: false,
  197. lineStyle: {
  198. color: '#fff'
  199. }
  200. },
  201. axisTick: {
  202. length: 14,
  203. lineStyle: {
  204. width: 2,
  205. fontSize: 16
  206. }
  207. },
  208. splitLine: {
  209. show: true,
  210. lineStyle: {
  211. color: '#fff',
  212. opacity: 0.3,
  213. cap: 'round',
  214. type: 'dashed',
  215. dashOffset: 5
  216. }
  217. }
  218. },
  219. {
  220. type: 'value',
  221. position: 'right',
  222. axisLabel: {
  223. show: false
  224. },
  225. axisTick: {
  226. show: true,
  227. length: 14,
  228. lineStyle: {
  229. width: 2,
  230. fontSize: 16
  231. }
  232. },
  233. axisLine: {
  234. show: false
  235. }
  236. }
  237. ],
  238. series: [
  239. {
  240. type: 'line',
  241. silent: true,
  242. symbolSize: 10,
  243. yAxisIndex: 0,
  244. itemStyle: {
  245. color: '#FFE1D4',
  246. borderColor: 'rgba(255, 162, 41, 0.7)',
  247. borderWidth: 3
  248. },
  249. lineStyle: {
  250. // opacity: 0
  251. color: '#3D7BF8',
  252. width: 2
  253. },
  254. markPoint: {
  255. // symbol: 'none',
  256. symbol: this.showMarkPoint ? 'path://m 0,0 h 48 a 5 5 0 0 1 4 4 v 20 a 5 5 0 0 1 -4 4 h -18 l -5,5 l -5,-5 h -18 a 5 5 0 0 1 -4 -4 v -20 a 5 5 0 0 1 4 -4 z' : 'none', // 带下箭头的圆角矩形
  257. symbolSize: function (val) {
  258. return [textSize(val, '14px').width + 20, 55] // 设置宽高
  259. },
  260. itemStyle: {
  261. color: '#262BB3' // %值的背景颜色
  262. },
  263. symbolOffset: ['0', '-40%'], // 相对位置
  264. symbolKeepAspect: true, // 是否保持宽高比
  265. label: {
  266. position: 'insideTop',
  267. fontSize: 14,
  268. distance: 10
  269. },
  270. data: markPointData,
  271. silent: true
  272. },
  273. areaStyle: {
  274. color: {
  275. type: 'linear',
  276. x: 0,
  277. y: 0,
  278. x2: 0,
  279. y2: 1,
  280. colorStops: [{
  281. offset: 0, color: 'rgba(21, 147, 222, 1)' // 0% 处的颜色
  282. }, {
  283. offset: max ? (max - min) / max : 1, color: 'rgba(61,123,248,0)' // 50% 处的颜色
  284. }, {
  285. offset: 1, color: 'rgba(61,123,248,0)' // 100% 处的颜色
  286. }],
  287. global: false // 缺省为 false
  288. }
  289. },
  290. data: lineData
  291. },
  292. {
  293. type: 'bar',
  294. barWidth: '25%',
  295. labelLine: {
  296. show: false
  297. },
  298. itemStyle: {
  299. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  300. { offset: 0, color: '#491CC7' },
  301. { offset: 1, color: '#E29163' }
  302. ])
  303. },
  304. data: seriesData
  305. }]
  306. }
  307. this.onlinePayDayBarInstance.setOption(option)
  308. this.onlinePayDayBarInstance.resize()
  309. },
  310. handleResize() {
  311. if (this.onlinePayDayBarInstance) {
  312. this.onlinePayDayBarInstance.resize()
  313. }
  314. },
  315. }
  316. }
  317. </script>
  318. <style lang="scss">
  319. @import '@/assets/css/function.scss';
  320. .online-pay-day-bar {
  321. width: 100%;
  322. // height: halfH(350);
  323. }
  324. .online-pay-day {
  325. .card-body{
  326. display: flex;
  327. }
  328. .total{
  329. height: halfH(24);
  330. line-height: halfH(24);
  331. padding: halfH(18) halfW(18);
  332. color: #fff;
  333. float: left;
  334. font-size: halfW(14);
  335. border-radius: 5px;
  336. background-color: rgba(17, 28, 48, 1);
  337. text-align: center;
  338. border: 1px solid rgba(0, 123, 211, 0.2);
  339. }
  340. .img{
  341. width: halfW(40);
  342. height: halfH(40);
  343. margin-right: halfW(27);
  344. margin-top: halfH(-7);
  345. padding: halfH(8) halfW(8);
  346. box-sizing: border-box;
  347. background: #12223C;
  348. border-radius: 50%;
  349. .icon{
  350. width: 100%;
  351. height: 100%;
  352. }
  353. }
  354. .info{
  355. width: halfW(160);
  356. // height: calc(100% - halfH(60));
  357. border: 1px solid rgba(0, 123, 211, 0.2);
  358. border-radius: halfW(5) halfH(5);
  359. display: flex;
  360. flex-direction: column;
  361. .p1{
  362. font-size: halfW(14);
  363. color: #B9E3F4;
  364. }
  365. .p2{
  366. font-size: halfW(18);
  367. color: #fff;
  368. }
  369. .p3{
  370. font-size: halfW(12);
  371. color: #9FA5B7;
  372. }
  373. }
  374. .text,.legend{
  375. padding: halfH(30) halfW(16);
  376. }
  377. .text{
  378. // height: halfH(125);
  379. flex: 1;
  380. // line-height: halfH(40);
  381. }
  382. .legend{
  383. color: #808BAD;
  384. background: #111C30;
  385. font-size: halfW(14);
  386. flex: 1;
  387. // line-height: halfH(40);
  388. .legend1-color, .legend2-color{
  389. display: inline-block;
  390. width: halfW(20);
  391. height: halfH(8);
  392. margin-right: halfW(10);
  393. vertical-align: middle;
  394. }
  395. .legend1-color{
  396. background: linear-gradient(90deg, #FEA373 0%, #FF678B 100%);
  397. }
  398. .legend2-color{
  399. background: linear-gradient(90deg, #0F67F8 0%, #98D7F1 50%, #77ECED 100%);
  400. }
  401. .legend3-color{
  402. display: inline-block;
  403. width: halfW(20);
  404. height: halfH(20);
  405. background: linear-gradient(90deg, #F6D1A7 0%, #F5BD7C 50%, #F4A850 100%);
  406. border-radius: 50%;
  407. margin-right: halfW(10);
  408. position: relative;
  409. .inner{
  410. display: inline-block;
  411. width: halfW(10);
  412. height: halfH(10);
  413. background: linear-gradient(90deg, #C9FFBF 0%, #FFB0BE 100%);
  414. border-radius: 50%;
  415. position: absolute;
  416. top: 50%;
  417. left: 50%;
  418. transform: translate(-50%, -50%);
  419. }
  420. }
  421. }
  422. }
  423. </style>