model = new \app\admin\model\FcUserExt; } /** * 会员列表(关联 fa_user 展示昵称 / 手机号 / 账户余额 / 真实姓名) * * @return string|\think\response\Json */ public function index() { if ($this->request->isAjax()) { list($where, $sort, $order, $offset, $limit) = $this->buildparams(); $total = $this->model->alias('e') ->join('user u', 'u.id = e.user_id', 'LEFT') ->where($where) ->count(); $list = $this->model->alias('e') ->join('user u', 'u.id = e.user_id', 'LEFT') ->where($where) ->field('e.*, u.nickname, u.mobile, u.money') ->order($sort, $order) ->limit($offset, $limit) ->select(); return json(['total' => $total, 'rows' => $list]); } return $this->view->fetch(); } /** * 用户详细信息综合看板(包含基本资料、实名信息、微信提现账户、分销佣金、会员特权及近期提现记录) * * @param int|null $ids 用户扩展记录ID * @return string */ public function detail($ids = null) { $id = $ids ? $ids : $this->request->param('ids'); $row = $this->model->get($id); if (!$row) { $this->error(__('No Results were found')); } $userId = (int)$row['user_id']; // 1. 主表 fa_user 用户基本信息 $user = Db::name('user')->where('id', $userId)->find(); if (!$user) { $user = [ 'id' => $userId, 'nickname' => '未注册用户', 'mobile' => '-', 'avatar' => '', 'money' => '0.00', 'score' => 0, 'createtime' => null, 'logintime' => null, 'loginip' => '', ]; } // 2. 上级邀请人信息 $inviterUser = null; if (!empty($row['inviter_id'])) { $inviterUser = Db::name('user') ->where('id', (int)$row['inviter_id']) ->field('id,nickname,mobile,avatar') ->find(); } // 3. 分销与佣金统计 $commissionTotal = (float)Db::name('fc_commission') ->where('user_id', $userId) ->where('status', '<>', 2) ->sum('amount'); $commissionSettled = (float)Db::name('fc_commission') ->where('user_id', $userId) ->where('status', 1) ->sum('amount'); $commissionPending = (float)Db::name('fc_commission') ->where('user_id', $userId) ->where('status', 0) ->sum('amount'); // 累计已成功提现金额 $withdrawPaidTotal = (float)Db::name('fc_withdraw') ->where('user_id', $userId) ->where('status', 'paid') ->sum('amount'); // 已占用提现金额(包含审核中、转账中、已打款) $withdrawAppliedTotal = (float)Db::name('fc_withdraw') ->where('user_id', $userId) ->where('status', 'in', ['auditing', 'paying', 'paid']) ->sum('amount'); // 当前剩余可提现金额 $withdrawable = max(0, $commissionSettled - $withdrawAppliedTotal); // 下级团队人数统计(一级、二级) $level1Count = (int)Db::name('fc_dist_relation') ->where('parent_id', $userId) ->where('level', 1) ->count(); $level2Count = (int)Db::name('fc_dist_relation') ->where('parent_id', $userId) ->where('level', 2) ->count(); // 4. 业务数据概览(发帖数与消费订单数) $postCount = (int)Db::name('fc_post')->where('user_id', $userId)->count(); $orderCount = (int)Db::name('fc_order')->where('user_id', $userId)->where('status', 'paid')->count(); $orderSpend = (float)Db::name('fc_order')->where('user_id', $userId)->where('status', 'paid')->sum('amount'); // 5. 最近 5 笔提现记录 $recentWithdraws = Db::name('fc_withdraw') ->where('user_id', $userId) ->order('id', 'desc') ->limit(5) ->select(); // 6. 最近 5 笔佣金明细 $recentCommissions = Db::name('fc_commission')->alias('c') ->join('user fu', 'fu.id = c.from_user_id', 'LEFT') ->where('c.user_id', $userId) ->field('c.*, fu.nickname as from_nickname') ->order('c.id', 'desc') ->limit(5) ->select(); $this->view->assign([ 'row' => $row, 'userInfo' => $user, 'inviterUser' => $inviterUser, 'commissionTotal' => round($commissionTotal, 2), 'commissionSettled' => round($commissionSettled, 2), 'commissionPending' => round($commissionPending, 2), 'withdrawPaidTotal' => round($withdrawPaidTotal, 2), 'withdrawable' => round($withdrawable, 2), 'level1Count' => $level1Count, 'level2Count' => $level2Count, 'postCount' => $postCount, 'orderCount' => $orderCount, 'orderSpend' => round($orderSpend, 2), 'recentWithdraws' => $recentWithdraws, 'recentCommissions' => $recentCommissions, ]); return $this->view->fetch(); } /** * 编辑用户扩展资料(包含实名姓名、会员等级、发帖额度等) * * @param int|null $ids 用户扩展记录ID * @return string */ public function edit($ids = null) { $id = $ids ? $ids : $this->request->param('ids'); $row = $this->model->get($id); if (!$row) { $this->error(__('No Results were found')); } if ($this->request->isPost()) { $params = $this->request->post('row/a'); if ($params) { $params = $this->preExcludeFields($params); // 1. 真实姓名与实名状态清洗 if (isset($params['realname'])) { $params['realname'] = trim((string)$params['realname']); } if (isset($params['realname_status'])) { $params['realname_status'] = (int)$params['realname_status'] === 1 ? 1 : 0; } // 2. 用户身份(1: 个人用户, 2: 商家) if (isset($params['user_type'])) { $params['user_type'] = (int)$params['user_type'] === 2 ? 2 : 1; } // 3. 会员状态与到期时间处理 if (isset($params['is_member'])) { $params['is_member'] = (int)$params['is_member'] === 1 ? 1 : 0; } if (isset($params['member_expiretime'])) { $expire = trim((string)$params['member_expiretime']); $params['member_expiretime'] = $expire !== '' ? (is_numeric($expire) ? (int)$expire : strtotime($expire)) : null; } // 4. 发帖配额及到期时间处理 if (isset($params['post_quota_left'])) { $params['post_quota_left'] = max(0, (int)$params['post_quota_left']); } if (isset($params['post_quota_expire'])) { $expire = trim((string)$params['post_quota_expire']); $params['post_quota_expire'] = $expire !== '' ? (is_numeric($expire) ? (int)$expire : strtotime($expire)) : null; } // 5. 免费电话查看配额处理 if (isset($params['free_view_quota'])) { $params['free_view_quota'] = max(0, (int)$params['free_view_quota']); } if (isset($params['free_view_used'])) { $params['free_view_used'] = max(0, (int)$params['free_view_used']); } // 6. 邀请人处理(避免自身成为自身邀请人) if (isset($params['inviter_id'])) { $inviterId = (int)$params['inviter_id']; if ($inviterId > 0 && $inviterId === (int)$row['user_id']) { $this->error('上级邀请人不能设置为当前用户本人'); } $params['inviter_id'] = $inviterId; } Db::startTrans(); try { $row->allowField(true)->save($params); Db::commit(); } catch (ValidateException $e) { Db::rollback(); $this->error($e->getMessage()); } catch (PDOException $e) { Db::rollback(); $this->error($e->getMessage()); } catch (\Exception $e) { Db::rollback(); $this->error($e->getMessage()); } $this->success('更新成功'); } $this->error(__('Parameter %s can not be empty', '')); } // 关联主表用户信息 $userInfo = Db::name('user')->where('id', (int)$row['user_id'])->find(); $inviterInfo = null; if (!empty($row['inviter_id'])) { $inviterInfo = Db::name('user')->where('id', (int)$row['inviter_id'])->field('id,nickname,mobile')->find(); } $this->view->assign([ 'row' => $row, 'userInfo' => $userInfo ?: [], 'inviterInfo' => $inviterInfo, ]); return $this->view->fetch(); } /** * 余额充值(给选中用户增加账户余额) * * POST /s.php/fc/userext/recharge * 入参:{ ids: '1001,1002' , amount: 100, remark?: '备注' } */ public function recharge() { $ids = (string)$this->request->post('ids', ''); $userIds = array_filter(array_map('intval', explode(',', $ids))); $userIds = array_values(array_unique($userIds)); if (!$userIds) { $this->error('请选择要充值的用户'); } $amount = round((float)$this->request->post('amount', 0), 2); if ($amount <= 0) { $this->error('充值金额需大于 0'); } if ($amount > 100000) { $this->error('单次充值金额过大'); } $remark = trim((string)$this->request->post('remark', '')); $now = time(); $done = 0; $missing = []; Db::startTrans(); try { foreach ($userIds as $uid) { // 加行锁,避免并发充值互相覆盖余额 $user = Db::name('user')->where('id', $uid)->lock(true)->find(); if (!$user) { $missing[] = $uid; continue; } $balance = round((float)$user['money'] + $amount, 2); Db::name('user')->where('id', $uid)->update([ 'money' => $balance, 'updatetime' => $now, ]); // 资金流水(平台口径:充值属于收入;scene=后台充值 与用户微信充值区分) Db::name('fc_finance_flow')->insert([ 'user_id' => $uid, 'flow_no' => 'R' . date('YmdHis') . mt_rand(100, 999) . $uid, 'type' => 'income', 'scene' => '后台充值', 'amount' => $amount, 'balance' => $balance, 'related_id' => $uid, 'remark' => $remark !== '' ? $remark : ('后台充值给用户 #' . $uid), 'createtime' => $now, ]); // 用户钱包流水(fa_user.money 增)→ 余额中心「余额明细」 Db::name('fc_wallet_flow')->insert([ 'user_id' => $uid, 'flow_no' => 'W' . date('YmdHis') . mt_rand(100, 999) . $uid, 'type' => 'income', 'scene' => '后台充值', 'amount' => $amount, 'balance' => $balance, 'related_id' => $uid, 'remark' => $remark !== '' ? $remark : ('后台充值给用户 #' . $uid), 'createtime' => $now, ]); // 站内通知 Db::name('fc_message')->insert([ 'user_id' => $uid, 'type' => 'system', 'title' => '余额充值到账', 'content' => '您的账户已充值 ¥' . number_format($amount, 2, '.', '') . ',当前余额 ¥' . number_format($balance, 2, '.', '') . '。' . ($remark !== '' ? '备注:' . $remark : ''), 'isread' => 0, 'readtime' => null, 'createtime' => $now, ]); $done++; } Db::commit(); } catch (\Exception $e) { Db::rollback(); $this->error('充值失败:' . $e->getMessage()); } if (!$done) { $this->error('未找到对应用户:' . implode(',', $missing) . '(请确认传的是用户ID)'); } $msg = '充值成功:' . $done . ' 个用户,每人 ¥' . number_format($amount, 2, '.', ''); if ($missing) { $msg .= ';已跳过不存在的用户:' . implode(',', $missing); } $this->success($msg); } }