User.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\service\CommissionService;
  4. use app\common\service\InvitationService;
  5. use think\facade\Db;
  6. use Throwable;
  7. use ba\Captcha;
  8. use ba\ClickCaptcha;
  9. use think\facade\Config;
  10. use app\common\facade\Token;
  11. use app\common\controller\Frontend;
  12. use app\api\validate\User as UserValidate;
  13. class User extends Frontend
  14. {
  15. protected array $noNeedLogin = ['checkIn','logout','subordinateList'];
  16. protected array $noNeedPermission = ['dashboard'];
  17. protected $invitationService;
  18. protected $commissionService;
  19. public function initialize(): void
  20. {
  21. parent::initialize();
  22. $this->invitationService = new InvitationService();
  23. $this->commissionService = new CommissionService();
  24. }
  25. /**
  26. * 会员签入(登录和注册)
  27. * @throws Throwable
  28. */
  29. public function checkIn(): void
  30. {
  31. $openMemberCenter = Config::get('buildadmin.open_member_center');
  32. if (!$openMemberCenter) {
  33. $this->error(__('Member center disabled'));
  34. }
  35. // 检查登录态
  36. if ($this->auth->isLogin()) {
  37. $this->success(__('You have already logged in. There is no need to log in again~'), [
  38. 'type' => $this->auth::LOGGED_IN
  39. ], $this->auth::LOGIN_RESPONSE_CODE);
  40. }
  41. $userLoginCaptchaSwitch = Config::get('buildadmin.user_login_captcha');
  42. if ($this->request->isPost()) {
  43. $params = $this->request->post();
  44. // 检查必填的 tab 字段
  45. if (!isset($params['tab']) || !in_array($params['tab'], ['login', 'register'])) {
  46. $this->error(__('Unknown operation'));
  47. }
  48. $validate = new UserValidate();
  49. try {
  50. if ($params['tab'] == 'register') {
  51. $registerType = $params['registerType'] ?? 'email';
  52. $validate->scene('register_' . $registerType)->check($params);
  53. } else {
  54. $validate->scene($params['tab'])->check($params);
  55. }
  56. } catch (Throwable $e) {
  57. $this->error($e->getMessage());
  58. }
  59. if ($params['tab'] == 'login') {
  60. if ($userLoginCaptchaSwitch) {
  61. $captchaObj = new ClickCaptcha();
  62. if (!isset($params['captchaId']) || !isset($params['captchaInfo']) ||
  63. !$captchaObj->check($params['captchaId'], $params['captchaInfo'])) {
  64. $this->error(__('Captcha error'));
  65. }
  66. }
  67. $username = $params['username'] ?? '';
  68. $password = $params['password'] ?? '';
  69. $keep = !empty($params['keep']);
  70. if (empty($username) || empty($password)) {
  71. $this->error(__('Please enter username and password'));
  72. }
  73. $res = $this->auth->login($username, $password, $keep);
  74. } elseif ($params['tab'] == 'register') {
  75. $registerType = $params['registerType'] ?? 'email';
  76. // 验证码验证
  77. $captchaObj = new Captcha();
  78. $captchaKey = $params[$registerType] ?? '';
  79. if (empty($captchaKey) || !$captchaObj->check($params['captcha'] ?? '', $captchaKey . 'user_register')) {
  80. $this->error(__('Please enter the correct verification code'));
  81. }
  82. $username = $params['username'] ?? '';
  83. $password = $params['password'] ?? '';
  84. $mobile = $params['mobile'] ?? '';
  85. $email = $params['email'] ?? '';
  86. $invitationCode = $params['inviteCode'] ?? ''; // 用户输入的邀请码(别人的)
  87. // 根据注册类型验证
  88. if ($registerType == 'mobile' && empty($mobile)) {
  89. $this->error(__('Please enter mobile number'));
  90. } elseif ($registerType == 'email' && empty($email)) {
  91. $this->error(__('Please enter email address'));
  92. }
  93. // 正常注册
  94. $group = 0;
  95. $res = $this->auth->register($username, $password, $mobile, $email, $group);
  96. // 注册成功后处理邀请关系,并为用户生成自己的邀请码
  97. if ($res === true) {
  98. $userId = $this->auth->id;
  99. if ($userId) {
  100. // 处理邀请关系(传入用户输入的邀请码)
  101. $this->invitationService->processRegistration($userId, $invitationCode);
  102. }
  103. }
  104. }
  105. if (isset($res) && $res === true) {
  106. $this->success(__('Login succeeded!'), [
  107. 'userInfo' => $this->auth->getUserInfo(),
  108. 'routePath' => '/'
  109. ]);
  110. } else {
  111. $msg = $this->auth->getError();
  112. $msg = $msg ?: __('Check in failed, please try again or contact the website administrator~');
  113. $this->error($msg);
  114. }
  115. }
  116. $this->success('', [
  117. 'userLoginCaptchaSwitch' => $userLoginCaptchaSwitch,
  118. 'accountVerificationType' => get_account_verification_type()
  119. ]);
  120. }
  121. /**
  122. * 我的主页数据
  123. */
  124. public function dashboard(): void
  125. {
  126. // 确保用户已登录
  127. if (!$this->auth->id) {
  128. $this->error('请先登录');
  129. }
  130. $userId = $this->auth->id;
  131. if (!$userId) {
  132. $this->error('用户ID获取失败');
  133. }
  134. try {
  135. // 1. 获取用户基本信息
  136. $user = Db::table('ba_user')
  137. ->where('id', $userId)
  138. ->field('id, username, nickname, email, mobile, avatar,
  139. last_login_time, join_time, join_ip, create_time')
  140. ->find();
  141. if (!$user) {
  142. $this->error('用户信息不存在');
  143. }
  144. // 2. 获取邀请统计
  145. $invitationService = new InvitationService();
  146. $invitationStats = $invitationService->getUserInvitationStats($userId);
  147. // 3. 获取佣金信息
  148. $commissionService = new CommissionService();
  149. $commissionDetail = $commissionService->getUserCommissionDetail($userId);
  150. // 4. 格式化时间
  151. $formatTime = function($timestamp) {
  152. if (!$timestamp) return '';
  153. if (is_numeric($timestamp)) {
  154. return date('Y-m-d H:i:s', $timestamp);
  155. }
  156. return $timestamp;
  157. };
  158. $response = [
  159. // 用户基本信息
  160. 'user_info' => [
  161. 'email' => $user['email'],
  162. 'username' => $user['username'],
  163. 'nickname' => $user['nickname'],
  164. 'mobile' => $user['mobile'],
  165. 'avatar' => $user['avatar'],
  166. 'join_time' => $formatTime($user['join_time']),
  167. 'create_time' => $formatTime($user['create_time']),
  168. ],
  169. // 登录信息
  170. 'login_info' => [
  171. 'last_login_time' => $formatTime($user['last_login_time']),
  172. 'current_login_time' => date('Y-m-d H:i:s'),
  173. 'join_ip' => $user['join_ip'],
  174. ],
  175. // 推广信息
  176. 'promotion_info' => [
  177. 'invitation_code' => $invitationStats['invitation_code'],
  178. 'promotion_link' => $commissionDetail['commission']['promotion_link'],
  179. 'today_invitation' => $invitationStats['today_invitation'] ?? 0, // 新增今日邀请人数
  180. 'total_invitation' => $invitationStats['total_invitation'] ?? 0, // 修改字段名
  181. ],
  182. // 佣金信息
  183. 'commission_info' => [
  184. 'current_commission' => $commissionDetail['commission']['current_commission'],
  185. 'total_commission' => $commissionDetail['commission']['total_commission'],
  186. 'withdrawn_commission' => $commissionDetail['commission']['withdrawn_commission'],
  187. 'frozen_commission' => $commissionDetail['commission']['frozen_commission'],
  188. 'today_income' => $commissionDetail['stats']['today_income'] ?? 0,
  189. 'month_income' => $commissionDetail['stats']['month_income'] ?? 0,
  190. ],
  191. // 快速统计
  192. // 'quick_stats' => [
  193. // 'total_orders' => $this->getUserOrderCount($userId),
  194. // 'pending_withdrawals' => $this->getPendingWithdrawalCount($userId),
  195. // ]
  196. ];
  197. } catch (\Throwable $e) {
  198. \think\facade\Log::error('获取我的主页数据失败: ' . $e->getMessage());
  199. $this->error('获取数据失败');
  200. }
  201. $this->success('', $response);
  202. }
  203. /**
  204. * 获取用户邀请统计
  205. */
  206. public function invitationStats(): void
  207. {
  208. // 确保用户已登录
  209. if (!$this->auth->isLogin()) {
  210. $this->error('请先登录');
  211. }
  212. $userId = $this->auth->id;
  213. $stats = $this->invitationService->getUserInvitationStats($userId);
  214. $this->success('', $stats);
  215. }
  216. /**
  217. * 获取下级用户列表
  218. */
  219. public function subordinateList(): void
  220. {
  221. // 确保用户已登录
  222. if (!$this->auth->isLogin()) {
  223. $this->error('请先登录');
  224. }
  225. $userId = $this->auth->id;
  226. $page = $this->request->get('page', 1);
  227. $pageSize = $this->request->get('pageSize', 10);
  228. $result = $this->invitationService->getSubordinateList($userId, $page, $pageSize);
  229. $this->success('', $result);
  230. }
  231. /**
  232. * 获取佣金详情
  233. */
  234. public function commissionDetail(): void
  235. {
  236. $userId = $this->auth->id;
  237. $detail = $this->commissionService->getUserCommissionDetail($userId);
  238. $this->success('', $detail);
  239. }
  240. /**
  241. * 获取佣金流水
  242. */
  243. public function commissionFlow(): void
  244. {
  245. $userId = $this->auth->id;
  246. $page = $this->request->get('page', 1);
  247. $pageSize = $this->request->get('pageSize', 20);
  248. try {
  249. $list = \think\facade\Db::name('commission_flow')
  250. ->where('user_id', $userId)
  251. ->order('create_time', 'desc')
  252. ->paginate([
  253. 'page' => $page,
  254. 'list_rows' => $pageSize
  255. ]);
  256. } catch (\Throwable $e) {
  257. $this->error('获取佣金流水失败');
  258. }
  259. $this->success('', [
  260. 'list' => $list->items(),
  261. 'total' => $list->total(),
  262. 'page' => $list->currentPage(),
  263. 'page_size' => $list->listRows(),
  264. 'page_count' => $list->lastPage()
  265. ]);
  266. }
  267. public function logout(): void
  268. {
  269. if ($this->request->isPost()) {
  270. $refreshToken = $this->request->post('refreshToken', '');
  271. if ($refreshToken) Token::delete((string)$refreshToken);
  272. $this->auth->logout();
  273. $this->success();
  274. }
  275. }
  276. }