Home.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. <template>
  2. <div class="home">
  3. <a-alert message="欢迎登录合作商运营管理平台系统" type="info" showIcon />
  4. <div class="report-page">
  5. <!-- 查询条件 -->
  6. <a-row>
  7. <a-card class="search-panel">
  8. <div class="toolsBar">
  9. <a-form ref="searchForm" :model="searchForm" layout="inline">
  10. <a-form-item props="queryWord" label="统计区间">
  11. <a-range-picker
  12. style="width: 220px;"
  13. @change="dateChange"
  14. id="statistics-queryWord"
  15. v-model.trim="searchForm.queryWord"
  16. :disabledDate="disabledDate"
  17. />
  18. </a-form-item>
  19. <a-form-item>
  20. 快捷筛选:
  21. <span
  22. :class="['searchItem',curentType==item.type?'active':'']"
  23. id="statistics-quick"
  24. v-for="(item,index) in tabList"
  25. :key="index"
  26. @click="getCurentSearchTime(item)">{{ item.name }}</span>
  27. </a-form-item>
  28. </a-form>
  29. </div>
  30. </a-card>
  31. </a-row>
  32. <!-- 业务量数据 -->
  33. <a-card class="panel" title="按业务量统计">
  34. <!-- 业务量趋势图表展示 -->
  35. <chart-line
  36. style="height: 350px;"
  37. color="#6C6FBE"
  38. :yMax="200"
  39. yUnit="单"
  40. :xAxisRotate="resize"
  41. :xAxisData="XdaysData"
  42. :seriesData="washCarsChartData"
  43. text="" />
  44. <span v-if="isNoData" class="noData">暂无数据</span>
  45. </a-card>
  46. <!-- 按各类型套餐销量查看 -->
  47. <a-card class="panel " title="按各类型套餐销量查看">
  48. <a-row :gutter="24">
  49. <a-col :md="4" :lg="4">
  50. <a-card class="border-radius background-skyblue">
  51. <div class="module-list ">
  52. <span>{{ chartData.xmbundleNum }}</span>
  53. <p>洗美套餐</p>
  54. </div>
  55. </a-card>
  56. </a-col>
  57. <a-col :md="4" :lg="4">
  58. <a-card class="border-radius background-greenBlue">
  59. <div class="module-list ">
  60. <span>{{ chartData.bybundleNum }}</span>
  61. <p>保养套餐</p>
  62. </div>
  63. </a-card>
  64. </a-col>
  65. <a-col :md="4" :lg="4">
  66. <a-card class="border-radius background-blackGreen">
  67. <div class="module-list ">
  68. <span>{{ chartData.xtyhbundleNum }}</span>
  69. <p>系统养护套餐</p>
  70. </div>
  71. </a-card>
  72. </a-col>
  73. </a-row>
  74. <!-- 套餐类型数据图表展示 -->
  75. <a-row :gutter="24">
  76. <a-col class="tab-card">
  77. <span :class="['tab-card-item',currentTabChart=='tab1'?'checked-item':'']" @click="currentTabChart='tab1'">详情数据</span>
  78. <span :class="['tab-card-item',currentTabChart=='tab2'?'checked-item':'']" @click="currentTabChart='tab2'">变化趋势</span>
  79. </a-col>
  80. <!-- 详情数据 -->
  81. <a-col span="24" v-if="currentTabChart=='tab1'">
  82. <chart-bar
  83. ref="ChartBar"
  84. style="height: 350px;"
  85. color="#6C6FBE"
  86. :xAxisRotate="resize"
  87. :yMax="200"
  88. yUnit="单"
  89. :xAxisData="XdaysData"
  90. :seriesData="washTypeBarData"
  91. text="" />
  92. <span v-if="isNoData" class="noData">暂无数据</span>
  93. </a-col>
  94. <!-- 变化趋势 -->
  95. <a-col span="24" v-if="currentTabChart=='tab2'">
  96. <chart-line
  97. ref="ChartLine"
  98. style="height: 350px;"
  99. color="#6C6FBE"
  100. :yMax="200"
  101. yUnit="单"
  102. :xAxisRotate="resize"
  103. :xAxisData="XdaysData"
  104. :seriesData="washTypeLineData"
  105. text="" />
  106. <span v-if="isNoData" class="noData">暂无数据</span>
  107. </a-col>
  108. </a-row>
  109. </a-card>
  110. <a-card class="panel chart-pie" title="各类型套餐销量分布">
  111. <a-row :gutter="24">
  112. <a-col span="12">
  113. <chart-pie
  114. ref="chartPie"
  115. class="chartPie-box"
  116. :searchData="XdaysData"
  117. :value="washTypePieData"
  118. title="套餐销售量(单)"
  119. :total="chartData.bundleNum"
  120. :color="washTypePieColor"
  121. :xAxisRotate="resize"
  122. text="" />
  123. </a-col>
  124. <a-col span="12">
  125. <!-- 套餐内总服务项目数使用展示 -->
  126. <chart-pie
  127. ref="serverChartPie"
  128. class="chartPie-box"
  129. :searchData="XdaysData"
  130. :value="couponChartData"
  131. title="套餐内总服务项目数(次)"
  132. :total="chartData.itemNum"
  133. :color="couponColor"
  134. :xAxisRotate="resize"
  135. text="" />
  136. </a-col>
  137. </a-row>
  138. </a-card>
  139. </div>
  140. </div>
  141. </template>
  142. <script>
  143. import {
  144. ChartPie,
  145. ChartBar,
  146. ChartLine
  147. } from '@/components/Echarts'
  148. import _ from 'lodash'
  149. import getDate from '@/libs/getDate'
  150. import moment from 'moment'
  151. import { getOrderstatistics } from '@/api/report-charts.js'
  152. export default {
  153. name: 'Home',
  154. components: {
  155. ChartPie,
  156. ChartBar,
  157. ChartLine
  158. },
  159. watch: {
  160. screenWidth (val) {
  161. // 为了避免频繁触发resize函数,使用定时器
  162. if (!this.timer) {
  163. this.screenWidth = val
  164. this.timer = true
  165. const that = this
  166. setTimeout(function () {
  167. // that.screenWidth = that.$store.state.canvasWidth
  168. console.log(that.screenWidth)
  169. that.timer = false
  170. }, 400)
  171. }
  172. }
  173. },
  174. computed: {
  175. resize () {
  176. console.log(this.screenWidth, 'this.screenWidth')
  177. if (this.screenWidth < 1640) {
  178. return 60
  179. } else {
  180. return 0
  181. }
  182. },
  183. // 各类型占比总计数据
  184. washTypePieData () {
  185. const data = [{
  186. 'name': '洗美套餐',
  187. 'value': this.chartData.xmbundleNum
  188. }, {
  189. 'name': '保养套餐',
  190. 'value': this.chartData.bybundleNum
  191. }, {
  192. 'name': '系统养护套餐',
  193. 'value': this.chartData.xtyhbundleNum
  194. }]
  195. return data
  196. },
  197. // 套餐内总服务项目数占比数据
  198. couponChartData () {
  199. const data = [{
  200. 'name': '套餐服务核销量',
  201. 'value': this.chartData.itemUsedNum
  202. }, {
  203. 'name': '套餐服务未核销量',
  204. 'value': this.chartData.itemUnUsedNum
  205. }]
  206. return data
  207. }
  208. },
  209. data () {
  210. return {
  211. screenWidth: document.body.clientWidth, // 这里是给到了一个默认值
  212. timer: false,
  213. form: this.$form.createForm(this, { name: 'searchForm' }),
  214. isNoData: false, // 是否有每天营业额及进店量数据
  215. searchForm: {
  216. queryWord: null // 时间查询条件,默认本周
  217. },
  218. chartData: {
  219. xmbundleNum: 0, // 洗美套餐
  220. bybundleNum: 0, // 保养套餐
  221. xtyhbundleNum: 0, // 系统养护套餐
  222. itemNum: 0, // 服务数量
  223. itemUsedNum: 0, // 已使用服务数量
  224. itemUnUsedNum: 0, // 未使用服务数量
  225. bundleNum: 0 // 套餐销售量
  226. },
  227. // 快速删选tab
  228. tabList: [{
  229. name: '今天',
  230. type: 'today'
  231. },
  232. {
  233. name: '本周',
  234. type: 'thisWeek'
  235. },
  236. {
  237. name: '上周',
  238. type: 'lastWeek'
  239. },
  240. {
  241. name: '本月',
  242. type: 'thisMonth'
  243. }
  244. ],
  245. curentType: 'thisWeek', // 当前所选时间查询类型
  246. beginDate: null, // 开始时间
  247. endDate: null, // 结束时间
  248. // 套餐量图表数据
  249. washCarsChartData: [{
  250. name: '当日套餐销售量',
  251. type: 'line',
  252. data: []
  253. },
  254. {
  255. name: '当日套餐使用量',
  256. type: 'line',
  257. data: []
  258. }
  259. ],
  260. couponColor: ['#d48265', '#ff55ff'],
  261. // 套餐类型数据
  262. currentTabChart: 'tab1', // 套餐类型详情数据与变化趋势的tab 默认展示详情数据
  263. XdaysData: [], // 图表X轴时间集合
  264. // 套餐类型柱状图表数据
  265. washTypeBarData: [{
  266. name: '洗美套餐',
  267. type: 'bar',
  268. data: []
  269. },
  270. {
  271. name: '保养套餐',
  272. type: 'bar',
  273. data: []
  274. },
  275. {
  276. name: '系统养护套餐',
  277. type: 'bar',
  278. data: []
  279. }
  280. ],
  281. // 套餐类型折线图表数据
  282. washTypeLineData: [{
  283. name: '洗美套餐',
  284. type: 'line',
  285. data: []
  286. },
  287. {
  288. name: '保养套餐',
  289. type: 'line',
  290. data: []
  291. },
  292. {
  293. name: '系统养护套餐',
  294. type: 'line',
  295. data: []
  296. }
  297. ],
  298. // 各类型占比
  299. washTypePieColor: ['#ffaa00', '#00ff00', '#00aaff', '#ff55ff', '#1dc5d4', '#8465c7', '#00ffff'],
  300. databack: {
  301. couponChartData: [],
  302. washTypePieData: [],
  303. chartData: {}
  304. }
  305. }
  306. },
  307. methods: {
  308. moment,
  309. // 时间改变
  310. dateChange (dates) {
  311. this.curentType = ''
  312. this.handleSearch()
  313. },
  314. // 不可选日期
  315. disabledDate (date) {
  316. return (date && date.valueOf() > Date.now()) || (date.valueOf() < Date.now() - (90 * 24 * 60 * 60 * 1000))
  317. },
  318. // 页面初始化
  319. pageInit () {
  320. this.form.resetFields()
  321. this.databack = {
  322. couponChartData: _.cloneDeep(this.couponChartData),
  323. washTypePieData: _.cloneDeep(this.washTypePieData),
  324. chartData: _.cloneDeep(this.chartData)
  325. }
  326. },
  327. // 查询
  328. handleSearch () {
  329. this.showChart = false
  330. if (this.searchForm.queryWord != ',' && this.searchForm.queryWord.length) {
  331. const searchTime = this.searchForm.queryWord.toString().split(',')
  332. this.beginDate = this.exitTime(searchTime[0])
  333. this.endDate = this.exitTime(searchTime[1])
  334. this.getPageData()
  335. } else {
  336. this.$message.error('请选择统计区间')
  337. }
  338. },
  339. // 格式化时间
  340. exitTime (time) {
  341. const D = new Date(time)
  342. const RES_DATE = D.getFullYear() + '-' + this.p((D.getMonth() + 1)) + '-' + this.p(D.getDate())
  343. return RES_DATE
  344. },
  345. // p为不够10添加0的函数
  346. p (s) {
  347. return s < 10 ? '0' + s : s
  348. },
  349. // 获取快速查询时间 并 赋值到时间选择框中
  350. getCurentSearchTime (item) {
  351. this.curentType = item ? item.type : this.curentType
  352. const quickType = {
  353. lastMonth: [moment(getDate.getLastMonthDays().starttime), moment(getDate.getLastMonthDays().endtime)],
  354. thisMonth: [moment(getDate.getCurrMonthDays().starttime), moment(getDate.getCurrMonthDays().endtime)],
  355. lastWeek: [moment(getDate.getLastWeekDays().starttime), moment(getDate.getLastWeekDays().endtime)],
  356. thisWeek: [moment(getDate.getCurrWeekDays().starttime), moment(getDate.getCurrWeekDays().endtime)],
  357. yesterday: [moment(getDate.getYesterday().starttime), moment(getDate.getYesterday().endtime)],
  358. today: [moment(getDate.getToday().starttime), moment(getDate.getToday().endtime)]
  359. }
  360. this.searchForm.queryWord = quickType[this.curentType]
  361. this.beginDate = quickType[this.curentType][0].format('YYYY-MM-DD')
  362. this.endDate = quickType[this.curentType][1].format('YYYY-MM-DD')
  363. this.getPageData()
  364. },
  365. // 根据查询条件获取所有数据
  366. getPageData () {
  367. this.XdaysData = [] // x轴置空
  368. const _date = {
  369. beginDate: this.beginDate,
  370. endDate: this.endDate
  371. }
  372. getOrderstatistics(_date).then(res => {
  373. if (res.status == 200) {
  374. this.chartData = res.data
  375. if (res.data.dateList && res.data.dateList.length) {
  376. this.isNoData = false
  377. this.filterData(res.data.dateList)
  378. } else {
  379. this.isNoData = true
  380. }
  381. } else {
  382. this.isNoData = true
  383. }
  384. })
  385. },
  386. // 整合图表每天数据
  387. filterData (data) {
  388. const days = [] // 日期合集
  389. const kxData = [] // 洗美套餐数据
  390. const jxData = [] // 保养套餐数据
  391. const dlxData = [] // 系统养护套餐数据
  392. const totalData = [] // 当日套餐销售量数据
  393. const useCouponData = [] // 当日套餐使用量数据
  394. console.log(data, '--data')
  395. data.map(item => {
  396. const itemDay = item.date.split('-')
  397. const month = Number(itemDay[1])
  398. const day = Number(itemDay[2])
  399. const time = month + '月' + day + '日'
  400. days.push(time)
  401. kxData.push(item.xmbundleNum)
  402. jxData.push(item.bybundleNum)
  403. dlxData.push(item.xtyhbundleNum)
  404. totalData.push(item.bundleNum)
  405. useCouponData.push(item.customerBundleUsedNum)
  406. })
  407. this.XdaysData = days
  408. const washTypeData = [kxData, jxData, dlxData]
  409. console.log(washTypeData, 'washTypeData')
  410. // 套餐类型柱状图表数据
  411. this.washTypeBarData.map((item, index) => {
  412. item.data = washTypeData[index]
  413. })
  414. // 套餐类型折线图表数据
  415. this.washTypeLineData.map((item, index) => {
  416. item.data = washTypeData[index]
  417. })
  418. // 套餐量图表数据赋值
  419. this.washCarsChartData[0].data = totalData
  420. this.washCarsChartData[1].data = useCouponData
  421. }
  422. },
  423. beforeRouteEnter (to, from, next) {
  424. next(vm => {
  425. vm.pageInit()
  426. vm.curentType = 'thisWeek'
  427. vm.getCurentSearchTime()
  428. })
  429. },
  430. // 将 reisze 事件在 vue mounted 的时候 去挂载一下它的方法
  431. mounted () {
  432. const that = this
  433. window.onresize = () => {
  434. return (() => {
  435. window.screenWidth = document.body.clientWidth
  436. that.screenWidth = window.screenWidth
  437. })()
  438. }
  439. }
  440. }
  441. </script>
  442. <style lang="less" scoped>
  443. .home{
  444. width: 100%;
  445. }
  446. .report-page {
  447. margin-top: 10px;
  448. height: calc(100vh - 285px);
  449. overflow-y: scroll;
  450. overflow-x: hidden;
  451. .search-panel {
  452. .ivu-card-body>div {
  453. display: inline-block;
  454. margin-right: 20px;
  455. }
  456. .desc {
  457. color: #999;
  458. }
  459. .searchItem {
  460. padding: 8px 20px;
  461. border: 1px dashed #EEEEEE;
  462. margin: 0 5px;
  463. border-radius: 5px;
  464. }
  465. .active {
  466. background-color: #ff9900;
  467. color: #fff;
  468. border: none;
  469. }
  470. }
  471. .panel {
  472. margin-top: 10px;
  473. background-color: #FFFFFF;
  474. .noData {
  475. background-color: rgba(50, 50, 50, 0.7);
  476. color: #fff;
  477. padding: 15px 30px;
  478. position: absolute;
  479. top: 40%;
  480. left: 40%;
  481. }
  482. .chartPie-box{
  483. height: 400px;
  484. width: 100%;
  485. }
  486. .panel-title {
  487. font-size: 18px;
  488. color: #333;
  489. padding-bottom: 5px;
  490. }
  491. .tab-card {
  492. float: right;
  493. .tab-card-item {
  494. padding: 5px 10px;
  495. border: 1px solid #eee;
  496. cursor: pointer;
  497. }
  498. .checked-item {
  499. border-color: #2d8cf0;
  500. color: #2d8cf0;
  501. }
  502. }
  503. .border-radius {
  504. border-radius: 15px;
  505. }
  506. .background-blue {
  507. background-color: #157edf;
  508. }
  509. .background-green {
  510. background-color: #29aa4f;
  511. }
  512. .background-yellow {
  513. background-color: #dbb211;
  514. }
  515. .background-pop {
  516. background-color: #6C6FBE;
  517. }
  518. .background-black {
  519. background-color: #1f2c65;
  520. }
  521. .background-pink {
  522. background-color: #d23e57;
  523. }
  524. .background-skyblue {
  525. background-color: #00aaff;
  526. }
  527. .background-greenBlue {
  528. background-color: #1b9eaa;
  529. }
  530. .background-blackGreen {
  531. background-color: #357c09;
  532. }
  533. .background-orange {
  534. background-color: #ffaa00;
  535. }
  536. }
  537. .module-list {
  538. display: flex;
  539. justify-content: center;
  540. align-items: center;
  541. flex-direction: column;
  542. color: #FFFFFF;
  543. span {
  544. font-weight: 600;
  545. font-size: 20px;
  546. }
  547. }
  548. .module-icon {
  549. width: 52px;
  550. height: 54px;
  551. }
  552. }
  553. </style>