用户相关api、jwt接入

This commit is contained in:
2025-05-05 14:20:17 +08:00
parent 147b2d3fd5
commit bd26d52fff
11 changed files with 660 additions and 27 deletions

View File

@@ -147,7 +147,9 @@ class BaseController
if (mb_strlen(strval($checkValue)) <= 0 && !in_array($fieldName, $this->notRequest)) {
$requiredFields[] = $fieldName;
} else {
$result[$fieldName] = $checkValue;
if (!empty($checkValue)) {
$result[$fieldName] = $checkValue;
}
}
}

View File

@@ -3,41 +3,94 @@
namespace App\BaseApp;
use App\Models\UserModel;
use App\Service\common\JWTService;
use App\Service\common\UtilsService;
use Exception;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class BaseService
{
/**
* @var mixed 单例实例,确保该类只有一个全局实例
*/
private static mixed $_instance;
protected static mixed $_instance;
/**
* @var object 工具类对象,用于提供通用的功能方法
*/
protected object $utils;
/**
* @var int 用户ID默认值为0表示未登录状态
*/
protected int $userId = 0;
/**
* @var array 用户信息
*/
protected array $userInfo = [];
/**
* @var object 数据模型对象,用于数据库操作
*/
protected $model;
protected $isAuth = true;
/**
* @var bool 是否需要验证用户权限
*/
protected bool $isAuth = true;
/**
* @var array 查询的字段
*/
protected array $selectField = ['*'];
/**
* @var array 查询条件Between
*/
protected array $whereBetween = [];
/**
* @var array 排序条件
*/
protected array $orderBy = [
'name' => 'id',
'sort' => 'desc',
];
/**
* @var array 查询条件
*/
protected array $where = [
['deleted_at', '=', 0]
];
/**
* @var array 查询条件In
*/
protected array $whereIn = [];
/**
* @var array 下拉列表字段
*/
protected array $optionField = ['id', 'name'];
/**
* @var array 关联加载
*/
protected array $with = [];
/**
* @var string 时间字段
*/
protected string $timeField = 'created_at';
public function __construct()
{
if ($this->isAuth) {
// 如果是home的接口可以不执行这个方法
if (!\request()->is('api/home/*')) {
$this->authUser();
}
$this->userInfo = JWTService::getInstance()->getToken()->getUserInfo();
$this->userId = $this->userInfo['id'] ?? 0;
}
$this->utils = UtilsService::getInstance();
}
@@ -56,15 +109,202 @@ class BaseService
return self::$_instance[$name];
}
private function authUser()
/**
* 获取列表数据
*
* 本函数负责根据设定的条件,从数据库中查询并返回分页后的数据列表
* 它会根据空值条件动态地修改查询,以实现灵活的查询需求
*
* @return array 返回包含分页信息和数据列表的数组
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getPageList($isArr = true, $isGetWhere = true): array
{
$token = \request()->header('Authorization');
$token = explode(' ', $token)[1];
$userModel = UserModel::where('session_key', $token)->first();
if (!$userModel) {
jexpire('token失效');
// 初始化查询条件
if ($isGetWhere === true) $this->getWhere();
// 获取范围查询条件
$searchTime = request()->get('search_time');
if (!empty($searchTime)) {
$this->getWhereBetween($searchTime);
}
$this->userId = $userModel->id;
$this->userInfo = $userModel->toArray();
// 执行数据库查询,根据条件动态构建查询语句
$result = $this->model::when(!empty($this->with), function ($query) {
// 如果关联加载条件存在,则添加关联加载
$query->with($this->with);
})
->when(!empty($this->where), function ($query) {
// 如果查询条件存在,则添加查询条件
$query->where($this->where);
})
->when(!empty($this->whereIn), function ($query) {
// 如果查询条件存在,则添加查询条件
$query->whereIn($this->whereIn[0], $this->whereIn[1]);
})
->when(!empty($this->whereBetween), function ($query) {
// 如果范围查询条件存在,则添加范围查询
$query->whereBetween($this->whereBetween[0], $this->whereBetween[1]);
})
->when(!empty($this->orderBy), function ($query) {
// 如果排序条件存在,则添加排序条件
$query->orderBy($this->orderBy['name'], $this->orderBy['sort']);
})
->select($this->selectField)
// 执行分页查询每页返回10条记录
->paginate(request()->get('pageSize', 20));
if ($isArr === true) {
$result = $result->toArray() ?? [];
// 返回分页信息和数据列表
return [
'page' => $result['current_page'],
'size' => $result['per_page'],
'page_count' => $result['last_page'],
'total' => $result['total'],
'items' => $result['data'],
];
}
// 返回分页信息和数据列表
return [
'page' => $result->currentPage(),
'size' => $result->perPage(),
'page_count' => $result->lastPage(),
'total' => $result->total(),
'items' => $result->items(),
];
}
/**
* 获取下拉列表数据
* @return mixed
*/
public function getOption(): mixed
{
$this->getWhere();
return $this->model::when(!empty($this->where), function ($query) {
$query->where($this->where);
})->when(!empty($this->whereIn), function ($query) {
$query->where($this->whereIn[0], $this->whereIn[1]);
})->orderBy($this->orderBy['name'], $this->orderBy['sort'])->get($this->optionField);
}
/**
* 详情
*
* @param $id
* @return mixed
* @throws Exception
*/
public function getDetail($id): mixed
{
$info = $this->model::with($this->with)->select($this->selectField)->find($id);
if (empty($info)) {
return $this->utils->notFound('数据不存在');
}
return $info;
}
/**
* 新增
* @param $params
* @return mixed
*/
public function insert($params): mixed
{
if (!array_key_exists('created_at', $params)) {
$params['created_at'] = time();
}
// return $this->model::insertGetId($this->utils->truncatedOss($params));
return $this->model::insertGetId($params);
}
/**
* 编辑
* @param $id
* @param $params
* @return mixed
* @throws Exception
*/
public function save($id, $params): mixed
{
if (empty(trim($id))) {
$this->utils->errorThrow('参数错误');
}
$this->where[] = ['id', '=', $id];
// 软删除
$info = $this->model::where($this->where)->first();
if (empty($info)) {
return $this->utils->notFound('数据不存在');
}
if (!array_key_exists('updated_at', $params)) {
$params['updated_at'] = time();
}
// return $this->model::where('id', $id)->update($this->utils->truncatedOss($params));
return $this->model::where('id', $id)->update($params);
}
/**
* 删除
*
* @param $id
* @return mixed|true
* @throws Exception
*/
public function del($id): mixed
{
// 软删除
$info = $this->model::whereIn('id', $id)->get(['id']);
if (empty($info)) {
return $this->utils->notFound('数据不存在');
}
if ($this->model::whereIn('id', $id)->update([
'deleted_at' => time(),
'updated_at' => time()
])) {
return true;
} else {
$this->utils->errorThrow('删除失败');
}
}
/**
* 获取查询条件
* @return void
*/
protected function getWhere(): void
{
$query = request()->query();
if (!empty($this->queryField)) {
foreach ($this->queryField as $key => $value) {
if (in_array($key, array_keys($query))) {
if (!empty($query[$key] ?? '') || $query[$key] == '0') {
switch ($value) {
case '=':
$this->where[] = [$key, $value, $query[$key]];
break;
case 'like':
$this->where[] = [$key, $value, '%' . $query[$key] . '%'];
break;
default:
break;
}
}
}
}
}
}
/**
* 获取时间范围查询条件
* @param $searchTime
* @return void
*/
protected function getWhereBetween($searchTime): void
{
$this->whereBetween = [$this->timeField, [strtotime($searchTime[0] ?? date('Y-m-01 00:00:00')), strtotime(date('Y-m-d 23:59:59', strtotime($searchTime[1])) ?? date('Y-m-d 23:59:59'))]];
}
}

