request->header('token'); if (empty($token)) { return null; } // 方式1: 从数据库 token 字段查找 try { $user = AssetUser::where('token', $token) ->where('token_expire_time', '>', time()) ->find(); if ($user) { return $user; } } catch (\Throwable $e) { // token 字段不存在时忽略,走 cache 兜底 } // 方式2: 从 file cache 查找 $userId = cache('asset_token_' . $token); if ($userId) { $user = AssetUser::where('id', $userId)->find(); return $user ?: null; } return null; } /** * @notes 获取当前有效用户(status=1 才返回) */ private function getAssetUser(): ?AssetUser { $user = $this->getAssetUserRaw(); if ($user && $user->status == 1) { return $user; } return null; } /** * @notes 小程序端登录 */ public function login() { $phone = $this->request->post('phone'); $password = $this->request->post('password'); if (empty($phone) || empty($password)) { return $this->fail('手机号或密码不能为空'); } $user = AssetUser::where('phone', $phone)->find(); if (!$user) { return $this->fail('账号不存在'); } if ($user->status != 1) { return $this->fail('账号已被禁用'); } if (!password_verify($password, $user->password)) { return $this->fail('密码错误'); } // 生成 token 并双写(DB + cache 兜底) $token = md5($user->id . time() . uniqid('asset', true)); // 写入 file cache(始终可用) cache('asset_token_' . $token, $user->id, self::TOKEN_EXPIRE); // 尝试写入数据库(需要已执行 SQL 迁移) try { $user->token = $token; $user->token_expire_time = time() + self::TOKEN_EXPIRE; $user->save(); } catch (\Throwable $e) { // token 字段不存在时忽略,cache 已经写入 } return $this->success('登录成功', [ 'token' => $token, 'user' => [ 'id' => $user->id, 'phone' => $user->phone ] ]); } /** * @notes 获取用户关联的资源列表 (或公开资源) */ public function getResourceList() { $token = $this->request->header('token'); $rawUser = !empty($token) ? $this->getAssetUserRaw() : null; $user = ($rawUser && $rawUser->status == 1) ? $rawUser : null; $isDisabled = ($rawUser && $rawUser->status != 1); // 用户存在但被禁用 $tokenInvalid = (!empty($token) && !$rawUser); // token 过期或无效 $type = $this->request->get('type', 1); $pageNo = $this->request->get('page_no', 1); $pageSize = $this->request->get('page_size', 20); $days = (int)$this->request->get('days', 0); $usageStatus = (int)$this->request->get('usage_status', 0); // 0=全部, 1=未使用, 2=已使用 $query = AssetResource::where('type', $type); $usedResourceIds = []; if ($user) { // 登录用户:自己的专属资源 + 所有公开资源 $exclusiveIds = AssetUserResource::where('user_id', $user->id)->column('resource_id'); $associatedResourceIds = AssetUserResource::column('resource_id'); $query = $query->where(function ($q) use ($exclusiveIds, $associatedResourceIds) { if (!empty($exclusiveIds)) { $q->whereIn('id', $exclusiveIds); } if (!empty($associatedResourceIds)) { if (!empty($exclusiveIds)) { $q->whereOr('id', 'not in', $associatedResourceIds); } else { $q->whereNotIn('id', $associatedResourceIds); } } }); // 获取该用户的使用记录 $usedResourceIds = \think\facade\Db::name('asset_resource_usage') ->where('user_id', $user->id) ->column('resource_id'); // 使用状态过滤 if ($usageStatus === 1) { // 未使用 if (!empty($usedResourceIds)) { $query = $query->whereNotIn('id', $usedResourceIds); } } elseif ($usageStatus === 2) { // 已使用 if (empty($usedResourceIds)) { return $this->data([ 'lists' => [], 'count' => 0, 'page_no' => $pageNo, 'page_size' => $pageSize, 'is_disabled' => $isDisabled, 'token_invalid' => $tokenInvalid, ]); } $query = $query->whereIn('id', $usedResourceIds); } } else { // 游客(未登录):只看公开资源(没关联给任何用户的资源) $associatedResourceIds = AssetUserResource::column('resource_id'); if (!empty($associatedResourceIds)) { $query = $query->whereNotIn('id', $associatedResourceIds); } } // 时间过滤 if ($days > 0) { $startTime = strtotime("-{$days} days", strtotime(date('Y-m-d'))); $query = $query->where('create_time', '>=', $startTime); } $count = (clone $query)->count(); $lists = (clone $query) ->order('id', 'desc') ->page($pageNo, $pageSize) ->select() ->toArray(); // 附加 is_used 字段 foreach ($lists as &$item) { $item['is_used'] = in_array($item['id'], $usedResourceIds); } return $this->data([ 'lists' => $lists, 'count' => $count, 'page_no' => $pageNo, 'page_size' => $pageSize, 'is_disabled' => $isDisabled, // 用户被禁用 'token_invalid' => $tokenInvalid, // token 过期或无效 ]); } /** * @notes 记录资源下载/使用 */ public function recordDownload() { $user = $this->getAssetUser(); if (!$user) { return $this->fail('请先登录', [], -1); } $resourceId = $this->request->post('resource_id'); if (empty($resourceId)) { return $this->fail('参数缺失'); } // 检查资源是否存在 $resource = AssetResource::find($resourceId); if (!$resource) { return $this->fail('资源不存在'); } // 检查是否有关联权限 (或者是公开资源) $isAssociated = AssetUserResource::where('user_id', $user->id)->where('resource_id', $resourceId)->find(); $isPublic = !AssetUserResource::where('resource_id', $resourceId)->find(); if (!$isAssociated && !$isPublic) { return $this->fail('无权操作此资源'); } // 记录下载 $exists = \think\facade\Db::name('asset_resource_usage') ->where('user_id', $user->id) ->where('resource_id', $resourceId) ->find(); if (!$exists) { \think\facade\Db::name('asset_resource_usage')->insert([ 'user_id' => $user->id, 'resource_id' => $resourceId, 'create_time' => time() ]); } return $this->success('记录成功'); } /** * @notes 修改密码 */ public function changePassword() { $user = $this->getAssetUser(); if (!$user) { return $this->fail('登录已过期,请重新登录', [], -1); } $oldPassword = $this->request->post('old_password'); $password = $this->request->post('password'); if (empty($oldPassword)) { return $this->fail('请输入原密码'); } if (empty($password)) { return $this->fail('请输入新密码'); } if (strlen($password) < 6) { return $this->fail('新密码至少6位'); } if (!password_verify($oldPassword, $user->password)) { return $this->fail('原密码不正确'); } $user->password = password_hash($password, PASSWORD_DEFAULT); $user->save(); return $this->success('密码修改成功'); } }