初始上传
This commit is contained in:
520
app/shop/view/stat/goods.html
Executable file
520
app/shop/view/stat/goods.html
Executable file
@@ -0,0 +1,520 @@
|
||||
<style>
|
||||
/* 公共样式修改 */
|
||||
.layui-layout-admin .layui-body .body-content{background-color: transparent;padding: 0;}
|
||||
/*时间选择*/
|
||||
.time-screen{display: flex;background-color: #fff;padding: 10px;margin-bottom: 10px;}
|
||||
.time-screen .item {height: 32px;line-height: 32px;padding: 0 20px;border: 1px solid #D2D2D2;cursor: pointer;border-right: none;border-left: none;position: relative}
|
||||
.time-screen .item:after{content: '';position: absolute;top: -1px;left: 0;bottom: -1px;right: -1px;border-right: 1px solid #D2D2D2;border-left: 1px solid #D2D2D2;}
|
||||
.time-screen .selected,.time-screen .item:hover{color: #fff;background: var(--base-color);border-color: var(--base-color) }
|
||||
.time-screen .selected:after, .time-screen .item:hover:after {border-right: 1px solid var(--base-color);border-left: 1px solid var(--base-color);}
|
||||
/* 商品统计 */
|
||||
.goods-stat{padding: 5px 20px;margin-bottom: 10px;background-color: #fff;}
|
||||
.goods-stat .goods-stat-item{display: flex;justify-content: space-between;align-items: center;border-bottom: 1px solid #eff0f4;padding: 15px 0;}
|
||||
.goods-stat .goods-stat-item:last-of-type{border-bottom: none;}
|
||||
.goods-stat .goods-stat-item .stat-item-content{width: 130px;display:flex;flex-direction: column;justify-content: center;}
|
||||
.goods-stat .goods-stat-item .stat-item-content > span{margin-top: 8px;font-size: 20px;font-weight: 600;}
|
||||
.goods-stat .goods-stat-item .js-prompt-top{color: #999;cursor: pointer;}
|
||||
/* 销售统计 */
|
||||
.market-stat{display: flex;justify-content: space-between; margin-bottom: 10px;}
|
||||
.market-stat .market-stat-item{background-color: #fff;width: calc(50% - 5px);}
|
||||
.market-stat .market-stat-item .market-item-head{height: 45px;line-height: 45px;padding: 0 15px;font-weight: bold;font-size: 14px;border-bottom: 1px solid #eff0f4;}
|
||||
.market-stat .market-stat-item .market-item-content{padding: 10px 20px;}
|
||||
.market-stat .market-stat-item .market-item-content li{height: 35px;line-height: 35px;display: flex;align-items: center;}
|
||||
.market-stat .market-stat-item .market-item-content li span:first-of-type{display: inline-block;max-width: 400px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;margin-right: 15px;color: #999;}
|
||||
/* 访客数 */
|
||||
.visitor-stat{background-color: #fff;}
|
||||
.visitor-stat .visitor-head{height: 45px;line-height: 45px;padding: 0 15px;font-weight: bold;font-size: 14px;border-bottom: 1px solid #eff0f4;}
|
||||
.visitor-stat .visitor-head .more{font-size: 12px;font-weight: 500;color:var(--base-color); cursor: pointer;}
|
||||
.visitor-stat .visitor-body {padding-top: 30px;display: flex;}
|
||||
.visitor-stat .visitor-body .main {flex: 1;height: 400px}
|
||||
.visitor-stat .visitor-body .main:nth-child(2) {margin-left: 15px}
|
||||
/* 加载动画 */
|
||||
.goods-stat-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}
|
||||
.goods-stat-wrap .loading i {font-size: 25px}
|
||||
.date-input{width: 300px}
|
||||
</style>
|
||||
|
||||
<div class="goods-stat-wrap">
|
||||
<div class="time-screen statistics">
|
||||
<div class="item selected" date-type="today">今日</div>
|
||||
<div class="item" date-type="yesterday">昨日</div>
|
||||
<div class="item" date-type="seven">7日内</div>
|
||||
<div class="item" date-type="thirty">30日内</div>
|
||||
<div class="item" date-type="custom">自定义</div>
|
||||
</div>
|
||||
|
||||
<ul class="goods-stat">
|
||||
<list class="goods-stat-item">
|
||||
<div class="stat-item-head">商品概况</div>
|
||||
<div class="stat-item-content">
|
||||
<div>
|
||||
<span>在架商品数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="当前时间,状态为上架的商品数量"></span>
|
||||
</div>
|
||||
<span data-value="goods_on_type_count">0</span>
|
||||
</div>
|
||||
<div class="stat-item-content">
|
||||
<div>
|
||||
<span>被访问商品数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,商品详情页浏览次数大于 0 的商品数"></span>
|
||||
</div>
|
||||
<span data-value="goods_visited_type_count">0</span>
|
||||
</div>
|
||||
<div class="stat-item-content">
|
||||
<div>
|
||||
<span>动销商品数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,销量不为 0 的商品数量"></span>
|
||||
</div>
|
||||
<span data-value="goods_order_type_count">0</span>
|
||||
</div>
|
||||
</list>
|
||||
<list class="goods-stat-item">
|
||||
<div class="stat-item-head">商品流量</div>
|
||||
<div class="stat-item-content">
|
||||
<div>
|
||||
<span>商品浏览量</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,所有商品详情页被访问的次数,一个人在统计时间内访问多次记为多次"></span>
|
||||
</div>
|
||||
<span data-value="goods_visit_count">0</span>
|
||||
</div>
|
||||
<div class="stat-item-content">
|
||||
<div>
|
||||
<span>商品访客数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,访问任何商品详情页的人数,一个人在统计时间范围内访问多次只记为一个"></span>
|
||||
</div>
|
||||
<span data-value="goods_visit_member_count">0</span>
|
||||
</div>
|
||||
<div class="stat-item-content">
|
||||
<!-- <div>
|
||||
<span>商品曝光数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,店铺所有商品在店铺首页、列表页、商品分组页、 微页面、搜索结果页以及商品页底部关联商品区域中的展示次数之和。(直接进入详情页或微页面中通过图片链接到商品不会统计)"></span>
|
||||
</div>
|
||||
<span data-value="goods_exposure_count">0</span> -->
|
||||
</div>
|
||||
</list>
|
||||
<list class="goods-stat-item">
|
||||
<div class="stat-item-head">商品转化</div>
|
||||
<div class="stat-item-content">
|
||||
<div>
|
||||
<span>加购件数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,添加商品进入购物车的商品件数"></span></div>
|
||||
<span data-value="goods_cart_count">0</span>
|
||||
</div>
|
||||
<div class="stat-item-content">
|
||||
<div>
|
||||
<span>下单件数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,成功下单的商品件数之和(不剔除退款订单)"></span></div>
|
||||
<span data-value="goods_order_count">0</span>
|
||||
</div>
|
||||
<div class="stat-item-content">
|
||||
<div>
|
||||
<span>支付件数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内, 成功付款订单的商品件数之和(不剔除退款订单)"></span></div>
|
||||
<span data-value="order_create_count">0</span>
|
||||
</div>
|
||||
</list>
|
||||
</ul>
|
||||
|
||||
<div class="market-stat">
|
||||
<div class="market-stat-item">
|
||||
<div class="market-item-head">销售额(元)TOP5</div>
|
||||
<ul class="market-item-content saleroom">
|
||||
<li>
|
||||
<span>暂无排名</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="market-stat-item">
|
||||
<div class="market-item-head">销量(件)TOP5</div>
|
||||
<ul class="market-item-content sales-volume">
|
||||
<li>
|
||||
<span>暂无排名</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="visitor-stat">
|
||||
<!-- <div class="visitor-head">
|
||||
<span>访客数TOP </span>
|
||||
<span class="more">查看更多商品</span>
|
||||
</div> -->
|
||||
<div class="visitor-body">
|
||||
<div class="main" id="main"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loading">
|
||||
<i class="common-loading-layer layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自定义时间 -->
|
||||
<script type="text/html" id="custom-box">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label sm">选择时间:</label>
|
||||
|
||||
<div class="layui-inline layui-inline-margin" id="time_fission">
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" id="date" name="date" autocomplete="off" class="layui-input date-input" placeholder="请选择日期">
|
||||
<i class="iconfont iconriqi"></i>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="start_time" value="">
|
||||
<input type="hidden" name="end_time" value="">
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script src="SHOP_JS/echarts.min.js"></script>
|
||||
<script>
|
||||
var form;
|
||||
var MAX_SALEMONEY = 5; //控制展示商品排行榜前几的销售额
|
||||
var MAX_SALE = 5; //控制展示商品排行榜前几的销量
|
||||
var timeType = 'today';
|
||||
|
||||
initFn();
|
||||
|
||||
// 初始化
|
||||
function initFn(){
|
||||
layui.use(['form'], function(){
|
||||
form = layui.form;
|
||||
});
|
||||
|
||||
var time = {
|
||||
start_time: (new Date('{$today} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$today} 23:59:59')).getTime() / 1000,
|
||||
};
|
||||
initChartFn();
|
||||
loadingMethod(time);
|
||||
}
|
||||
|
||||
// 选择时间
|
||||
$('.time-screen.statistics .item').click(function () {
|
||||
var self = this;
|
||||
timeType = $(this).attr('date-type');
|
||||
if (timeType != 'custom') $(this).addClass('selected').siblings().removeClass('selected');
|
||||
|
||||
switch (timeType) {
|
||||
case 'today':
|
||||
var time = {
|
||||
start_time: (new Date('{$today} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$today} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
loadingMethod(time);
|
||||
break;
|
||||
case 'yesterday':
|
||||
var time = {
|
||||
start_time: (new Date('{$yesterday} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$yesterday} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
loadingMethod(time);
|
||||
break;
|
||||
case 'seven':
|
||||
var dateObj = new Date(Date.now() - 604800000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
var time = {start_time: new Date(date).getTime() / 1000};
|
||||
loadingMethod(time,'day');
|
||||
break;
|
||||
case 'thirty':
|
||||
var dateObj = new Date(Date.now() - 2592000000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
var time = {start_time: new Date(date).getTime() / 1000};
|
||||
loadingMethod(time,'day');
|
||||
break;
|
||||
case 'custom':
|
||||
var _layer = layer.open({
|
||||
title: '自定义时间选择',
|
||||
type: 1,
|
||||
area: ['480px', '160px'], //自定义文本域宽高
|
||||
btn: ['确认', '取消'],
|
||||
content: $('#custom-box').html(),
|
||||
success: function (layero, index) {
|
||||
new LayDate({
|
||||
elem: '#date',
|
||||
type: 'datetime',
|
||||
rangeId:['start_time','end_time'],
|
||||
max: '{:date("Y-m-d")}',
|
||||
done: function(value, date, endDate){
|
||||
var time_arr = value.split(' - ');
|
||||
var start_time = time_arr[0];
|
||||
var end_time = time_arr[1];
|
||||
$('input[name="start_time"]').val(time_arr[0]);
|
||||
$('input[name="end_time"]').val(time_arr[1]);
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function () {
|
||||
var start_time = $('input[name="start_time"]').val();
|
||||
var end_time = $('input[name="end_time"]').val();
|
||||
if (start_time == ''){
|
||||
layer.msg('请选择时间');
|
||||
return;
|
||||
}
|
||||
var time = {
|
||||
start_time: (new Date(start_time)).getTime() / 1000,
|
||||
end_time: (new Date(end_time)).getTime() / 1000
|
||||
};
|
||||
loadingMethod(time,'day');
|
||||
$(self).addClass('selected').siblings().removeClass('selected');
|
||||
layer.close(_layer);
|
||||
}
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
// 获取商品统计数量
|
||||
var today_goods_stat = 0;
|
||||
function getGoodsStat(time){
|
||||
$('.goods-stat-wrap .loading').show();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: ns.url("shop/stat/getstattotal"),
|
||||
data: time,
|
||||
dataType: 'JSON',
|
||||
success: function(res){
|
||||
$('.goods-stat-wrap .loading').hide();
|
||||
if (res.code == 0) {
|
||||
if(timeType == 'today') today_goods_stat = res.data['goods_on_type_count'];
|
||||
Object.keys(res.data).forEach(function (key) {
|
||||
if(timeType != 'today' && timeType != 'yesterday'&& key=='goods_on_type_count') $('.goods-stat [data-value="'+ key +'"]').text(today_goods_stat);
|
||||
else $('.goods-stat [data-value="'+ key +'"]').text(res.data[key]);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品排行榜 销量
|
||||
* */
|
||||
function countGoodsSale(data) {
|
||||
$.ajax({
|
||||
dataType: 'JSON',
|
||||
type: 'POST',
|
||||
url: ns.url("shop/stat/countGoodsSale"),
|
||||
data: data,
|
||||
success: function(res) {
|
||||
var html = "";
|
||||
if(res.code >= 0 && res.data.list.length){
|
||||
try{
|
||||
res.data.list.forEach((item,index)=>{
|
||||
if(index >= MAX_SALE) throw new Error('end');
|
||||
html += `
|
||||
<li>
|
||||
<span>${item.goods_name}</span>
|
||||
<span>${item.sale_num}</span>
|
||||
</li>
|
||||
`;
|
||||
});
|
||||
}catch(e){
|
||||
if(e.message != "end") throw e;
|
||||
}
|
||||
$(".market-item-content.sales-volume").html(html);
|
||||
}else{
|
||||
html += `
|
||||
<li>
|
||||
<span>暂无排名</span>
|
||||
</li>
|
||||
`;
|
||||
$(".market-item-content.sales-volume").html(html);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品排行榜 销售额
|
||||
* */
|
||||
function countGoodsSaleMoney(data) {
|
||||
$.ajax({
|
||||
dataType: 'JSON',
|
||||
type: 'POST',
|
||||
url: ns.url("shop/stat/countGoodsSaleMoney"),
|
||||
data: data,
|
||||
success: function(res) {
|
||||
var html = "";
|
||||
if(res.code >= 0 && res.data.list.length){
|
||||
try{
|
||||
res.data.list.forEach((item,index)=>{
|
||||
if(index >= MAX_SALEMONEY) throw new Error('end');
|
||||
html += `
|
||||
<li>
|
||||
<span>${item.goods_name}</span>
|
||||
<span>${item.order_money}</span>
|
||||
</li>
|
||||
`;
|
||||
});
|
||||
}catch(e){
|
||||
if(e.message != "end") throw e;
|
||||
}
|
||||
$(".market-item-content.saleroom").html(html);
|
||||
}else{
|
||||
html += `
|
||||
<li>
|
||||
<span>暂无排名</span>
|
||||
</li>
|
||||
`;
|
||||
$(".market-item-content.saleroom").html(html);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var statData = []; // 图表数据
|
||||
var today_stat_data = []; //展示今日商品数据
|
||||
function getGoodsChartData(data, type) {
|
||||
$.ajax({
|
||||
dataType: 'JSON',
|
||||
type: 'POST',
|
||||
url: type == 'hour' ? ns.url("shop/stat/getstathourdata") : ns.url("shop/stat/getStatData"),
|
||||
data: data,
|
||||
success: function(res) {
|
||||
statData = res;
|
||||
if(timeType == 'today') today_stat_data = statData['goods_on_type_count'];
|
||||
analyzeChartData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化图表
|
||||
var baseColor,myChart,option;
|
||||
function initChartFn(){
|
||||
if(!$('#main').length) return;
|
||||
baseColor = getComputedStyle(document.documentElement).getPropertyValue('--base-color');
|
||||
myChart = echarts.init(document.getElementById('main'));
|
||||
option = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ["在架商品数"],
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: "#000"
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '4%'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} '
|
||||
},
|
||||
splitLine:{
|
||||
show:false
|
||||
},
|
||||
},
|
||||
color: [baseColor],
|
||||
series: [
|
||||
{
|
||||
name: '在架商品数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
color: [
|
||||
'#8dc1a9'
|
||||
],
|
||||
data: [],
|
||||
},{
|
||||
name: '被访问商品数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
color: [
|
||||
'#e69d87'
|
||||
],
|
||||
data: [],
|
||||
},{
|
||||
name: '动销商品数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
color: [
|
||||
'#759aa0'
|
||||
],
|
||||
data: [],
|
||||
},{
|
||||
name: '商品浏览量',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
color: [
|
||||
'#73a373'
|
||||
],
|
||||
data: [],
|
||||
},{
|
||||
name: '商品访客数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
color: [
|
||||
'#73b9bc'
|
||||
],
|
||||
data: [],
|
||||
},{
|
||||
name: '加购件数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
color: [
|
||||
'#7289ab'
|
||||
],
|
||||
data: [],
|
||||
},{
|
||||
name: '下单件数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
color: [
|
||||
'#91ca8c'
|
||||
],
|
||||
data: [],
|
||||
},{
|
||||
name: '支付件数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
color: [
|
||||
'#f49f42'
|
||||
],
|
||||
data: [],
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染echart图表
|
||||
*/
|
||||
function analyzeChartData() {
|
||||
option.xAxis.data = statData.time;
|
||||
var obj = {
|
||||
goods_on_type_count: '在架商品数',
|
||||
goods_visited_type_count: '被访问商品数',
|
||||
goods_order_type_count: '动销商品数',
|
||||
// goods_exposure_count: '商品曝光数',
|
||||
goods_visit_count: '商品浏览量',
|
||||
goods_visit_member_count: '商品访客数',
|
||||
goods_cart_count: '加购件数',
|
||||
goods_order_count: '下单件数',
|
||||
order_create_count: '支付件数'
|
||||
};
|
||||
var num = 0;
|
||||
for(var key in obj){
|
||||
option.legend.data[num] = obj[key];
|
||||
option.series[num].name = obj[key];
|
||||
if(timeType != 'today' && timeType != 'yesterday'&& key=='goods_on_type_count') option.series[num].data = today_stat_data;
|
||||
else option.series[num].data = statData[key];
|
||||
num++;
|
||||
}
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
// 加载方法
|
||||
function loadingMethod(time,type='hour'){
|
||||
getGoodsStat(time);
|
||||
getGoodsChartData(time, type);
|
||||
countGoodsSale(time);
|
||||
countGoodsSaleMoney(time);
|
||||
}
|
||||
</script>
|
||||
303
app/shop/view/stat/member.html
Executable file
303
app/shop/view/stat/member.html
Executable file
@@ -0,0 +1,303 @@
|
||||
<style>
|
||||
/*时间选择*/
|
||||
.time-screen .screen{display: flex}
|
||||
.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}
|
||||
.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;}
|
||||
.time-screen .screen .selected,.time-screen .item:hover{color: #fff;background: var(--base-color);border-color: var(--base-color) }
|
||||
.time-screen .screen .selected:after, .time-screen .item:hover:after {border-right: 1px solid var(--base-color);border-left: 1px solid var(--base-color);}
|
||||
|
||||
.data-wrap {display: flex;margin-top: 15px;}
|
||||
.data-wrap .data-item {flex: 1;display: flex}
|
||||
.data-wrap .data-item .box {flex: 1;margin-right: 15px;border: 1px solid #eee;box-sizing: border-box;padding: 15px;cursor: pointer}
|
||||
.data-wrap .data-item:last-child .box {margin-right: 0}
|
||||
.data-wrap .data-item .value {font-size: 25px;font-weight: bolder;line-height: 40px}
|
||||
.data-wrap .data-item .js-prompt-top {color:#C8C9CC;font-size:14px;z-index:999;cursor:pointer;}
|
||||
.data-wrap .data-item .info {font-size: 12px;color: #999;}
|
||||
.data-wrap .info .iconfont {font-size: 12px;}
|
||||
.data-wrap .data-item .text-color-green {color: #00A717}
|
||||
.data-wrap .data-item .text-color-red {color: #ff0000}
|
||||
.data-wrap .data-item.selected .box {border-color: var(--base-color);color: var(--base-color);}
|
||||
.statistics-wrap {position: relative}
|
||||
.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}
|
||||
.statistics-wrap .loading i {font-size: 25px}
|
||||
|
||||
.layui-layer-content .layui-form-label {width: 100px}
|
||||
.echart {margin-top: 15px}
|
||||
.echart-wrap {margin-top: 30px;display: flex;}
|
||||
.echart-wrap .main {flex: 1;height: 400px}
|
||||
.echart-wrap .main:nth-child(2) {margin-left: 15px}
|
||||
.date-input{width: 300px}
|
||||
</style>
|
||||
|
||||
<div class="main-wrap">
|
||||
<div class="time-screen statistics">
|
||||
<div class="screen">
|
||||
<div class="item selected" date-type="today">今日</div>
|
||||
<div class="item" date-type="yesterday">昨日</div>
|
||||
<div class="item" date-type="seven">7日内</div>
|
||||
<div class="item" date-type="thirty">30日内</div>
|
||||
<div class="item" date-type="custom">自定义</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-wrap">
|
||||
<div class="data-wrap">
|
||||
<div class="data-item selected" data-value="member_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">新增会员数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,新注册会员的数量"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="order_member_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">下单会员数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,下单会员的数量"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="member_recharge_member_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">储值会员数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,充值会员的数量"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="member_level_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">会员开卡数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,会员开卡的数量"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="coupon_member_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">领券会员数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,领取优惠券会员的数量"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="loading">
|
||||
<i class="common-loading-layer layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="echart-wrap">
|
||||
<div class="main" id="main"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="custom-box">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">选择时间:</label>
|
||||
|
||||
<div class="layui-inline layui-inline-margin" id="time_fission">
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" id="date" name="date" autocomplete="off" class="layui-input date-input" placeholder="请选择日期">
|
||||
<i class="iconfont iconriqi"></i>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="start_time" value="">
|
||||
<input type="hidden" name="end_time" value="">
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script src="SHOP_JS/echarts.min.js"></script>
|
||||
<script>
|
||||
$('.time-screen.statistics .item').click(function () {
|
||||
// if ($(this).hasClass('selected')) return;
|
||||
|
||||
var type = $(this).attr('date-type'),
|
||||
self = this;
|
||||
if (type != 'custom') $(this).addClass('selected').siblings().removeClass('selected');
|
||||
|
||||
switch (type) {
|
||||
case 'today':
|
||||
var time = {
|
||||
start_time: (new Date('{$today} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$today} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'hour');
|
||||
break;
|
||||
case 'yesterday':
|
||||
var time = {
|
||||
start_time: (new Date('{$yesterday} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$yesterday} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'hour');
|
||||
break;
|
||||
case 'seven':
|
||||
var dateObj = new Date(Date.now() - 604800000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
getShopStatistics({start_time: new Date(date).getTime() / 1000});
|
||||
getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
|
||||
break;
|
||||
case 'thirty':
|
||||
var dateObj = new Date(Date.now() - 2592000000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
getShopStatistics({start_time: new Date(date).getTime() / 1000});
|
||||
getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
|
||||
break;
|
||||
case 'custom':
|
||||
var _layer = layer.open({
|
||||
title: '自定义时间选择',
|
||||
type: 1,
|
||||
area: ['480px', '160px'], //自定义文本域宽高
|
||||
btn: ['确认', '取消'],
|
||||
content: $('#custom-box').html(),
|
||||
success: function (layero, index) {
|
||||
new LayDate({
|
||||
elem: '#date',
|
||||
type: 'datetime',
|
||||
rangeId:['start_time','end_time'],
|
||||
max: '{:date("Y-m-d")}',
|
||||
done: function(value, date, endDate){
|
||||
var time_arr = value.split(' - ');
|
||||
var start_time = time_arr[0];
|
||||
var end_time = time_arr[1];
|
||||
$('input[name="start_time"]').val(time_arr[0]);
|
||||
$('input[name="end_time"]').val(time_arr[1]);
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function () {
|
||||
var start_time = $('input[name="start_time"]').val();
|
||||
var end_time = $('input[name="end_time"]').val();
|
||||
if (start_time == ''){
|
||||
layer.msg('请选择时间');
|
||||
return;
|
||||
}
|
||||
var time = {
|
||||
start_time: (new Date(start_time)).getTime() / 1000,
|
||||
end_time: (new Date(end_time)).getTime() / 1000
|
||||
};
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'day');
|
||||
$(self).addClass('selected').siblings().removeClass('selected');
|
||||
layer.close(_layer);
|
||||
}
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
* */
|
||||
function getShopStatistics(data) {
|
||||
$('.statistics-wrap .loading').show();
|
||||
$.ajax({
|
||||
dataType: "JSON",
|
||||
type: "POST",
|
||||
data: data,
|
||||
url: ns.url("shop/stat/getstattotal"),
|
||||
success: function(res){
|
||||
$('.statistics-wrap .loading').hide();
|
||||
if (res.code == 0) {
|
||||
Object.keys(res.data).forEach(function (key) {
|
||||
var type = $('[data-value="'+ key +'"] .value').attr('data-type');
|
||||
var value = type == 'money' ? moneyFormat(res.data[key]) : parseInt(res.data[key]);
|
||||
$('[data-value="'+ key +'"] .value').text(value);
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
getShopStatistics({});
|
||||
|
||||
/**
|
||||
* 获取趋势数据
|
||||
* */
|
||||
var statData = [];
|
||||
function getShopStatData(data, type) {
|
||||
$.ajax({
|
||||
dataType: 'JSON',
|
||||
type: 'POST',
|
||||
url: type == 'hour' ? ns.url("shop/stat/getstathourdata") : ns.url("shop/stat/getStatData"),
|
||||
data: data,
|
||||
success: function(res) {
|
||||
statData = res;
|
||||
fetchEchart();
|
||||
}
|
||||
});
|
||||
}
|
||||
getShopStatData({}, 'hour');
|
||||
|
||||
// 图表
|
||||
if($('#main').length) {
|
||||
var baseColor = getComputedStyle(document.documentElement).getPropertyValue('--base-color');
|
||||
var myChart = echarts.init(document.getElementById('main'));
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ['新增商品数'],
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: "#000"
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '4%'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} '
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
color: [baseColor],
|
||||
series: [
|
||||
{
|
||||
name: '新增商品数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [],
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 渲染echart图表
|
||||
*/
|
||||
function fetchEchart() {
|
||||
var key = $('.statistics-wrap .data-item.selected').attr('data-value');
|
||||
option.xAxis.data = statData.time;
|
||||
option.legend.data[0] = $('.statistics-wrap .data-item.selected .title-text').text();
|
||||
option.series[0].name = $('.statistics-wrap .data-item.selected .title-text').text();
|
||||
option.series[0].data = statData[key];
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
$('.statistics-wrap .data-item').click(function () {
|
||||
if ($(this).hasClass('selected')) return;
|
||||
$('.statistics-wrap .data-item').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
fetchEchart();
|
||||
})
|
||||
</script>
|
||||
483
app/shop/view/stat/order.html
Executable file
483
app/shop/view/stat/order.html
Executable file
@@ -0,0 +1,483 @@
|
||||
<style>
|
||||
/*时间选择*/
|
||||
.time-screen .screen{display: flex}
|
||||
.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}
|
||||
.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;}
|
||||
.time-screen .screen .selected,.time-screen .item:hover{color: #fff;background: var(--base-color);border-color: var(--base-color) }
|
||||
.time-screen .screen .selected:after, .time-screen .item:hover:after {border-right: 1px solid var(--base-color);border-left: 1px solid var(--base-color);}
|
||||
|
||||
.data-wrap {display: flex;margin-top: 15px;}
|
||||
.data-wrap .data-item {flex: 1;display: flex}
|
||||
.data-wrap .data-item .box {flex: 1;margin-right: 15px;border: 1px solid #eee;box-sizing: border-box;padding: 15px;cursor: pointer}
|
||||
.data-wrap .data-item:last-child .box {margin-right: 0}
|
||||
.data-wrap .data-item .value {font-size: 25px;font-weight: bolder;line-height: 40px}
|
||||
.data-wrap .data-item .js-prompt-top {color:#C8C9CC;font-size:14px;z-index:999;cursor:pointer;}
|
||||
.data-wrap .data-item .info {font-size: 12px;color: #999;}
|
||||
.data-wrap .info .iconfont {font-size: 12px;}
|
||||
.data-wrap .data-item .text-color-green {color: #00A717}
|
||||
.data-wrap .data-item .text-color-red {color: #ff0000}
|
||||
.data-wrap .data-item.selected .box {border-color: var(--base-color);color: var(--base-color);}
|
||||
.statistics-wrap {position: relative}
|
||||
.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}
|
||||
.statistics-wrap .loading i {font-size: 25px}
|
||||
|
||||
.layui-layer-content .layui-form-label {width: 100px}
|
||||
.echart {margin-top: 15px}
|
||||
.echart-wrap {margin-top: 30px;display: flex;}
|
||||
.echart-wrap .main {flex: 1;height: 400px}
|
||||
.echart-wrap .main:nth-child(2) {margin-left: 15px}
|
||||
|
||||
.survey {margin:15px 15px 15px 0;background:#f2f3f5;display:flex;box-shadow:unset;align-items: center}
|
||||
.survey .layui-card {background:#f2f3f5;vertical-align:top;width:50%;display:inline-block;border-radius:0;float:left;margin-top:10px;box-shadow:unset;}
|
||||
.survey .layui-card-header {font-size:14px;box-shadow:unset;border:0;white-space: nowrap}
|
||||
.survey .layui-card {margin-bottom: 10px;}
|
||||
.survey .layui-card-body {padding-top:0px;font-size: 24px;white-space: nowrap;}
|
||||
.survey .layui-card-footer {padding: 0 15px;}
|
||||
.survey .symbol { padding: 35px 20px; font-size: 18px; }
|
||||
.constitute-wrap {display: flex;}
|
||||
.constitute-wrap .survey:first-child {flex: 1}
|
||||
.constitute-wrap .survey:last-child {margin-right: 0}
|
||||
.date-input{width: 300px}
|
||||
</style>
|
||||
|
||||
<div class="main-wrap">
|
||||
<div class="time-screen statistics">
|
||||
<div class="screen">
|
||||
<div class="item selected" date-type="today">今日</div>
|
||||
<div class="item" date-type="yesterday">昨日</div>
|
||||
<div class="item" date-type="seven">7日内</div>
|
||||
<div class="item" date-type="thirty">30日内</div>
|
||||
<div class="item" date-type="custom">自定义</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-wrap">
|
||||
<div class="data-wrap">
|
||||
<div class="data-item selected" data-value="expected_earnings_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">预计收入</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,店铺收入金额减去支出的金额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="earnings_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">营业收入</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,店铺收入的金额(订单、会员充值、会员开卡等)"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="expenditure_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">营业支出</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,店铺支出的金额(退款、会员提现)"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-wrap">
|
||||
<div class="data-item" data-value="order_pay_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">商城订单</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,商城订单的支付金额的总额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="cashier_order_pay_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">收银订单</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,收银台订单的支付金额的总额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="member_recharge_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">会员充值</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,会员充值金额的总额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="member_level_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">会员卡订单</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,会员卡订单金额的总额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
{if addon_is_exit('giftcard')}
|
||||
<div class="data-item" data-value="member_giftcard_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">礼品卡订单</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,礼品卡订单金额的总额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="data-item" data-value="refund_total">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">订单退款</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,店铺订单退款金额的总额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="member_withdraw_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">会员提现</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,会员提现的金额的总额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="loading">
|
||||
<i class="common-loading-layer layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="constitute-wrap">
|
||||
<div class="survey stat">
|
||||
<div class="layui-card layui-input-inline" data-value="earnings_total_money">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">收入总额</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="symbol"> = </div>
|
||||
|
||||
<div class="layui-card layui-input-inline" data-value="order_pay_money">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">商城订单(元)</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
<div class="layui-card-footer">
|
||||
<a href="{:href_url('shop/order/lists')}" class="text-color">明细</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="symbol"> + </div>
|
||||
|
||||
{if addon_is_exit('cashier', request()->siteid())}
|
||||
<div class="layui-card layui-input-inline" data-value="cashier_order_pay_money">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">收银订单(元)</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
<div class="layui-card-footer">
|
||||
<a href="{:href_url('cashier://shop/order/lists')}" class="text-color">明细</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="symbol"> + </div>
|
||||
{/if}
|
||||
|
||||
<div class="layui-card layui-input-inline" data-value="member_recharge_total_money">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">会员充值(元)</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
<div class="layui-card-footer">
|
||||
<a href="{:href_url('memberrecharge://shop/memberrecharge/orderlists')}" class="text-color">明细</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="symbol"> + </div>
|
||||
|
||||
<div class="layui-card layui-input-inline" data-value="member_level_total_money">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">会员开卡(元)</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
<div class="layui-card-footer">
|
||||
<a href="{:href_url('supermember://shop/membercard/order')}" class="text-color">明细</a>
|
||||
</div>
|
||||
</div>
|
||||
{if addon_is_exit('giftcard')}
|
||||
<div class="symbol"> + </div>
|
||||
<div class="layui-card layui-input-inline" data-value="member_giftcard_total_money">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">礼品卡订单(元)</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
<div class="layui-card-footer">
|
||||
<a href="{:href_url('giftcard://shop/order/order')}" class="text-color">明细</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="survey stat">
|
||||
<div class="layui-card layui-input-inline" data-value="expenditure_total_money">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">支出总额</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="symbol"> = </div>
|
||||
|
||||
<div class="layui-card layui-input-inline" data-value="refund_total">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">订单退款(元)</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
<div class="layui-card-footer">
|
||||
<a href="{:href_url('shop/orderrefund/lists')}" class="text-color">明细</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="symbol"> + </div>
|
||||
|
||||
<div class="layui-card layui-input-inline" data-value="member_withdraw_total_money">
|
||||
<div class="layui-card-header">
|
||||
<span class="hint">会员提现(元)</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<span class="num total_income value" data-type="money">0.00</span>
|
||||
</div>
|
||||
<div class="layui-card-footer">
|
||||
<a href="{:href_url('shop/memberwithdraw/lists')}" class="text-color">明细</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="echart-wrap">
|
||||
<div class="main" id="main"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="custom-box">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">选择时间:</label>
|
||||
|
||||
<div class="layui-inline layui-inline-margin" id="time_fission">
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" id="date" name="date" autocomplete="off" class="layui-input date-input" placeholder="请选择日期">
|
||||
<i class="iconfont iconriqi"></i>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="start_time" value="">
|
||||
<input type="hidden" name="end_time" value="">
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script src="SHOP_JS/echarts.min.js"></script>
|
||||
<script>
|
||||
$('.time-screen.statistics .item').click(function () {
|
||||
// if ($(this).hasClass('selected')) return;
|
||||
|
||||
var type = $(this).attr('date-type'),
|
||||
self = this;
|
||||
if (type != 'custom') $(this).addClass('selected').siblings().removeClass('selected');
|
||||
|
||||
switch (type) {
|
||||
case 'today':
|
||||
var time = {
|
||||
start_time: (new Date('{$today} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$today} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'hour');
|
||||
break;
|
||||
case 'yesterday':
|
||||
var time = {
|
||||
start_time: (new Date('{$yesterday} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$yesterday} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'hour');
|
||||
break;
|
||||
case 'seven':
|
||||
var dateObj = new Date(Date.now() - 604800000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
getShopStatistics({start_time: new Date(date).getTime() / 1000});
|
||||
getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
|
||||
break;
|
||||
case 'thirty':
|
||||
var dateObj = new Date(Date.now() - 2592000000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
getShopStatistics({start_time: new Date(date).getTime() / 1000});
|
||||
getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
|
||||
break;
|
||||
case 'custom':
|
||||
var _layer = layer.open({
|
||||
title: '自定义时间选择',
|
||||
type: 1,
|
||||
area: ['480px', '160px'], //自定义文本域宽高
|
||||
btn: ['确认', '取消'],
|
||||
content: $('#custom-box').html(),
|
||||
success: function (layero, index) {
|
||||
new LayDate({
|
||||
elem: '#date',
|
||||
type: 'datetime',
|
||||
rangeId:['start_time','end_time'],
|
||||
max: '{:date("Y-m-d")}',
|
||||
done: function(value, date, endDate){
|
||||
var time_arr = value.split(' - ');
|
||||
var start_time = time_arr[0];
|
||||
var end_time = time_arr[1];
|
||||
$('input[name="start_time"]').val(time_arr[0]);
|
||||
$('input[name="end_time"]').val(time_arr[1]);
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function () {
|
||||
var start_time = $('input[name="start_time"]').val();
|
||||
var end_time = $('input[name="end_time"]').val();
|
||||
if (start_time == ''){
|
||||
layer.msg('请选择时间');
|
||||
return;
|
||||
}
|
||||
var time = {
|
||||
start_time: (new Date(start_time)).getTime() / 1000,
|
||||
end_time: (new Date(end_time)).getTime() / 1000
|
||||
};
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'day');
|
||||
$(self).addClass('selected').siblings().removeClass('selected');
|
||||
layer.close(_layer);
|
||||
}
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
* */
|
||||
function getShopStatistics(data) {
|
||||
$('.statistics-wrap .loading').show();
|
||||
$.ajax({
|
||||
dataType: "JSON",
|
||||
type: "POST",
|
||||
data: data,
|
||||
url: ns.url("shop/stat/getstattotal"),
|
||||
success: function(res){
|
||||
$('.statistics-wrap .loading').hide();
|
||||
if (res.code == 0) {
|
||||
Object.keys(res.data).forEach(function (key) {
|
||||
var type = $('[data-value="'+ key +'"] .value').attr('data-type');
|
||||
var value = type == 'money' ? moneyFormat(res.data[key]) : parseInt(res.data[key]);
|
||||
$('[data-value="'+ key +'"] .value').text(value);
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
getShopStatistics({});
|
||||
|
||||
/**
|
||||
* 获取趋势数据
|
||||
* */
|
||||
var statData = [];
|
||||
function getShopStatData(data, type) {
|
||||
$.ajax({
|
||||
dataType: 'JSON',
|
||||
type: 'POST',
|
||||
url: type == 'hour' ? ns.url("shop/stat/getstathourdata") : ns.url("shop/stat/getStatData"),
|
||||
data: data,
|
||||
success: function(res) {
|
||||
statData = res;
|
||||
fetchEchart();
|
||||
}
|
||||
});
|
||||
}
|
||||
getShopStatData({}, 'hour');
|
||||
|
||||
// 图表
|
||||
if($('#main').length) {
|
||||
var baseColor = getComputedStyle(document.documentElement).getPropertyValue('--base-color');
|
||||
var myChart = echarts.init(document.getElementById('main'));
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ['新增商品数'],
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: "#000"
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '4%'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} '
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
color: [baseColor],
|
||||
series: [
|
||||
{
|
||||
name: '新增商品数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [],
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 渲染echart图表
|
||||
*/
|
||||
function fetchEchart() {
|
||||
var key = $('.statistics-wrap .data-item.selected').attr('data-value');
|
||||
option.xAxis.data = statData.time;
|
||||
option.legend.data[0] = $('.statistics-wrap .data-item.selected .title-text').text();
|
||||
option.series[0].name = $('.statistics-wrap .data-item.selected .title-text').text();
|
||||
option.series[0].data = statData[key];
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
$('.statistics-wrap .data-item').click(function () {
|
||||
if ($(this).hasClass('selected')) return;
|
||||
$('.statistics-wrap .data-item').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
fetchEchart();
|
||||
})
|
||||
</script>
|
||||
325
app/shop/view/stat/shop.html
Executable file
325
app/shop/view/stat/shop.html
Executable file
@@ -0,0 +1,325 @@
|
||||
<style>
|
||||
/*时间选择*/
|
||||
.time-screen .screen{display: flex}
|
||||
.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}
|
||||
.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;}
|
||||
.time-screen .screen .selected,.time-screen .item:hover{color: #fff;background: var(--base-color);border-color: var(--base-color) }
|
||||
.time-screen .screen .selected:after, .time-screen .item:hover:after {border-right: 1px solid var(--base-color);border-left: 1px solid var(--base-color);}
|
||||
|
||||
.data-wrap {display: flex;margin-top: 15px;}
|
||||
.data-wrap .data-item {flex: 1;display: flex}
|
||||
.data-wrap .data-item .box {flex: 1;margin-right: 15px;border: 1px solid #eee;box-sizing: border-box;padding: 15px;cursor: pointer}
|
||||
.data-wrap .data-item:last-child .box {margin-right: 0}
|
||||
.data-wrap .data-item .value {font-size: 25px;font-weight: bolder;line-height: 40px}
|
||||
.data-wrap .data-item .js-prompt-top {color:#C8C9CC;font-size:14px;z-index:999;cursor:pointer;}
|
||||
.data-wrap .data-item .info {font-size: 12px;color: #999;}
|
||||
.data-wrap .info .iconfont {font-size: 12px;}
|
||||
.data-wrap .data-item .text-color-green {color: #00A717}
|
||||
.data-wrap .data-item .text-color-red {color: #ff0000}
|
||||
.data-wrap .data-item.selected .box {border-color: var(--base-color);color: var(--base-color);}
|
||||
.statistics-wrap {position: relative}
|
||||
.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}
|
||||
.statistics-wrap .loading i {font-size: 25px}
|
||||
|
||||
.layui-layer-content .layui-form-label {width: 100px}
|
||||
.echart {margin-top: 15px}
|
||||
.echart-wrap {margin-top: 30px;display: flex;}
|
||||
.echart-wrap .main {flex: 1;height: 400px}
|
||||
.echart-wrap .main:nth-child(2) {margin-left: 15px}
|
||||
.date-input{width: 300px}
|
||||
</style>
|
||||
|
||||
<div class="main-wrap">
|
||||
<div class="time-screen statistics">
|
||||
<div class="screen">
|
||||
<div class="item selected" date-type="today">今日</div>
|
||||
<div class="item" date-type="yesterday">昨日</div>
|
||||
<div class="item" date-type="seven">7日内</div>
|
||||
<div class="item" date-type="thirty">30日内</div>
|
||||
<div class="item" date-type="custom">自定义</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-wrap">
|
||||
<div class="data-wrap">
|
||||
<div class="data-item selected" data-value="expected_earnings_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">预计收入</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,店铺收入金额减去支出的金额"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="earnings_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">营业收入</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,店铺收入的金额(订单、会员充值、会员开卡等)"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="expenditure_total_money">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">营业支出</span>(元)
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,店铺支出的金额(退款、会员提现)"></span>
|
||||
</div>
|
||||
<div class="value" data-type="money">0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data-wrap">
|
||||
<div class="data-item" data-value="visit_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">访客人数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,站点访问人数"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="member_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">新增会员数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,新注册的用户数"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="order_pay_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">支付订单数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,支付订单的数量"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="order_member_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">下单人数</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,用户下单人数"></span>
|
||||
</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="loading">
|
||||
<i class="common-loading-layer layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="echart-wrap">
|
||||
<div class="main" id="main"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="custom-box">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">选择时间:</label>
|
||||
|
||||
<div class="layui-inline layui-inline-margin" id="time_fission">
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" id="date" name="date" autocomplete="off" class="layui-input date-input" placeholder="请选择日期">
|
||||
<i class="iconfont iconriqi"></i>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="start_time" value="">
|
||||
<input type="hidden" name="end_time" value="">
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script src="SHOP_JS/echarts.min.js"></script>
|
||||
<script>
|
||||
$('.time-screen.statistics .item').click(function () {
|
||||
// if ($(this).hasClass('selected')) return;
|
||||
|
||||
var type = $(this).attr('date-type'),
|
||||
self = this;
|
||||
if (type != 'custom') $(this).addClass('selected').siblings().removeClass('selected');
|
||||
|
||||
switch (type) {
|
||||
case 'today':
|
||||
var time = {
|
||||
start_time: (new Date('{$today} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$today} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'hour');
|
||||
break;
|
||||
case 'yesterday':
|
||||
var time = {
|
||||
start_time: (new Date('{$yesterday} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$yesterday} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'hour');
|
||||
break;
|
||||
case 'seven':
|
||||
var dateObj = new Date(Date.now() - 604800000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
getShopStatistics({start_time: new Date(date).getTime() / 1000});
|
||||
getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
|
||||
break;
|
||||
case 'thirty':
|
||||
var dateObj = new Date(Date.now() - 2592000000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
getShopStatistics({start_time: new Date(date).getTime() / 1000});
|
||||
getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
|
||||
break;
|
||||
case 'custom':
|
||||
|
||||
var _layer = layer.open({
|
||||
title: '自定义时间选择',
|
||||
type: 1,
|
||||
area: ['480px', '160px'], //自定义文本域宽高
|
||||
btn: ['确认', '取消'],
|
||||
content: $('#custom-box').html(),
|
||||
success: function (layero, index) {
|
||||
new LayDate({
|
||||
elem: '#date',
|
||||
type: 'datetime',
|
||||
rangeId:['start_time','end_time'],
|
||||
max: '{:date("Y-m-d")}',
|
||||
done: function(value, date, endDate){
|
||||
var time_arr = value.split(' - ');
|
||||
var start_time = time_arr[0];
|
||||
var end_time = time_arr[1];
|
||||
$('input[name="start_time"]').val(time_arr[0]);
|
||||
$('input[name="end_time"]').val(time_arr[1]);
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function () {
|
||||
var start_time = $('input[name="start_time"]').val();
|
||||
var end_time = $('input[name="end_time"]').val();
|
||||
if (start_time == ''){
|
||||
layer.msg('请选择时间');
|
||||
return;
|
||||
}
|
||||
var time = {
|
||||
start_time: (new Date(start_time)).getTime() / 1000,
|
||||
end_time: (new Date(end_time)).getTime() / 1000
|
||||
};
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'day');
|
||||
$(self).addClass('selected').siblings().removeClass('selected');
|
||||
layer.close(_layer);
|
||||
}
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
* */
|
||||
function getShopStatistics(data) {
|
||||
$('.statistics-wrap .loading').show();
|
||||
$.ajax({
|
||||
dataType: "JSON",
|
||||
type: "POST",
|
||||
data: data,
|
||||
url: ns.url("shop/stat/getstattotal"),
|
||||
success: function(res){
|
||||
$('.statistics-wrap .loading').hide();
|
||||
if (res.code == 0) {
|
||||
Object.keys(res.data).forEach(function (key) {
|
||||
var type = $('[data-value="'+ key +'"] .value').attr('data-type');
|
||||
var value = type == 'money' ? moneyFormat(res.data[key]) : parseInt(res.data[key]);
|
||||
$('[data-value="'+ key +'"] .value').text(value);
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
getShopStatistics({});
|
||||
|
||||
/**
|
||||
* 获取趋势数据
|
||||
* */
|
||||
var statData = [];
|
||||
function getShopStatData(data, type) {
|
||||
$.ajax({
|
||||
dataType: 'JSON',
|
||||
type: 'POST',
|
||||
url: type == 'hour' ? ns.url("shop/stat/getstathourdata") : ns.url("shop/stat/getStatData"),
|
||||
data: data,
|
||||
success: function(res) {
|
||||
statData = res;
|
||||
fetchEchart();
|
||||
}
|
||||
});
|
||||
}
|
||||
getShopStatData({}, 'hour');
|
||||
|
||||
// 图表
|
||||
if($('#main').length) {
|
||||
var myChart = echarts.init(document.getElementById('main'));
|
||||
var baseColor = getComputedStyle(document.documentElement).getPropertyValue('--base-color');
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ['新增商品数'],
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: "#000"
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '4%'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} '
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
color: [baseColor],
|
||||
series: [
|
||||
{
|
||||
name: '新增商品数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [],
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 渲染echart图表
|
||||
*/
|
||||
function fetchEchart() {
|
||||
var key = $('.statistics-wrap .data-item.selected').attr('data-value');
|
||||
option.xAxis.data = statData.time;
|
||||
option.legend.data[0] = $('.statistics-wrap .data-item.selected .title-text').text();
|
||||
option.series[0].name = $('.statistics-wrap .data-item.selected .title-text').text();
|
||||
option.series[0].data = statData[key];
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
$('.statistics-wrap .data-item').click(function () {
|
||||
if ($(this).hasClass('selected')) return;
|
||||
$('.statistics-wrap .data-item').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
fetchEchart();
|
||||
})
|
||||
</script>
|
||||
373
app/shop/view/stat/visit.html
Executable file
373
app/shop/view/stat/visit.html
Executable file
@@ -0,0 +1,373 @@
|
||||
<style>
|
||||
/*时间选择*/
|
||||
.time-screen .screen{display: flex}
|
||||
.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}
|
||||
.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;}
|
||||
.time-screen .screen .selected,.time-screen .item:hover{color: #fff;background: var(--base-color);border-color: var(--base-color) }
|
||||
.time-screen .screen .selected:after, .time-screen .item:hover:after {border-right: 1px solid var(--base-color);border-left: 1px solid var(--base-color);}
|
||||
|
||||
.data-wrap {display: flex;margin-top: 15px;}
|
||||
.data-wrap .data-item {flex: 1;display: flex}
|
||||
.data-wrap .data-item .box {flex: 1;margin-right: 15px;border: 1px solid #eee;box-sizing: border-box;padding: 15px;cursor: pointer}
|
||||
.data-wrap .data-item:last-child .box {margin-right: 0}
|
||||
.data-wrap .data-item .js-prompt-top {color:#C8C9CC;font-size:14px;z-index:999;cursor:pointer;}
|
||||
.data-wrap .data-item .info {font-size: 12px;color: #999;}
|
||||
.data-wrap .info .iconfont {font-size: 12px;}
|
||||
.data-wrap .data-item .text-color-green {color: #00A717}
|
||||
.data-wrap .data-item .text-color-red {color: #ff0000}
|
||||
.data-wrap .data-item.selected .box {border-color: var(--base-color);color: var(--base-color);}
|
||||
.data-wrap .data-item .data {display: flex;justify-content: space-between;align-items: end;font-size: 14px;color: #999;margin-top: 15px}
|
||||
.statistics-wrap {position: relative}
|
||||
.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}
|
||||
.statistics-wrap .loading i {font-size: 25px}
|
||||
|
||||
.layui-layer-content .layui-form-label {width: 100px}
|
||||
.echart {margin-top: 15px}
|
||||
.echart-wrap {margin-top: 30px;display: flex;}
|
||||
.echart-wrap .main {flex: 1;height: 400px}
|
||||
.echart-wrap .main:nth-child(2) {margin-left: 15px}
|
||||
|
||||
.stat-board {display: flex;margin-top: 15px}
|
||||
.stat-board .board-title {color:#fff;display: flex;flex-direction: column;align-items: center;justify-content: center;width: 100px;height: 120px;}
|
||||
.stat-board .board-title .iconfont{color: #fff;font-size: 36px;margin-bottom: 10px;}
|
||||
.stat-board.visit{background: #f3f8ff;}
|
||||
.stat-board.order{background: #fffaf3;}
|
||||
.stat-board.visit .board-title {background: #177bff;}
|
||||
.stat-board.order .board-title {background: #ff9f15;}
|
||||
.stat-board .board-item {display: flex;flex-direction: column;justify-content: center;padding: 0 50px;width: 15%}
|
||||
.stat-board .board-item .title {font-size: 14px;}
|
||||
.stat-board .board-item .value {font-size: 26px;margin: 8px 0;}
|
||||
.stat-board .board-item .ratio {font-size: 12px;color: #999;line-height: 1}
|
||||
.stat-board .board-item .iconfont {font-size: 12px}
|
||||
.stat-board .board-item .rise {color: #f97337}
|
||||
.stat-board .board-item .decline {color: #0cc361}
|
||||
.date-input{width: 300px}
|
||||
</style>
|
||||
|
||||
<div class="main-wrap">
|
||||
<div class="time-screen statistics">
|
||||
<div class="screen">
|
||||
<div class="item selected" date-type="today">今日</div>
|
||||
<div class="item" date-type="yesterday">昨日</div>
|
||||
<div class="item" date-type="seven">7日内</div>
|
||||
<div class="item" date-type="thirty">30日内</div>
|
||||
<div class="item" date-type="custom">自定义</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-wrap">
|
||||
<div class="data-wrap">
|
||||
<div class="data-item selected" data-value="visit_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">全部</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,全部端口总的访客人数"></span>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div class="name">访客数</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="h5_visit_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">H5</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,H5端的访客人数"></span>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div class="name">访客数</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="weapp_visit_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">小程序</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,微信小程序端的访客人数"></span>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div class="name">访客数</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-item" data-value="wechat_visit_count">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<span class="title-text">公众号</span>
|
||||
<span class="iconfont iconwenhao js-prompt-top" data-tips="统计时间内,微信公众号端的访客人数"></span>
|
||||
</div>
|
||||
<div class="data">
|
||||
<div class="name">访客数</div>
|
||||
<div class="value" data-type="num">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="loading">
|
||||
<i class="common-loading-layer layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="echart-wrap">
|
||||
<div class="main" id="main"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-board visit">
|
||||
<div class="board-title">
|
||||
<i class="iconfont iconyonghu3"></i>
|
||||
<div>浏览访问</div>
|
||||
</div>
|
||||
<div class="board-item">
|
||||
<div class="title">访客数(人)</div>
|
||||
<div class="value">{$stat_today.visit_count}</div>
|
||||
{if $day_rate.visit_count < 0}
|
||||
<div class="ratio">比前日<i class="iconfont iconxia--jiantou decline"></i><span class="decline">{$day_rate.visit_count}</span></div>
|
||||
{else/}
|
||||
<div class="ratio">比前日<i class="iconfont iconshang--jiantou rise"></i><span class="rise">{$day_rate.visit_count}</span></div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="board-item">
|
||||
<div class="title">新增会员数(人)</div>
|
||||
<div class="value">{$stat_today.member_count}</div>
|
||||
{if $day_rate.member_count < 0}
|
||||
<div class="ratio">比前日<i class="iconfont iconxia--jiantou decline"></i><span class="decline">{$day_rate.member_count}</span></div>
|
||||
{else/}
|
||||
<div class="ratio">比前日<i class="iconfont iconshang--jiantou rise"></i><span class="rise">{$day_rate.member_count}</span></div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-board order">
|
||||
<div class="board-title">
|
||||
<i class="iconfont iconyingxiaozhongxin"></i>
|
||||
<div>成交转化</div>
|
||||
</div>
|
||||
<div class="board-item">
|
||||
<div class="title">支付人数(人)</div>
|
||||
<div class="value">{$stat_today.order_member_count}</div>
|
||||
{if $day_rate.order_member_count < 0}
|
||||
<div class="ratio">比前日<i class="iconfont iconxia--jiantou decline"></i><span class="decline">{$day_rate.order_member_count}</span></div>
|
||||
{else/}
|
||||
<div class="ratio">比前日<i class="iconfont iconshang--jiantou rise"></i><span class="rise">{$day_rate.order_member_count}</span></div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="board-item">
|
||||
<div class="title">访问-支付转化率(%)</div>
|
||||
<div class="value">{$stat_today.conversion_ratio}</div>
|
||||
{if $day_rate.conversion_ratio < 0}
|
||||
<div class="ratio">比前日<i class="iconfont iconxia--jiantou decline"></i><span class="decline">{$day_rate.conversion_ratio}</span></div>
|
||||
{else/}
|
||||
<div class="ratio">比前日<i class="iconfont iconshang--jiantou rise"></i><span class="rise">{$day_rate.conversion_ratio}</span></div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="custom-box">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">选择时间:</label>
|
||||
|
||||
<div class="layui-inline layui-inline-margin" id="time_fission">
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" id="date" name="date" autocomplete="off" class="layui-input date-input" placeholder="请选择日期">
|
||||
<i class="iconfont iconriqi"></i>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="start_time" value="">
|
||||
<input type="hidden" name="end_time" value="">
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<script src="SHOP_JS/echarts.min.js"></script>
|
||||
<script>
|
||||
$('.time-screen.statistics .item').click(function () {
|
||||
// if ($(this).hasClass('selected')) return;
|
||||
|
||||
var type = $(this).attr('date-type'),
|
||||
self = this;
|
||||
if (type != 'custom') $(this).addClass('selected').siblings().removeClass('selected');
|
||||
|
||||
switch (type) {
|
||||
case 'today':
|
||||
var time = {
|
||||
start_time: (new Date('{$today} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$today} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'hour');
|
||||
break;
|
||||
case 'yesterday':
|
||||
var time = {
|
||||
start_time: (new Date('{$yesterday} 00:00:00')).getTime() / 1000,
|
||||
end_time: (new Date('{$yesterday} 23:59:59')).getTime() / 1000,
|
||||
}
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'hour');
|
||||
break;
|
||||
case 'seven':
|
||||
var dateObj = new Date(Date.now() - 604800000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
getShopStatistics({start_time: new Date(date).getTime() / 1000});
|
||||
getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
|
||||
break;
|
||||
case 'thirty':
|
||||
var dateObj = new Date(Date.now() - 2592000000);
|
||||
var date = dateObj.getFullYear() + '-' + (dateObj.getMonth() + 1) + '-' + dateObj.getDate();
|
||||
getShopStatistics({start_time: new Date(date).getTime() / 1000});
|
||||
getShopStatData({start_time: new Date(date).getTime() / 1000}, 'day');
|
||||
break;
|
||||
case 'custom':
|
||||
var _layer = layer.open({
|
||||
title: '自定义时间选择',
|
||||
type: 1,
|
||||
area: ['480px', '160px'], //自定义文本域宽高
|
||||
btn: ['确认', '取消'],
|
||||
content: $('#custom-box').html(),
|
||||
success: function (layero, index) {
|
||||
new LayDate({
|
||||
elem: '#date',
|
||||
type: 'datetime',
|
||||
rangeId:['start_time','end_time'],
|
||||
max: '{:date("Y-m-d")}',
|
||||
done: function(value, date, endDate){
|
||||
var time_arr = value.split(' - ');
|
||||
var start_time = time_arr[0];
|
||||
var end_time = time_arr[1];
|
||||
$('input[name="start_time"]').val(time_arr[0]);
|
||||
$('input[name="end_time"]').val(time_arr[1]);
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function () {
|
||||
var start_time = $('input[name="start_time"]').val();
|
||||
var end_time = $('input[name="end_time"]').val();
|
||||
if (start_time == ''){
|
||||
layer.msg('请选择时间');
|
||||
return;
|
||||
}
|
||||
var time = {
|
||||
start_time: (new Date(start_time)).getTime() / 1000,
|
||||
end_time: (new Date(end_time)).getTime() / 1000
|
||||
};
|
||||
getShopStatistics(time);
|
||||
getShopStatData(time, 'day');
|
||||
$(self).addClass('selected').siblings().removeClass('selected');
|
||||
layer.close(_layer);
|
||||
}
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
* */
|
||||
function getShopStatistics(data) {
|
||||
$('.statistics-wrap .loading').show();
|
||||
$.ajax({
|
||||
dataType: "JSON",
|
||||
type: "POST",
|
||||
data: data,
|
||||
url: ns.url("shop/stat/getstattotal"),
|
||||
success: function(res){
|
||||
$('.statistics-wrap .loading').hide();
|
||||
if (res.code == 0) {
|
||||
Object.keys(res.data).forEach(function (key) {
|
||||
var type = $('[data-value="'+ key +'"] .value').attr('data-type');
|
||||
var value = type == 'money' ? moneyFormat(res.data[key]) : parseInt(res.data[key]);
|
||||
$('[data-value="'+ key +'"] .value').text(value);
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
getShopStatistics({});
|
||||
|
||||
/**
|
||||
* 获取趋势数据
|
||||
* */
|
||||
var statData = [];
|
||||
function getShopStatData(data, type) {
|
||||
$.ajax({
|
||||
dataType: 'JSON',
|
||||
type: 'POST',
|
||||
url: type == 'hour' ? ns.url("shop/stat/getstathourdata") : ns.url("shop/stat/getStatData"),
|
||||
data: data,
|
||||
success: function(res) {
|
||||
statData = res;
|
||||
fetchEchart();
|
||||
}
|
||||
});
|
||||
}
|
||||
getShopStatData({}, 'hour');
|
||||
|
||||
// 图表
|
||||
var baseColor = getComputedStyle(document.documentElement).getPropertyValue('--base-color');
|
||||
if($('#main').length) {
|
||||
var myChart = echarts.init(document.getElementById('main'));
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ['新增商品数'],
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: "#000"
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '4%'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value} '
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
color: [baseColor],
|
||||
series: [
|
||||
{
|
||||
name: '新增商品数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [],
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染echart图表
|
||||
*/
|
||||
function fetchEchart() {
|
||||
var key = $('.statistics-wrap .data-item.selected').attr('data-value');
|
||||
option.xAxis.data = statData.time;
|
||||
option.legend.data[0] = $('.statistics-wrap .data-item.selected .title-text').text();
|
||||
option.series[0].name = $('.statistics-wrap .data-item.selected .title-text').text();
|
||||
option.series[0].data = statData[key];
|
||||
myChart.setOption(option);
|
||||
}
|
||||
|
||||
$('.statistics-wrap .data-item').click(function () {
|
||||
if ($(this).hasClass('selected')) return;
|
||||
$('.statistics-wrap .data-item').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
fetchEchart();
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user