index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. <template>
  2. <Card :title="title" :subTitle="subTitle" :icon="icon" unit="单位(万元)" 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 / 10000)
  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: "rgba(160, 179, 214, 0.1)",
  175. type: "dashed",
  176. width: 1,
  177. }
  178. },
  179. max: function (value) { // x轴左侧留白
  180. return value.max + 0.3
  181. },
  182. min: function (value) { // x轴左侧留白
  183. return -0.3
  184. },
  185. data: xAxisData
  186. },
  187. yAxis: [
  188. {
  189. axisLabel: {
  190. color: 'rgba(160, 179, 214, 0.7)',
  191. fontSize: 11,
  192. margin: 12
  193. },
  194. axisLine: {
  195. show: false,
  196. lineStyle: {
  197. color: '#fff'
  198. }
  199. },
  200. axisTick: {
  201. length: 14,
  202. lineStyle: {
  203. width: 2,
  204. fontSize: 16
  205. }
  206. },
  207. splitLine: {
  208. show: true,
  209. lineStyle: {
  210. color: "rgba(160, 179, 214, 0.1)",
  211. type: "dashed",
  212. width: 1,
  213. dashOffset: 5
  214. }
  215. }
  216. },
  217. {
  218. type: 'value',
  219. position: 'right',
  220. axisLabel: {
  221. show: false
  222. },
  223. axisTick: {
  224. show: true,
  225. length: 14,
  226. lineStyle: {
  227. width: 2,
  228. fontSize: 16
  229. }
  230. },
  231. axisLine: {
  232. show: false
  233. }
  234. }
  235. ],
  236. series: [
  237. {
  238. type: 'line',
  239. silent: true,
  240. symbolSize: 10,
  241. yAxisIndex: 0,
  242. itemStyle: {
  243. color: '#FFE1D4',
  244. borderColor: 'rgba(255, 162, 41, 0.7)',
  245. borderWidth: 3
  246. },
  247. lineStyle: {
  248. // opacity: 0
  249. color: '#3D7BF8',
  250. width: 2
  251. },
  252. markPoint: {
  253. // symbol: 'none',
  254. 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', // 带下箭头的圆角矩形
  255. symbolSize: function (val) {
  256. return [textSize(val, '14px').width + 20, 55] // 设置宽高
  257. },
  258. itemStyle: {
  259. color: '#262BB3' // %值的背景颜色
  260. },
  261. symbolOffset: ['0', '-40%'], // 相对位置
  262. symbolKeepAspect: true, // 是否保持宽高比
  263. label: {
  264. position: 'insideTop',
  265. fontSize: 14,
  266. distance: 10
  267. },
  268. data: markPointData,
  269. silent: true
  270. },
  271. areaStyle: {
  272. color: {
  273. type: 'linear',
  274. x: 0,
  275. y: 0,
  276. x2: 0,
  277. y2: 1,
  278. colorStops: [{
  279. offset: 0, color: 'rgba(21, 147, 222, 1)' // 0% 处的颜色
  280. }, {
  281. offset: max ? (max - min) / max : 1, color: 'rgba(61,123,248,0)' // 50% 处的颜色
  282. }, {
  283. offset: 1, color: 'rgba(61,123,248,0)' // 100% 处的颜色
  284. }],
  285. global: false // 缺省为 false
  286. }
  287. },
  288. data: lineData
  289. },
  290. {
  291. type: 'bar',
  292. barWidth: '25%',
  293. labelLine: {
  294. show: false
  295. },
  296. itemStyle: {
  297. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  298. { offset: 0, color: '#491CC7' },
  299. { offset: 1, color: '#E29163' }
  300. ])
  301. },
  302. data: seriesData
  303. }]
  304. }
  305. this.onlinePayDayBarInstance.setOption(option)
  306. this.onlinePayDayBarInstance.resize()
  307. },
  308. handleResize() {
  309. if (this.onlinePayDayBarInstance) {
  310. this.onlinePayDayBarInstance.resize()
  311. }
  312. },
  313. }
  314. }
  315. </script>
  316. <style lang="scss">
  317. @import '@/assets/css/function.scss';
  318. .online-pay-day-bar {
  319. width: 100%;
  320. // height: halfH(350);
  321. }
  322. .online-pay-day {
  323. .card-body{
  324. display: flex;
  325. }
  326. .total{
  327. height: halfH(24);
  328. line-height: halfH(24);
  329. padding: halfH(18) halfW(18);
  330. color: #fff;
  331. float: left;
  332. font-size: halfW(14);
  333. border-radius: 5px;
  334. background-color: rgba(17, 28, 48, 1);
  335. text-align: center;
  336. border: 1px solid rgba(0, 123, 211, 0.2);
  337. }
  338. .img{
  339. width: halfW(40);
  340. height: halfH(40);
  341. margin-right: halfW(27);
  342. margin-top: halfH(-7);
  343. padding: halfH(8) halfW(8);
  344. box-sizing: border-box;
  345. background: #12223C;
  346. border-radius: 50%;
  347. .icon{
  348. width: 100%;
  349. height: 100%;
  350. }
  351. }
  352. .info{
  353. width: halfW(160);
  354. // height: calc(100% - halfH(60));
  355. border: 1px solid rgba(0, 123, 211, 0.2);
  356. border-radius: halfW(5) halfH(5);
  357. display: flex;
  358. flex-direction: column;
  359. .p1{
  360. font-size: halfW(14);
  361. color: #B9E3F4;
  362. }
  363. .p2{
  364. font-size: halfW(18);
  365. color: #fff;
  366. }
  367. .p3{
  368. font-size: halfW(12);
  369. color: #9FA5B7;
  370. }
  371. }
  372. .text,.legend{
  373. padding: halfH(30) halfW(16);
  374. }
  375. .text{
  376. // height: halfH(125);
  377. flex: 1;
  378. // line-height: halfH(40);
  379. }
  380. .legend{
  381. color: #808BAD;
  382. background: #111C30;
  383. font-size: halfW(14);
  384. flex: 1;
  385. // line-height: halfH(40);
  386. .legend1-color, .legend2-color{
  387. display: inline-block;
  388. width: halfW(20);
  389. height: halfH(8);
  390. margin-right: halfW(10);
  391. vertical-align: middle;
  392. }
  393. .legend1-color{
  394. background: linear-gradient(90deg, #FEA373 0%, #FF678B 100%);
  395. }
  396. .legend2-color{
  397. background: linear-gradient(90deg, #0F67F8 0%, #98D7F1 50%, #77ECED 100%);
  398. }
  399. .legend3-color{
  400. display: inline-block;
  401. width: halfW(20);
  402. height: halfH(20);
  403. background: linear-gradient(90deg, #F6D1A7 0%, #F5BD7C 50%, #F4A850 100%);
  404. border-radius: 50%;
  405. margin-right: halfW(10);
  406. position: relative;
  407. .inner{
  408. display: inline-block;
  409. width: halfW(10);
  410. height: halfH(10);
  411. background: linear-gradient(90deg, #C9FFBF 0%, #FFB0BE 100%);
  412. border-radius: 50%;
  413. position: absolute;
  414. top: 50%;
  415. left: 50%;
  416. transform: translate(-50%, -50%);
  417. }
  418. }
  419. }
  420. }
  421. </style>