diff --git a/app/admin/controller/Order.php b/app/admin/controller/Order.php index 1750aca..e6a604c 100755 --- a/app/admin/controller/Order.php +++ b/app/admin/controller/Order.php @@ -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]; } diff --git a/app/admin/controller/User.php b/app/admin/controller/User.php index e4661cd..118ff67 100755 --- a/app/admin/controller/User.php +++ b/app/admin/controller/User.php @@ -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; + } + } } diff --git a/app/admin/route/app.php b/app/admin/route/app.php index 83c3cb2..9c0525f 100755 --- a/app/admin/route/app.php +++ b/app/admin/route/app.php @@ -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'); diff --git a/app/admin/view/User/user_profit_loss_list.html b/app/admin/view/User/user_profit_loss_list.html new file mode 100644 index 0000000..0832adc --- /dev/null +++ b/app/admin/view/User/user_profit_loss_list.html @@ -0,0 +1,182 @@ +{include file="Public:header3" /} +
+
+
+
+
用户盈亏列表
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ + + +
+
+
+ + +
+ + + + + + + + + + + + +
+
+
+
+
+ + +{include file="Public:footer3" /} + \ No newline at end of file diff --git a/config/menu.php b/config/menu.php index c17ae9f..680d6ef 100755 --- a/config/menu.php +++ b/config/menu.php @@ -12,6 +12,10 @@ return [ 'url' => '/admin/user_profit_loss', 'name' => '用户盈亏', ], + [ + 'url' => '/admin/user_profit_loss_list', + 'name' => '用户盈亏列表', + ], [ 'url' => '/admin/record', 'name' => '流水排行',