提交代码

This commit is contained in:
youda 2025-05-04 21:48:41 +08:00
parent 119f9dc6cc
commit ecfd6498e3
5 changed files with 517 additions and 0 deletions

View File

@ -1022,6 +1022,7 @@ class Order extends Base
// $where[] = ['u.istest', '=', 0];
if ($user_id) {
$user_id = $this->convertUidToUserId($user_id);
$where[] = ['o.user_id', '=', $user_id];
}

View File

@ -1506,4 +1506,331 @@ class User extends Base
return json(['status' => 0, 'msg' => '手机号绑定失败']);
}
}
/**
* 用户盈亏列表页面
*/
public function userProfitLossList()
{
return View::fetch('User/user_profit_loss_list');
}
/**
* 获取用户盈亏数据
*/
public function getUserProfitLoss()
{
$param = input();
// 构建查询条件
$where = [];
$whereUser = 'u.status=1 and u.istest=0 and o.status=1';
$whereUser1 = '';
// 处理时间范围参数
if (!empty($param['time_range'])) {
$dates = explode(' - ', $param['time_range']);
if (count($dates) == 2) {
$start_time = strtotime($dates[0]);
// 结束日期加一天减1秒确保包含当天所有数据
$end_time = strtotime($dates[1] . ' 23:59:59');
// 只有当提供了时间范围时,才添加时间条件
$whereUser .= " and o.addtime > {$start_time} and o.addtime < {$end_time}";
$whereUser1 = "and addtime < {$end_time}";
}
}
// 处理用户ID/UID参数
if (!empty($param['uid'])) {
$uid = trim($param['uid']);
// 判断是否为数字UID或者字符串UID
if (is_numeric($uid)) {
$user = \app\common\model\User::where('id', $uid)->whereOr('uid', $uid)->find();
if ($user) {
$whereUser .= " and o.user_id = {$user['id']}";
}
} else {
$user = \app\common\model\User::where('uid', $uid)->find();
if ($user) {
$whereUser .= " and o.user_id = {$user['id']}";
}
}
}
// 构建SQL查询
$sql = "select c.* from (
select t.*,
(CASE
WHEN t.use_money>0 THEN (t.use_money-t.fh_money-t.bb_money-t.money2)
ELSE 0
END) yue_money
from (
SELECT o.user_id, u.uid, u.nickname, u.headimg, u.mobile,
u.money,
u.integral,
count(1) orderCount,
sum(IFNULL(order_zhe_total,0)) order_zhe_total,
IFNULL(sum(price),0) money_1,
IFNULL(sum(use_money),0) money_2,
IFNULL(sum(price)+SUM(use_money),0) use_money,
(select IFNULL(sum(goodslist_money),0) sc_money from order_list where user_id=o.user_id and status=2 {$whereUser1}) fh_money,
(select IFNULL(sum(goodslist_money),0) sc_money from order_list where user_id=o.user_id and status=0 {$whereUser1}) bb_money,
(TRUNCATE(u.money2/100, 2)) money2
FROM `order` o LEFT join `user` u ON o.user_id=u.id where {$whereUser} group by o.user_id ) t where use_money>0
) c order by yue_money desc";
// 分页处理
$page = isset($param['page']) ? intval($param['page']) : 1;
$limit = isset($param['limit']) ? intval($param['limit']) : 20;
// 获取总记录数
$countSql = "SELECT COUNT(*) as count FROM ({$sql}) as temp";
$count = \think\facade\Db::query($countSql)[0]['count'];
// 添加分页
$sql .= " LIMIT " . (($page - 1) * $limit) . ", {$limit}";
// 执行查询
$list = \think\facade\Db::query($sql);
// 处理结果数据
foreach ($list as &$item) {
// 处理图片URL
$item['headimg'] = empty($item['headimg']) ? '' : imageUrl($item['headimg']);
// 格式化数值
$item['money'] = floatval($item['money']);
$item['integral'] = floatval($item['integral']);
$item['money2'] = floatval($item['money2']);
$item['order_zhe_total'] = floatval($item['order_zhe_total']);
$item['money_1'] = floatval($item['money_1']);
$item['money_2'] = floatval($item['money_2']);
$item['use_money'] = floatval($item['use_money']);
$item['fh_money'] = floatval($item['fh_money']);
$item['bb_money'] = floatval($item['bb_money']);
$item['yue_money'] = floatval($item['yue_money']);
// 处理盈亏状态
$item['profit_status'] = $item['yue_money'] > 0 ? '亏损' : '盈利';
$item['profit_value'] = abs($item['yue_money']);
}
return json([
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list
]);
}
/**
* 导出用户盈亏列表到Excel
*/
public function exportUserProfitLoss()
{
$param = input();
// 构建查询条件
$where = [];
$whereUser = 'u.status=1 and u.istest=0 and o.status=1';
$whereUser1 = '';
// 处理时间范围参数
if (!empty($param['time_range'])) {
$dates = explode(' - ', $param['time_range']);
if (count($dates) == 2) {
$start_time = strtotime($dates[0]);
// 结束日期加一天减1秒确保包含当天所有数据
$end_time = strtotime($dates[1] . ' 23:59:59');
// 只有当提供了时间范围时,才添加时间条件
$whereUser .= " and o.addtime > {$start_time} and o.addtime < {$end_time}";
$whereUser1 = "and addtime < {$end_time}";
}
}
// 处理用户ID/UID参数
if (!empty($param['uid'])) {
$uid = trim($param['uid']);
// 判断是否为数字UID或者字符串UID
if (is_numeric($uid)) {
$user = \app\common\model\User::where('id', $uid)->whereOr('uid', $uid)->find();
if ($user) {
$whereUser .= " and o.user_id = {$user['id']}";
}
} else {
$user = \app\common\model\User::where('uid', $uid)->find();
if ($user) {
$whereUser .= " and o.user_id = {$user['id']}";
}
}
}
// 构建SQL查询 - 不应用分页限制,获取全部数据
$sql = "select c.* from (
select t.*,
(CASE
WHEN t.use_money>0 THEN (t.use_money-t.fh_money-t.bb_money-t.money2)
ELSE 0
END) yue_money
from (
SELECT o.user_id, u.uid, u.nickname, u.headimg, u.mobile,
u.money,
u.integral,
count(1) orderCount,
sum(IFNULL(order_zhe_total,0)) order_zhe_total,
IFNULL(sum(price),0) money_1,
IFNULL(sum(use_money),0) money_2,
IFNULL(sum(price)+SUM(use_money),0) use_money,
(select IFNULL(sum(goodslist_money),0) sc_money from order_list where user_id=o.user_id and status=2 {$whereUser1}) fh_money,
(select IFNULL(sum(goodslist_money),0) sc_money from order_list where user_id=o.user_id and status=0 {$whereUser1}) bb_money,
(TRUNCATE(u.money2/100, 2)) money2
FROM `order` o LEFT join `user` u ON o.user_id=u.id where {$whereUser} group by o.user_id ) t where use_money>0
) c order by yue_money desc";
// 执行查询
$list = \think\facade\Db::query($sql);
// 处理结果数据
foreach ($list as &$item) {
// 格式化数值
$item['money'] = floatval($item['money']);
$item['integral'] = floatval($item['integral']);
$item['money2'] = floatval($item['money2']);
$item['order_zhe_total'] = floatval($item['order_zhe_total']);
$item['money_1'] = floatval($item['money_1']);
$item['money_2'] = floatval($item['money_2']);
$item['use_money'] = floatval($item['use_money']);
$item['fh_money'] = floatval($item['fh_money']);
$item['bb_money'] = floatval($item['bb_money']);
$item['yue_money'] = floatval($item['yue_money']);
// 处理盈亏状态
$item['profit_status'] = $item['yue_money'] > 0 ? '亏损' : '盈利';
$item['profit_value'] = abs($item['yue_money']);
}
// 引入PHPExcel
// ThinkPHP 6.0使用composer自动加载
if (!class_exists('\\PhpOffice\\PhpSpreadsheet\\Spreadsheet')) {
return json(['code' => 1, 'msg' => '请先安装PhpSpreadsheet扩展']);
}
// 使用PhpSpreadsheet
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 设置文档属性
$spreadsheet->getProperties()
->setCreator("系统")
->setLastModifiedBy("系统")
->setTitle("用户盈亏列表")
->setSubject("用户盈亏列表")
->setDescription("用户盈亏列表导出数据");
// 设置表头
$headers = [
'A' => '序号',
'B' => 'UID',
'C' => '用户ID',
'D' => '用户昵称',
'E' => '手机号',
'F' => '钻石',
'G' => 'UU币',
'H' => '达达券',
'I' => '订单数',
'J' => '订单总额',
'K' => 'RMB支付',
'L' => '钻石支付',
'M' => '用户支付金额',
'N' => '用户发货金额',
'O' => '用户背包金额',
'P' => '剩余达达券',
'Q' => '亏损/盈利状态',
'R' => '亏损/盈利金额',
'S' => '利润值'
];
foreach ($headers as $key => $val) {
$sheet->setCellValue($key . '1', $val);
// 设置表头单元格样式
$sheet->getStyle($key . '1')->getFont()->setBold(true);
$sheet->getStyle($key . '1')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
}
// 写入数据
$row = 2;
foreach ($list as $index => $item) {
$sheet->setCellValue('A' . $row, $index + 1);
$sheet->setCellValue('B' . $row, $item['uid']);
$sheet->setCellValue('C' . $row, $item['user_id']);
$sheet->setCellValue('D' . $row, $item['nickname']);
$sheet->setCellValue('E' . $row, $item['mobile']);
$sheet->setCellValue('F' . $row, $item['money']);
$sheet->setCellValue('G' . $row, $item['integral']);
$sheet->setCellValue('H' . $row, $item['money2']);
$sheet->setCellValue('I' . $row, $item['orderCount']);
$sheet->setCellValue('J' . $row, $item['order_zhe_total']);
$sheet->setCellValue('K' . $row, $item['money_1']);
$sheet->setCellValue('L' . $row, $item['money_2']);
$sheet->setCellValue('M' . $row, $item['use_money']);
$sheet->setCellValue('N' . $row, $item['fh_money']);
$sheet->setCellValue('O' . $row, $item['bb_money']);
$sheet->setCellValue('P' . $row, $item['money2']);
$sheet->setCellValue('Q' . $row, $item['profit_status']);
$sheet->setCellValue('R' . $row, $item['profit_value']);
$sheet->setCellValue('S' . $row, $item['yue_money']);
// 为亏损和盈利设置不同颜色
if ($item['yue_money'] > 0) {
// 亏损标红
$sheet->getStyle('Q' . $row)->getFont()->getColor()->setARGB('FFFF0000');
$sheet->getStyle('R' . $row)->getFont()->getColor()->setARGB('FFFF0000');
$sheet->getStyle('S' . $row)->getFont()->getColor()->setARGB('FFFF0000');
} else {
// 盈利标绿
$sheet->getStyle('Q' . $row)->getFont()->getColor()->setARGB('FF008000');
$sheet->getStyle('R' . $row)->getFont()->getColor()->setARGB('FF008000');
$sheet->getStyle('S' . $row)->getFont()->getColor()->setARGB('FF008000');
}
$row++;
}
// 调整列宽
foreach ($headers as $key => $val) {
$sheet->getColumnDimension($key)->setAutoSize(true);
}
// 设置sheet名称
$sheet->setTitle('用户盈亏列表');
// 输出Excel文件
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="用户盈亏列表_' . date('YmdHis') . '.xlsx"');
header('Cache-Control: max-age=0');
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('php://output');
exit;
}
/**
* 将UID转换为用户ID
*/
protected function convertUidToUserId($uid)
{
if (empty($uid)) {
return 0;
}
// 如果是数字可能是用户ID或UID
if (is_numeric($uid)) {
$user = \app\common\model\User::where('id', $uid)->whereOr('uid', $uid)->find();
return $user ? $user['id'] : 0;
} else {
// 如果是字符串尝试查找UID
$user = \app\common\model\User::where('uid', $uid)->find();
return $user ? $user['id'] : 0;
}
}
}

