visit.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. {extend name="base"/}
  2. {block name="resources"}
  3. <style>
  4. /*时间选择*/
  5. .time-screen .screen{display: flex}
  6. .time-screen .screen .item {height: 32px;line-height: 32px;padding: 0 20px;border: 1px solid #D2D2D2;cursor: pointer;border-right: none;border-left: none;position: relative}
  7. .time-screen .screen .item:after{content: '';position: absolute;top: -1px;left: 0;bottom: -1px;right: -1px;border-right: 1px solid #D2D2D2;border-left: 1px solid #D2D2D2;}
  8. .time-screen .screen .selected,.time-screen .item:hover{color: #fff;background: var(--base-color);border-color: var(--base-color) }
  9. .time-screen .screen .selected:after, .time-screen .item:hover:after {border-right: 1px solid var(--base-color);border-left: 1px solid var(--base-color);}
  10. .data-wrap {display: flex;margin-top: 15px;}
  11. .data-wrap .data-item {flex: 1;display: flex}
  12. .data-wrap .data-item .box {flex: 1;margin-right: 15px;border: 1px solid #eee;box-sizing: border-box;padding: 15px;cursor: pointer}
  13. .data-wrap .data-item:last-child .box {margin-right: 0}
  14. .data-wrap .data-item .js-prompt-top {color:#C8C9CC;font-size:14px;z-index:999;cursor:pointer;}
  15. .data-wrap .data-item .info {font-size: 12px;color: #999;}
  16. .data-wrap .info .iconfont {font-size: 12px;}
  17. .data-wrap .data-item .text-color-green {color: #00A717}
  18. .data-wrap .data-item .text-color-red {color: #ff0000}
  19. .data-wrap .data-item.selected .box {border-color: var(--base-color);color: var(--base-color);}
  20. .data-wrap .data-item .data {display: flex;justify-content: space-between;align-items: end;font-size: 14px;color: #999;margin-top: 15px}
  21. .statistics-wrap {position: relative}
  22. .statistics-wrap .loading {background: rgba(255,255,255,.5);position: absolute;left: 0; top: 0;text-align: center;width: 100%;height: 100%;box-sizing: border-box;padding-top: 100px;display: none}
  23. .statistics-wrap .loading i {font-size: 25px}
  24. .layui-layer-content .layui-form-label {width: 100px}
  25. .echart {margin-top: 15px}
  26. .echart-wrap {margin-top: 30px;display: flex;}
  27. .echart-wrap .main {flex: 1;height: 400px}
  28. .echart-wrap .main:nth-child(2) {margin-left: 15px}
  29. .stat-board {display: flex;margin-top: 15px}
  30. .stat-board .board-title {color:#fff;display: flex;flex-direction: column;align-items: center;justify-content: center;width: 100px;height: 120px;}
  31. .stat-board .board-title .iconfont{color: #fff;font-size: 36px;margin-bottom: 10px;}
  32. .stat-board.visit{background: #f3f8ff;}
  33. .stat-board.order{background: #fffaf3;}
  34. .stat-board.visit .board-title {background: #177bff;}
  35. .stat-board.order .board-title {background: #ff9f15;}
  36. .stat-board .board-item {display: flex;flex-direction: column;justify-content: center;padding: 0 50px;width: 15%}
  37. .stat-board .board-item .title {font-size: 14px;}
  38. .stat-board .board-item .value {font-size: 26px;margin: 8px 0;}
  39. .stat-board .board-item .ratio {font-size: 12px;color: #999;line-height: 1}
  40. .stat-board .board-item .iconfont {font-size: 12px}
  41. .stat-board .board-item .rise {color: #f97337}
  42. .stat-board .board-item .decline {color: #0cc361}
  43. .date-input{width: 300px}
  44. </style>
  45. {/block}
  46. {block name="main"}
  47. <div class="main-wrap">
  48. <div class="time-screen statistics">
  49. <div class="screen">
  50. <div class="item selected" date-type="today">今日</div>
  51. <div class="item" date-type="yesterday">昨日</div>
  52. <div class="item" date-type="seven">7日内</div>
  53. <div class="item" date-type="thirty">30日内</div>
  54. <div class="item" date-type="custom">自定义</div>
  55. </div>
  56. </div>
  57. <div class="statistics-wrap">
  58. <div class="data-wrap">
  59. <div class="data-item selected" data-value="visit_count">
  60. <div class="box">
  61. <div class="title">
  62. <span class="title-text">全部</span>
  63. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,全部端口总的访客人数"></span>
  64. </div>
  65. <div class="data">
  66. <div class="name">访客数</div>
  67. <div class="value" data-type="num">0</div>
  68. </div>
  69. </div>
  70. </div>
  71. <div class="data-item" data-value="h5_visit_count">
  72. <div class="box">
  73. <div class="title">
  74. <span class="title-text">H5</span>
  75. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,H5端的访客人数"></span>
  76. </div>
  77. <div class="data">
  78. <div class="name">访客数</div>
  79. <div class="value" data-type="num">0</div>
  80. </div>
  81. </div>
  82. </div>
  83. <div class="data-item" data-value="weapp_visit_count">
  84. <div class="box">
  85. <div class="title">
  86. <span class="title-text">小程序</span>
  87. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,微信小程序端的访客人数"></span>
  88. </div>
  89. <div class="data">
  90. <div class="name">访客数</div>
  91. <div class="value" data-type="num">0</div>
  92. </div>
  93. </div>
  94. </div>
  95. <div class="data-item" data-value="wechat_visit_count">
  96. <div class="box">
  97. <div class="title">
  98. <span class="title-text">公众号</span>
  99. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,微信公众号端的访客人数"></span>
  100. </div>
  101. <div class="data">
  102. <div class="name">访客数</div>
  103. <div class="value" data-type="num">0</div>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. <div class="loading">
  109. <i class="common-loading-layer layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>
  110. </div>
  111. </div>
  112. <div class="echart-wrap">
  113. <div class="main" id="main"></div>
  114. </div>
  115. </div>
  116. <div class="stat-board visit">
  117. <div class="board-title">
  118. <i class="iconfont iconyonghu3"></i>
  119. <div>浏览访问</div>
  120. </div>
  121. <div class="board-item">
  122. <div class="title">访客数(人)</div>
  123. <div class="value">{$stat_today.visit_count}</div>
  124. {if $day_rate.visit_count < 0}
  125. <div class="ratio">比前日<i class="iconfont iconxia--jiantou decline"></i><span class="decline">{$day_rate.visit_count}</span></div>
  126. {else/}
  127. <div class="ratio">比前日<i class="iconfont iconshang--jiantou rise"></i><span class="rise">{$day_rate.visit_count}</span></div>
  128. {/if}
  129. </div>
  130. <div class="board-item">
  131. <div class="title">新增会员数(人)</div>
  132. <div class="value">{$stat_today.member_count}</div>
  133. {if $day_rate.member_count < 0}
  134. <div class="ratio">比前日<i class="iconfont iconxia--jiantou decline"></i><span class="decline">{$day_rate.member_count}</span></div>
  135. {else/}
  136. <div class="ratio">比前日<i class="iconfont iconshang--jiantou rise"></i><span class="rise">{$day_rate.member_count}</span></div>
  137. {/if}
  138. </div>
  139. </div>
  140. <div class="stat-board order">
  141. <div class="board-title">
  142. <i class="iconfont iconyingxiaozhongxin"></i>
  143. <div>成交转化</div>
  144. </div>
  145. <div class="board-item">
  146. <div class="title">支付人数(人)</div>
  147. <div class="value">{$stat_today.order_member_count}</div>
  148. {if $day_rate.order_member_count < 0}
  149. <div class="ratio">比前日<i class="iconfont iconxia--jiantou decline"></i><span class="decline">{$day_rate.order_member_count}</span></div>
  150. {else/}
  151. <div class="ratio">比前日<i class="iconfont iconshang--jiantou rise"></i><span class="rise">{$day_rate.order_member_count}</span></div>
  152. {/if}
  153. </div>
  154. <div class="board-item">
  155. <div class="title">访问-支付转化率(%)</div>
  156. <div class="value">{$stat_today.conversion_ratio}</div>
  157. {if $day_rate.conversion_ratio < 0}
  158. <div class="ratio">比前日<i class="iconfont iconxia--jiantou decline"></i><span class="decline">{$day_rate.conversion_ratio}</span></div>
  159. {else/}
  160. <div class="ratio">比前日<i class="iconfont iconshang--jiantou rise"></i><span class="rise">{$day_rate.conversion_ratio}</span></div>
  161. {/if}
  162. </div>
  163. </div>
  164. <script type="text/html" id="custom-box">
  165. <div class="layui-form-item">
  166. <div class="layui-inline">
  167. <label class="layui-form-label">选择时间:</label>
  168. <div class="layui-inline layui-inline-margin" id="time_fission">
  169. <div class="layui-input-inline">
  170. <input type="text" id="date" name="date" autocomplete="off" class="layui-input date-input" placeholder="请选择日期">
  171. <i class="iconfont iconriqi"></i>
  172. </div>
  173. </div>
  174. <input type="hidden" name="start_time" value="">
  175. <input type="hidden" name="end_time" value="">
  176. </div>
  177. </div>
  178. </script>
  179. {/block}
  180. {block name="script"}
  181. <script src="SHOP_JS/echarts.min.js"></script>
  182. <script>
  183. $('.time-screen.statistics .item').click(function () {
  184. // if ($(this).hasClass('selected')) return;
  185. var type = $(this).attr('date-type'),
  186. self = this;
  187. if (type != 'custom') $(this).addClass('selected').siblings().removeClass('selected');
  188. switch (type) {
  189. case 'today':
  190. var time = {
  191. start_time: (new Date('{$today} 00:00:00')).getTime() / 1000,
  192. end_time: (new Date('{$today} 23:59:59')).getTime() / 1000,
  193. }
  194. getShopStatistics(time);
  195. getShopStatData(time, 'hour');
  196. break;
  197. case 'yesterday':
  198. var time = {
  199. start_time: (new Date('{$yesterday} 00:00:00')).getTime() / 1000,
  200. end_time: (new Date('{$yesterday} 23:59:59')).getTime() / 1000,
  201. }
  202. getShopStatistics(time);
  203. getShopStatData(time, 'hour');
  204. break;
  205. case 'seven':
  206. var dateObj = new Date(Date.now() - 604800000);
  207. var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
  208. getShopStatistics({start_time: new Date(date).getTime() / 1000});
  209. getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
  210. break;
  211. case 'thirty':
  212. var dateObj = new Date(Date.now() - 2592000000);
  213. var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
  214. getShopStatistics({start_time: new Date(date).getTime() / 1000});
  215. getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
  216. break;
  217. case 'custom':
  218. var _layer = layer.open({
  219. title: '自定义时间选择',
  220. type: 1,
  221. area: ['480px', '160px'], //自定义文本域宽高
  222. btn: ['确认', '取消'],
  223. content: $('#custom-box').html(),
  224. success: function (layero, index) {
  225. new LayDate({
  226. elem: '#date',
  227. type: 'datetime',
  228. rangeId:['start_time','end_time'],
  229. max: '{:date("Y-m-d")}',
  230. done: function(value, date, endDate){
  231. var time_arr = value.split(' - ');
  232. var start_time = time_arr[0];
  233. var end_time = time_arr[1];
  234. $('input[name="start_time"]').val(time_arr[0]);
  235. $('input[name="end_time"]').val(time_arr[1]);
  236. }
  237. });
  238. },
  239. yes: function () {
  240. var start_time = $('input[name="start_time"]').val();
  241. var end_time = $('input[name="end_time"]').val();
  242. if (start_time == ''){
  243. layer.msg('请选择时间');
  244. return;
  245. }
  246. var time = {
  247. start_time: (new Date(start_time)).getTime() / 1000,
  248. end_time: (new Date(end_time)).getTime() / 1000
  249. };
  250. getShopStatistics(time);
  251. getShopStatData(time, 'day');
  252. $(self).addClass('selected').siblings().removeClass('selected');
  253. layer.close(_layer);
  254. }
  255. })
  256. break;
  257. }
  258. })
  259. /**
  260. * 获取统计数据
  261. * */
  262. function getShopStatistics(data) {
  263. $('.statistics-wrap .loading').show();
  264. $.ajax({
  265. dataType: "JSON",
  266. type: "POST",
  267. data: data,
  268. url: ns.url("shop/stat/getstattotal"),
  269. success: function(res){
  270. $('.statistics-wrap .loading').hide();
  271. if (res.code == 0) {
  272. Object.keys(res.data).forEach(function (key) {
  273. var type = $('[data-value="'+ key +'"] .value').attr('data-type');
  274. var value = type == 'money' ? moneyFormat(res.data[key]) : parseInt(res.data[key]);
  275. $('[data-value="'+ key +'"] .value').text(value);
  276. })
  277. }
  278. }
  279. })
  280. }
  281. getShopStatistics({});
  282. /**
  283. * 获取趋势数据
  284. * */
  285. var statData = [];
  286. function getShopStatData(data, type) {
  287. $.ajax({
  288. dataType: 'JSON',
  289. type: 'POST',
  290. url: type == 'hour' ? ns.url("shop/stat/getstathourdata") : ns.url("shop/stat/getStatData"),
  291. data: data,
  292. success: function(res) {
  293. statData = res;
  294. fetchEchart();
  295. }
  296. });
  297. }
  298. getShopStatData({}, 'hour');
  299. // 图表
  300. var baseColor = getComputedStyle(document.documentElement).getPropertyValue('--base-color');
  301. var myChart = echarts.init(document.getElementById('main'));
  302. var option = {
  303. tooltip: {
  304. trigger: 'axis'
  305. },
  306. legend: {
  307. data: ['新增商品数'],
  308. textStyle: {
  309. fontSize: 14,
  310. color: "#000"
  311. }
  312. },
  313. grid: {
  314. left: '4%',
  315. right: '4%'
  316. },
  317. xAxis: {
  318. type: 'category',
  319. boundaryGap: false,
  320. data: []
  321. },
  322. yAxis: {
  323. type: 'value',
  324. axisLabel: {
  325. formatter: '{value} '
  326. },
  327. splitLine:{
  328. show:false
  329. },
  330. },
  331. color: [baseColor],
  332. series: [
  333. {
  334. name: '新增商品数',
  335. type: 'line',
  336. smooth: true,
  337. data: [],
  338. }
  339. ]
  340. };
  341. /**
  342. * 渲染echart图表
  343. */
  344. function fetchEchart() {
  345. var key = $('.statistics-wrap .data-item.selected').attr('data-value');
  346. option.xAxis.data = statData.time;
  347. option.legend.data[0] = $('.statistics-wrap .data-item.selected .title-text').text();
  348. option.series[0].name = $('.statistics-wrap .data-item.selected .title-text').text();
  349. option.series[0].data = statData[key];
  350. myChart.setOption(option);
  351. }
  352. $('.statistics-wrap .data-item').click(function () {
  353. if ($(this).hasClass('selected')) return;
  354. $('.statistics-wrap .data-item').removeClass('selected');
  355. $(this).addClass('selected');
  356. fetchEchart();
  357. })
  358. </script>
  359. {/block}