Files
zyt/server/app/api/controller/asset/AssetAppController.php
T

252 lines
8.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\api\controller\asset;
use app\api\controller\BaseApiController;
use app\common\model\AssetUser;
use app\common\model\AssetResource;
use app\common\model\AssetUserResource;
use think\facade\Db;
class AssetAppController extends BaseApiController
{
// 所有接口都免框架登录验证(使用独立 asset_token 体系,在方法内自行校验)
public array $notNeedLogin = ['login', 'getResourceList', 'changePassword', 'recordDownload'];
/** token 有效期:7 天 */
const TOKEN_EXPIRE = 86400 * 7;
/**
* @notes 通过 token 获取当前用户(DB 优先,file cache 兜底)
*/
private function getAssetUser(): ?AssetUser
{
$token = $this->request->header('token');
if (empty($token)) {
return null;
}
// 方式1: 从数据库 token 字段查找(需要已执行 asset_user_token.sql
try {
$user = AssetUser::where('token', $token)
->where('token_expire_time', '>', time())
->where('status', 1)
->find();
if ($user) {
return $user;
}
} catch (\Throwable $e) {
// token 字段不存在时忽略,走 cache 兜底
}
// 方式2: 从 file cache 查找(兼容旧登录 / 未执行 SQL 迁移)
$userId = cache('asset_token_' . $token);
if ($userId) {
$user = AssetUser::where('id', $userId)->where('status', 1)->find();
return $user ?: null;
}
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()
{
$user = $this->getAssetUser();
$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) {
// 登录用户:只看自己的专属资源
$resourceIds = AssetUserResource::where('user_id', $user->id)->column('resource_id');
if (empty($resourceIds)) {
return $this->data(['lists' => [], 'count' => 0, 'page_no' => $pageNo, 'page_size' => $pageSize]);
}
$query = $query->whereIn('id', $resourceIds);
// 获取该用户的使用记录
$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]);
}
$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,
]);
}
/**
* @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('密码修改成功');
}
}