初始化项目
This commit is contained in:
135
app/Service/LoginService.php
Normal file
135
app/Service/LoginService.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
/**
|
||||
* @var mixed 单例实例,确保该类只有一个全局实例
|
||||
*/
|
||||
private static mixed $_instance;
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @param $account
|
||||
* @param $password
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function login($account, $password): array
|
||||
{
|
||||
$userModel = UserModel::with(['roles:id,name,value'])->where('account', $account)->first();
|
||||
if (empty($userModel)) {
|
||||
UtilsService::getInstance()->errorThrow('用户或密码错误!');
|
||||
// return $this->register($account, $password);
|
||||
}
|
||||
|
||||
if (!password_verify($password, $userModel->password)) {
|
||||
UtilsService::getInstance()->errorThrow('用户或密码错误!');
|
||||
}
|
||||
|
||||
if ($userModel->ip !== get_ip()) {
|
||||
$ipTable = json_decode($userModel->ip_table, true);
|
||||
if (!in_array(get_ip(), $ipTable)) {
|
||||
$ipTable[] = get_ip();
|
||||
}
|
||||
$update = UserModel::where('id', $userModel->id)->update([
|
||||
'ip' => get_ip(),
|
||||
'ip_table' => json_encode($ipTable),
|
||||
'updated_at' => get_time()
|
||||
]);
|
||||
|
||||
if (!$update) {
|
||||
UtilsService::getInstance()->errorThrow('更新失败!');
|
||||
}
|
||||
|
||||
$userModel = UserModel::where('id', $userModel->id)->first();
|
||||
}
|
||||
$result = [
|
||||
'id' => $userModel->id,
|
||||
'account' => $userModel->account,
|
||||
'nick_name' => $userModel->nick_name,
|
||||
'avatar' => $userModel->avatar,
|
||||
'email' => $userModel->email,
|
||||
'role_name' => $userModel->roles->name,
|
||||
'role_value' => $userModel->roles->value,
|
||||
'ip' => $userModel->ip,
|
||||
'ip_table' => $userModel->ip_table,
|
||||
];
|
||||
$token = JWTService::getInstance()->generateToken($result);
|
||||
$result['token'] = $token;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册
|
||||
* @param $account
|
||||
* @param $password
|
||||
* @param $email
|
||||
* @param $code
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function register($account, $password, $email, $code): array
|
||||
{
|
||||
$userModel = UserModel::where('account', $account)->first();
|
||||
if ($userModel) {
|
||||
UtilsService::getInstance()->errorThrow('账号已被占用!');
|
||||
}
|
||||
|
||||
$createModel = UserModel::create([
|
||||
'account' => $account,
|
||||
'email' => $email,
|
||||
'password' => password_hash($password, PASSWORD_DEFAULT),
|
||||
'nick_name' => '新用户'. Str::random(),
|
||||
'avatar' => 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
|
||||
'role_id' => 2,
|
||||
'ip' => get_ip(),
|
||||
'ip_table' => json_encode([get_ip()]),
|
||||
'created_at' => get_time()
|
||||
]);
|
||||
|
||||
if (!$createModel) {
|
||||
UtilsService::getInstance()->errorThrow('注册失败!');
|
||||
}
|
||||
|
||||
$userInfo = UserModel::with(['roles:id,name,value'])->where('id', $createModel->id)->first();
|
||||
|
||||
$result = [
|
||||
'id' => $userInfo->id,
|
||||
'account' => $userInfo->account,
|
||||
'nick_name' => $userInfo->nick_name,
|
||||
'avatar' => $userInfo->avatar,
|
||||
'email' => $userInfo->email?? '',
|
||||
'role_name' => $userInfo->roles->name,
|
||||
'role_value' => $userInfo->roles->value,
|
||||
'ip' => $userInfo->ip,
|
||||
'ip_table' => $userInfo->ip_table,
|
||||
];
|
||||
$token = JWTService::getInstance()->generateToken($result);
|
||||
$result['token'] = $token;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
210
app/Service/UserService.php
Normal file
210
app/Service/UserService.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\BaseApp\BaseService;
|
||||
use App\Enum\UserStatusEnum;
|
||||
use App\Models\CollectionModel;
|
||||
use App\Models\RoleModel;
|
||||
use App\Models\UserModel;
|
||||
use App\Models\UserPayModel;
|
||||
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', 'is_sys_notifications', 'is_collection_notifications', 'is_marketing_notifications', 'qr_code', 'role_id', 'ip', 'ip_table', 'status', 'last_reset_password_at', 'created_at', 'updated_at', 'deleted_at', ];
|
||||
$this->model = UserModel::class;
|
||||
$this->queryField = [
|
||||
'account' => 'like',
|
||||
'nick_name' => 'like',
|
||||
'email' => 'like',
|
||||
'role_id' => '=',
|
||||
'status' => '=',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
* @return array
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function list(): array
|
||||
{
|
||||
$this->with = [
|
||||
'roles'
|
||||
];
|
||||
$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();
|
||||
$v['last_reset_password_at'] = format_time($v['last_reset_password_at']);
|
||||
}
|
||||
|
||||
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 $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function myInfo(): mixed
|
||||
{
|
||||
$this->with = [
|
||||
'roles'
|
||||
];
|
||||
$result = $this->getDetail($this->userId);
|
||||
$result['created_day_at'] = format_time(strtotime($result['created_at']), 'Y-m-d');
|
||||
$result['account'] = desensitization($result['account']);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户统计
|
||||
* @return array[]
|
||||
*/
|
||||
public function userStats()
|
||||
{
|
||||
$payProject = UserPayModel::where('user_id', $this->userId)->count();
|
||||
$collection = CollectionModel::where('user_id', $this->userId)->count();
|
||||
$role = $this->userInfo['role_name'];
|
||||
return [
|
||||
'pay_project' => [
|
||||
'label' => '已购项目',
|
||||
'value' => $payProject,
|
||||
'icon' => 'shopping-bag'
|
||||
],
|
||||
'collection' => [
|
||||
'label' => '我的收藏',
|
||||
'value' => $collection,
|
||||
'icon' => 'heart'
|
||||
],
|
||||
'role' => [
|
||||
'label' => '用户类型',
|
||||
'value' => $role,
|
||||
'icon' => 'user'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
112
app/Service/common/JWTService.php
Executable file
112
app/Service/common/JWTService.php
Executable file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\common;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Exception;
|
||||
|
||||
class JWTService
|
||||
{
|
||||
private static mixed $_instance;
|
||||
private string $secretKey = 'cc_spa_jwt_secret_key'; // 请替换为你的密钥
|
||||
|
||||
private string $token;
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Token
|
||||
* @return $this|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getToken(): null|static
|
||||
{
|
||||
$token = request()->bearerToken();
|
||||
if (empty($token)) return UtilsService::getInstance()->notAuth('请先登录');
|
||||
$this->token = $token;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 JWT Token
|
||||
* @param array $data 要嵌入到 token 中的数据
|
||||
* @return string
|
||||
*/
|
||||
public function generateToken(array $data): string
|
||||
{
|
||||
$issuedAt = time();
|
||||
$expirationTime = $issuedAt + config('cc.redis.jwt_ttl', 600000);
|
||||
|
||||
$payload = [
|
||||
'iat' => $issuedAt,
|
||||
'exp' => $expirationTime,
|
||||
'data' => $data
|
||||
];
|
||||
RedisService::getInstance()->init(config('cc.redis.jwt'))->set($data['id'], json_encode($data));
|
||||
return JWT::encode($payload, $this->secretKey, 'HS256');
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JWT Token
|
||||
* @return object|null 返回解码后的 payload 或者 null 如果验证失败
|
||||
* @throws Exception
|
||||
*/
|
||||
public function parseToken(): ?object
|
||||
{
|
||||
try {
|
||||
if (empty($this->token)) return UtilsService::getInstance()->notAuth('请先登录');
|
||||
return JWT::decode($this->token, new Key($this->secretKey, 'HS256'));
|
||||
} catch (Exception $e) {
|
||||
return UtilsService::getInstance()->notAuth('【1】Token解析失败!请重新登录:'. $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 解析 JWT Token
|
||||
* @return array|null 返回解码后的 payload 或者 null 如果验证失败
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getUserInfo(): ?array
|
||||
{
|
||||
try {
|
||||
$jwt = $this->parseToken();
|
||||
$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) {
|
||||
return UtilsService::getInstance()->notAuth('【2】Token解析失败!请重新登录:'. $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 续签 JWT Token
|
||||
* @return string|null 新的 JWT 字符串或者 null 如果原 token 已过期或无效
|
||||
* @throws Exception
|
||||
*/
|
||||
public function refreshToken(): ?string
|
||||
{
|
||||
$decoded = $this->parseToken();
|
||||
if ($decoded === null || !property_exists($decoded, 'data')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->generateToken((array)$decoded->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
94
app/Service/common/RedisService.php
Executable file
94
app/Service/common/RedisService.php
Executable file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\common;
|
||||
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class RedisService
|
||||
{
|
||||
|
||||
private static mixed $_instance;
|
||||
|
||||
private $prefix = 'default';
|
||||
|
||||
private $redis;
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @param string $prefix
|
||||
* @return RedisService
|
||||
*/
|
||||
public function init(string $prefix = 'default'): static
|
||||
{
|
||||
$this->redis = Redis::class;
|
||||
$this->prefix = $prefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @param int $expire
|
||||
* @return true
|
||||
*/
|
||||
public function set($key, $value, int $expire = 0): true
|
||||
{
|
||||
$this->redis::set($this->prefix . $key, $value);
|
||||
if ($expire > 0) {
|
||||
$this->redis::expire($this->prefix . $key, $expire);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 累加
|
||||
* @param $key
|
||||
* @param int $value
|
||||
* @param int $expire
|
||||
* @return true
|
||||
*/
|
||||
public function incr($key, int $value = 1, int $expire = 0): true
|
||||
{
|
||||
$this->redis::incr($this->prefix . $key, $value);
|
||||
if ($expire > 0) {
|
||||
$this->redis::expire($this->prefix . $key, $expire);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存
|
||||
*
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key): mixed
|
||||
{
|
||||
return $this->redis::get($this->prefix . $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @param $key
|
||||
* @return bool
|
||||
*/
|
||||
public function del($key): bool
|
||||
{
|
||||
return $this->redis::del($this->prefix . $key);
|
||||
}
|
||||
}
|
||||
89
app/Service/common/UploadService.php
Normal file
89
app/Service/common/UploadService.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\common;
|
||||
|
||||
use App\BaseApp\BaseService;
|
||||
use App\Models\ProjectModel;
|
||||
use App\Models\RoleModel;
|
||||
use App\Models\UserModel;
|
||||
use App\Service\common\upload\LocalhostStorageService;
|
||||
use App\Service\common\upload\QiniuStorageService;
|
||||
use App\Service\FileService;
|
||||
use Exception;
|
||||
use Illuminate\Support\Str;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
class UploadService extends BaseService
|
||||
{
|
||||
private $uploadService;
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = RoleModel::class;
|
||||
|
||||
switch (env('ECS')) {
|
||||
case 'aliyun':
|
||||
// $this->uploadService = AliyunStorageService::getInstance();
|
||||
break;
|
||||
case 'qcloud':
|
||||
// $this->uploadService = QcloudStorageService::getInstance();
|
||||
break;
|
||||
case 'qiniu':
|
||||
$this->uploadService = QiniuStorageService::getInstance();
|
||||
break;
|
||||
default:
|
||||
$this->uploadService = LocalhostStorageService::getInstance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传OSS图片
|
||||
* @param $file
|
||||
* @return array|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function uploadImage($file): array|bool
|
||||
{
|
||||
// 获取文件后缀
|
||||
$ext = $file->getClientOriginalExtension();
|
||||
$key = 'spa/image/'. date('Ymd') . '/' . 'cc_upload_'. Str::random(). uniqid() . '.' . $ext;
|
||||
$result = $this->uploadService->uploadVideo($file, $key);
|
||||
// $result = [
|
||||
// 'key' => $key,
|
||||
// 'url' => 'https://img2.baidu.com/it/u=1629222614,1358629025&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500&a='. rand(1111111, 9999999)
|
||||
// ];
|
||||
FileService::getInstance()->create([
|
||||
'user_id' => $this->userId,
|
||||
'url' => $result['url'],
|
||||
]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传OSS视频
|
||||
* @param $file
|
||||
* @return array|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function uploadVideo($file): array|bool
|
||||
{
|
||||
// 获取文件后缀
|
||||
$ext = $file->getClientOriginalExtension();
|
||||
$key = 'spa/video/'. date('Ymd') . '/' . 'cc_upload_'. Str::random(). uniqid() . '.' . $ext;
|
||||
$result = $this->uploadService->uploadVideo($file, $key);
|
||||
// $result = [
|
||||
// 'key' => $key,
|
||||
// 'url' => 'http://d-jy.nailaoyun.cn//storage/video//20250327/2cc1abf9bd69410ce7c69660daf54260.mp4'
|
||||
// ];
|
||||
FileService::getInstance()->create([
|
||||
'user_id' => $this->userId,
|
||||
'url' => $result['url'],
|
||||
]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
247
app/Service/common/UtilsService.php
Executable file
247
app/Service/common/UtilsService.php
Executable file
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\common;
|
||||
|
||||
use App\Enum\ErrorEnum;
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Random\RandomException;
|
||||
use ReflectionClass;
|
||||
|
||||
class UtilsService
|
||||
{
|
||||
private static mixed $_instance;
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 抛出异常
|
||||
*
|
||||
* @param string $msg
|
||||
* @param ErrorEnum $code
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function errorThrow(string $msg = '请求出了问题!', ErrorEnum $code = ErrorEnum::FAIL): mixed
|
||||
{
|
||||
throw new Exception($msg, $code->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 抛出未找到异常 2000
|
||||
*
|
||||
* @param $msg
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function notFound($msg): mixed
|
||||
{
|
||||
return self::errorThrow($msg, ErrorEnum::NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* 未授权 401
|
||||
*
|
||||
* @param $msg
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function notAuth($msg): mixed
|
||||
{
|
||||
return self::errorThrow($msg, ErrorEnum::NOT_AUTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成密码
|
||||
* @param $password
|
||||
* @return string
|
||||
*/
|
||||
public function genPassword($password): string
|
||||
{
|
||||
return password_hash($password, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码验证
|
||||
*
|
||||
* @param $password
|
||||
* @param $passwordAse
|
||||
* @return bool
|
||||
*/
|
||||
public function checkPassword($password, $passwordAse): bool
|
||||
{
|
||||
// 盐
|
||||
return password_verify($password, $passwordAse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成OpenId
|
||||
* @return string
|
||||
* @throws RandomException
|
||||
*/
|
||||
public function genOpenId(): string
|
||||
{
|
||||
// 获取当前时间戳(精确到秒)
|
||||
$timestamp = dechex(time());
|
||||
|
||||
// 生成16字节的随机数据,并转换为32个十六进制字符组成的字符串
|
||||
$randomString = bin2hex(random_bytes(16));
|
||||
|
||||
// 结合时间和随机字符串,确保总长度为28个字符
|
||||
return substr($timestamp . $randomString, 0, 28);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归生成树形结构
|
||||
* @param $data
|
||||
* @param int $pid
|
||||
* @return array
|
||||
*/
|
||||
public function tree($data, int $pid = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($data as $v) {
|
||||
if ($v['pid'] == $pid) {
|
||||
$v['children'] = $this->tree($data, $v['id']);
|
||||
if (empty($v['children'])) {
|
||||
unset($v['children']);
|
||||
}
|
||||
$tree[] = $v;
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查手机号格式
|
||||
*
|
||||
* @param string $phone
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkPhone(string $phone): bool
|
||||
{
|
||||
$phone = trim($phone);
|
||||
if (preg_match('/^1[3456789]\d{9}$/', $phone)) {
|
||||
return true;
|
||||
} else {
|
||||
self::errorThrow('手机号格式不正确');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成订单号
|
||||
* @param int $type
|
||||
* @return string
|
||||
*/
|
||||
public function genOrderNo(int $type = 0): string
|
||||
{
|
||||
$len = 9999999999;
|
||||
switch ($type) {
|
||||
case 0:
|
||||
return 'DK' . date('Ymd') . str_pad(mt_rand(1, $len), 11, '0', STR_PAD_LEFT);
|
||||
case 1:
|
||||
return 'DD' . date('Ymd') . str_pad(mt_rand(1, $len), 11, '0', STR_PAD_LEFT);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是开发环境
|
||||
* @return bool
|
||||
*/
|
||||
public static function isDev(): bool
|
||||
{
|
||||
return env('ECS') === 'localhost';
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据身份证号计算年龄
|
||||
* @param string $idno 身份证号(15位或18位)
|
||||
* @return int|false 成功返回年龄,失败返回false
|
||||
*/
|
||||
public function getAgeFromIdNo($idno = '')
|
||||
{
|
||||
// 校验身份证号长度
|
||||
$len = strlen($idno);
|
||||
if (!in_array($len, [15, 18])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 提取出生日期部分
|
||||
if ($len === 18) {
|
||||
$datePart = substr($idno, 6, 8);
|
||||
} else {
|
||||
// 15位身份证补全年份为19XX
|
||||
$datePart = '19' . substr($idno, 6, 6);
|
||||
}
|
||||
|
||||
// 分解年月日
|
||||
$year = substr($datePart, 0, 4);
|
||||
$month = substr($datePart, 4, 2);
|
||||
$day = substr($datePart, 6, 2);
|
||||
|
||||
// 校验年月日是否为数字
|
||||
if (!ctype_digit($year) || !ctype_digit($month) || !ctype_digit($day)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 尝试创建日期对象
|
||||
try {
|
||||
$birthDate = new DateTime("$year-$month-$day");
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$currentDate = new DateTime();
|
||||
|
||||
// 检查出生日期是否在当前日期之前
|
||||
if ($birthDate > $currentDate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算年龄差
|
||||
$ageInterval = $currentDate->diff($birthDate);
|
||||
return $ageInterval->y;
|
||||
}
|
||||
|
||||
public function autoRouteRegister($class): void
|
||||
{
|
||||
foreach ($class as $key => $value) {
|
||||
|
||||
// 获取控制器$value的所有方法
|
||||
$methods = (new ReflectionClass($value))->getMethods();
|
||||
|
||||
// 注册路由
|
||||
foreach ($methods as $method) {
|
||||
// 获取方法注释 @Method
|
||||
$docComment = $method->getDocComment();
|
||||
if ($method->name === '__construct' || preg_match('/@Method\s+(NO)\b/', $docComment, $matches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$httpMethod = 'any';
|
||||
// 查询 @Method GET 或者 @Method POST
|
||||
if (preg_match('/@Method\s+(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD|ANY)\b/', $docComment, $matches)) {
|
||||
$httpMethod = $matches[1];
|
||||
}
|
||||
Route::$httpMethod($key . '/' . cc_camel_case_to_dash($method->getName()), [$value, conjunction_symbol_processing($method->name)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
108
app/Service/common/upload/LocalhostStorageService.php
Normal file
108
app/Service/common/upload/LocalhostStorageService.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\common\upload;
|
||||
|
||||
use App\BaseApp\BaseService;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class LocalhostStorageService extends BaseService
|
||||
{
|
||||
/**
|
||||
* @var mixed 单例实例,确保该类只有一个全局实例
|
||||
*/
|
||||
protected static mixed $_instance;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片
|
||||
*
|
||||
* @param string $filePath 文件本地路径
|
||||
* @param string $key 上传到本地存储的文件名
|
||||
* @return array|bool
|
||||
*/
|
||||
public function uploadImage($filePath, $key): bool|array
|
||||
{
|
||||
return $this->uploadFile($filePath, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传视频
|
||||
*
|
||||
* @param string $filePath 文件本地路径
|
||||
* @param string $key 上传到本地存储的文件名
|
||||
* @return array|bool
|
||||
*/
|
||||
public function uploadVideo($filePath, $key): bool|array
|
||||
{
|
||||
return $this->uploadFile($filePath, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除图片
|
||||
*
|
||||
* @param string $key 本地存储的文件名
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteImage($key): bool
|
||||
{
|
||||
return $this->deleteFile($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除视频
|
||||
*
|
||||
* @param string $key 本地存储的文件名
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteVideo($key): bool
|
||||
{
|
||||
return $this->deleteFile($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param string $filePath 文件本地路径
|
||||
* @param string $key 上传到本地存储的文件名
|
||||
* @return array|bool
|
||||
*/
|
||||
private function uploadFile(string $filePath, string $key): bool|array
|
||||
{
|
||||
if (Storage::put($key, file_get_contents($filePath))) {
|
||||
return [
|
||||
'key' => $key,
|
||||
'url' => asset('/storage/' . $key)
|
||||
];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param string $key 本地存储的文件名
|
||||
* @return bool
|
||||
*/
|
||||
private function deleteFile(string $key): bool
|
||||
{
|
||||
return Storage::delete($key);
|
||||
}
|
||||
}
|
||||
132
app/Service/common/upload/QiniuStorageService.php
Normal file
132
app/Service/common/upload/QiniuStorageService.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\common\upload;
|
||||
|
||||
use App\BaseApp\BaseService;
|
||||
use Exception;
|
||||
use Qiniu\Auth;
|
||||
use Qiniu\Storage\BucketManager;
|
||||
use Qiniu\Storage\UploadManager;
|
||||
|
||||
class QiniuStorageService extends BaseService
|
||||
{
|
||||
/**
|
||||
* @var mixed 单例实例,确保该类只有一个全局实例
|
||||
*/
|
||||
protected static mixed $_instance;
|
||||
private $accessKey;
|
||||
private $secretKey;
|
||||
private $bucket;
|
||||
private $domain;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->accessKey = config('cc.oss.qiniu.access_key');
|
||||
$this->secretKey = config('cc.oss.qiniu.secret_key');
|
||||
$this->bucket = config('cc.oss.qiniu.bucket');
|
||||
$this->domain = config('cc.oss.qiniu.domain');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片
|
||||
*
|
||||
* @param string $filePath 文件本地路径
|
||||
* @param string $key 上传到七牛云的文件名
|
||||
* @return array|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function uploadImage($filePath, $key): bool|array
|
||||
{
|
||||
return $this->uploadFile($filePath, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传视频
|
||||
*
|
||||
* @param string $filePath 文件本地路径
|
||||
* @param string $key 上传到七牛云的文件名
|
||||
* @return array|bool
|
||||
*/
|
||||
public function uploadVideo($filePath, $key): bool|array
|
||||
{
|
||||
return $this->uploadFile($filePath, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除图片
|
||||
*
|
||||
* @param string $key 七牛云存储的文件名
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteImage($key): bool
|
||||
{
|
||||
return $this->deleteFile($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除视频
|
||||
*
|
||||
* @param string $key 七牛云存储的文件名
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteVideo($key): bool
|
||||
{
|
||||
return $this->deleteFile($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param string $filePath 文件本地路径
|
||||
* @param string $key 上传到七牛云的文件名
|
||||
* @return array|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
private function uploadFile(string $filePath, string $key): bool|array
|
||||
{
|
||||
$auth = new Auth($this->accessKey, $this->secretKey);
|
||||
$token = $auth->uploadToken($this->bucket);
|
||||
$uploadMgr = new UploadManager();
|
||||
|
||||
list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath);
|
||||
if ($err !== null) {
|
||||
return false;
|
||||
} else {
|
||||
return [
|
||||
'key' => $ret['key'],
|
||||
'url' => $this->domain . '/' . $ret['key']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param string $key 七牛云存储的文件名
|
||||
* @return bool
|
||||
*/
|
||||
private function deleteFile(string $key): bool
|
||||
{
|
||||
$auth = new Auth($this->accessKey, $this->secretKey);
|
||||
$bucketMgr = new BucketManager($auth);
|
||||
|
||||
$err = $bucketMgr->delete($this->bucket, $key);
|
||||
return $err === null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user