index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. <template>
  2. <div class="statistical-page" ref="container">
  3. <view v-show="isShowBox">
  4. <div class="navs">
  5. <div class="list">
  6. <div class="item" :class="time == 'today' ? 'on' : ''" @click="setTime('today')">
  7. 今天
  8. </div>
  9. <div class="item" :class="time == 'yesterday' ? 'on' : ''" @click="setTime('yesterday')">
  10. 昨天
  11. </div>
  12. <div class="item" :class="time == 'seven' ? 'on' : ''" @click="setTime('seven')">
  13. 最近7天
  14. </div>
  15. <div class="item" :class="time == 'month' ? 'on' : ''" @click="setTime('month')">
  16. 本月
  17. </div>
  18. <div class="item" :class="time == 'date' ? 'on' : ''" @click="dateTitle">
  19. <!-- <span class="iconfont icon-xiangxia"></span>
  20. <span v-for="(value, index) in renderValues" :key="index">
  21. {{ value }}</span
  22. > -->
  23. 自定义
  24. </div>
  25. </div>
  26. </div>
  27. <div class="wrapper">
  28. <div class="title">
  29. {{ title }}{{ where.type == 1 ? "营业额(元)" : "订单量(份)" }}
  30. </div>
  31. <div v-if="where.type == 1" class="money">{{ time_price }}</div>
  32. <div v-else class="money">{{ time_price }}</div>
  33. <div class="increase acea-row row-between-wrapper">
  34. <div>
  35. {{ title }}增长率:<span :class="increase_time_status === 1 ? 'red' : 'green'">{{ increase_time_status === 1 ? "" : "-" }}{{ growth_rate }}%
  36. <span class="iconfont" :class="
  37. increase_time_status === 1
  38. ? 'icon-xiangshang1'
  39. : 'icon-xiangxia2'
  40. "></span></span>
  41. </div>
  42. <div>
  43. {{ title }}增长:<span :class="increase_time_status === 1 ? 'red' : 'green'">{{ increase_time_status === 1 ? "" : "-" }}{{ increase_time }}
  44. <span class="iconfont" :class="
  45. increase_time_status === 1
  46. ? 'icon-xiangshang1'
  47. : 'icon-xiangxia2'
  48. "></span></span>
  49. </div>
  50. </div>
  51. </div>
  52. <div class="chart" v-if="showChart">
  53. <div class="chart-title">
  54. 单位({{where.type == 1?'元':'份'}})
  55. </div>
  56. <canvas canvas-id="canvasLineA" id="canvasLineA" class="charts" disable-scroll=true @touchstart="touchLineA"
  57. @touchmove="moveLineA" @touchend="touchEndLineA"></canvas>
  58. </div>
  59. <div class="public-wrapper">
  60. <div class="title">
  61. <span class="iconfont icon-xiangxishuju"></span>详细数据
  62. </div>
  63. <div class="nav acea-row row-between-wrapper">
  64. <div class="data">日期</div>
  65. <div class="browse">订单量</div>
  66. <div class="turnover">成交额</div>
  67. </div>
  68. <div class="conter">
  69. <div class="item acea-row row-between-wrapper" v-for="(item, index) in list" :key="index">
  70. <div class="data">{{ item.day }}</div>
  71. <div class="browse">{{ item.total }}</div>
  72. <div class="turnover">{{ item.pay_price }}</div>
  73. </div>
  74. </div>
  75. </div>
  76. </view>
  77. <uni-calendar ref="calendar" :date="info.date" :insert="info.insert" :lunar="info.lunar" :startDate="info.startDate"
  78. :endDate="info.endDate" :range="info.range" @confirm="confirm" :showMonth="info.showMonth" @close="close" />
  79. <div class="mask" @touchmove.prevent v-show="current === true" @click="close"></div>
  80. </div>
  81. </template>
  82. <script>
  83. // +----------------------------------------------------------------------
  84. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  85. // +----------------------------------------------------------------------
  86. // | Copyright (c) 2016~2024 https://www.crmeb.com All rights reserved.
  87. // +----------------------------------------------------------------------
  88. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  89. // +----------------------------------------------------------------------
  90. // | Author: CRMEB Team <admin@crmeb.com>
  91. // +----------------------------------------------------------------------
  92. import uCharts from '@/components/ucharts/ucharts'
  93. import uniCalendar from '@/components/uni-calendar/uni-calendar.vue'
  94. var canvaLineA = null;
  95. import {
  96. orderPrice,
  97. orderNumberStatistics,
  98. turnoverStatistics
  99. } from "@/api/admin";
  100. // import Loading from "@components/Loading";
  101. const year = new Date().getFullYear();
  102. const month = new Date().getMonth() + 1;
  103. const day = new Date().getDate();
  104. export default {
  105. name: "Statistics",
  106. components: {
  107. // Calendar,
  108. // uCharts
  109. uniCalendar
  110. },
  111. props: {},
  112. data: function() {
  113. return {
  114. isShowBox:true,
  115. showChart: false,
  116. value: [
  117. [year, month, day - 1],
  118. [year, month, day]
  119. ],
  120. isrange: true,
  121. weekSwitch: false,
  122. ismulti: false,
  123. monFirst: true,
  124. clean: false, //简洁模式
  125. lunar: false, //显示农历
  126. renderValues: [],
  127. monthRange: [],
  128. current: false,
  129. where: {
  130. start: "",
  131. stop: "",
  132. type: ""
  133. },
  134. types: "", //类型|order=订单数|price=营业额
  135. time: "", //时间|today=今天|yesterday=昨天|month=本月
  136. title: "", //时间|today=今天|yesterday=昨天|month=本月
  137. growth_rate: "", //增长率
  138. increase_time: "", //增长率
  139. increase_time_status: "", //增长率
  140. time_price: "", //增长率
  141. order_num: "", //订单量
  142. loaded: false,
  143. loading: false,
  144. filter: {
  145. page: 1,
  146. limit: 10,
  147. start: "",
  148. stop: ""
  149. },
  150. list: [],
  151. // charts
  152. cWidth: '',
  153. cHeight: '',
  154. pixelRatio: 1,
  155. textarea: '',
  156. "LineA": {
  157. "categories": ["2012", "2013", "2014", "2015", "2016", "2017"],
  158. "series": [{
  159. "data": [35, 8, 25, 37, 4, 20]
  160. }]
  161. },
  162. info: {
  163. startDate: '',
  164. endDate: '',
  165. lunar: false,
  166. range: true,
  167. insert: false,
  168. selected: [],
  169. showMonth: false
  170. },
  171. merId: ''
  172. };
  173. },
  174. watch: {
  175. "$route.params": function(newVal) {
  176. var that = this;
  177. if (newVal != undefined) {
  178. that.setType(newVal.type);
  179. that.setTime(newVal.time);
  180. that.getIndex();
  181. }
  182. }
  183. },
  184. onLoad: function(options) {
  185. this.merId = options.merId;
  186. this.setType(options.type);
  187. this.setTime(options.time);
  188. this.cWidth = uni.upx2px(690);
  189. this.cHeight = uni.upx2px(500);
  190. // this.handelRenderValues();
  191. // this.getIndex();
  192. this.getInfo();
  193. // this.$scroll(this.$refs.container, () => {
  194. // !this.loading && this.getInfo();
  195. // });
  196. },
  197. computed: {
  198. monthRangeText() {
  199. return this.monthRange.length ? "固定" : "指定范围";
  200. }
  201. },
  202. methods: {
  203. getIndex: function() {
  204. let tempDay = []
  205. let tempNum = []
  206. var that = this;
  207. that.where.type == 1 ?
  208. turnoverStatistics(that.where, that.merId).then(
  209. res => {
  210. var _info = res.data.chart,
  211. day = [],
  212. num = [];
  213. _info.forEach(function(item) {
  214. day.push(item.time);
  215. num.push(item.num);
  216. });
  217. that.growth_rate = res.data.growth_rate;
  218. that.increase_time = res.data.increase_time;
  219. that.increase_time_status = res.data.increase_time_status;
  220. that.time_price = res.data.time;
  221. res.data.chart.forEach((item, index) => {
  222. tempDay.push(item.time)
  223. tempNum.push(item.num)
  224. })
  225. that.LineA.categories = tempDay
  226. that.LineA.series[0].data = tempNum
  227. that.showLineA("canvasLineA", that.LineA);
  228. },
  229. error => {
  230. that.$dialog.error(error.msg);
  231. }
  232. ) : orderNumberStatistics(that.where, this.merId).then(
  233. res => {
  234. var _info = res.data.chart,
  235. day = [],
  236. num = [];
  237. _info.forEach(function(item) {
  238. day.push(item.time);
  239. num.push(item.num);
  240. });
  241. that.growth_rate = res.data.growth_rate;
  242. that.increase_time = res.data.increase_time;
  243. that.increase_time_status = res.data.increase_time_status;
  244. that.time_price = res.data.time;
  245. res.data.chart.forEach((item, index) => {
  246. tempDay.push(item.time)
  247. tempNum.push(item.num)
  248. })
  249. that.LineA.categories = tempDay
  250. that.LineA.series[0].data = tempNum
  251. that.showLineA("canvasLineA", that.LineA);
  252. },
  253. error => {
  254. that.$dialog.error(error.msg);
  255. }
  256. )
  257. },
  258. setTime: function(time) {
  259. let self = this
  260. this.time = time;
  261. this.showChart = true;
  262. var year = new Date().getFullYear(),
  263. month = new Date().getMonth() + 1,
  264. day = new Date().getDate();
  265. this.list = [];
  266. this.filter.page = 1;
  267. this.loaded = false;
  268. this.loading = false;
  269. switch (time) {
  270. case "today":
  271. this.showChart = false;
  272. this.where.start =
  273. new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
  274. 1000;
  275. this.where.stop =
  276. new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
  277. 1000 +
  278. 24 * 60 * 60 -
  279. 1;
  280. this.where.month = 0
  281. this.title = "今日";
  282. this.getIndex();
  283. this.getInfo();
  284. break;
  285. case "yesterday":
  286. this.showChart = false;
  287. this.where.start =
  288. new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
  289. 1000 -
  290. 24 * 60 * 60;
  291. this.where.stop =
  292. new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
  293. 1000 -
  294. 1;
  295. this.where.month = 0
  296. this.title = "昨日";
  297. this.getIndex();
  298. this.getInfo();
  299. break;
  300. case "month":
  301. this.where.start =
  302. new Date(year, new Date().getMonth(), 1).getTime() / 1000;
  303. this.where.stop = new Date(year, month, 1).getTime() / 1000 - 1;
  304. this.title = "本月";
  305. this.where.month = 1
  306. this.getIndex();
  307. this.getInfo();
  308. break;
  309. case "seven":
  310. this.where.start =
  311. new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
  312. 1000 +
  313. 24 * 60 * 60 -
  314. 7 * 3600 * 24;
  315. this.where.stop =
  316. new Date(Date.parse(year + "/" + month + "/" + day)).getTime() /
  317. 1000 +
  318. 24 * 60 * 60 -
  319. 1;
  320. this.title = "七日";
  321. this.where.month = 0
  322. this.getIndex();
  323. this.getInfo();
  324. break;
  325. }
  326. },
  327. setType: function(type) {
  328. switch (type) {
  329. case "price":
  330. this.where.type = 1;
  331. break;
  332. case "order":
  333. this.where.type = 2;
  334. break;
  335. }
  336. },
  337. dateTitle: function() {
  338. this.isShowBox = false
  339. this.$refs.calendar.open()
  340. this.time = 'date'
  341. this.title = "自定义";
  342. this.where.month = 0;
  343. // this.current = true;
  344. },
  345. close: function() {
  346. this.current = false;
  347. this.isShowBox = true
  348. },
  349. getInfo: function() {
  350. var that = this;
  351. if (that.loading || that.loaded) return;
  352. that.loading = true;
  353. that.filter.start = that.where.start;
  354. that.filter.stop = that.where.stop;
  355. orderPrice(that.filter, this.merId).then(
  356. res => {
  357. that.loading = false;
  358. that.loaded = res.data.length < that.filter.limit;
  359. that.list.push.apply(that.list, res.data);
  360. that.filter.page = that.filter.page + 1;
  361. },
  362. error => {
  363. that.$dialog.message(error.msg);
  364. }
  365. )
  366. },
  367. // 创建charts
  368. showLineA(canvasId, chartData) {
  369. let _self = this
  370. canvaLineA = new uCharts({
  371. $this: _self,
  372. canvasId: canvasId,
  373. type: 'line',
  374. fontSize: 11,
  375. padding: [15, 15, 0, 15],
  376. legend: {
  377. show: false,
  378. padding: 5,
  379. lineHeight: 11,
  380. margin: 5,
  381. },
  382. dataLabel: true,
  383. dataPointShape: true,
  384. dataPointShapeType: 'hollow',
  385. background: '#FFFFFF',
  386. pixelRatio: _self.pixelRatio,
  387. categories: chartData.categories,
  388. series: chartData.series,
  389. animation: true,
  390. enableScroll: true, //开启图表拖拽功能
  391. xAxis: {
  392. disableGrid: false,
  393. type: 'grid',
  394. gridType: 'dash',
  395. itemCount: 4,
  396. scrollShow: true,
  397. scrollAlign: 'left'
  398. },
  399. yAxis: {
  400. //disabled:true
  401. gridType: 'dash',
  402. splitNumber: 8,
  403. min: 0,
  404. max: 30,
  405. format: (val) => {
  406. return val.toFixed(0)
  407. } //如不写此方法,Y轴刻度默认保留两位小数
  408. },
  409. width: _self.cWidth * _self.pixelRatio,
  410. height: _self.cHeight * _self.pixelRatio,
  411. extra: {
  412. line: {
  413. type: 'straight'
  414. }
  415. },
  416. });
  417. },
  418. // charts触摸事件
  419. touchLineA(e) {
  420. canvaLineA.scrollStart(e);
  421. },
  422. moveLineA(e) {
  423. canvaLineA.scroll(e);
  424. },
  425. touchEndLineA(e) {
  426. canvaLineA.scrollEnd(e);
  427. },
  428. // 日历确定
  429. confirm(e) {
  430. let self = this
  431. if (e.range.after && e.range.before) {
  432. // let star = e.range.after ? new Date(e.range.after).getTime()/1000 : new Date(e.fulldate).getTime()/1000
  433. // let stop = e.range.before ? new Date(e.range.before).getTime()/1000 : new Date(e.fulldate).getTime()/1000
  434. let star = new Date(e.range.after + ' 00:00:00').getTime() / 1000
  435. let stop = new Date(e.range.before + ' 00:00:00').getTime() / 1000
  436. self.where.start = star < stop ? star : stop
  437. self.where.stop = (stop > star ? stop : star) - 1 + 86400
  438. self.where.month = 0
  439. self.list = [];
  440. self.filter.page = 1;
  441. self.loaded = false;
  442. self.loading = false;
  443. self.isShowBox = true
  444. Promise.all([self.getIndex(), self.getInfo()]);
  445. }
  446. },
  447. },
  448. onReachBottom() {
  449. this.getInfo();
  450. }
  451. };
  452. </script>
  453. <style>
  454. /*交易额统计*/
  455. .statistical-page .navs {
  456. width: 100%;
  457. height: 96upx;
  458. background-color: #fff;
  459. overflow: hidden;
  460. line-height: 96upx;
  461. position: fixed;
  462. top: 0;
  463. left: 0;
  464. z-index: 9;
  465. }
  466. .statistical-page .navs .list {
  467. overflow-y: hidden;
  468. overflow-x: auto;
  469. white-space: nowrap;
  470. -webkit-overflow-scrolling: touch;
  471. width: 100%;
  472. }
  473. .statistical-page .navs .item {
  474. font-size: 32upx;
  475. color: #282828;
  476. margin-left: 60upx;
  477. display: inline-block;
  478. }
  479. .statistical-page .navs .item.on {
  480. color: #2291f8;
  481. }
  482. .statistical-page .navs .item .iconfont {
  483. font-size: 25upx;
  484. margin-left: 13upx;
  485. }
  486. .statistical-page .wrapper {
  487. width: 740upx;
  488. background-color: #fff;
  489. border-radius: 10upx;
  490. margin: 119upx auto 0 auto;
  491. padding: 50upx 60upx;
  492. }
  493. .statistical-page .wrapper .title {
  494. font-size: 30upx;
  495. color: #999;
  496. text-align: center;
  497. }
  498. .statistical-page .wrapper .money {
  499. font-size: 72upx;
  500. color: #fba02a;
  501. text-align: center;
  502. margin-top: 10upx;
  503. }
  504. .statistical-page .wrapper .increase {
  505. font-size: 28upx;
  506. color: #999;
  507. margin-top: 20upx;
  508. }
  509. .statistical-page .wrapper .increase .red {
  510. color: #ff6969;
  511. }
  512. .statistical-page .wrapper .increase .green {
  513. color: #1abb1d;
  514. }
  515. .statistical-page .wrapper .increase .iconfont {
  516. font-size: 23upx;
  517. margin-left: 15upx;
  518. }
  519. .statistical-page .chart {
  520. width: 690upx;
  521. background-color: #fff;
  522. border-radius: 10upx;
  523. margin: 23upx auto 0 auto;
  524. /* padding: 25upx 22upx 0 22upx; */
  525. }
  526. .statistical-page .chart .chart-title {
  527. padding: 20upx 20upx 10upx;
  528. font-size: 26upx;
  529. color: #999;
  530. }
  531. .statistical-page .chart canvas {
  532. width: 100%;
  533. height: 530rpx;
  534. }
  535. .statistical-page .chart .company {
  536. font-size: 26upx;
  537. color: #999;
  538. }
  539. .yd-confirm {
  540. background-color: #fff;
  541. font-size: unset;
  542. width: 540upx;
  543. height: 250upx;
  544. border-radius: 40upx;
  545. }
  546. .yd-confirm-hd {
  547. text-align: center;
  548. }
  549. .yd-confirm-title {
  550. color: #030303;
  551. font-weight: bold;
  552. font-size: 36upx;
  553. }
  554. .yd-confirm-bd {
  555. text-align: center;
  556. font-size: 28upx;
  557. color: #333333;
  558. }
  559. .yd-confirm-ft {
  560. line-height: 90upx;
  561. margin-top: 14px;
  562. border-top: 1upx solid #eee;
  563. }
  564. .yd-confirm-ft>a {
  565. color: #e93323;
  566. }
  567. .yd-confirm-ft>a.primary {
  568. border-left: 1upx solid #eee;
  569. color: #e93323;
  570. }
  571. .echarts {
  572. width: 100%;
  573. height: 550upx;
  574. }
  575. .calendar-wrapper {
  576. position: fixed;
  577. bottom: 0;
  578. left: 0;
  579. width: 100%;
  580. z-index: 777;
  581. transform: translate3d(0, 100%, 0);
  582. transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
  583. }
  584. .calendar-wrapper.on {
  585. transform: translate3d(0, 0, 0);
  586. }
  587. .statistical-page .wrapper .increase {
  588. font-size: 26upx;
  589. }
  590. .statistical-page .wrapper .increase .iconfont {
  591. margin-left: 0;
  592. }
  593. .public-wrapper .title {
  594. font-size: 30upx;
  595. color: #282828;
  596. padding: 0 30upx;
  597. margin-bottom: 20upx;
  598. }
  599. .public-wrapper .title .iconfont {
  600. color: #2291f8;
  601. font-size: 40upx;
  602. margin-right: 13upx;
  603. vertical-align: middle;
  604. }
  605. .public-wrapper {
  606. margin: 18upx auto 0 auto;
  607. width: 690upx;
  608. background-color: #fff;
  609. border-radius: 10upx;
  610. padding-top: 25upx;
  611. }
  612. .public-wrapper .nav {
  613. padding: 0 30upx;
  614. height: 70upx;
  615. line-height: 70upx;
  616. font-size: 24upx;
  617. color: #999;
  618. }
  619. .public-wrapper .data {
  620. width: 210upx;
  621. text-align: left;
  622. }
  623. .public-wrapper .browse {
  624. width: 192upx;
  625. text-align: right;
  626. }
  627. .public-wrapper .turnover {
  628. width: 227upx;
  629. text-align: right;
  630. }
  631. .public-wrapper .conter {
  632. padding: 0 30upx;
  633. }
  634. .public-wrapper .conter .item {
  635. border-bottom: 1px solid #f7f7f7;
  636. height: 70upx;
  637. font-size: 24upx;
  638. }
  639. .public-wrapper .conter .item .turnover {
  640. color: #d84242;
  641. }
  642. </style>