flow-analyse.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. <?php
  2. use common\helpers\ComponentHelper;
  3. ComponentHelper::loadComponentView('components/count-to', __DIR__);
  4. ComponentHelper::loadComponentView('components/list', __DIR__);
  5. ComponentHelper::loadComponentView('components/my-table', __DIR__);
  6. ComponentHelper::loadComponentView('components/mini-echarts', __DIR__);
  7. ComponentHelper::loadComponentView('components/screen-contain', __DIR__);
  8. ComponentHelper::loadComponentView('components/header-time', __DIR__);
  9. ?>
  10. <style>
  11. .screen-container {
  12. min-width: 100%;
  13. }
  14. #flow-analysis{
  15. height: 100%;
  16. }
  17. .flow-analysis {
  18. min-height: 700px;
  19. }
  20. .flow-analysis .header {
  21. display: flex;
  22. justify-content: center;
  23. align-items: center;
  24. height: 80px;
  25. color: #F8F8F8;
  26. }
  27. .count-to {
  28. font-size: 60px;
  29. margin-left: 24px;
  30. }
  31. .fa-content {
  32. padding: 50px 80px;
  33. justify-content: space-between;
  34. flex-wrap: wrap;
  35. }
  36. .fa-content-left {
  37. padding: 27px 30px 30px;
  38. }
  39. .fa-content-left,
  40. .fa-content-right {
  41. /* width: 482px; */
  42. width: 30%;
  43. }
  44. .fa-content-right{
  45. display: flex;
  46. flex-direction: column;
  47. }
  48. .fa-content-center {
  49. /* width: 617px; */
  50. width: 37%;
  51. margin: 0 23px;
  52. position: relative;
  53. }
  54. .center-tabs{
  55. position: absolute;
  56. width: 100%;
  57. bottom: 0;
  58. }
  59. .echrats-item-bg {
  60. background: linear-gradient(137deg, #0034E4 0%, #14141A 20%, rgba(7, 7, 9, 0.89) 80%, #0034E4 100%);
  61. border: 1px solid #0034E4;
  62. border-radius: 16px;
  63. }
  64. .fa-content-right>div {
  65. width: 100%;
  66. height: 379px;
  67. /* height: 227px; */
  68. padding-top: 20px;
  69. margin-bottom: 15px;
  70. /* flex: 1; */
  71. }
  72. .fa-content-right>div:last-child {
  73. margin-bottom: 0;
  74. }
  75. #echarts3,
  76. #echarts2 {
  77. width: 100%;
  78. height: 100%;
  79. }
  80. .commodity-flow-title {
  81. font-size: 30px;
  82. font-family: Source Han Sans CN;
  83. font-weight: 500;
  84. color: #F8F8F8;
  85. margin-bottom: 23px;
  86. }
  87. .fcl-title {
  88. font-size: 30px;
  89. font-family: Source Han Sans CN;
  90. font-weight: 500;
  91. line-height: 30px;
  92. color: #F8F8F8;
  93. margin-bottom: 27px;
  94. }
  95. .item {
  96. /* width: 203px; */
  97. flex-basis: 47%;
  98. height: 92px;
  99. background: linear-gradient(90deg, rgba(0, 52, 228, 0.4) 0%, rgba(0, 0, 3, 0) 100%);
  100. border-radius: 8px;
  101. margin-bottom: 20px;
  102. padding-left: 30px;
  103. }
  104. .item-number {
  105. font-size: 26px;
  106. font-family: DIN;
  107. font-weight: bold;
  108. line-height: 32px;
  109. color: #F8F8F8;
  110. }
  111. .item-label {
  112. font-size: 15px;
  113. font-family: Source Han Sans CN;
  114. font-weight: 400;
  115. line-height: 25px;
  116. color: #CCCFDA;
  117. opacity: 1;
  118. }
  119. .item-img {
  120. width: 60px;
  121. height: 45px;
  122. /* border-top: 2px solid #0034E4;
  123. background: linear-gradient(180deg, rgba(0, 52, 228, 0.56) 0%, rgba(0, 52, 228, 0) 100%); */
  124. margin-bottom: 6px;
  125. }
  126. .test-echrats {
  127. width: 100%;
  128. height: 100%;
  129. }
  130. .echarts3-text{
  131. font-size: 16px;
  132. flex: 1;
  133. text-align: center;
  134. }
  135. .echarts3-num{
  136. font-size: 28px;
  137. line-height: 50px;
  138. }
  139. .echarts3-left-bor{
  140. width: 12px;
  141. height: 12px;
  142. display: inline-block;
  143. border-radius: 50%;
  144. line-height: 16px;
  145. }
  146. .echarts3-bottom{
  147. margin: 20px 0;
  148. }
  149. </style>
  150. <div id="flow-analysis" v-cloak>
  151. <screen-contain text-left="流量分析" :is-fix="false">
  152. <template v-slot:right>
  153. <!-- <div flex style="padding: 0 10px;">
  154. <div flex>
  155. <div style="font-size: 38px;">9:34</div>
  156. <div style="font-size: 16px;flex-direction: column;margin-left :10px " flex="main:center">
  157. <div style="width: 100%;">星期五 上午</div>
  158. <div>2021年7月23日</div>
  159. </div>
  160. </div>
  161. </div> -->
  162. <header-time></header-time>
  163. </template>
  164. <div class="flow-analysis">
  165. <div class="header">
  166. <div style="font-size: 45px;">平台总人数</div>
  167. <count-to :end-val="totalCount" :duration="10000" style="margin: 0 20px" class="count-to"></count-to>
  168. <div style="font-size: 18px;">
  169. <div>访问数:<span>{{echartsData.flow_datas?echartsData.flow_datas.total_visitors:'-'}}</span></div>
  170. <div>流量数:<span>{{echartsData.flow_datas?echartsData.flow_datas.total_views:'-'}}</span></div>
  171. </div>
  172. </div>
  173. <div class="fa-content" flex>
  174. <div class="fa-content-left echrats-item-bg">
  175. <div class="fcl-title">流量数据</div>
  176. <div flex="wrap:wrap main:justify">
  177. <div class="item" flex="cross:center main:justify" v-for="(item,index) in flowList" :key="index" :style=" index >= flowList.length - 2 ? 'margin-bottom:0': '' ">
  178. <div>
  179. <div class="item-number">{{echartsData.flow_datas?numSystemVal(echartsData.flow_datas[item.key], item.key):'-'}}</div>
  180. <div class="item-label">{{item.text}}</div>
  181. </div>
  182. <div flex="wrap:wrap main:right">
  183. <div class="item-img">
  184. <mini-echarts></mini-echarts>
  185. </div>
  186. <!-- <div>
  187. <span style="color: #1BBC26;"><i class="el-icon-arrow-down"></i>1.2%</span>
  188. <span style="color: #C12727;"><i class="el-icon-arrow-up"></i>1.2%</span>
  189. </div> -->
  190. </div>
  191. </div>
  192. </div>
  193. </div>
  194. <div class="fa-content-center">
  195. <div style="height: 469px;margin-bottom:15px">
  196. <div id="echarts2"></div>
  197. </div>
  198. <div class="echrats-item-bg center-tabs" flex style="height: 284px;padding: 20px;flex-direction: column;">
  199. <div class="commodity-flow-title">地区订单数</div>
  200. <div style="flex:1;height:0">
  201. <my-table :data="orderSort" :options="orderOptions">
  202. <template v-slot:sort="{ item,index }">
  203. <div>{{index+1}}</div>
  204. </template>
  205. </my-table>
  206. </div>
  207. </div>
  208. </div>
  209. <div class="fa-content-right">
  210. <div class="echrats-item-bg">
  211. <div class="fcl-title" style="padding-left: 30px;">新老客户占比</div>
  212. <div style="height: 190px;" id="echarts3"></div>
  213. <div class="echarts3-bottom" flex>
  214. <div class="echarts3-text">
  215. <div class="echarts3-num">{{echartsData.flow_datas?echartsData.flow_datas.new_customers:'-'}}</div>
  216. <div>
  217. <span style="background: #ED7453;" class="echarts3-left-bor"></span>
  218. 新客户人数
  219. </div>
  220. </div>
  221. <div class="echarts3-text">
  222. <div class="echarts3-num">{{echartsData.flow_datas?echartsData.flow_datas.regular_customers:'-'}}</div>
  223. <div>
  224. <span style="background: #0034E4;" class="echarts3-left-bor"></span>
  225. 老客户人数
  226. </div>
  227. </div>
  228. </div>
  229. </div>
  230. <div class="echrats-item-bg" flex style="height: 405px;padding: 30px 30px ;flex-direction: column;">
  231. <div class="commodity-flow-title">商品流量排行</div>
  232. <div style="flex:1;height:0">
  233. <my-table :data="echartsData.good_rankings" :options="goodsOptions">
  234. <template v-slot:sort="{ item,index }">
  235. <div>{{index+1}}</div>
  236. </template>
  237. </my-table>
  238. </div>
  239. </div>
  240. </div>
  241. </div>
  242. </div>
  243. </screen-contain>
  244. </div>
  245. <!-- <script src="https://cdn.jsdelivr.net/npm/echarts@5.2.2/dist/echarts.min.js"></script> -->
  246. <script src="/resources/unpkg/echarts@5.2.2/dist/echarts.min.js"></script>
  247. <script src="/resources/js/china.js"></script>
  248. <script>
  249. const app = new Vue({
  250. el: '#flow-analysis',
  251. data() {
  252. return {
  253. flowList: [{
  254. key: 'total_users',
  255. text: '注册人数'
  256. }, {
  257. key: 'visitors_rate',
  258. text: '访客占比'
  259. }, {
  260. key: 'number_of_orders',
  261. text: '下单人数'
  262. }, {
  263. key: 'total_pay_people',
  264. text: '支付人数'
  265. }, {
  266. key: 'total_pay_orders',
  267. text: '支付订单'
  268. }, {
  269. key: 'total_pay_money',
  270. text: '支付金额'
  271. }, {
  272. key: 'customer_unit_price',
  273. text: '客单价'
  274. }, {
  275. key: 'access_pay_rate',
  276. text: '访问-支付转化率'
  277. }, {
  278. key: 'access_place_order_rate',
  279. text: '访问-下单转化率'
  280. }, {
  281. key: 'repurchase_people',
  282. text: '复购人数'
  283. }, {
  284. key: 'repurchase_money',
  285. text: '复购金额'
  286. }, {
  287. key: 'share_people',
  288. text: '分享人数'
  289. },],
  290. orderOptions: [{
  291. props: "sort",
  292. label: '排行',
  293. slot: true,
  294. textAlign: 'left',
  295. width: 50,
  296. }, {
  297. props: "province_name",
  298. // width: 200,
  299. label: '地区名称',
  300. textAlign: 'left'
  301. }, {
  302. props: "total_orders",
  303. label: '订单数',
  304. },],
  305. goodsOptions: [{
  306. props: "sort",
  307. label: '排行',
  308. slot: true,
  309. textAlign: 'left',
  310. width: 50,
  311. }, {
  312. props: "goods_name",
  313. label: '商品名称',
  314. textAlign: 'left'
  315. }, {
  316. props: "total_views",
  317. label: '浏览量',
  318. }, ],
  319. echartsData: {},
  320. totalCount: 0,
  321. orderSort: [],
  322. }
  323. },
  324. methods: {
  325. getEchartsData(){
  326. let that = this;
  327. request({
  328. params: {
  329. r: 'mall/data-census/flowan-alyse',
  330. },
  331. method: 'get'
  332. }).then(e => {
  333. if (e.data.code === 0) {
  334. console.info(e.data.data);
  335. this.echartsData = e.data.data;
  336. this.totalCount = e.data.data.flow_datas.total_users;
  337. this.orderSort.push(...e.data.data.region_datas.sort((a,b) => { return b.total_orders-a.total_orders}).slice(0,10));
  338. } else {
  339. this.$message.error(e.data.msg);
  340. }
  341. this.echarts3Init()
  342. this.echarts2Init()
  343. });
  344. },
  345. echarts3Init() {
  346. var chartDom = document.getElementById('echarts3');
  347. var myChart = echarts.init(chartDom);
  348. var option = {
  349. tooltip: {
  350. trigger: 'item'
  351. },
  352. color: ['#0034E4', '#ED7453'],
  353. series: [{
  354. name: '会员等级分布',
  355. type: 'pie',
  356. radius: ['50%', '70%'],
  357. avoidLabelOverlap: false,
  358. label: {
  359. show: true,
  360. position: 'outside',
  361. color: '#fff',
  362. formatter: (params) => {
  363. return params.value + '%\n' + params.name;
  364. }
  365. },
  366. labelLine: {
  367. show: true,
  368. length: 15,
  369. lineStyle: {
  370. color: '#fff'
  371. }
  372. },
  373. data: [{
  374. value: this.echartsData.pie_chart_datas.data[1],
  375. name: this.echartsData.pie_chart_datas.names[1],
  376. },
  377. {
  378. value: this.echartsData.pie_chart_datas.data[0],
  379. name: this.echartsData.pie_chart_datas.names[0],
  380. }
  381. ]
  382. }]
  383. };
  384. option && myChart.setOption(option);
  385. },
  386. echarts2Init() {
  387. // 基于准备好的dom,初始化echarts实例
  388. var mapChart = echarts.init(document.getElementById('echarts2'));
  389. // 地图数据
  390. let newData = [];
  391. this.echartsData.map_order_datas.forEach(item => {
  392. item.name = item.name.split('省')[0];
  393. item.name = item.name.split('市')[0];
  394. item.name = item.name.split('特别行政区')[0];
  395. item.name = item.name.split('壮族自治区')[0];
  396. item.name = item.name.split('回族自治区')[0];
  397. item.name = item.name.split('维吾尔自治区')[0];
  398. item.name = item.name.split('自治区')[0];
  399. if(!item.value){
  400. newData.push(item)
  401. }
  402. });
  403. this.echartsData.map_order_datas = this.echartsData.map_order_datas.filter(v => {return v.value > 0})
  404. console.log(newData);
  405. var option = {
  406. tooltip: {
  407. trigger: 'item',
  408. formatter: (params) => {
  409. return params.name + ': ' + (params.value || 0);
  410. }
  411. },
  412. visualMap: {
  413. show: false,
  414. x: 'left',
  415. y: 'bottom',
  416. splitList: [
  417. {
  418. start: 0,
  419. end: 80
  420. }, {
  421. start: 80,
  422. end: 90
  423. },
  424. {
  425. start: 90,
  426. end: 100
  427. }, {
  428. start: 100,
  429. // end: 99999999
  430. },
  431. ],
  432. /* inRange: {
  433. color: ['#1e60ff', '#0540c3', '#0032c1', '#002390']
  434. }, */
  435. // color: ['#002390','#1E60FF', '#0540c3', '#0032c1']
  436. color: ['#0032c1','#0540c3', '#1E60FF']
  437. },
  438. series: [{
  439. type: 'map',
  440. mapType: 'china',
  441. roam: false,
  442. label: {
  443. normal: {
  444. show: false
  445. },
  446. emphasis: {
  447. show: false
  448. }
  449. },
  450. itemStyle: {
  451. areaColor: '#002390',
  452. borderColor: '#4478F5'
  453. },
  454. data: this.echartsData.map_order_datas,
  455. },]
  456. };
  457. mapChart.setOption(option);
  458. },
  459. numSystemVal(val, key) {
  460. if (val * 1 < 10000) {
  461. val = val * 1
  462. } else {
  463. if ((val * 1) % 10000 == 0) {
  464. val = parseInt((val * 1) / 10000) + 'W'
  465. } else {
  466. val = parseInt((val * 1) / 10000) + 'W+'
  467. }
  468. }
  469. let rateKeys = ['visitors_rate', 'access_pay_rate', 'access_place_order_rate'];
  470. if (-1 != rateKeys.indexOf(key) && val > 0) {
  471. val *= 100;
  472. val = val.toFixed(2)
  473. val += '%';
  474. }
  475. return val
  476. }
  477. },
  478. mounted() {
  479. this.getEchartsData();
  480. }
  481. })
  482. </script>