Merge branch 'master' of 192.168.195.14:server/manghe

This commit is contained in:
youda 2025-05-27 06:55:42 +08:00
commit a43d9ae922
4 changed files with 424 additions and 347 deletions

View File

@ -2148,4 +2148,120 @@ class Statistics extends Base
}
}
/**
* 获取每日数据统计
* @return \think\response\Json
*/
public function getDailyStatistics()
{
try {
// 获取日期范围默认最近30天
$endDate = date('Y-m-d');
$startDate = date('Y-m-d', strtotime('-30 days'));
// 1. 按天订单数据统计
$orderStats = Db::query("
SELECT
DATE(FROM_UNIXTIME(o.addtime)) as day,
COUNT(1) as order_count,
COUNT(DISTINCT o.user_id) as user_count,
IFNULL(SUM(price), 0) as price,
IFNULL(SUM(use_money), 0) as use_money,
IFNULL(SUM(use_integral), 0) as use_integral,
IFNULL(SUM(use_money2), 0) as use_money2
FROM `order` o
LEFT JOIN `user` u ON o.user_id = u.id
WHERE u.status = 1
AND u.istest = 0
AND o.status = 1
AND o.addtime >= UNIX_TIMESTAMP(?)
AND o.addtime < UNIX_TIMESTAMP(?)
GROUP BY DATE(FROM_UNIXTIME(o.addtime))
", [$startDate, $endDate]);
// 2. 登录人数统计
$loginStats = Db::query("
SELECT
login_date as day,
COUNT(1) as user_login
FROM user_login_log
WHERE login_date >= ?
AND login_date < ?
GROUP BY login_date
", [$startDate, $endDate]);
// 3. 每日新增用户统计
$registerStats = Db::query("
SELECT
DATE(FROM_UNIXTIME(addtime)) as day,
COUNT(1) as user_register
FROM `user`
WHERE status = 1
AND istest = 0
AND addtime >= UNIX_TIMESTAMP(?)
AND addtime < UNIX_TIMESTAMP(?)
GROUP BY DATE(FROM_UNIXTIME(addtime))
", [$startDate, $endDate]);
// 4. 钻石每日消费数据
$diamondStats = Db::query("
SELECT
DATE(o.created_at) as day,
IFNULL(SUM(amount_paid), 0) as amount_paid
FROM diamond_orders o
LEFT JOIN `user` u ON o.user_id = u.id
WHERE o.status = 'success'
AND u.status = 1
AND u.istest = 0
AND o.created_at >= ?
AND o.created_at < ?
GROUP BY DATE(o.created_at)
", [$startDate, $endDate]);
// 生成日期范围内的所有日期
$allDates = [];
$currentDate = strtotime($startDate);
$endTimestamp = strtotime($endDate);
while ($currentDate < $endTimestamp) {
$allDates[] = date('Y-m-d', $currentDate);
$currentDate = strtotime('+1 day', $currentDate);
}
// 将统计数据转换为以日期为键的关联数组
$orderMap = array_column($orderStats, null, 'day');
$loginMap = array_column($loginStats, null, 'day');
$registerMap = array_column($registerStats, null, 'day');
$diamondMap = array_column($diamondStats, null, 'day');
// 合并所有数据
$result = [];
foreach ($allDates as $date) {
$result[] = [
'day' => $date,
'order_count' => isset($orderMap[$date]) ? intval($orderMap[$date]['order_count']) : 0,
'user_count' => isset($orderMap[$date]) ? intval($orderMap[$date]['user_count']) : 0,
'price' => isset($orderMap[$date]) ? floatval($orderMap[$date]['price']) : 0,
'use_money' => isset($orderMap[$date]) ? floatval($orderMap[$date]['use_money']) : 0,
'use_integral' => isset($orderMap[$date]) ? floatval($orderMap[$date]['use_integral']) : 0,
'use_money2' => isset($orderMap[$date]) ? floatval($orderMap[$date]['use_money2']) : 0,
'user_login' => isset($loginMap[$date]) ? intval($loginMap[$date]['user_login']) : 0,
'user_register' => isset($registerMap[$date]) ? intval($registerMap[$date]['user_register']) : 0,
'amount_paid' => isset($diamondMap[$date]) ? floatval($diamondMap[$date]['amount_paid']) : 0
];
}
return json([
'code' => 0,
'msg' => '获取成功',
'data' => $result
]);
} catch (\Exception $e) {
return json([
'code' => 1,
'msg' => '获取数据失败:' . $e->getMessage()
]);
}
}
}

View File

@ -336,6 +336,8 @@ Route::rule('statistics_orderList', 'Statistics/goodsList', 'GET');
Route::rule('statistics_order', 'Statistics/orderList', 'GET');
//出货概览
Route::rule('statistics_productsOverview', 'Statistics/productsOverview', 'GET');
//每日数据统计
Route::rule('statistics_dailyStatistics', 'Statistics/getDailyStatistics', 'GET');
//利润支出
Route::rule('ProfitExpenses', 'Profit/index', 'GET');

View File

@ -8,30 +8,34 @@
</style>
<body>
<!-- 表格容器移到上面 -->
<div class="layui-fluid">
<div class="layui-card">
<div class="layui-card-body">
<table id="dataTable" lay-filter="dataTable"></table>
</div>
</div>
</div>
<!-- 统计图表移到下面 -->
<div class="layui-fluid">
<div class="layui-card">
<div class="layui-row">
<div class="layui-col-xs6">
<div class="layui-card">
<div class="layui-card-body" style="padding: 0px;">
<div class="layui-row">
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width: 100%;height:350px;"></div>
</div>
</div>
</div>
</div>
<div class="layui-col-xs6">
<div class="layui-card">
<div class="layui-card-body" style="padding: 0px;">
<div class="layui-row">
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="chongzhi" style="width: 100%;height:350px;"></div>
</div>
</div>
</div>
</div>
@ -39,62 +43,58 @@
<div class="layui-card">
<div class="layui-card-body" style="padding: 0px;">
<div class="layui-row">
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="lirun" style="width: 100%;height:350px;"></div>
</div>
<div>
备注:总收入=订单支付(微信收入+钻石收入)+其他收入;<br />
备注:总支出=订单出货+其他支出;<br />
备注:利润=总收入-总支出;<br />
</div>
</div>
</div>
</div>
<div class="layui-col-xs6">
<div class="layui-card">
<div class="layui-card-body" style="padding: 0px;">
<div class="layui-row">
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="qita" style="width: 100%;height:350px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{include file="Public:footer"/}
<script type="text/javascript">
// 通用图表初始化方法
function initChart(divId, option) {
var chart = echarts.init(document.getElementById(divId));
chart.setOption(option);
return chart;
}
// 假设这是你的 JSON 数据
var jsonData = {$list|json_encode|raw};
// var jsonData = { $list| json_encode | raw};
// 将 JSON 数据转换为以日期为键的对象,方便快速查找
var dataMap = {};
jsonData.forEach(function (item) {
var date = item.record_date; // 提取日期
dataMap[date] = {
login: item.login_count,
register: item.register_count,
consume: item.consume_user_count,
consume_rmb_count: item.consume_rmb_count,
recharge_amount: item.recharge_amount,
balance_consume: item.balance_consume,
recharge_sum: item.recharge_sum,
shipment_money: item.shipment_money,
send_money: item.send_money,
recycle_money: item.recycle_money,
profit_money: item.profit_money,
all_shipment_money: item.all_shipment_money,
all_recycle_money: item.all_recycle_money,
all_money: item.all_money,
};
});
// jsonData.forEach(function (item) {
// var date = item.record_date; // 提取日期
// dataMap[date] = {
// login: item.login_count,
// register: item.register_count,
// consume: item.consume_user_count,
// consume_rmb_count: item.consume_rmb_count,
// recharge_amount: item.recharge_amount,
// balance_consume: item.balance_consume,
// recharge_sum: item.recharge_sum,
// shipment_money: item.shipment_money,
// send_money: item.send_money,
// recycle_money: item.recycle_money,
// profit_money: item.profit_money,
// all_shipment_money: item.all_shipment_money,
// all_recycle_money: item.all_recycle_money,
// all_money: item.all_money,
// };
// });
// 生成从 2025-03-01 到当前日期的所有日期
function generateDateRange(startDate, endDate) {
@ -130,44 +130,40 @@
var all_shipment_money = [];
var all_recycle_money = [];
var all_money = [];
dateRange.forEach(function (date) {
var data = dataMap[date] || {
login: 0, register: 0, consume: 0, consume_rmb_count: 0,
recharge_amount: 0,
balance_consume: 0,
recharge_sum: 0,
shipment_money: 0,
send_money: 0,
recycle_money: 0,
profit_money: 0,
all_shipment_money: 0,
all_recycle_money: 0,
all_money: 0
}; // 如果数据不存在,则默认为 0
loginData.push([date, data.login]);
registerData.push([date, data.register]);
consumeData.push([date, data.consume]);
consume_rmb_count.push([date, data.consume_rmb_count]);
recharge_amount.push([date, data.recharge_amount]);
balance_consume.push([date, data.balance_consume]);
recharge_sum.push([date, data.recharge_sum]);
shipment_money.push([date, data.shipment_money]);
send_money.push([date, data.send_money]);
recycle_money.push([date, data.recycle_money]);
profit_money.push([date, data.profit_money]);
all_shipment_money.push([date, data.all_shipment_money]);
all_recycle_money.push([date, data.all_recycle_money]);
all_money.push([date, data.all_money]);
});
// 输出结果
console.log('登录人数数据:', loginData);
console.log('注册人数数据:', registerData);
console.log('充值人数数据:', consumeData);
$(function () {
$.ajax({
url: '/admin/statistics_dailyStatistics',
type: 'GET',
success: function (res) {
console.log(res);
var recharge_amount = [];
var recharge_d = [];
res.data.forEach(function (item) {
// {
// "day": "2025-04-29",
// "order_count": 615,
// "user_count": 1,
// "price": 0,
// "use_money": 70495,
// "use_integral": 50,
// "use_money2": 222450,
// "user_login": 6,
// "user_register": 0,
// "amount_paid": 0
// }
loginData.push([item.day, item.user_login]);
registerData.push([item.day, item.user_register]);
recharge_amount.push([item.day, item.price]);
recharge_d.push([item.day, item.use_money]);
});
console.log(loginData);
console.log(registerData);
initUserOption();
initChongzhiOption(recharge_amount, recharge_d);
initDataTable(res.data); // 初始化表格
}
})
})
// 生成时间序列数据
function generateTimeSeriesData(startDate, count, interval) {
@ -183,289 +179,252 @@
return data;
}
function initUserOption() {
var option = {
title: {
text: '用户数据'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['登录', '注册']
},
grid: {
left: '3%',
right: '4%',
bottom: '15%', // 为 dataZoom 留出空间
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'time', // 设置为时间轴
boundaryGap: false,
axisLabel: {
formatter: '{MM}-{dd}' // 自定义时间显示格式
}
},
yAxis: {
type: 'value'
},
dataZoom: [ // 添加 dataZoom 组件
{
type: 'slider', // 滑动条型 dataZoom
xAxisIndex: 0, // 控制 x 轴
start: 50, // 默认起始位置0%
end: 100 // 默认结束位置50%
},
{
type: 'inside', // 内置型 dataZoom支持鼠标滚轮缩放
xAxisIndex: 0
}
],
series: [
{
name: '登录',
type: 'line',
data: loginData // 使用生成的时间序列数据
},
{
name: '注册',
type: 'line',
data: registerData // 使用生成的时间序列数据
},
// {
// name: '消费人数',
// type: 'line',
// data: consumeData // 使用生成的时间序列数据
// },
// {
// name: '微信充值人数',
// type: 'line',
// stack: 'Total',
// data: consume_rmb_count // 使用生成的时间序列数据
// }
]
};
// 使用刚指定的配置项和数据显示图表
var myChart = initChart('main', option);
}
// 指定图表的配置项和数据
var option = {
title: {
text: '用户数据'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['登录', '注册']
},
grid: {
left: '3%',
right: '4%',
bottom: '15%', // 为 dataZoom 留出空间
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'time', // 设置为时间轴
boundaryGap: false,
axisLabel: {
formatter: '{MM}-{dd}' // 自定义时间显示格式
}
},
yAxis: {
type: 'value'
},
dataZoom: [ // 添加 dataZoom 组件
{
type: 'slider', // 滑动条型 dataZoom
xAxisIndex: 0, // 控制 x 轴
start: 50, // 默认起始位置0%
end: 100 // 默认结束位置50%
function initChongzhiOption(recharge_amount, recharge_d) {
// 指定图表的配置项和数据
var option1 = {
title: {
text: '订单支付数据'
},
{
type: 'inside', // 内置型 dataZoom支持鼠标滚轮缩放
xAxisIndex: 0
}
],
series: [
{
name: '登录',
type: 'line',
data: loginData // 使用生成的时间序列数据
tooltip: {
trigger: 'axis'
},
{
name: '注册',
type: 'line',
data: registerData // 使用生成的时间序列数据
legend: {
data: ['RMB支付', '钻石支付']
},
// {
// name: '消费人数',
// type: 'line',
// data: consumeData // 使用生成的时间序列数据
// },
// {
// name: '微信充值人数',
// type: 'line',
// stack: 'Total',
// data: consume_rmb_count // 使用生成的时间序列数据
// }
]
};
// 使用刚指定的配置项和数据显示图表
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
// 指定图表的配置项和数据
var option1 = {
title: {
text: '充值数据'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['总消费', '微信消费', '钻石消费']
},
grid: {
left: '3%',
right: '4%',
bottom: '15%', // 为 dataZoom 留出空间
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'time', // 设置为时间轴
boundaryGap: false,
axisLabel: {
formatter: '{MM}-{dd}' // 自定义时间显示格式
}
},
yAxis: {
type: 'value'
},
dataZoom: [ // 添加 dataZoom 组件
{
type: 'slider', // 滑动条型 dataZoom
xAxisIndex: 0, // 控制 x 轴
start: 50, // 默认起始位置0%
end: 100 // 默认结束位置50%
grid: {
left: '3%',
right: '4%',
bottom: '15%', // 为 dataZoom 留出空间
containLabel: true
},
{
type: 'inside', // 内置型 dataZoom支持鼠标滚轮缩放
xAxisIndex: 0
}
],
series: [
{
name: '总消费',
type: 'line',
data: recharge_sum // 使用生成的时间序列数据
toolbox: {
feature: {
saveAsImage: {}
}
},
{
name: '微信消费',
type: 'line',
data: recharge_amount // 使用生成的时间序列数据
xAxis: {
type: 'time', // 设置为时间轴
boundaryGap: false,
axisLabel: {
formatter: '{MM}-{dd}' // 自定义时间显示格式
}
},
{
name: '钻石消费',
type: 'line',
data: balance_consume // 使用生成的时间序列数据
}
]
};
// 使用刚指定的配置项和数据显示图表
var chongzhi = echarts.init(document.getElementById('chongzhi'));
chongzhi.setOption(option1);
// 指定图表的配置项和数据
var option2 = {
title: {
text: '充值数据'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['总收入', '总支出']
},
grid: {
left: '3%',
right: '4%',
bottom: '15%', // 为 dataZoom 留出空间
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'time', // 设置为时间轴
boundaryGap: false,
axisLabel: {
formatter: '{MM}-{dd}' // 自定义时间显示格式
}
},
yAxis: {
type: 'value'
},
dataZoom: [ // 添加 dataZoom 组件
{
type: 'slider', // 滑动条型 dataZoom
xAxisIndex: 0, // 控制 x 轴
start: 50, // 默认起始位置0%
end: 100 // 默认结束位置50%
yAxis: {
type: 'value'
},
{
type: 'inside', // 内置型 dataZoom支持鼠标滚轮缩放
xAxisIndex: 0
}
],
series: [
// {
// name: '利润',
// type: 'line',
dataZoom: [ // 添加 dataZoom 组件
{
type: 'slider', // 滑动条型 dataZoom
xAxisIndex: 0, // 控制 x 轴
start: 50, // 默认起始位置0%
end: 100 // 默认结束位置50%
},
{
type: 'inside', // 内置型 dataZoom支持鼠标滚轮缩放
xAxisIndex: 0
}
],
series: [
{
name: 'RMB支付',
type: 'line',
// data: all_money // 使用生成的时间序列数据
// },
{
name: '总收入',
type: 'line',
data: recharge_amount // 使用生成的时间序列数据
},
{
name: '钻石支付',
type: 'line',
data: all_recycle_money // 使用生成的时间序列数据
data: recharge_d // 使用生成的时间序列数据
}
]
};
// 使用刚指定的配置项和数据显示图表
var chongzhi = initChart('chongzhi', option1);
}
function initLirunOption() {
// 指定图表的配置项和数据
var option3 = {
title: {
text: '其他数据'
},
{
name: '总支出',
type: 'line',
data: all_shipment_money // 使用生成的时间序列数据
}
]
};
// 使用刚指定的配置项和数据显示图表
// var lirun = echarts.init(document.getElementById('lirun'));
// lirun.setOption(option2);
// 指定图表的配置项和数据
var option3 = {
title: {
text: '其他数据'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['出货价值','发货价值', '回收价值']
},
grid: {
left: '3%',
right: '4%',
bottom: '15%', // 为 dataZoom 留出空间
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'time', // 设置为时间轴
boundaryGap: false,
axisLabel: {
formatter: '{MM}-{dd}' // 自定义时间显示格式
}
},
yAxis: {
type: 'value'
},
dataZoom: [ // 添加 dataZoom 组件
{
type: 'slider', // 滑动条型 dataZoom
xAxisIndex: 0, // 控制 x 轴
start: 50, // 默认起始位置0%
end: 100 // 默认结束位置50%
tooltip: {
trigger: 'axis'
},
{
type: 'inside', // 内置型 dataZoom支持鼠标滚轮缩放
xAxisIndex: 0
}
],
series: [
{
name: '出货价值',
type: 'line',
data: shipment_money // 使用生成的时间序列数据
legend: {
data: ['出货价值', '发货价值', '回收价值']
},
{
name: '发货价值',
type: 'line',
data: send_money // 使用生成的时间序列数据
grid: {
left: '3%',
right: '4%',
bottom: '15%', // 为 dataZoom 留出空间
containLabel: true
},
{
name: '回收价值',
type: 'line',
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'time', // 设置为时间轴
boundaryGap: false,
axisLabel: {
formatter: '{MM}-{dd}' // 自定义时间显示格式
}
},
yAxis: {
type: 'value'
},
dataZoom: [ // 添加 dataZoom 组件
{
type: 'slider', // 滑动条型 dataZoom
xAxisIndex: 0, // 控制 x 轴
start: 50, // 默认起始位置0%
end: 100 // 默认结束位置50%
},
{
type: 'inside', // 内置型 dataZoom支持鼠标滚轮缩放
xAxisIndex: 0
}
],
series: [
{
name: '出货价值',
type: 'line',
data: recycle_money // 使用生成的时间序列数据
}
]
};
// 使用刚指定的配置项和数据显示图表
// var qita = echarts.init(document.getElementById('qita'));
// qita.setOption(option3);
data: shipment_money // 使用生成的时间序列数据
},
{
name: '发货价值',
type: 'line',
data: send_money // 使用生成的时间序列数据
},
{
name: '回收价值',
type: 'line',
data: recycle_money // 使用生成的时间序列数据
}
]
};
// 使用刚指定的配置项和数据显示图表
var qita = initChart('qita', option3);
}
// 初始化数据表格
function initDataTable(data) {
layui.use('table', function () {
var table = layui.table;
// 表格初始化
table.render({
elem: '#dataTable',
data: data,
title: '统计数据',
cols: [[
{ field: 'day', title: '日期', width: 180, sort: true, rowspan: 3 },
{ title: '用户信息', colspan: 2 },
{ title: '订单信息', colspan: 6 },
{ title: '钻石商城',colspan: 2 }
], [
{ field: 'user_register', title: '注册人数', width: 120 },
{ field: 'user_login', title: '登录人数', width: 120 },
{ field: 'order_count', title: '订单数量', width: 120 },
{ field: 'user_count', title: '用户数量', width: 120 },
{ field: 'price', title: 'RMB支付', width: 120 },
{ field: 'use_money', title: '钻石支付', width: 120 },
{ field: 'use_integral', title: 'UU币支付', width: 120 },
{ field: 'use_money2', title: '哒哒券支付', width: 120 },
{ field: 'amount_paid', title: '支付总额', width: 120 }
]],
page: true, // 开启分页
limit: 10, // 每页显示的条数
limits: [10, 20, 30, 50], // 每页条数的选择项
height: 'full-200', // 表格高度
text: {
none: '暂无相关数据'
}
});
});
}
</script>
</body>

View File

@ -112,10 +112,10 @@ return [
'url' => '/admin/ProfitRvenue',
'name' => '其它收入',
],
// [
// 'url' => '/admin/user_statistics',
// 'name' => '数据统计',
// ],
[
'url' => '/admin/user_statistics',
'name' => '每日数据统计',
],
],
],
[