index.vue 11 KB

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