member.html 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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 .value {font-size: 25px;font-weight: bolder;line-height: 40px}
  15. .data-wrap .data-item .js-prompt-top {color:#C8C9CC;font-size:14px;z-index:999;cursor:pointer;}
  16. .data-wrap .data-item .info {font-size: 12px;color: #999;}
  17. .data-wrap .info .iconfont {font-size: 12px;}
  18. .data-wrap .data-item .text-color-green {color: #00A717}
  19. .data-wrap .data-item .text-color-red {color: #ff0000}
  20. .data-wrap .data-item.selected .box {border-color: var(--base-color);color: var(--base-color);}
  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. .date-input{width: 300px}
  30. </style>
  31. {/block}
  32. {block name="main"}
  33. <div class="main-wrap">
  34. <div class="time-screen statistics">
  35. <div class="screen">
  36. <div class="item selected" date-type="today">今日</div>
  37. <div class="item" date-type="yesterday">昨日</div>
  38. <div class="item" date-type="seven">7日内</div>
  39. <div class="item" date-type="thirty">30日内</div>
  40. <div class="item" date-type="custom">自定义</div>
  41. </div>
  42. </div>
  43. <div class="statistics-wrap">
  44. <div class="data-wrap">
  45. <div class="data-item selected" data-value="member_count">
  46. <div class="box">
  47. <div class="title">
  48. <span class="title-text">新增会员数</span>
  49. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,新注册会员的数量"></span>
  50. </div>
  51. <div class="value" data-type="num">0</div>
  52. </div>
  53. </div>
  54. <div class="data-item" data-value="order_member_count">
  55. <div class="box">
  56. <div class="title">
  57. <span class="title-text">下单会员数</span>
  58. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,下单会员的数量"></span>
  59. </div>
  60. <div class="value" data-type="num">0</div>
  61. </div>
  62. </div>
  63. <div class="data-item" data-value="member_recharge_member_count">
  64. <div class="box">
  65. <div class="title">
  66. <span class="title-text">储值会员数</span>
  67. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,充值会员的数量"></span>
  68. </div>
  69. <div class="value" data-type="num">0</div>
  70. </div>
  71. </div>
  72. <div class="data-item" data-value="member_level_count">
  73. <div class="box">
  74. <div class="title">
  75. <span class="title-text">会员开卡数</span>
  76. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,会员开卡的数量"></span>
  77. </div>
  78. <div class="value" data-type="num">0</div>
  79. </div>
  80. </div>
  81. <div class="data-item" data-value="coupon_member_count">
  82. <div class="box">
  83. <div class="title">
  84. <span class="title-text">领券会员数</span>
  85. <span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,领取优惠券会员的数量"></span>
  86. </div>
  87. <div class="value" data-type="num">0</div>
  88. </div>
  89. </div>
  90. </div>
  91. <div class="loading">
  92. <i class="common-loading-layer layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>
  93. </div>
  94. </div>
  95. <div class="echart-wrap">
  96. <div class="main" id="main"></div>
  97. </div>
  98. </div>
  99. <script type="text/html" id="custom-box">
  100. <div class="layui-form-item">
  101. <div class="layui-inline">
  102. <label class="layui-form-label">选择时间:</label>
  103. <div class="layui-inline layui-inline-margin" id="time_fission">
  104. <div class="layui-input-inline">
  105. <input type="text" id="date" name="date" autocomplete="off" class="layui-input date-input" placeholder="请选择日期">
  106. <i class="iconfont iconriqi"></i>
  107. </div>
  108. </div>
  109. <input type="hidden" name="start_time" value="">
  110. <input type="hidden" name="end_time" value="">
  111. </div>
  112. </div>
  113. </script>
  114. {/block}
  115. {block name="script"}
  116. <script src="SHOP_JS/echarts.min.js"></script>
  117. <script>
  118. $('.time-screen.statistics .item').click(function () {
  119. // if ($(this).hasClass('selected')) return;
  120. var type = $(this).attr('date-type'),
  121. self = this;
  122. if (type != 'custom') $(this).addClass('selected').siblings().removeClass('selected');
  123. switch (type) {
  124. case 'today':
  125. var time = {
  126. start_time: (new Date('{$today} 00:00:00')).getTime() / 1000,
  127. end_time: (new Date('{$today} 23:59:59')).getTime() / 1000,
  128. }
  129. getShopStatistics(time);
  130. getShopStatData(time, 'hour');
  131. break;
  132. case 'yesterday':
  133. var time = {
  134. start_time: (new Date('{$yesterday} 00:00:00')).getTime() / 1000,
  135. end_time: (new Date('{$yesterday} 23:59:59')).getTime() / 1000,
  136. }
  137. getShopStatistics(time);
  138. getShopStatData(time, 'hour');
  139. break;
  140. case 'seven':
  141. var dateObj = new Date(Date.now() - 604800000);
  142. var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
  143. getShopStatistics({start_time: new Date(date).getTime() / 1000});
  144. getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
  145. break;
  146. case 'thirty':
  147. var dateObj = new Date(Date.now() - 2592000000);
  148. var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
  149. getShopStatistics({start_time: new Date(date).getTime() / 1000});
  150. getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
  151. break;
  152. case 'custom':
  153. var _layer = layer.open({
  154. title: '自定义时间选择',
  155. type: 1,
  156. area: ['480px', '160px'], //自定义文本域宽高
  157. btn: ['确认', '取消'],
  158. content: $('#custom-box').html(),
  159. success: function (layero, index) {
  160. new LayDate({
  161. elem: '#date',
  162. type: 'datetime',
  163. rangeId:['start_time','end_time'],
  164. max: '{:date("Y-m-d")}',
  165. done: function(value, date, endDate){
  166. var time_arr = value.split(' - ');
  167. var start_time = time_arr[0];
  168. var end_time = time_arr[1];
  169. $('input[name="start_time"]').val(time_arr[0]);
  170. $('input[name="end_time"]').val(time_arr[1]);
  171. }
  172. });
  173. },
  174. yes: function () {
  175. var start_time = $('input[name="start_time"]').val();
  176. var end_time = $('input[name="end_time"]').val();
  177. if (start_time == ''){
  178. layer.msg('请选择时间');
  179. return;
  180. }
  181. var time = {
  182. start_time: (new Date(start_time)).getTime() / 1000,
  183. end_time: (new Date(end_time)).getTime() / 1000
  184. };
  185. getShopStatistics(time);
  186. getShopStatData(time, 'day');
  187. $(self).addClass('selected').siblings().removeClass('selected');
  188. layer.close(_layer);
  189. }
  190. })
  191. break;
  192. }
  193. })
  194. /**
  195. * 获取统计数据
  196. * */
  197. function getShopStatistics(data) {
  198. $('.statistics-wrap .loading').show();
  199. $.ajax({
  200. dataType: "JSON",
  201. type: "POST",
  202. data: data,
  203. url: ns.url("shop/stat/getstattotal"),
  204. success: function(res){
  205. $('.statistics-wrap .loading').hide();
  206. if (res.code == 0) {
  207. Object.keys(res.data).forEach(function (key) {
  208. var type = $('[data-value="'+ key +'"] .value').attr('data-type');
  209. var value = type == 'money' ? moneyFormat(res.data[key]) : parseInt(res.data[key]);
  210. $('[data-value="'+ key +'"] .value').text(value);
  211. })
  212. }
  213. }
  214. })
  215. }
  216. getShopStatistics({});
  217. /**
  218. * 获取趋势数据
  219. * */
  220. var statData = [];
  221. function getShopStatData(data, type) {
  222. $.ajax({
  223. dataType: 'JSON',
  224. type: 'POST',
  225. url: type == 'hour' ? ns.url("shop/stat/getstathourdata") : ns.url("shop/stat/getStatData"),
  226. data: data,
  227. success: function(res) {
  228. statData = res;
  229. fetchEchart();
  230. }
  231. });
  232. }
  233. getShopStatData({}, 'hour');
  234. // 图表
  235. var baseColor = getComputedStyle(document.documentElement).getPropertyValue('--base-color');
  236. var myChart = echarts.init(document.getElementById('main'));
  237. var option = {
  238. tooltip: {
  239. trigger: 'axis'
  240. },
  241. legend: {
  242. data: ['新增商品数'],
  243. textStyle: {
  244. fontSize: 14,
  245. color: "#000"
  246. }
  247. },
  248. grid: {
  249. left: '4%',
  250. right: '4%'
  251. },
  252. xAxis: {
  253. type: 'category',
  254. boundaryGap: false,
  255. data: []
  256. },
  257. yAxis: {
  258. type: 'value',
  259. axisLabel: {
  260. formatter: '{value} '
  261. },
  262. splitLine:{
  263. show:false
  264. },
  265. },
  266. color: [baseColor],
  267. series: [
  268. {
  269. name: '新增商品数',
  270. type: 'line',
  271. smooth: true,
  272. data: [],
  273. }
  274. ]
  275. };
  276. /**
  277. * 渲染echart图表
  278. */
  279. function fetchEchart() {
  280. var key = $('.statistics-wrap .data-item.selected').attr('data-value');
  281. option.xAxis.data = statData.time;
  282. option.legend.data[0] = $('.statistics-wrap .data-item.selected .title-text').text();
  283. option.series[0].name = $('.statistics-wrap .data-item.selected .title-text').text();
  284. option.series[0].data = statData[key];
  285. myChart.setOption(option);
  286. }
  287. $('.statistics-wrap .data-item').click(function () {
  288. if ($(this).hasClass('selected')) return;
  289. $('.statistics-wrap .data-item').removeClass('selected');
  290. $(this).addClass('selected');
  291. fetchEchart();
  292. })
  293. </script>
  294. {/block}