20
app/Enum/StatusEnum.php Executable file
View File

@@ -0,0 +1,20 @@
<?php
namespace App\Enum;
/**
* 状态码定义
*/
enum StatusEnum: int
{
// 状态 0正常 1禁用
case NORMAL = 0;
case DISABLE = 1;
public function description(): string
{
return match ($this) {
self::NORMAL => '正常',
self::DISABLE => '禁用',
};
}
}

23
app/Enum/UserStatusEnum.php Executable file
View File

@@ -0,0 +1,23 @@
<?php
namespace App\Enum;
/**
* 状态码定义
*/
enum UserStatusEnum: int
{
// 状态 0正常 1冻结 2封号 3注销
case NORMAL = 0;
case DISABLE = 1;
case DELETED = 2;
public function description(): string
{
return match ($this) {
self::NORMAL => '正常',
self::DISABLE => '冻结',
self::DELETED => '注销',
default => '未知',
};
}
}

View File

@@ -3,8 +3,54 @@
namespace App\Http\Controllers;
use App\BaseApp\BaseController;
use App\Service\UserService;
use Exception;
use Illuminate\Http\JsonResponse;
class UserController extends BaseController
{
//
public function __construct()
{
parent::__construct();
$this->service = UserService::getInstance();
$this->insertField = [ 'account', 'nick_name', 'password', 'role_id' ];
$this->updateField = [ 'id', 'account', 'nick_name', 'role_id' ];
$this->notRequest = ['qr_code', 'avatar', 'email', 'status'];
}
/**
* 修改密码
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function changePassword(): JsonResponse
{
$this->insertField = ['password', 'new_password'];
$params = $this->checkRequiredFields(request()->post());
return jok(
$this->service->changePassword($params['password'], $params['new_password']),
'重置密码成功'
);
}
/**
* 重置密码
* @Method POST
* @return JsonResponse
* @throws Exception
*/
public function resetPassword(): JsonResponse
{
$this->insertField = ['id', 'password', 'new_password'];
$params = $this->checkRequiredFields(request()->post());
return jok(
$this->service->resetPassword($params['id'], $params['password'], $params['new_password']),
'重置密码成功'
);
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Service;
use App\Models\UserModel;
use App\Service\common\JWTService;
use App\Service\common\UtilsService;
use Exception;
use Illuminate\Support\Str;
class LoginService
@@ -29,11 +30,19 @@ class LoginService
return self::$_instance[$name];
}
/**
* 登录
* @param $account
* @param $password
* @return array
* @throws Exception
*/
public function login($account, $password)
{
$userModel = UserModel::where('account', $account)->first();
if (empty($userModel)) {
return $this->register($account, $password);
UtilsService::getInstance()->errorThrow('用户或密码错误!');
// return $this->register($account, $password);
}
if (!password_verify($password, $userModel->password)) {
@@ -62,6 +71,7 @@ class LoginService
'account' => $userModel->account,
'nick_name' => $userModel->nick_name,
'avatar' => $userModel->avatar,
'email' => $userModel->email,
'ip' => $userModel->ip,
'ip_table' => $userModel->ip_table,
];
@@ -70,7 +80,14 @@ class LoginService
return $result;
}
public function register($account, $password)
/**
* 注册
* @param $account
* @param $password
* @return array
* @throws Exception
*/
public function register($account, $password): array
{
$userModel = UserModel::where('account', $account)->first();
if ($userModel) {
@@ -96,6 +113,7 @@ class LoginService
'account' => $createModel->account,
'nick_name' => $createModel->nick_name,
'avatar' => $createModel->avatar,
'email' => $userModel->email?? '',
'ip' => $createModel->ip,
'ip_table' => $createModel->ip_table,
];

View File

@@ -3,8 +3,151 @@
namespace App\Service;
use App\BaseApp\BaseService;
use App\Enum\UserStatusEnum;
use App\Models\UserModel;
use Exception;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class UserService extends BaseService
{
public function __construct()
{
parent::__construct();
$this->selectField = [ 'id', 'account', 'nick_name', 'avatar', 'email', 'balance', 'qr_code', 'role_id', 'ip', 'ip_table', 'status', 'last_reset_password_at', 'created_at', 'updated_at', 'deleted_at', ];
$this->model = UserModel::class;
}
/**
* 获取用户列表
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function list(): array
{
$result = $this->getPageList();
foreach ($result['items'] as &$v) {
$v['ip_table'] = json_decode($v['ip_table'], true);
$v['status_text'] = UserStatusEnum::from($v['status'])->description();
}
return $result;
}
public function detail($id)
{
$result = $this->getDetail($id);
$result['ip_table'] = json_decode($result['ip_table'], true);
$result['status_text'] = UserStatusEnum::from($result['status'])->description();
return $result;
}
public function option()
{
$this->optionField = ['id', 'nick_name'];
return $this->getOption();
}
/**
* 创建用户
* @param $params
* @return mixed
* @throws Exception
*/
public function create($params): mixed
{
$params['ip_table'] = json_encode([]);
$params['password'] = password_hash($params['password'], PASSWORD_DEFAULT);
$existsUser = $this->model::where('account', $params['account'])->whereOr('email', $params['email'])->exists();
if ($existsUser) {
$this->utils->errorThrow('账号或邮箱已存在');
}
return $this->insert($params);
}
/**
* 编辑用户
* @param $id
* @param $params
* @return mixed
* @throws Exception
*/
public function update($id, $params): mixed
{
return $this->save($id, $params);
}
/**
* 删除用户
* @param $ids
* @return mixed|true
* @throws Exception
*/
public function delete($ids): mixed
{
return $this->del($ids);
}
/**
* 修改密码
* @param $id
* @param $password
* @param $newPassword
* @return mixed
* @throws Exception
*/
public function changePassword($password, $newPassword): mixed
{
$info = $this->model::find($this->userId);
if (empty($info)) {
return $this->utils->notFound('数据不存在');
}
if (!password_verify($password, $info['password'])) {
return $this->utils->errorThrow('密码错误');
}
if (password_verify($newPassword, $info['password'])) {
return $this->utils->errorThrow('新密码不能与旧密码相同');
}
$result = $this->model::where('id', $this->userId)->update([
'password' => password_hash($newPassword, PASSWORD_DEFAULT),
'last_reset_password_at' => get_time()
]);
if (!$result) {
return $this->utils->errorThrow('重置密码失败');
}
return $result;
}
/**
* 重置密码
* @param $id
* @param $password
* @param $newPassword
* @return mixed
* @throws Exception
*/
public function resetPassword($id, $password, $newPassword): mixed
{
if ($password !== $newPassword) {
return $this->utils->errorThrow('两次密码不一致');
}
$info = $this->model::find($id);
if (empty($info)) {
return $this->utils->notFound('数据不存在');
}
if (password_verify($newPassword, $info['password'])) {
return $this->utils->errorThrow('新密码不能与旧密码相同');
}
$result = $this->model::where('id', $id)->update([
'password' => password_hash($newPassword, PASSWORD_DEFAULT),
'last_reset_password_at' => get_time()
]);
if (!$result) {
return $this->utils->errorThrow('重置密码失败');
}
return $result;
}
}

View File

@@ -48,7 +48,7 @@ class JWTService
public function generateToken(array $data): string
{
$issuedAt = time();
$expirationTime = $issuedAt + config('xk.redis.jwt_ttl');
$expirationTime = $issuedAt + config('cc.redis.jwt_ttl', 600000);
$payload = [
'iat' => $issuedAt,
@@ -84,7 +84,7 @@ class JWTService
{
try {
$jwt = $this->parseToken();
$user = RedisService::getInstance()->init(config('xk.redis.jwt'))->get($jwt->data->id);
$user = RedisService::getInstance()->init(config('cc.redis.jwt'))->get($jwt->data->id);
if (empty($user)) return UtilsService::getInstance()->notAuth('登录状态过期');
return json_decode($user, true);
} catch (Exception $e) {

135
config/cc.php Executable file
View File

@@ -0,0 +1,135 @@
<?php
return [
/*
* 过期时间配置
*/
'time_out' => [
// 订单
'product_order' => [
'over_time' => 24*3600,//秒,自动取消时间
// 'over_time' => 3,//秒,自动取消时间
'received_time' => 7*24*3600,//自动确认收货时间
'forbidden_refund_time' => 30*24*3600, //不允许退款时间
'settlement_time' => 0//7*24*3600//订单发货 分账自动结算时间
],
// 处方
'prescription' => [
'over_time' => 24*3600 //处方审核自动失效时间
// 'over_time' => 0 //处方审核自动失效时间
],
],
/*
* redis配置
*/
'redis' => [
'jwt' => 'xk_login_',
'jwt_ttl' => 360000,
// 'jwt_ttl' => 360,
'email' => 'xk_email_',
'phone' => 'xk_phone_',
'login_out_key' => 'xk_login_out_',
'menu_key' => 'xk_menu_',
],
/*
* api白名单
*/
'api' => [
'white_list' => [
'/api/admin/login',
'/api/admin/register',
]
],
/*
* 阿里云oss配置
*/
'oss' => [
'truncated_list' => [
'avatar',
'logo',
'url',
'image_url',
],
'redis_key' => 'xk_oss_url_',
'ali' => [
'accessKeyId' => env('OSS_ACCESS_KEY_ID'),
'accessKeySecret' => env('OSS_ACCESS_KEY_SECRET'),
'endpoint' => env('OSS_ENDPOINT'),
'bucket' => env('OSS_BUCKET'),
'domain' => env('OSS_DOMAIN'),
]
],
/*
* 短信配置
*/
'sms' => [
'ali' => [
'status' => '1',
'access_key_id' => env('ALIYUN_SMS_ACCESS_KEY_ID'),
'access_key_secret' => env('ALIYUN_SMS_ACCESS_KEY_SECRET'),
'sign_name' => env('ALIYUN_SMS_SIGN_NAME'),
'captcha' => [
"template_id" => "SMS_275060336", // 模板id
"template_variable" => "code", //模板变量
],
"doctor" => [
"register" => [ //挂号订单提醒
"template_id" => "SMS_462205458",
"template_variable" => ""
],
"prescription_pass" => [
"template_id" => "SMS_462260412",
"template_variable" => "order"
],
"prescription_refuse" => [
"template_id" => "SMS_462230433",
"template_variable" => [
"order",
"cause"
]
]
],
"pharmacist" => [
"wait_approval" => [
"template_id" => "SMS_462255406",
"template_variable" => ""
]
]
]
],
/*
* 旧接口配置
*/
'base_url' => [
'old_api' => env('BASE_OLD_API_URL', ''),
'old_shop_api' => env('BASE_OLD_SHOP_API_URL', ''),
// 微信接口
'we_chat_api' => env('BASE_WE_CHAT_API_URL', ''),
],
/*
* 日志配置
*/
'log' => [
// 不添加返回记录的api接口
'no_insert' => [
'api/admin/auth/login',
'api/admin/auth/send-verification-code',
'api/admin/auth/my-info',
'api/admin/auth/codes',
'api/admin/auth/menu',
'api/admin/log/api-list',
'api/admin/log/ledger-list',
'api/admin/log/op-list',
'api/admin/log/prescription-list',
]
],
'app' => [
'we_chat' => [
'app_id' => '',
'app_secret' => '',
'merchant_id' => '',
'merchant_key' => '',
'apiclient_cert' => '',
'apiclient_key' => ''
]
],
];

View File

@@ -13,3 +13,9 @@ Route::get('/', function () {
UtilsService::class::getInstance()->autoRouteRegister([
'' => \App\Http\Controllers\LoginController::class, // 登录控制器
]);
Route::group([], function () {
UtilsService::class::getInstance()->autoRouteRegister([
'user' => \App\Http\Controllers\UserController::class, // 用户控制器
]);
});

View File

@@ -3,12 +3,12 @@
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
$framework = \App\Models\ProjectModel::with([
'frameworks',
'labels',
'technologyStacks',
])->get();
ds($framework);
//
// $framework = \App\Models\ProjectModel::with([
// 'frameworks',
// 'labels',
// 'technologyStacks',
// ])->get();
// ds($framework);
return view('welcome');
});