statistics.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. <template>
  2. <view class="order-statistics">
  3. <view class="select-date">
  4. <u-input
  5. style="flex: 1;"
  6. v-model="timeRange"
  7. type="select"
  8. :selectOpen="show"
  9. border
  10. placeholder="选择时间范围"
  11. @click="show = true"
  12. height="76rpx"
  13. />
  14. <view style="margin-left: 16rpx;"><u-icon name="download" size="48"></u-icon></view>
  15. <u-calendar
  16. v-model="show"
  17. mode="range"
  18. @change="bindDateChange"
  19. startText="开始日期"
  20. endText="结束日期"
  21. active-bg-color="#00C18A"
  22. active-color="#FFFFFF"
  23. range-bg-color="#00C18A"
  24. rangeColor="#FFFFFF"
  25. zIndex="9999999"
  26. >
  27. </u-calendar>
  28. </view>
  29. <!-- 四个框框(统计数据) -->
  30. <view class="overview-data-box">
  31. <view class="data-item" v-for="(item, index) in overviewData" :key="index">
  32. <data-item :dataItem="item" :globalImages="globalImages"/>
  33. </view>
  34. </view>
  35. <u-card v-show="!show" padding="32" full :showHead="false">
  36. <view slot="body" style="width: 100%;height: 400rpx;position: relative;">
  37. <BtnGroup v-model="orderSelect" :defaultVal="2" :options="orderOptions"></BtnGroup>
  38. <EcChart v-if="optionReady" :chartOption="option" width="100%" height="100%" />
  39. <!-- <uni-ec-canvas class="uni-ec-canvas" id="order-revenue" canvas-id="order-revenue-chart" :ec="ec1" ref="canvas1"></uni-ec-canvas> -->
  40. </view>
  41. </u-card>
  42. <view></view>
  43. <u-card v-show="!show" padding="32" full :showHead="false">
  44. <view slot="body" style="width: 100%;height: 400rpx;position: relative;">
  45. <BtnGroup v-model="compareSelect" :defaultVal="2" :options="compareOptions"></BtnGroup>
  46. <EcChart v-if="optionReady2" :chartOption="option2" width="100%" height="100%" />
  47. <!-- <uni-ec-canvas class="uni-ec-canvas" id="data-compare" canvas-id="data-compare-chart" :ec="ec2" ref="canvas2"></uni-ec-canvas> -->
  48. </view>
  49. </u-card>
  50. </view>
  51. </template>
  52. <script>
  53. import DataItem from './DataItem.vue'
  54. import BtnGroup from './BtnGroup.vue'
  55. // import uniEcCanvas from '@/echarts/uni-ec-canvas/uni-ec-canvas'
  56. // import * as echarts from '@/echarts/uni-ec-canvas/echarts.min.js'
  57. import EcChart from '@/echarts/EcChart.vue'
  58. import { waitForGlobalImages } from '@/utils/globalImageLoader'
  59. export default {
  60. components: { DataItem, BtnGroup, EcChart },
  61. data() {
  62. return {
  63. globalImages: null,
  64. // 表示选中的日期,格式为"YYYY-MM-DD"
  65. timeRange: null,
  66. show: false,
  67. overviewData: [
  68. { title: '订单总量', value: '1248', status: 'up', fluctuate: '12.5%', bg: '#E8FBF6', valueColor: '#00C18A' },
  69. { title: '总收入', value: '¥8642', status: 'up', fluctuate: '8.3%', bg: '#FCF6EC', valueColor: '#E6A23C' },
  70. { title: '完成率', value: '98.7%', status: 'up', fluctuate: '1.2%', bg: '#ECF5FF', valueColor: '#409EFF' },
  71. { title: '平均评分', value: '4.9', status: 'down', fluctuate: '0.1', bg: '#FFE9E9', valueColor: '#F56C6C' },
  72. ],
  73. // ec1: {
  74. // option: {},
  75. // },
  76. // ec2: {
  77. // option: {},
  78. // },
  79. optionReady: false,
  80. option: {},
  81. optionReady2: false,
  82. option2: {},
  83. a: '',
  84. orderSelect: 2,
  85. orderOptions: [
  86. { label: '日', value: 1 },
  87. { label: '周', value: 2 },
  88. { label: '月', value: 3 },
  89. ],
  90. compareSelect: null,
  91. compareOptions: [
  92. { label: '环比', value: 1 },
  93. { label: '同比', value: 2 },
  94. ],
  95. }
  96. },
  97. onLoad(e) {
  98. waitForGlobalImages().then((path) => {
  99. this.globalImages = path
  100. })
  101. // setTimeout(() => {
  102. // this.$nextTick(() => {
  103. // this.$refs.canvas1.init(this.initChart1)
  104. // this.$refs.canvas2.init(this.initChart2)
  105. // })
  106. // }, 20)
  107. this.$Request.getT('/app/orderStatistics/getTrend?choose=week').then(res => {
  108. if (res.code == 0) {
  109. const days = res.data.map(item => item.day)
  110. const moneys = res.data.map(item => item.money)
  111. const totals = res.data.map(item => item.total)
  112. // this.$refs.canvas1.init(this.initChart1)
  113. this.setOption(days, moneys, totals)
  114. }
  115. })
  116. this.$Request.getT('/app/orderStatistics/getYoYandQoQ?choose=t').then(res => {
  117. if (res.code == 0) {
  118. const days = res.data.map(item => item.day)
  119. const lastTotals = res.data.map(item => item.lastTotal)
  120. const totals = res.data.map(item => item.total)
  121. this.setOption2(days, lastTotals, totals)
  122. }
  123. })
  124. this.getStatistics()
  125. },
  126. watch: {
  127. orderSelect(newVal) {
  128. if(newVal) {
  129. // this.$refs.canvas1.init(this.initChart1)
  130. this.optionReady = false
  131. this.getTrend()
  132. }
  133. },
  134. compareSelect(newVal) {
  135. if(newVal) {
  136. // this.$refs.canvas2.init(this.initChart2)
  137. this.optionReady2 = false
  138. this.getYoYandQoQ()
  139. }
  140. },
  141. },
  142. methods: {
  143. // 订单总量 总收入 完成率 平均分接口
  144. getStatistics(start, end) {
  145. let data = {
  146. startTime: start ? start : '',
  147. endTime: end ? end : ''
  148. }
  149. this.$Request.getT('/app/orderStatistics/getStatistics', data).then(res => {
  150. if (res.code == 0) {
  151. this.overviewData.forEach((item, index) => {
  152. if(item.title === '订单总量') {
  153. item.value = res.data.total
  154. item.fluctuate = res.data.totalChange
  155. item.status = res.data.totalChangeSymbol == 0 ? 'up' : 'down'
  156. } else if(item.title === '总收入') {
  157. item.value = res.data.money
  158. item.fluctuate = res.data.moneyChange
  159. item.status = res.data.moneyChangeSymbol == 0 ? 'up' : 'down'
  160. } else if(item.tite === '完成率') {
  161. item.value = res.data.completionRate
  162. item.fluctuate = res.data.completionRateChange
  163. item.status = res.data.completionRateChangeSymbol == 0 ? 'up' : 'down'
  164. } else {
  165. item.value = res.data.avg
  166. item.fluctuate = res.data.avgChange
  167. item.status = res.data.avgChangeSymbol == 0 ? 'up' : 'down'
  168. }
  169. })
  170. }
  171. })
  172. },
  173. // 订单与收入趋势接口
  174. getTrend() {
  175. let choo = 'week'
  176. if (this.orderSelect == 1) {
  177. choo = 'day'
  178. } else if (this.orderSelect == 2) {
  179. choo = 'week'
  180. } else {
  181. choo = 'month'
  182. }
  183. this.$Request.getT('/app/orderStatistics/getTrend?choose=' + choo).then(res => {
  184. if (res.code == 0) {
  185. const days = res.data.map(item => item.day)
  186. const moneys = res.data.map(item => item.money)
  187. const totals = res.data.map(item => item.total)
  188. // this.$refs.canvas1.init(this.initChart1)
  189. this.optionReady = false
  190. this.option={}
  191. this.setOption(days, moneys, totals)
  192. }
  193. })
  194. },
  195. // 同比环比接口
  196. getYoYandQoQ() {
  197. let choo = 't'
  198. if (this.compareSelect == 1) {
  199. choo = 'h'
  200. } else {
  201. choo = 't'
  202. }
  203. this.$Request.getT('/app/orderStatistics/getYoYandQoQ?choose=' + choo).then(res => {
  204. if (res.code == 0) {
  205. const days = res.data.map(item => item.day)
  206. const lastTotals = res.data.map(item => item.lastTotal)
  207. const totals = res.data.map(item => item.total)
  208. // this.$refs.canvas1.init(this.initChart1)
  209. this.optionReady2 = false
  210. this.option2={}
  211. this.setOption2(days, lastTotals, totals)
  212. }
  213. })
  214. },
  215. // { startYear, startMonth, startDay, startDate, startWeek, endYear, endMonth, endDay, endDate, endWeek }
  216. bindDateChange(event) {
  217. this.timeRange = event.startDate + ' - ' + event.endDate
  218. this.getStatistics(event.startDate, event.endDate)
  219. },
  220. setOption(days, moneys, totals) {
  221. console.log(days, moneys, totals, 'days, moneys, totals');
  222. this.option = {
  223. title: {
  224. text: '订单与收入趋势',
  225. left: 0,
  226. top: 0,
  227. textStyle: {
  228. fontSize: 14
  229. },
  230. },
  231. grid: {
  232. top: '36%',
  233. left: '10%',
  234. right: '5%',
  235. bottom: '20%',
  236. containLabel: true,
  237. },
  238. legend: {
  239. bottom: 0,
  240. itemGap: 20,
  241. data: ['订单量', '收入'],
  242. },
  243. tooltip: {
  244. trigger: 'axis',
  245. axisPointer: {
  246. type: 'line'
  247. },
  248. backgroundColor: 'rgba(0, 193, 138, 0.01)',
  249. borderColor: '#00c18a',
  250. textStyle: {
  251. color: '#333',
  252. },
  253. },
  254. xAxis: {
  255. type: 'category',
  256. data: days,
  257. boundaryGap: ['20%', '20%'],
  258. axisTick: {
  259. show: false,
  260. },
  261. splitLine: {
  262. show: false,
  263. },
  264. axisLine: {
  265. lineStyle: {
  266. color: '#E4E7ED',
  267. },
  268. },
  269. axisLabel: {
  270. color: '#333333',
  271. }
  272. },
  273. yAxis: [
  274. {
  275. type: 'value',
  276. name: '订单量',
  277. min: 0,
  278. nameGap: 24,
  279. nameLocation: 'end',
  280. nameTextStyle: {
  281. align: 'right',
  282. padding: [0, 10, 0, 0],
  283. color: '#333333',
  284. },
  285. boundaryGap: ['10%', '10%'],
  286. axisTick: {
  287. show: false,
  288. },
  289. axisLine: {
  290. show: false,
  291. },
  292. splitLine: {
  293. lineStyle: {
  294. color: '#E4E7ED',
  295. },
  296. },
  297. axisLabel: {
  298. color: '#333333',
  299. },
  300. splitNumber: 3,
  301. },
  302. {
  303. type: 'value',
  304. name: '收入',
  305. min: 0,
  306. nameGap: 24,
  307. nameLocation: 'end',
  308. nameTextStyle: {
  309. align: 'left',
  310. padding: [0, 0, 0, 20],
  311. color: '#333333',
  312. },
  313. axisLabel: {
  314. formatter: '¥ {value}',
  315. color: '#333333',
  316. },
  317. boundaryGap: ['10%', '10%'],
  318. axisTick: {
  319. show: false,
  320. },
  321. axisLine: {
  322. show: false,
  323. },
  324. splitLine: {
  325. lineStyle: {
  326. color: '#E4E7ED',
  327. },
  328. },
  329. splitNumber: 3,
  330. },
  331. ],
  332. series: [
  333. {
  334. name: '订单量',
  335. data: totals,
  336. type: 'bar',
  337. yAxisIndex: 0,
  338. itemStyle: {
  339. color: '#E8FBF6',
  340. borderRadius: [5, 5, 0, 0]
  341. },
  342. barWidth: 10,
  343. },
  344. {
  345. name: '收入',
  346. data: moneys,
  347. type: 'line',
  348. yAxisIndex: 1,
  349. itemStyle: {
  350. color: '#00C18A',
  351. },
  352. // symbolSize: 8,
  353. }
  354. ]
  355. }
  356. this.optionReady = true // 让组件渲染
  357. },
  358. setOption2(days, lastTotals, totals) {
  359. this.option2 = {
  360. title: {
  361. text: '数据对比',
  362. left: 0,
  363. top: 0,
  364. textStyle: {
  365. fontSize: 14
  366. },
  367. },
  368. grid: {
  369. top: '36%',
  370. left: '5%',
  371. right: '0%',
  372. bottom: '20%',
  373. containLabel: true,
  374. },
  375. legend: {
  376. bottom: 0,
  377. itemGap: 20,
  378. data: [this.compareSelect == 1 ? '本周' : '本年', this.compareSelect == 1 ? '上周' : '去年',],
  379. icon: 'roundRect',
  380. },
  381. tooltip: {
  382. trigger: 'axis',
  383. axisPointer: {
  384. type: 'line'
  385. },
  386. backgroundColor: 'rgba(0, 193, 138, 0.1)',
  387. borderColor: '#00c18a',
  388. textStyle: {
  389. color: '#333',
  390. },
  391. },
  392. xAxis: {
  393. type: 'category',
  394. data: days,
  395. boundaryGap: [50, 50],
  396. axisTick: {
  397. show: false,
  398. },
  399. splitLine: {
  400. show: false,
  401. }
  402. },
  403. yAxis: {
  404. type: 'value',
  405. name: '订单量',
  406. nameGap: 30,
  407. nameLocation: 'end',
  408. nameTextStyle: {
  409. align: 'right',
  410. padding: [0, 10, 0, 0]
  411. },
  412. boundaryGap: ['10%', '10%'],
  413. splitNumber: 4,
  414. axisTick: {
  415. show: false,
  416. },
  417. axisLine: {
  418. show: false,
  419. },
  420. splitLine: {
  421. lineStyle: {
  422. color: '#E4E7ED',
  423. },
  424. },
  425. },
  426. series: [
  427. {
  428. name: this.compareSelect == 1 ? '本周' : '本年',
  429. data: totals,
  430. type: 'bar',
  431. itemStyle: {
  432. color: '#F56C6C',
  433. borderRadius: [5, 5, 0, 0]
  434. },
  435. barWidth: 10,
  436. },
  437. {
  438. name: this.compareSelect == 1 ? '上周' : '去年',
  439. data: lastTotals,
  440. type: 'bar',
  441. itemStyle: {
  442. color: '#00C18A',
  443. borderRadius: [5, 5, 0, 0]
  444. },
  445. barWidth: 10,
  446. }
  447. ]
  448. }
  449. this.optionReady2 = true // 让组件渲染
  450. },
  451. // initChart1(canvas, width, height, canvasDpr) {
  452. // let chart = echarts.init(canvas, null, {
  453. // width: width,
  454. // height: height,
  455. // devicePixelRatio: canvasDpr
  456. // })
  457. // canvas.setChart(chart)
  458. // let option = {
  459. // title: {
  460. // text: '订单与收入趋势',
  461. // left: 0,
  462. // top: 0,
  463. // textStyle: {
  464. // fontSize: 14
  465. // },
  466. // },
  467. // grid: {
  468. // top: '36%',
  469. // left: '5%',
  470. // right: '0%',
  471. // bottom: '20%',
  472. // containLabel: true,
  473. // },
  474. // legend: {
  475. // bottom: 0,
  476. // itemGap: 20,
  477. // data: ['订单量', '收入'],
  478. // },
  479. // xAxis: {
  480. // type: 'category',
  481. // data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
  482. // boundaryGap: ['20%', '20%'],
  483. // axisTick: {
  484. // show: false,
  485. // },
  486. // splitLine: {
  487. // show: false,
  488. // },
  489. // axisLine: {
  490. // lineStyle: {
  491. // color: '#E4E7ED',
  492. // },
  493. // },
  494. // axisLabel: {
  495. // color: '#333333',
  496. // }
  497. // },
  498. // yAxis: [
  499. // {
  500. // type: 'value',
  501. // name: '订单量',
  502. // nameGap: 24,
  503. // nameLocation: 'end',
  504. // nameTextStyle: {
  505. // align: 'right',
  506. // padding: [0, 10, 0, 0],
  507. // color: '#333333',
  508. // },
  509. // boundaryGap: ['10%', '10%'],
  510. // axisTick: {
  511. // show: false,
  512. // },
  513. // axisLine: {
  514. // show: false,
  515. // },
  516. // splitLine: {
  517. // lineStyle: {
  518. // color: '#E4E7ED',
  519. // },
  520. // },
  521. // axisLabel: {
  522. // color: '#333333',
  523. // },
  524. // splitNumber: 3,
  525. // },
  526. // {
  527. // type: 'value',
  528. // name: '收入',
  529. // nameGap: 24,
  530. // nameLocation: 'end',
  531. // nameTextStyle: {
  532. // align: 'left',
  533. // padding: [0, 0, 0, 20],
  534. // color: '#333333',
  535. // },
  536. // axisLabel: {
  537. // formatter: '¥ {value}',
  538. // color: '#333333',
  539. // },
  540. // boundaryGap: ['10%', '10%'],
  541. // axisTick: {
  542. // show: false,
  543. // },
  544. // axisLine: {
  545. // show: false,
  546. // },
  547. // splitLine: {
  548. // lineStyle: {
  549. // color: '#E4E7ED',
  550. // },
  551. // },
  552. // splitNumber: 3,
  553. // },
  554. // ],
  555. // series: [
  556. // {
  557. // name: '订单量',
  558. // data: [120, 200, 150, 80, 70, 110, 130],
  559. // type: 'bar',
  560. // yAxisIndex: 0,
  561. // itemStyle: {
  562. // color: '#E8FBF6',
  563. // borderRadius: [5, 5, 0, 0]
  564. // },
  565. // barWidth: 10,
  566. // },
  567. // {
  568. // name: '收入',
  569. // data: [120, 200, 150, 80, 70, 110, 130],
  570. // type: 'line',
  571. // yAxisIndex: 1,
  572. // itemStyle: {
  573. // color: '#00C18A',
  574. // },
  575. // // symbolSize: 8,
  576. // }
  577. // ]
  578. // }
  579. // chart.setOption(option)
  580. // return chart
  581. // },
  582. // initChart2(canvas, width, height, canvasDpr) {
  583. // let chart = echarts.init(canvas, null, {
  584. // width: width,
  585. // height: height,
  586. // devicePixelRatio: canvasDpr
  587. // })
  588. // canvas.setChart(chart)
  589. // let option = {
  590. // title: {
  591. // text: '数据对比',
  592. // left: 0,
  593. // top: 0,
  594. // textStyle: {
  595. // fontSize: 14
  596. // },
  597. // },
  598. // grid: {
  599. // top: '36%',
  600. // left: '5%',
  601. // right: '0%',
  602. // bottom: '20%',
  603. // containLabel: true,
  604. // },
  605. // legend: {
  606. // bottom: 0,
  607. // itemGap: 20,
  608. // data: ['本周', '上周'],
  609. // icon: 'roundRect',
  610. // },
  611. // xAxis: {
  612. // type: 'category',
  613. // data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
  614. // boundaryGap: [50, 50],
  615. // axisTick: {
  616. // show: false,
  617. // },
  618. // splitLine: {
  619. // show: false,
  620. // }
  621. // },
  622. // yAxis: {
  623. // type: 'value',
  624. // name: '订单量',
  625. // nameGap: 30,
  626. // nameLocation: 'end',
  627. // nameTextStyle: {
  628. // align: 'right',
  629. // padding: [0, 10, 0, 0]
  630. // },
  631. // boundaryGap: ['10%', '10%'],
  632. // splitNumber: 4,
  633. // axisTick: {
  634. // show: false,
  635. // },
  636. // axisLine: {
  637. // show: false,
  638. // },
  639. // splitLine: {
  640. // lineStyle: {
  641. // color: '#E4E7ED',
  642. // },
  643. // },
  644. // },
  645. // series: [
  646. // {
  647. // name: '本周',
  648. // data: [120, 200, 150, 80, 70, 110, 130],
  649. // type: 'bar',
  650. // itemStyle: {
  651. // color: '#F56C6C',
  652. // borderRadius: [5, 5, 0, 0]
  653. // },
  654. // barWidth: 10,
  655. // },
  656. // {
  657. // name: '上周',
  658. // data: [110, 190, 130, 60, 50, 90, 110],
  659. // type: 'bar',
  660. // itemStyle: {
  661. // color: '#00C18A',
  662. // borderRadius: [5, 5, 0, 0]
  663. // },
  664. // barWidth: 10,
  665. // }
  666. // ]
  667. // }
  668. // chart.setOption(option)
  669. // return chart
  670. // },
  671. },
  672. }
  673. </script>
  674. <style lang="scss">
  675. .order-statistics {
  676. width: 100%;
  677. position: relative;
  678. padding: 16rpx 32rpx;
  679. box-sizing: border-box;
  680. .select-date {
  681. display: flex;
  682. justify-content: space-between;
  683. align-items: center;
  684. margin-top: 16rpx;
  685. }
  686. .overview-data-box {
  687. margin-top: 24rpx;
  688. display: flex;
  689. flex-wrap: wrap;
  690. gap: 24rpx; /* 控制间距 */
  691. width: 100%;
  692. .data-item {
  693. flex: 1 1 calc(50% - 24rpx);
  694. position: relative;
  695. }
  696. }
  697. }
  698. </style>