View File

@ -37,6 +37,9 @@ Route::rule('userdel', 'User/userdel', 'GET|POST');
Route::rule('usertest', 'User/usertest', 'GET|POST');
Route::rule('user_profit_loss', 'User/user_profit_loss', 'GET|POST');
Route::rule('user_profit_loss_list', 'User/userProfitLossList', 'GET');
Route::rule('get_user_profit_loss', 'User/getUserProfitLoss', 'POST');
Route::rule('export_user_profit_loss', 'User/exportUserProfitLoss', 'GET');
Route::rule('user_shangdai', 'User/user_shangdai', 'GET|POST');
Route::rule('vip', 'User/vip', 'GET|POST');
Route::rule('vip_edit', 'User/vip_edit', 'GET|POST');

View File

@ -0,0 +1,182 @@
{include file="Public:header3" /}
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-header">用户盈亏列表</div>
<div class="layui-card-body">
<!-- 搜索条件 -->
<div class="layui-form layui-form-pane">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">用户ID/UID</label>
<div class="layui-input-inline">
<input type="text" name="uid" id="uid" autocomplete="off" placeholder="请输入用户ID或UID"
class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">时间范围</label>
<div class="layui-input-inline" style="width: 300px;">
<input type="text" name="time_range" id="time_range" autocomplete="off"
placeholder="请选择时间范围" class="layui-input">
</div>
</div>
<div class="layui-inline">
<button class="layui-btn" lay-submit lay-filter="search">
<i class="layui-icon layui-icon-search"></i> 搜索
</button>
<button class="layui-btn layui-btn-primary" id="reset">
<i class="layui-icon layui-icon-refresh"></i> 重置
</button>
<button class="layui-btn layui-btn-normal" id="exportExcel">
<i class="layui-icon layui-icon-download-circle"></i> 导出Excel
</button>
</div>
</div>
</div>
<!-- 数据表格 -->
<table id="profit-loss-table" lay-filter="profit-loss-table"></table>
<!-- 表格用户信息模板 -->
<script type="text/html" id="userInfoTpl">
<div style="display: flex; align-items: center;">
<div style="margin-right: 10px;">
<img src="{{d.headimg}}" style="width: 40px; height: 40px; border-radius: 50%;" onerror="this.src='__STATIC__/admin/images/avatar.png'">
</div>
<div>
<p>ID: {{d.user_id}}</p>
<p>昵称: {{d.nickname || '未设置'}}</p>
<p>手机: {{d.mobile || '未绑定'}}</p>
</div>
</div>
</script>
<!-- 用户货币信息模板 -->
<script type="text/html" id="currencyInfoTpl">
<p>钻石: {{d.money || 0}}</p>
<p>UU币: {{d.integral || 0}}</p>
<p>达达券: {{d.money2 || 0}}</p>
</script>
<!-- 订单统计模板 -->
<script type="text/html" id="orderStatTpl">
<p>支付次数: {{d.orderCount || 0}}</p>
<p>订单总额: {{d.order_zhe_total || 0}}</p>
<p>RMB支付: {{d.money_1 || 0}}</p>
<p>钻石支付: {{d.money_2 || 0}}</p>
</script>
<!-- 用户利润模板 -->
<script type="text/html" id="profitTpl">
<p style="color: {{d.yue_money > 0 ? '#FF5722' : '#5FB878'}};">{{d.yue_money > 0 ? '亏损' : '盈利'}}: {{Math.abs(d.yue_money)}}</p>
<p> 支付金额({{d.use_money}}-发货金额({{d.fh_money}}-背包金额({{d.bb_money}}- 用户剩余达达券({{d.money2}}= {{d.yue_money}}</p>
</script>
</div>
</div>
</div>
</div>
</div>
{include file="Public:footer3" /}
<script>
layui.use(['table', 'form', 'laydate'], function () {
var table = layui.table,
form = layui.form,
laydate = layui.laydate,
$ = layui.$;
// 日期范围选择器
laydate.render({
elem: '#time_range',
type: 'date',
range: true
});
// 表格实例
table.render({
elem: '#profit-loss-table',
url: '/admin/get_user_profit_loss',
method: 'post',
page: true,
height: 'full-140',
lineStyle: 'height:170px',
limits: [10, 20, 50, 100],
limit: 20,
cols: [[
{ type: 'numbers', title: '序号', width: 60 },
{ field: 'uid', title: 'UID', width: 80, sort: true },
{ field: 'userInfo', title: '用户信息', templet: '#userInfoTpl', width: 240 },
{ field: 'currencyInfo', title: '用户货币', templet: '#currencyInfoTpl', width: 200 },
{ field: 'orderStat', title: '订单统计', templet: '#orderStatTpl', width: 180 },
{ field: 'use_money', title: '支付金额', width: 120, sort: true },
{ field: 'fh_money', title: '发货金额', width: 120, sort: true },
{ field: 'bb_money', title: '背包金额', width: 120, sort: true },
{ field: 'money2', title: '剩余达达券', width: 120, sort: true },
{ field: 'yue_money', title: '亏损/盈利', minWidth: 260, templet: '#profitTpl' }
]],
parseData: function (res) {
return {
"code": res.code === 0 ? 0 : 1,
"msg": res.msg,
"count": res.count,
"data": res.data
};
},
response: {
statusCode: 0
}
});
// 搜索
form.on('submit(search)', function (data) {
var formData = data.field;
table.reload('profit-loss-table', {
where: {
uid: formData.uid,
time_range: formData.time_range
},
page: {
curr: 1
}
});
return false;
});
// 重置
$('#reset').on('click', function () {
$('#uid').val('');
$('#time_range').val('');
table.reload('profit-loss-table', {
where: {
uid: '',
time_range: ''
},
page: {
curr: 1
}
});
});
// 导出Excel
$('#exportExcel').on('click', function () {
var uid = $('#uid').val();
var time_range = $('#time_range').val();
// 构建下载URL
var url = '/admin/export_user_profit_loss?uid=' + encodeURIComponent(uid || '') + '&time_range=' + encodeURIComponent(time_range || '');
// 创建临时链接并模拟点击下载
var a = document.createElement('a');
a.href = url;
a.download = '用户盈亏列表.xlsx';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
layer.msg('正在导出,请稍候...', {icon: 6});
});
});
</script>

View File

@ -12,6 +12,10 @@ return [
'url' => '/admin/user_profit_loss',
'name' => '用户盈亏',
],
[
'url' => '/admin/user_profit_loss_list',
'name' => '用户盈亏列表',
],
[
'url' => '/admin/record',
'name' => '流水排行',