index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. <template>
  2. <base-page>
  3. <view class="common-wrap">
  4. <view class="title">营业数据</view>
  5. <view class="choice-day">
  6. <view class="date-btn" :class="dateType == 'today' ? 'select' : ''" @click="switchDateType('today')"
  7. value="today">今日</view>
  8. <view class="date-btn" :class="dateType == 'yesterday' ? 'select' : ''"
  9. @click="switchDateType('yesterday')" value="yesterday">昨日</view>
  10. <view class="date-btn" :class="dateType == 'week' ? 'select' : ''" @click="switchDateType('week')"
  11. value="week">7日内</view>
  12. <view class="date-btn" :class="dateType == 'month' ? 'select' : ''" @click="switchDateType('month')"
  13. value="month">30日内</view>
  14. <view class="date-btn" :class="dateType == 'custom' ? 'select' : ''" @click="switchDateType('custom')"
  15. value="custom">自定义</view>
  16. <view class="report text-color">
  17. <text class="move iconfont iconicon-test"></text>
  18. <text></text>
  19. </view>
  20. </view>
  21. <view class="money" v-if="businessdata">
  22. <view class="estimate" :class="statType == 'expected_earnings_total_money' ? 'estimate-active' : ''">
  23. <view class="income">
  24. <text class="income-name">预计收入(元)</text>
  25. <!-- <uni-dropdown>
  26. <view class="action" slot="dropdown-link"><i class="iconfont iconbangzhu js-prompt-top"></i></view>
  27. <view slot="dropdown">
  28. <view class="dropdown-content-box">
  29. <view class="text">弹框展示内容</view>
  30. <view class="arrow"></view>
  31. </view>
  32. </view>
  33. </uni-dropdown> -->
  34. </view>
  35. <view class="num-money">
  36. <text class="last_income">{{ businessdata.expected_earnings_total_money || 0.0 }}</text>
  37. <text class="detail" @click="switchStatType('expected_earnings_total_money')">查看详情</text>
  38. </view>
  39. </view>
  40. <view class="estimate" :class="statType == 'billing_money' ? 'estimate-active' : ''">
  41. <view class="income">
  42. <text class="income-name">开单金额数(元)</text>
  43. <!-- <uni-dropdown>
  44. <view class="action" slot="dropdown-link"><i class="iconfont iconbangzhu js-prompt-top"></i></view>
  45. <view slot="dropdown">
  46. <view class="dropdown-content-box">
  47. <view class="text">弹框展示内容</view>
  48. <view class="arrow"></view>
  49. </view>
  50. </view>
  51. </uni-dropdown> -->
  52. </view>
  53. <view class="num-money">
  54. <text class="last_income">{{ businessdata.billing_money || 0.0 }}</text>
  55. <text class="detail" @click="switchStatType('billing_money')">查看详情</text>
  56. </view>
  57. </view>
  58. <view class="estimate" :class="statType == 'billing_count' ? 'estimate-active' : ''">
  59. <view class="income"><text class="income-name">开单数量</text></view>
  60. <view class="num-money">
  61. <text class="last_income">{{ businessdata.billing_count || 0 }}</text>
  62. <text class="detail" @click="switchStatType('billing_count')">查看详情</text>
  63. </view>
  64. </view>
  65. <view class="estimate" :class="statType == 'buycard_money' ? 'estimate-active' : ''">
  66. <view class="income"><text class="income-name">办卡金额数(元)</text></view>
  67. <view class="num-money">
  68. <text class="last_income">{{ businessdata.buycard_money || 0.0 }}</text>
  69. <text class="detail" @click="switchStatType('buycard_money')">查看详情</text>
  70. </view>
  71. </view>
  72. <view class="estimate" :class="statType == 'buycard_count' ? 'estimate-active' : ''">
  73. <view class="income"><text class="income-name">办卡数</text></view>
  74. <view class="num-money">
  75. <text class="last_income">{{ businessdata.buycard_count || 0 }}</text>
  76. <text class="detail" @click="switchStatType('buycard_count')">查看详情</text>
  77. </view>
  78. </view>
  79. <view class="estimate" :class="statType == 'recharge_money' ? 'estimate-active' : ''">
  80. <view class="income"><text class="income-name">会员充值金额(元)</text></view>
  81. <view class="num-money">
  82. <text class="last_income">{{ businessdata.recharge_money || 0.0 }}</text>
  83. <text class="detail" @click="switchStatType('recharge_money')">查看详情</text>
  84. </view>
  85. </view>
  86. <view class="estimate" :class="statType == 'recharge_count' ? 'estimate-active' : ''">
  87. <view class="income"><text class="income-name">会员充值数量</text></view>
  88. <view class="num-money">
  89. <text class="last_income">{{ businessdata.recharge_count || 0 }}</text>
  90. <text class="detail" @click="switchStatType('recharge_count')">查看详情</text>
  91. </view>
  92. </view>
  93. <view class="estimate" :class="statType == 'refund_money' ? 'estimate-active' : ''">
  94. <view class="income"><text class="income-name">会员退款金额(元)</text></view>
  95. <view class="num-money">
  96. <text class="last_income">{{ businessdata.refund_money || 0.0 }}</text>
  97. <text class="detail" @click="switchStatType('refund_money')">查看详情</text>
  98. </view>
  99. </view>
  100. <view class="estimate" :class="statType == 'refund_count' ? 'estimate-active' : ''">
  101. <view class="income"><text class="income-name">会员退款数量</text></view>
  102. <view class="num-money">
  103. <text class="last_income">{{ businessdata.refund_count || 0 }}</text>
  104. <text class="detail" @click="switchStatType('refund_count')">查看详情</text>
  105. </view>
  106. </view>
  107. <view class="estimate" :class="statType == 'order_member_count' ? 'estimate-active' : ''">
  108. <view class="income"><text class="income-name">门店下单会员数</text></view>
  109. <view class="num-money">
  110. <text class="last_income">{{ businessdata.order_member_count || 0 }}</text>
  111. <text class="detail" @click="switchStatType('order_member_count')">查看详情</text>
  112. </view>
  113. </view>
  114. <view class="estimate" :class="statType == 'balance_money' ? 'estimate-active' : ''">
  115. <view class="income"><text class="income-name">会员余额消费金额</text></view>
  116. <view class="num-money">
  117. <text class="last_income">{{ businessdata.balance_money || 0.0 }}</text>
  118. <text class="detail" @click="switchStatType('balance_money')">查看详情</text>
  119. </view>
  120. </view>
  121. </view>
  122. </view>
  123. <uni-popup ref="customTime">
  124. <view class="pop-box">
  125. <view class="pop-header">
  126. <view class="pop-header-text">自定义时间选择</view>
  127. <view class="pop-header-close" @click="$refs.customTime.close()"><i
  128. class="iconguanbi1 iconfont"></i></view>
  129. </view>
  130. <view class="pop-content ">
  131. <uni-datetime-picker v-model="timeObj.custom" @change="changeTime" :end="endDate" :clearIcon="false"
  132. type="datetimerange" rangeSeparator="至" />
  133. </view>
  134. <view class="pop-bottom"><button class="primary-btn" @click="getStatData()">确定</button></view>
  135. </view>
  136. </uni-popup>
  137. <uni-popup ref="chartsPop">
  138. <view class="pop-box charts-pop">
  139. <view class="pop-header">
  140. <view class="pop-header-text">运营数据图表展示</view>
  141. <view class="pop-header-close" @click="$refs.chartsPop.close()"><i class="iconguanbi1 iconfont"></i>
  142. </view>
  143. </view>
  144. <view class="pop-content">
  145. <qiun-data-charts type="line" :chartData="chartData" :eopts="{ seriesTemplate: { smooth: true } }"
  146. :ontouch="true" :opts="chartsOpts" />
  147. </view>
  148. <!-- <view class="pop-bottom"><button class="primary-btn" @click="getStatData()">确定</button></view> -->
  149. </view>
  150. </uni-popup>
  151. </base-page>
  152. </template>
  153. <script>
  154. export default {
  155. data() {
  156. return {
  157. statType: 'expected_earnings_total_money',
  158. statTypeArr: {
  159. expected_earnings_total_money: '预计收入',
  160. billing_money: '开单金额数',
  161. billing_count: '开单数量',
  162. buycard_money: '办卡金额数',
  163. buycard_count: '办卡数',
  164. recharge_money: '会员充值金额',
  165. recharge_count: '会员充值数量',
  166. refund_money: '会员退款金额',
  167. refund_count: '会员退款数量',
  168. order_member_count: '门店下单会员数',
  169. balance_money: '会员余额消费金额'
  170. },
  171. dateType: 'today',
  172. timeObj: {
  173. today: [],
  174. yesterday: [],
  175. week: [],
  176. month: [],
  177. custom: []
  178. },
  179. chartData: {
  180. categories: [],
  181. series: []
  182. },
  183. businessdata: null,
  184. chartsOpts: {
  185. enableScroll: true,
  186. xAxis: {
  187. scrollShow: true,
  188. itemCount: 24,
  189. disableGrid: true
  190. }
  191. }
  192. };
  193. },
  194. onLoad() {
  195. this.setDate();
  196. this.getStatData();
  197. },
  198. onShow() {
  199. let date = new Date();
  200. var y = date.getFullYear();
  201. var m = date.getMonth() + 1;
  202. var d = date.getDate();
  203. this.endDate = y + '-' + m + '-' + d + ' 23:59:59';
  204. },
  205. methods: {
  206. // 重置图表数据
  207. resetChartData() {
  208. this.chartData.categories = [];
  209. this.chartData.series = [];
  210. },
  211. setDate() {
  212. let time = this.$util.timeTurnTimeStamp(this.$util.timeFormat(Date.now() / 1000, 'y-m-d'));
  213. this.timeObj.today = [time, time + 86399];
  214. this.timeObj.yesterday = [time - 86400, time - 1];
  215. this.timeObj.week = [time - 604800, time];
  216. this.timeObj.month = [time - 2592000, time];
  217. },
  218. switchDateType(type) {
  219. this.dateType = type;
  220. if (type == 'custom') {
  221. this.$refs.customTime.open();
  222. return false;
  223. }
  224. if (type == 'month') this.chartsOpts.xAxis.itemCount = 10;
  225. else this.chartsOpts.xAxis.itemCount = 24;
  226. this.getStatData();
  227. },
  228. switchStatType(type) {
  229. this.statType = type;
  230. this.$refs.chartsPop.open();
  231. this.resetChartData();
  232. this.getStatData();
  233. setTimeout(() => {
  234. this.getChartData();
  235. }, 500);
  236. },
  237. changeTime(e) {
  238. this.timeObj.custom = e;
  239. this.chartsOpts.xAxis.itemCount = 10;
  240. },
  241. getStatData() {
  242. if (this.dateType == 'custom') {
  243. this.$refs.customTime.close();
  244. this.timeObj.custom[0] = this.$util.timeTurnTimeStamp(this.timeObj.custom[0]) *
  245. 1000; // 解决自定义数据保存之后再次点击出现的数据错乱
  246. this.timeObj.custom[1] = this.$util.timeTurnTimeStamp(this.timeObj.custom[1]) *
  247. 1000; // 解决自定义数据保存之后再次点击出现的数据错乱
  248. }
  249. this.getBusinessData();
  250. },
  251. getChartData() {
  252. let url = '/cashier/storeapi/stat/dayStatData';
  253. let data = {};
  254. data.start_time = this.timeObj[this.dateType][0];
  255. if (this.dateType == 'today' || this.dateType == 'yesterday') url = '/cashier/storeapi/stat/hourStatData';
  256. else data.end_time = this.timeObj[this.dateType][1];
  257. this.$api.sendRequest({
  258. url: url,
  259. data: data,
  260. success: res => {
  261. if (res.code >= 0) {
  262. this.chartData.series = [];
  263. this.chartData.series.push({
  264. data: res.data[this.statType],
  265. name: this.statTypeArr[this.statType]
  266. });
  267. this.chartData.categories = res.data.time;
  268. }
  269. }
  270. });
  271. },
  272. getBusinessData() {
  273. let data = {};
  274. data.start_time = this.dateType == 'custom' ? parseInt(this.timeObj[this.dateType][0] / 1000) : parseInt(
  275. this.timeObj[this.dateType][0]);
  276. data.end_time = this.dateType == 'custom' ? parseInt(this.timeObj[this.dateType][1] / 1000) : parseInt(this
  277. .timeObj[this.dateType][1]);
  278. this.$api.sendRequest({
  279. url: '/cashier/storeapi/stat/statTotal',
  280. data: data,
  281. success: res => {
  282. if (res.code >= 0) {
  283. this.businessdata = res.data;
  284. }
  285. }
  286. });
  287. }
  288. }
  289. };
  290. </script>
  291. <style>
  292. .stat-input-inline .uni-date {}
  293. .pop-content>>>.uni-icons {
  294. line-height: 0.32rem;
  295. }
  296. </style>
  297. <style lang="scss" scoped>
  298. .common-wrap {
  299. padding: 0.2rem;
  300. height: 100vh;
  301. box-sizing: border-box;
  302. }
  303. .title {
  304. display: flex;
  305. margin-bottom: 0.21rem;
  306. font-size: 0.16rem;
  307. font-family: Source Han Sans CN;
  308. font-weight: bold;
  309. line-height: 0.2rem;
  310. }
  311. .choice-day {
  312. display: flex;
  313. }
  314. .choice-time {
  315. margin-top: 0.09rem;
  316. font-size: 0.12rem;
  317. font-family: Source Han Sans CN;
  318. font-weight: 400;
  319. line-height: 0.36rem;
  320. }
  321. .report {
  322. display: flex;
  323. justify-content: flex-end;
  324. margin-right: 0.2rem;
  325. font-size: 0.14rem;
  326. font-family: Source Han Sans CN;
  327. font-weight: 400;
  328. line-height: 0.36rem;
  329. cursor: pointer;
  330. }
  331. .move {
  332. margin-right: 0.06rem;
  333. }
  334. .money {
  335. display: flex;
  336. flex-wrap: wrap;
  337. margin-top: 0.35rem;
  338. .estimate {
  339. width: calc((100% - 0.85rem) / 5);
  340. margin: 0 0.08rem 0.2rem;
  341. padding: 0.2rem;
  342. background: #fff;
  343. border: 0.01rem solid #eee;
  344. border-radius: 0.02rem;
  345. cursor: pointer;
  346. position: relative;
  347. box-sizing: border-box;
  348. .income {
  349. display: flex;
  350. flex-direction: row;
  351. box-sizing: border-box;
  352. line-height: 0.2rem;
  353. .income-name {
  354. font-size: 0.16rem;
  355. }
  356. }
  357. .num-money {
  358. .last_income {
  359. display: block;
  360. margin: 0.15rem 0;
  361. font-size: 0.24rem;
  362. font-weight: 500;
  363. line-height: 0.2rem;
  364. }
  365. .detail {
  366. display: block;
  367. text-align: right;
  368. color: $primary-color;
  369. font-size: $uni-font-size-sm;
  370. position: relative;
  371. bottom: -0.05rem;
  372. }
  373. }
  374. }
  375. .estimate:last-child {
  376. margin-right: 0;
  377. }
  378. }
  379. .jantou {
  380. margin-top: 0.05rem;
  381. padding-left: 0.1rem;
  382. height: 0.11rem;
  383. }
  384. .yesterday {
  385. display: flex;
  386. flex-wrap: wrap;
  387. font-size: 0.12rem;
  388. }
  389. .top-num {
  390. display: flex;
  391. margin-left: 0.05rem;
  392. font-size: 0.12rem;
  393. font-weight: 400;
  394. }
  395. .date-btn {
  396. height: 0.42rem;
  397. line-height: 0.42rem;
  398. font-size: 0.14rem;
  399. padding: 0 0.3rem;
  400. box-sizing: border-box;
  401. border: 0.01rem solid #d2d2d2;
  402. cursor: pointer;
  403. border-right: none;
  404. border-left: none;
  405. position: relative;
  406. }
  407. .date-btn:nth-child(6)::after {
  408. border-radius: 0 0.02rem 0.02rem 0;
  409. }
  410. .date-btn:first-child::after {
  411. border-radius: 0.02rem 0 0 0.02rem;
  412. }
  413. .date-btn:first-child {
  414. border-radius: 0.02rem 0 0 0.02rem;
  415. }
  416. .date-btn::after {
  417. content: '';
  418. position: absolute;
  419. top: -0.01rem;
  420. left: 0;
  421. bottom: -0.01rem;
  422. right: -0.01rem;
  423. border-right: 0.01rem solid #d2d2d2;
  424. border-left: 0.01rem solid #d2d2d2;
  425. }
  426. .select {
  427. color: #fff;
  428. background-color: $primary-color;
  429. border-color: $primary-color;
  430. }
  431. .select::after {
  432. z-index: 2;
  433. border-color: $primary-color;
  434. }
  435. .select:first-child {
  436. border-radius: 0.02rem 0 0 0.02rem;
  437. }
  438. .seleced:nth-child(6) {
  439. border-radius: 0 0.02rem 0.02rem 0;
  440. }
  441. .c-datepicker-picker {
  442. z-index: 99999999 !important;
  443. }
  444. .yesterday {
  445. display: none;
  446. }
  447. .dropdown-content-box {
  448. padding: 0.05rem 0;
  449. margin-top: 0.05rem;
  450. background-color: #fff;
  451. border: 0.01rem solid #ebeef5;
  452. border-radius: 0.04rem;
  453. box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
  454. position: relative;
  455. .arrow {
  456. position: absolute;
  457. top: -0.06rem;
  458. right: 0.06rem;
  459. width: 0;
  460. height: 0;
  461. border-left: 0.06rem solid transparent;
  462. border-right: 0.06rem solid transparent;
  463. border-bottom: 0.06rem solid #fff;
  464. }
  465. .text {
  466. display: flex;
  467. align-items: center;
  468. justify-content: center;
  469. margin: 0;
  470. padding: 0 0.1rem;
  471. transition: all 0.3s;
  472. font-size: 0.12rem;
  473. width: 1.5rem;
  474. box-sizing: border-box;
  475. text-align: left;
  476. line-height: 1.5;
  477. }
  478. }
  479. .js-prompt-top {
  480. color: #c8c9cc;
  481. font-size: 0.14rem;
  482. z-index: 999;
  483. margin-left: 0.05rem;
  484. cursor: pointer;
  485. }
  486. // pop弹框
  487. .pop-box {
  488. background: #ffffff;
  489. width: 6rem;
  490. height: 3.38rem;
  491. .pop-header {
  492. padding: 0 0.15rem 0 0.2rem;
  493. height: 0.5rem;
  494. line-height: 0.5rem;
  495. border-bottom: 0.01rem solid #f0f0f0;
  496. font-size: 0.14rem;
  497. color: #333;
  498. overflow: hidden;
  499. border-radius: 0.02rem 0.2rem 0 0;
  500. box-sizing: border-box;
  501. display: flex;
  502. justify-content: space-between;
  503. .pop-header-text {}
  504. .pop-header-close {
  505. cursor: pointer;
  506. i {
  507. font-size: 0.18rem;
  508. }
  509. }
  510. }
  511. .pop-content {
  512. height: calc(100% - 1.05rem);
  513. // overflow-y: scroll;
  514. padding: 0.2rem;
  515. box-sizing: border-box;
  516. }
  517. .pop-bottom {
  518. padding: 0.1rem;
  519. height: 0.65rem;
  520. border-top: 0.01rem solid #eee;
  521. button {
  522. width: 95%;
  523. }
  524. }
  525. }
  526. .charts-pop {
  527. width: 9.5rem;
  528. height: 5.4rem;
  529. background-color: #fff;
  530. .pop-content {
  531. width: 100%;
  532. height: calc(100% - 1rem);
  533. }
  534. }
  535. </style>