User.php 11 KB

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