样机小程序
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\AgreementValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Agreement;
|
||||
use support\Request;
|
||||
|
||||
class AgreementService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Agreement::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = AgreementValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'show':
|
||||
if (isset($p['type']) && !empty($p['type'])) {
|
||||
$config['where']['type'] = $p['type'];
|
||||
}
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\AuthLogic;
|
||||
use app\common\model\User;
|
||||
use app\common\utils\Feishu;
|
||||
use support\Db;
|
||||
|
||||
class AuthService
|
||||
{
|
||||
|
||||
/**
|
||||
* 飞书授权
|
||||
*/
|
||||
public function feishuAuthorize(string $corpAbbr, string $systemCcode)
|
||||
{
|
||||
$logic = new AuthLogic();
|
||||
$certificate = $logic->feishuAppInfo($corpAbbr, $systemCcode);
|
||||
$feishu = new Feishu($certificate['app_id'], $certificate['app_secret'], $certificate['abbr']);
|
||||
return ['auth_url' => $feishu->authorize($certificate)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录,支持多类型
|
||||
*/
|
||||
public function login(array $data): array
|
||||
{
|
||||
$loginType = $data['login_type'] ?? 'upwd';
|
||||
$logic = new AuthLogic();
|
||||
|
||||
return match ($loginType) {
|
||||
default => $logic->uPwdLogin($data),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
public function register(array $data)
|
||||
{
|
||||
$logic = new AuthLogic();
|
||||
try {
|
||||
Db::beginTransaction();
|
||||
$result = $logic->register($data);
|
||||
Db::commit();
|
||||
return $result;
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验token
|
||||
*/
|
||||
public function verifyToken(string $token, string $systemCode): array
|
||||
{
|
||||
return (new AuthLogic())->verifyToken($token, $systemCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新token
|
||||
* @param string $refreshToken
|
||||
* @param string|null $systemCode
|
||||
*/
|
||||
public function refreshToken(string $refreshToken, string $systemCode): array
|
||||
{
|
||||
return (new AuthLogic())->refreshToken($refreshToken, $systemCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出(失效token)
|
||||
*/
|
||||
public function logout(?string $token, string $systemCode): void
|
||||
{
|
||||
(new AuthLogic())->logout($token, $systemCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制拉黑token
|
||||
*/
|
||||
public function blockToken(string $token, string $systemCode): void
|
||||
{
|
||||
(new AuthLogic())->blockToken($token, $systemCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\BannerModule;
|
||||
use app\common\validate\BannerValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Banner;
|
||||
|
||||
class BannerService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Banner::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = BannerValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
public function getBanner($params){
|
||||
$where = [];
|
||||
if(isset($params['module'])){
|
||||
$where['module'] = $params['module'];
|
||||
}
|
||||
return Banner::where('status','1')->where($where)->get();
|
||||
}
|
||||
|
||||
public function getBannerModule(){
|
||||
return BannerModule::where('status','1')->get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\Corp;
|
||||
use app\common\model\Systems;
|
||||
use support\Redis;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class BasicDataService
|
||||
{
|
||||
// 定义Redis键名前缀常量
|
||||
const LOGIN_TYPE_KEY = 'bsh_info_login_types';
|
||||
const SYSTEM_CODE_KEY = 'bsh_info_system_codes';
|
||||
|
||||
/**
|
||||
* 检查并缓存独立的基础参数
|
||||
*/
|
||||
public function checkAndCacheBaseParams($loginType, $systemCode)
|
||||
{
|
||||
if (!$loginType && !$systemCode) {
|
||||
throw new BusinessException('header缺少必要参数');
|
||||
}
|
||||
|
||||
// 检查并缓存登录类型
|
||||
if (!$this->checkParamInCache(self::LOGIN_TYPE_KEY, $loginType)) {
|
||||
$this->cacheLoginTypes();
|
||||
if (!$this->checkParamInCache(self::LOGIN_TYPE_KEY, $loginType)) {
|
||||
throw new BusinessException('无效的登录方式');
|
||||
}
|
||||
}
|
||||
|
||||
// 检查并缓存系统码
|
||||
if (!$this->checkParamInCache(self::SYSTEM_CODE_KEY, $systemCode)) {
|
||||
$this->cacheSystemCodes();
|
||||
if (!$this->checkParamInCache(self::SYSTEM_CODE_KEY, $systemCode)) {
|
||||
throw new BusinessException('无效的系统码');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数是否在Redis集合中
|
||||
*/
|
||||
private function checkParamInCache($cacheKey, $param)
|
||||
{
|
||||
return Redis::sIsMember($cacheKey, $param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存所有登录类型到集合
|
||||
*/
|
||||
private function cacheLoginTypes()
|
||||
{
|
||||
$cacheKey = self::LOGIN_TYPE_KEY;
|
||||
|
||||
// 如果集合已存在,直接返回
|
||||
// if (Redis::exists($cacheKey)) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
$loginTypes = $this->getAllLoginTypes();
|
||||
if (empty($loginTypes)) {
|
||||
throw new BusinessException('未获取到登录类型数据');
|
||||
}
|
||||
|
||||
// 批量添加值到集合
|
||||
Redis::sAdd($cacheKey, ...$loginTypes);
|
||||
Redis::expire($cacheKey, 3600); // 1小时有效期
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存所有系统码到集合
|
||||
*/
|
||||
private function cacheSystemCodes()
|
||||
{
|
||||
$cacheKey = self::SYSTEM_CODE_KEY;
|
||||
|
||||
// 如果集合已存在,直接返回
|
||||
// if (Redis::exists($cacheKey)) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
$systemCodes = $this->getAllSystemCodes();
|
||||
if (empty($systemCodes)) {
|
||||
throw new BusinessException('未获取到系统码数据');
|
||||
}
|
||||
|
||||
// 批量添加值到集合
|
||||
Redis::sAdd($cacheKey, ...$systemCodes);
|
||||
Redis::expire($cacheKey, 3600); // 1小时有效期
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有有效的登录类型
|
||||
*/
|
||||
private function getAllLoginTypes()
|
||||
{
|
||||
return ['upwd', 'feishu', 'wechat', 'qrcode']; // 示例数据
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有有效的系统码
|
||||
*/
|
||||
private function getAllSystemCodes()
|
||||
{
|
||||
return Systems::pluck('code')->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有有效的公司标识
|
||||
*/
|
||||
private function getAllCorpAbbrs()
|
||||
{
|
||||
return Corp::pluck('abbr')->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\MessageNoticeValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\MessageNotice;
|
||||
use support\Request;
|
||||
|
||||
class MessageNoticeService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = MessageNotice::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = MessageNoticeValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/** 分页列表 */
|
||||
public function serviceSelfList(Request $request, string $scene = 'self')
|
||||
{
|
||||
$result = $this->cqyProcess(ucfirst($scene), $request);
|
||||
if ($result === false) {
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
$limit = (int)$request->get('size', 15);
|
||||
$page = (int)$request->get('current', 1);
|
||||
$result = $this->logicList($config, $limit, $page);
|
||||
}
|
||||
return $this->postProcess(ucfirst($scene), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'self':
|
||||
$config['where']['receiver_user_id'] = $request->user->uid;
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function beforeServiceSelf($data, Request $request)
|
||||
{
|
||||
MessageNotice::where('receiver_user_id', $request->user->uid)->update(['is_read' => 1]);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use OSS\OssClient;
|
||||
use OSS\Core\OssException;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class OssService
|
||||
{
|
||||
private $accessKeyId;
|
||||
private $accessKeySecret;
|
||||
private $bucket;
|
||||
private $endpoint;
|
||||
private $domain;
|
||||
private $ossClient;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->accessKeyId = getenv('OSS_ACCESSID');
|
||||
$this->accessKeySecret = getenv('OSS_ACCESSSECRET');
|
||||
$this->bucket = getenv('OSS_BUCKET');
|
||||
$this->endpoint = getenv('OSS_ENDPOINT');
|
||||
$this->domain = getenv('OSS_DOMAIN');
|
||||
$this->ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片到 OSS
|
||||
* @param string $filePath 本地文件路径
|
||||
* @param string $objectKey OSS上存储的对象名称
|
||||
* @return string 图片的 URL
|
||||
*/
|
||||
public function uploadImage($filePath, $objectKey)
|
||||
{
|
||||
try {
|
||||
// 上传文件到 OSS
|
||||
$this->ossClient->uploadFile($this->bucket, $objectKey, $filePath);
|
||||
// 构造图片的私有 URL
|
||||
$url = $this->generatePrivateUrl($objectKey);
|
||||
return $url;
|
||||
} catch (OssException $e) {
|
||||
// 错误处理
|
||||
throw new \RuntimeException('OSS Error: ' . $e->getMessage());
|
||||
} catch (\Throwable $th) {
|
||||
// 错误处理
|
||||
throw new BusinessException('Error: ' . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成图片的私有访问 URL
|
||||
* @param string $objectKey
|
||||
* @return string
|
||||
*/
|
||||
public function generatePrivateUrl($objectKey, $expireTime = 3600)
|
||||
{
|
||||
// 生成 OSS 私有 URL(有效期为 3600 秒)
|
||||
$originalUrl = $this->ossClient->signUrl($this->bucket, $objectKey, $expireTime);
|
||||
|
||||
// // 使用正则表达式替换
|
||||
$originalUrl = preg_replace(
|
||||
'#^https?://[^/]+#',
|
||||
'https://static.hnzhwlkj.cn',
|
||||
$originalUrl
|
||||
);
|
||||
return $originalUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 OSS 上的文件
|
||||
* @param string $objectKey OSS上存储的对象名称
|
||||
* @return bool 删除是否成功
|
||||
*/
|
||||
public function deleteFile($objectKey)
|
||||
{
|
||||
try {
|
||||
// 删除 OSS 上的文件
|
||||
$this->ossClient->deleteObject($this->bucket, $objectKey);
|
||||
return true;
|
||||
} catch (OssException $e) {
|
||||
// 错误处理
|
||||
throw new \RuntimeException('OSS Delete Error: ' . $e->getMessage());
|
||||
} catch (\Throwable $th) {
|
||||
// 错误处理
|
||||
throw new BusinessException('Delete Error: ' . $th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\PermLogic;
|
||||
use support\Cache;
|
||||
|
||||
class PermService
|
||||
{
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new PermLogic());
|
||||
}
|
||||
|
||||
// 用户资源缓存key
|
||||
protected static function cacheKey(int $userId, string $systemCode): string
|
||||
{
|
||||
return "user_resources_{$userId}_{$systemCode}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有资源(合并角色+直接分配),结果缓存
|
||||
*/
|
||||
public function getUserResources(int $userId, string $systemCode)
|
||||
{
|
||||
$cacheKey = self::cacheKey($userId, $systemCode);
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
}
|
||||
// 调用 Logic 层获取资源
|
||||
$resources = $this->logic->getUserResources($userId, $systemCode);
|
||||
// 缓存结果
|
||||
Cache::set($cacheKey, $resources, 3600);
|
||||
return $resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建目录/菜单树,节点包含权限与打开方式
|
||||
*/
|
||||
public function getMenuTree(int $userId, string $systemCode): array
|
||||
{
|
||||
// 调用 Logic 层处理菜单构建
|
||||
$resources = $this->getUserResources($userId, $systemCode);
|
||||
return $this->logic->buildTree($resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有权限code
|
||||
*/
|
||||
public function getPermissionCodes(int $userId, string $systemCode): array
|
||||
{
|
||||
return $this->logic->getPermissionCodes($userId, $systemCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除资源相关缓存
|
||||
*/
|
||||
public function clearCache(int $userId, string $systemCode): void
|
||||
{
|
||||
Cache::delete(self::cacheKey($userId, $systemCode));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\PostCategoryLogic;
|
||||
use app\common\model\NavItems;
|
||||
use app\common\validate\PostCategoryValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\PostCategory;
|
||||
use support\Request;
|
||||
|
||||
class PostCategoryService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
protected $logic;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostCategory::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = PostCategoryValidate::class;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new PostCategoryLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList($params)
|
||||
{
|
||||
$where = [];
|
||||
if(isset($params['parent_id']) && $params['parent_id']) {
|
||||
$where['parent_id'] = $params['parent_id'];
|
||||
}else{
|
||||
$where['parent_id'] = 0;
|
||||
}
|
||||
$result = $this->logic->getList($where)->toArray();
|
||||
foreach ($result as $key => $value) {
|
||||
$where = [];
|
||||
$where['parent_id'] = $value['id'];
|
||||
$result[$key]['children'] = $this->logic->getList($where)->toArray();
|
||||
foreach ( $result[$key]['children'] as $k => $v) {
|
||||
$where = [];
|
||||
$where['parent_id'] = $v['id'];
|
||||
$result[$key]['children'][$k]['children'] = $this->logic->getList($where)->toArray();
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$brand_id = $data['parent_id'] ?? 0;
|
||||
if($brand_id == 0) {
|
||||
$data['level'] = 1;
|
||||
$data['path'] = '';
|
||||
return $data;
|
||||
}
|
||||
$parent = PostCategory::where('id', $data['parent_id'])->first();
|
||||
$parent['path'] = !empty($parent['path'])?:'/';
|
||||
$data['level'] = $parent['level']+1;
|
||||
$data['path'] = $parent['path'].$parent['id'].'/';
|
||||
|
||||
if($data['level'] > 3) {
|
||||
throw new \Exception("分类层级不能超过三层");
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\MessageNotice;
|
||||
use app\common\model\Post;
|
||||
use app\common\validate\PostCommentValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\PostComment;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class PostCommentService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostComment::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = PostCommentValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
// 帖子
|
||||
if (isset($p['post_id']) && !empty($p['post_id'])) {
|
||||
$config['where']['post_id'] = $p['post_id'];
|
||||
}
|
||||
// 用户
|
||||
if (isset($p['user_id']) && !empty($p['user_id'])) {
|
||||
$config['where']['user_id'] = $p['user_id'];
|
||||
}
|
||||
// 只查询根评论
|
||||
if (isset($p['parent_id']) && $p['parent_id'] == 0) {
|
||||
$config['where']['parent_id'] = 0;
|
||||
}
|
||||
// 根评论ID
|
||||
if (isset($p['parent_id']) && !empty($p['parent_id'])) {
|
||||
$config['where']['root_id'] = $p['parent_id'];
|
||||
}
|
||||
// 根评论ID
|
||||
if (isset($p['received_id']) && !empty($p['received_id'])) {
|
||||
$config['where']['id'] = ['not in', $p['received_id']];
|
||||
}
|
||||
// 根评论ID
|
||||
if (isset($p['status']) && !empty($p['status'])) {
|
||||
$config['where']['status'] = $p['status'];
|
||||
}
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['user_id'] = $request->user->uid;;
|
||||
$data['root_id'] = 0;
|
||||
if(!empty($data['parent_id'])){
|
||||
$data['root_id'] = PostComment::where('id', $data['parent_id'])->value('root_id');
|
||||
if($data['root_id'] == 0){
|
||||
$data['root_id'] = $data['parent_id'];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function afterServiceStore($res)
|
||||
{
|
||||
$data = [];
|
||||
$data['post_id'] = $res['post_id'];
|
||||
$data['receiver_user_id'] = Post::where(['id' => $data['post_id']])->value('user_id');
|
||||
$data['sender_user_id'] = $res['user_id'];
|
||||
$data['comment_id'] = $res['id'];
|
||||
$data['type'] = 3;
|
||||
MessageNotice::create($data);
|
||||
$post = Post::where(['id' => $data['post_id']])->first();
|
||||
$post['comment'] = $post['comment']+1;
|
||||
$post->save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function serviceDelete(Request $request)
|
||||
{
|
||||
$param = $request->all();
|
||||
|
||||
if (empty($param['id'])) {
|
||||
throw new \Exception("参数错误");
|
||||
}
|
||||
|
||||
$where = [];
|
||||
$where['id'] = $param['id'];
|
||||
$comment = PostComment::where($where)->first();
|
||||
|
||||
$post = Post::where(['id' => $comment['post_id']])->first();
|
||||
$post['comment'] = $post['comment']-1;
|
||||
$post->save();
|
||||
|
||||
$count = $comment->delete();
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\MessageNotice;
|
||||
use app\common\model\Post;
|
||||
use app\common\model\PostLike;
|
||||
use app\common\validate\PostFavoriteValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\PostFavorite;
|
||||
use support\Request;
|
||||
|
||||
class PostFavoriteService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostFavorite::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = PostFavoriteValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/** 分页列表 */
|
||||
public function serviceSelfList(Request $request, string $scene = 'self')
|
||||
{
|
||||
$result = $this->cqyProcess(ucfirst($scene), $request);
|
||||
if ($result === false) {
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
$limit = (int)$request->get('size', 15);
|
||||
$page = (int)$request->get('current', 1);
|
||||
$result = $this->logicList($config, $limit, $page);
|
||||
}
|
||||
return $this->postProcess(ucfirst($scene), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'self':
|
||||
$config['where']['user_id'] = $request->user->uid;
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['user_id'] = $request->user->uid;;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function afterServiceStore($res)
|
||||
{
|
||||
$data = [];
|
||||
$data['post_id'] = $res['post_id'];
|
||||
$data['receiver_user_id'] = Post::where(['id' => $data['post_id']])->value('user_id');
|
||||
$data['sender_user_id'] = $res['user_id'];
|
||||
$data['type'] = 2;
|
||||
MessageNotice::create($data);
|
||||
$post = Post::where(['id' => $data['post_id']])->first();
|
||||
$post['favorite'] = $post['favorite']+1;
|
||||
$post->save();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function serviceDelete(Request $request)
|
||||
{
|
||||
$param = $request->all();
|
||||
|
||||
if (empty($param['post_id']) && empty($param['user_id'])) {
|
||||
throw new \Exception("参数错误");
|
||||
}
|
||||
|
||||
$where = [];
|
||||
$where['post_id'] = $param['post_id'];
|
||||
$where['user_id'] = $request->user->uid;
|
||||
$count = PostFavorite::where($where)->delete();
|
||||
|
||||
if ($count) {
|
||||
$post = Post::where(['id' => $param['post_id']])->first();
|
||||
$post['favorite'] = $post['favorite']-1;
|
||||
$post['favorite'] = $post['favorite']<0?0:$post['favorite'];
|
||||
$post->save();
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\MessageNotice;
|
||||
use app\common\model\Post;
|
||||
use app\common\model\PostMedia;
|
||||
use app\common\validate\PostLikeValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\PostLike;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class PostLikeService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostLike::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = PostLikeValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/** 分页列表 */
|
||||
public function serviceSelfList(Request $request, string $scene = 'self')
|
||||
{
|
||||
$result = $this->cqyProcess(ucfirst($scene), $request);
|
||||
if ($result === false) {
|
||||
$config = $this->buildQueryConfig($request, $scene);
|
||||
$limit = (int)$request->get('size', 15);
|
||||
$page = (int)$request->get('current', 1);
|
||||
$result = $this->logicList($config, $limit, $page);
|
||||
}
|
||||
return $this->postProcess(ucfirst($scene), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'self':
|
||||
$config['where']['user_id'] = $request->user->uid;
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['user_id'] = $request->user->uid;;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function afterServiceStore($res)
|
||||
{
|
||||
$data = [];
|
||||
$data['post_id'] = $res['post_id'];
|
||||
$data['receiver_user_id'] = Post::where(['id' => $data['post_id']])->value('user_id');
|
||||
$data['sender_user_id'] = $res['user_id'];
|
||||
$data['type'] = 1;
|
||||
MessageNotice::create($data);
|
||||
$post = Post::where(['id' => $data['post_id']])->first();
|
||||
$post['like'] = $post['like']+1;
|
||||
$post->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function serviceDelete(Request $request)
|
||||
{
|
||||
$param = $request->all();
|
||||
|
||||
if (empty($param['post_id']) && empty($param['user_id'])) {
|
||||
throw new \Exception("参数错误");
|
||||
}
|
||||
|
||||
$where = [];
|
||||
$where['post_id'] = $param['post_id'];
|
||||
$where['user_id'] = $request->user->uid;
|
||||
$count = PostLike::where($where)->delete();
|
||||
|
||||
if ($count) {
|
||||
$post = Post::where(['id' => $param['post_id']])->first();
|
||||
$post['like'] = $post['like']-1;
|
||||
$post['like'] = $post['like']<0?0:$post['like'];
|
||||
$post->save();
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\PostMediaValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\PostMedia;
|
||||
|
||||
class PostMediaService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostMedia::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = PostMediaValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\PostMedia;
|
||||
use app\common\model\User;
|
||||
use app\common\validate\PostValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Post;
|
||||
use support\exception\BusinessException;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class PostService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Post::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = PostValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
if (isset($p['category_id']) && $p['category_id']) {
|
||||
$config['where']['category_id'] = $p['category_id'];
|
||||
}
|
||||
if (isset($p['scene']) && $p['scene']=='self') {
|
||||
if(!empty($request->user) && !empty($request->user->uid)){
|
||||
$config['where']['user_id'] = $request->user->uid;
|
||||
}else{
|
||||
$config['where']['user_id'] = -1;
|
||||
}
|
||||
}
|
||||
if(isset($p['year']) && $p['year']){
|
||||
$from = strtotime($p['year'].'-01-01');
|
||||
$to = strtotime($p['year'].'-12-31 23:59:59');
|
||||
$config['where']['created_at'] = [
|
||||
'between', [$from, $to]
|
||||
];
|
||||
}
|
||||
if (isset($p['keyword']) && $p['keyword']) {
|
||||
$config['where']['content'] = ['like', '%'.$p['keyword'].'%'];
|
||||
}
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
|
||||
if (isset($p['favorite']) && $p['favorite']) {
|
||||
$config['order']['favorite'] = 'desc';
|
||||
} elseif (isset($p['browse']) && $p['browse']) {
|
||||
$config['order']['browse'] = 'desc';
|
||||
} else {
|
||||
$config['order']['id'] = 'desc';
|
||||
}
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['user_id'] = $request->user->uid;;
|
||||
// $user = User::where('id', $data['user_id'])->first();
|
||||
// if($user->is_release == 0){
|
||||
// throw new BusinessException('无发布权限');
|
||||
// }
|
||||
$media = serialize($data['media']);
|
||||
redis::set('PostMedia_'.$data['user_id'],$media,30);
|
||||
unset($data['media']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function afterServiceStore($res)
|
||||
{
|
||||
$media = redis::get('PostMedia_'.$res['user_id']);
|
||||
$media = unserialize($media);
|
||||
if(!is_array($media)){
|
||||
$media = explode(',',$media);
|
||||
}
|
||||
foreach ($media as $v) {
|
||||
PostMedia::create([
|
||||
'post_id' => $res->id,
|
||||
'media_type' => $this->getMediaTypeByUrl($v),
|
||||
'url' => $v,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceUpdate($data, Request $request)
|
||||
{
|
||||
$data['user_id'] = $request->user->uid;;
|
||||
$media = serialize($data['media']);
|
||||
redis::set('PostMedia_'.$data['user_id'],$media,30);
|
||||
unset($data['media']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加后置处理
|
||||
*/
|
||||
public function afterServiceUpdate($res)
|
||||
{
|
||||
PostMedia::where('post_id', $res->id)->delete();
|
||||
$media = redis::get('PostMedia_'.$res['user_id']);
|
||||
$media = unserialize($media);
|
||||
foreach ($media as $v) {
|
||||
PostMedia::create([
|
||||
'post_id' => $res->id,
|
||||
'media_type' => $this->getMediaTypeByUrl($v['url']),
|
||||
'url' => $v['url'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加前置处理
|
||||
*/
|
||||
public function beforeServiceShow($data, Request $request)
|
||||
{
|
||||
$post = Post::find($data['id']);
|
||||
if(!$post){
|
||||
$post->browse = $post->browse+1;
|
||||
$post->save();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function getMediaTypeByUrl(string $url): int
|
||||
{
|
||||
// 提取后缀
|
||||
$ext = strtolower(pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION));
|
||||
|
||||
// 图片类型
|
||||
$imageExt = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
|
||||
// 视频类型
|
||||
$videoExt = ['mp4', 'mov', 'avi', 'wmv', 'flv', 'mkv'];
|
||||
|
||||
if (in_array($ext, $imageExt)) {
|
||||
return 1; // 图片
|
||||
}
|
||||
if (in_array($ext, $videoExt)) {
|
||||
return 2; // 视频
|
||||
}
|
||||
|
||||
return 0; // 未知类型
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\ResourceLogic;
|
||||
use app\common\validate\ResourceValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Resource;
|
||||
use app\common\utils\Tree;
|
||||
use support\Request;
|
||||
|
||||
class ResourceService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Resource::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = ResourceValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['where']['system_id'] = ['in', [0, $p['system_id']]];
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'menuList':
|
||||
$config['where']['status'] = 1;
|
||||
$config['where']['type'] = ['!=', 'permission'];
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'menuTreeList':
|
||||
$config['where']['system_id'] = ['in', [0, $p['system_id']]];
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function serviceMenuList(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'menuList');
|
||||
$result = $this->logicListAll($config);
|
||||
return $this->postProcess('MenuList', $result);
|
||||
}
|
||||
|
||||
public function serviceMenuTreeList(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'menuTreeList');
|
||||
$result = (new ResourceLogic())->logicListAllResources($request, $config);
|
||||
return $this->postProcess('MenuTreeList', $result);
|
||||
}
|
||||
|
||||
|
||||
protected function afterServiceDefault($data)
|
||||
{
|
||||
$data = Tree::buildMenuTreeWithReference($data->toArray());
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function afterServiceMenuList($data)
|
||||
{
|
||||
$data = Tree::buildMenuTree($data->toArray());
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function afterServiceMenuTreeList($data)
|
||||
{
|
||||
$data = Tree::buildMenuTree($data->toArray());
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function beforeServiceStore($data, Request $request)
|
||||
{
|
||||
$data['parent_id'] = $data['parent_id'] != '' ? $data['parent_id'] : 0;
|
||||
$data['system_id'] = $data['system_id'] != '' ? $data['system_id'] : 0;
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function beforeServiceUpdate($data, Request $request)
|
||||
{
|
||||
$data['parent_id'] = $data['parent_id'] != '' ? $data['parent_id'] : 0;
|
||||
$data['system_id'] = $data['system_id'] != '' ? $data['system_id'] : 0;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\RoleLogic;
|
||||
use app\common\validate\RoleValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Role;
|
||||
use support\Db;
|
||||
|
||||
class RoleService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Role::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = RoleValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色资源
|
||||
*/
|
||||
public function menuResource($request, $data)
|
||||
{
|
||||
return (new RoleLogic)->updateRoleResources($data);
|
||||
}
|
||||
|
||||
|
||||
public function getList()
|
||||
{
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
return $this->logicListAll($config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\SkuAttributeValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\SkuAttribute;
|
||||
|
||||
class SkuAttributeService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = SkuAttribute::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = SkuAttributeValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\SkuAttributeValueValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\SkuAttributeValue;
|
||||
|
||||
class SkuAttributeValueService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = SkuAttributeValue::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = SkuAttributeValueValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\SkuValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Sku;
|
||||
|
||||
class SkuService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Sku::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = SkuValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\SystemsLogic;
|
||||
|
||||
class SystemsService
|
||||
{
|
||||
|
||||
protected $logic;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new SystemsLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统list
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
|
||||
class UploadService
|
||||
{
|
||||
|
||||
/**
|
||||
* 从服务器本地路径上传文件到 OSS
|
||||
*
|
||||
* @param Request $request
|
||||
* - path: 本地文件绝对路径
|
||||
* - scene: 业务分区/场景
|
||||
* - category: 文件分类(可选)
|
||||
* - original_name: 原始文件名(可选)
|
||||
*/
|
||||
public function uploadLocalFile($param)
|
||||
{
|
||||
try {
|
||||
$filePath = $param['path'];
|
||||
$scene = $param['scene'];
|
||||
$category = $param['category']??'general';
|
||||
$providedOriginalName = $param['original_name']??'';
|
||||
|
||||
if (empty($filePath)) {
|
||||
Log::error('本地文件路径不能为空',$param);
|
||||
throw new BusinessException('本地文件路径不能为空');
|
||||
}
|
||||
|
||||
if (!file_exists($filePath) || !is_readable($filePath)) {
|
||||
Log::error('本地文件不存在或不可读',$param);
|
||||
throw new BusinessException('本地文件不存在或不可读');
|
||||
}
|
||||
if (empty($scene)) {
|
||||
Log::error('上传场景不能为空',$param);
|
||||
throw new BusinessException('上传场景不能为空');
|
||||
}
|
||||
|
||||
$basename = basename($filePath);
|
||||
$originalName = $providedOriginalName ?: $basename;
|
||||
$extensionFromName = pathinfo($originalName, PATHINFO_EXTENSION);
|
||||
$extensionFromPath = pathinfo($basename, PATHINFO_EXTENSION);
|
||||
$extension = $extensionFromName ?: $extensionFromPath;
|
||||
|
||||
$mime = mime_content_type($filePath) ?: 'application/octet-stream';
|
||||
$size = filesize($filePath) ?: 0;
|
||||
|
||||
$sceneUrl = $scene ? ($scene . '/') : '';
|
||||
$dir = 'bsh_sample/' . $sceneUrl . date('Ymd') . '/';
|
||||
// 使用传入的 original_name 命名(缺少扩展名时补上推断的扩展名),并做简单安全处理
|
||||
$safeBaseName = preg_replace('/[\\\\\/]+/', '_', $originalName);
|
||||
if ($extension && strtolower(pathinfo($safeBaseName, PATHINFO_EXTENSION)) !== strtolower($extension)) {
|
||||
// 若提供的名称没有扩展名或扩展名不一致,则以推断扩展名为准
|
||||
$safeBaseName = pathinfo($safeBaseName, PATHINFO_FILENAME) . '.' . $extension;
|
||||
} elseif (!$extension && !pathinfo($safeBaseName, PATHINFO_EXTENSION)) {
|
||||
// 实在没有扩展名信息时,保持原名
|
||||
}
|
||||
|
||||
// 重名检测:同一目录、同名且同类型则在文件名后追加序号
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
$candidateName = $safeBaseName;
|
||||
$nameBody = pathinfo($safeBaseName, PATHINFO_FILENAME);
|
||||
$nameExt = pathinfo($safeBaseName, PATHINFO_EXTENSION);
|
||||
$counter = 1;
|
||||
while (true) {
|
||||
$candidatePath = $dir . $candidateName;
|
||||
$existing = $uploadedFilesService->findFile(['file_path' => $candidatePath]);
|
||||
if (!$existing) {
|
||||
break;
|
||||
}
|
||||
// 若存在同路径同名,且类型也相同,则追加序号
|
||||
if (isset($existing->file_type) && strtolower($existing->file_type) === strtolower($mime)) {
|
||||
$suffix = ' (' . $counter . ')';
|
||||
$candidateName = $nameBody . $suffix . ($nameExt !== '' ? ('.' . $nameExt) : '');
|
||||
$counter++;
|
||||
continue;
|
||||
}
|
||||
// 类型不同则允许同名,结束循环
|
||||
break;
|
||||
}
|
||||
|
||||
$objectKey = $dir . $candidateName;
|
||||
|
||||
$ossService = new OssService();
|
||||
$ossService->uploadImage($filePath, $objectKey);
|
||||
$privateUrl = $ossService->generatePrivateUrl($objectKey);
|
||||
|
||||
// 记录文件信息到数据库
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
$fileInfo = [
|
||||
'file_name' => basename($objectKey),
|
||||
'file_path' => $objectKey,
|
||||
'file_size' => $size,
|
||||
'file_type' => $mime,
|
||||
'original_name' => $originalName,
|
||||
];
|
||||
$recordResult = $uploadedFilesService->recordFileInfo($fileInfo, null, $scene, $category);
|
||||
|
||||
$data = [
|
||||
'original_name' => $originalName,
|
||||
'file_name' => $objectKey,
|
||||
'file_url' => $privateUrl,
|
||||
'file_id' => $recordResult['id'] ?? null,
|
||||
'partition' => $scene,
|
||||
'category' => $category,
|
||||
];
|
||||
|
||||
return $data;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error($e->getMessage(),$param);
|
||||
throw new BusinessException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 OSS 上的文件
|
||||
*
|
||||
* @param array $param
|
||||
* - object_key: OSS 对象键名-oss路径(必需)
|
||||
* - file_id: 数据库文件记录ID(可选,用于删除数据库记录)
|
||||
* @return bool 删除是否成功
|
||||
*
|
||||
* 示例
|
||||
* $uploadService = new UploadService();
|
||||
*
|
||||
* 只删除 OSS 文件
|
||||
* $uploadService->deleteOssFile([
|
||||
* 'object_key' => 'vehicle_album/documents/20241201/abc123.pdf'
|
||||
* ]);
|
||||
*
|
||||
* 同时删除 OSS 文件和数据库记录
|
||||
* $uploadService->deleteOssFile([
|
||||
* 'object_key' => 'vehicle_album/images/20241201/abc123.jpg',
|
||||
* 'file_id' => 123
|
||||
* ]);
|
||||
*/
|
||||
public function deleteOssFile($objectKey,$fileId = null)
|
||||
{
|
||||
try {
|
||||
|
||||
if (empty($objectKey)) {
|
||||
Log::error('OSS对象键名不能为空', $objectKey);
|
||||
throw new BusinessException('OSS对象键名不能为空');
|
||||
}
|
||||
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
// 如果提供了文件ID,同时删除数据库记录
|
||||
if ($fileId) {
|
||||
$uploadedFilesService->deleteFile($fileId);
|
||||
}else{
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
if (empty($fileId)) {
|
||||
$where = ['file_path' => $objectKey];
|
||||
$file = $uploadedFilesService->getFile($where);
|
||||
$fileId = $file->id;
|
||||
}
|
||||
if(!empty($fileId)){
|
||||
$uploadedFilesService->deleteFile($fileId);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除 OSS 上的文件
|
||||
$ossService = new OssService();
|
||||
$ossService->deleteFile($objectKey);
|
||||
|
||||
Log::info('OSS文件删除成功', ['object_key' => $objectKey, 'file_id' => $fileId]);
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('删除OSS文件失败: ' . $e->getMessage());
|
||||
throw new BusinessException('删除OSS文件失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\validate\UploadedFilesValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\UploadedFiles;
|
||||
use support\Request;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class UploadedFilesService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = UploadedFiles::class;
|
||||
|
||||
/**
|
||||
* 文件上传分区配置
|
||||
*/
|
||||
protected array $uploadPartitions = [
|
||||
'image' => [
|
||||
'path' => 'images',
|
||||
'max_size' => 5 * 1024 * 1024, // 5MB
|
||||
'allowed_types' => ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
||||
'extensions' => ['jpg', 'jpeg', 'png', 'gif', 'webp']
|
||||
],
|
||||
'document' => [
|
||||
'path' => 'documents',
|
||||
'max_size' => 10 * 1024 * 1024, // 10MB
|
||||
'allowed_types' => ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
|
||||
'extensions' => ['pdf', 'doc', 'docx']
|
||||
],
|
||||
'audio' => [
|
||||
'path' => 'audios',
|
||||
'max_size' => 20 * 1024 * 1024, // 20MB
|
||||
'allowed_types' => ['audio/mp3', 'audio/wav', 'audio/ogg'],
|
||||
'extensions' => ['mp3', 'wav', 'ogg']
|
||||
],
|
||||
'other' => [
|
||||
'path' => 'others',
|
||||
'max_size' => 5 * 1024 * 1024, // 5MB
|
||||
'allowed_types' => [],
|
||||
'extensions' => []
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* 记录文件信息到数据库
|
||||
*
|
||||
* @param array $fileInfo 文件信息
|
||||
* @param Request|null $request 请求对象(可选)
|
||||
* @param string $partition 分区名称
|
||||
* @param string $category 文件分类
|
||||
* @return array
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function recordFileInfo(array $fileInfo, ?Request $request = null, string $partition = 'other', string $category = 'general'): array
|
||||
{
|
||||
|
||||
// 验证必需的文件信息
|
||||
$requiredFields = ['file_name', 'file_path', 'file_size', 'file_type'];
|
||||
foreach ($requiredFields as $field) {
|
||||
if (!isset($fileInfo[$field])) {
|
||||
throw new BusinessException("缺少必需的文件信息字段: {$field}");
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文件扩展名
|
||||
$fileExtension = pathinfo($fileInfo['file_name'], PATHINFO_EXTENSION);
|
||||
|
||||
// 记录到数据库
|
||||
$uploadIp = $request ? $request->getRealIp() : '0.0.0.0';
|
||||
$userAgent = $request ? $request->header('User-Agent', '') : '';
|
||||
|
||||
$fileData = [
|
||||
'file_name' => $fileInfo['file_name'],
|
||||
'file_path' => $fileInfo['file_path'],
|
||||
'file_size' => $fileInfo['file_size'],
|
||||
'file_type' => $fileInfo['file_type'],
|
||||
'category' => $category,
|
||||
'original_name' => $fileInfo['original_name'] ?? '',
|
||||
'extension' => $fileExtension,
|
||||
'partition' => $partition,
|
||||
'upload_ip' => $uploadIp,
|
||||
'user_agent' => $userAgent,
|
||||
];
|
||||
|
||||
$uploadedFile = $this->logicCreate($fileData);
|
||||
|
||||
return [
|
||||
'id' => $uploadedFile->id,
|
||||
'file_name' => $fileInfo['file_name'],
|
||||
'file_path' => $fileInfo['file_path'],
|
||||
'file_url' => getenv('MAIN_DOMAIN') . $fileInfo['file_path'],
|
||||
'file_size' => $fileInfo['file_size'],
|
||||
'file_type' => $fileInfo['file_type'],
|
||||
'category' => $category,
|
||||
'partition' => $partition,
|
||||
'original_name' => $fileInfo['original_name'] ?? '',
|
||||
'extension' => $fileExtension,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
*
|
||||
* @param int $fileId
|
||||
* @return array|null
|
||||
*/
|
||||
public function getFileInfo(int $fileId): ?array
|
||||
{
|
||||
$file = $this->logicShow(['where' => ['id' => $fileId]]);
|
||||
|
||||
if (!$file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $file->id,
|
||||
'file_name' => $file->file_name,
|
||||
'file_path' => $file->file_path,
|
||||
'file_url' => getenv('MAIN_DOMAIN') . $file->file_path,
|
||||
'file_size' => $file->file_size,
|
||||
'file_type' => $file->file_type,
|
||||
'category' => $file->category,
|
||||
'partition' => $file->partition ?? 'other',
|
||||
'original_name' => $file->original_name ?? '',
|
||||
'extension' => $file->extension ?? '',
|
||||
'created_at' => $file->created_at,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool|\Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
public function getFile(array $where)
|
||||
{
|
||||
$config['model'] = $this->modelClass;
|
||||
$config['where'] = $where;
|
||||
$file = $this->logicShow($config);
|
||||
|
||||
if (!$file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
/**
|
||||
* 获取文件
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool|\Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
public function findFile(array $where)
|
||||
{
|
||||
$file = UploadedFiles::where(['file_path' => $where['file_path']]);
|
||||
|
||||
if (!$file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param int $fileId
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteFile(int $fileId): bool
|
||||
{
|
||||
$config['model'] = $this->modelClass;
|
||||
$config['where'] = ['id' => $fileId];
|
||||
$file = $this->logicShow($config);
|
||||
|
||||
if (!$file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 删除数据库记录
|
||||
$config =[
|
||||
'model' => $this->modelClass,
|
||||
'where' => ['id' => $fileId],
|
||||
];
|
||||
return $this->logicDeleteBy($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分区配置
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPartitionConfig(): array
|
||||
{
|
||||
return $this->uploadPartitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文件名
|
||||
*
|
||||
* @param $file
|
||||
* @return string
|
||||
*/
|
||||
protected function generateFileName($file): string
|
||||
{
|
||||
$extension = $file->getUploadExtension();
|
||||
$timestamp = time();
|
||||
$random = substr(md5(uniqid()), 0, 8);
|
||||
|
||||
return $timestamp . '_' . $random . '.' . $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小
|
||||
*
|
||||
* @param int $bytes
|
||||
* @return string
|
||||
*/
|
||||
protected function formatFileSize(int $bytes): string
|
||||
{
|
||||
$units = ['B', 'KB', 'MB', 'GB'];
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
$bytes /= pow(1024, $pow);
|
||||
|
||||
return round($bytes, 2) . ' ' . $units[$pow];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\logic\AuthLogic;
|
||||
use app\common\validate\UserValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\User;
|
||||
use app\common\logic\UserLogic;
|
||||
use app\common\utils\Jwt;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
class UserService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = User::class;
|
||||
|
||||
|
||||
protected $logic;
|
||||
|
||||
// 字符集配置
|
||||
protected static $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logic = (new UserLogic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = UserValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信二维码
|
||||
*/
|
||||
public function makeQrUrl()
|
||||
{
|
||||
$wechat = new WechatService();
|
||||
return $wechat->makeQrUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
public function userInfo(string $code, string $state)
|
||||
{
|
||||
$logic = new UserLogic();
|
||||
$accessToken = $logic->getAccessToken($code, $state);
|
||||
// $accessToken['openid'] = 'op9DT6xBzVF05dypmQ2JsM5DP6yw';
|
||||
// $accessToken['unionid'] = 'o04nT6-St_2MZR6VRduYEwiicmiA';
|
||||
$userInfo = $logic->checkUser($accessToken['openid'], $accessToken['unionid']);
|
||||
|
||||
if ($userInfo === false) {
|
||||
return [
|
||||
'is_bind' => false,
|
||||
'access_token' => $accessToken['access_token'],
|
||||
'openid' => $accessToken['openid'],
|
||||
'unionid' => $accessToken['unionid'],
|
||||
];
|
||||
}
|
||||
|
||||
$jwt = new Jwt();
|
||||
$token = $jwt->generateToken($logic->buildJwtPayload($userInfo));
|
||||
$refreshToken = (new AuthLogic())->generateRefreshToken($userInfo->id, 'board');
|
||||
return array_merge($userInfo->toArray(), ['access_token' => $token, 'is_bind' => true, 'refresh_token'=> $refreshToken, 'expires_in' => config('jwt.jwt_expiration')]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户信息(包括菜单和权限)
|
||||
*/
|
||||
public function getUserInfo(int $uid)
|
||||
{
|
||||
$user = $this->logic->userInfo($uid);
|
||||
$ossservice = new OssService();
|
||||
$user['avatar_pull'] = $user->avatar;
|
||||
if(strpos($user->avatar, 'http') === false && !empty($user->avatar)){
|
||||
$user['avatar_pull'] = $ossservice->generatePrivateUrl($user->avatar);
|
||||
// $user['avatar_pull'] = '/proxy/ossurl?file='.$user->avatar;
|
||||
}
|
||||
return [
|
||||
'user' => [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'avatar' => $user->avatar,
|
||||
'avatar_pull' => $user['avatar_pull'],
|
||||
'mobile' => $user->mobile,
|
||||
'email' => $user->email,
|
||||
'nickname' => $user->nickname,
|
||||
'status' => $user->status,
|
||||
'openid' => $user->openid,
|
||||
'unionid' => $user->unionid,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定用户
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function bindUser(array $data)
|
||||
{
|
||||
$logic = new UserLogic();
|
||||
$wechat = [
|
||||
'access_token' => $data['access_token'],
|
||||
'openid' => $data['openid'],
|
||||
];
|
||||
$wechatUserInfo = $logic->getWechatUserInfo($wechat);
|
||||
$uData = [
|
||||
'nickname' => $wechatUserInfo['nickname'],
|
||||
'avatar' => $wechatUserInfo['headimgurl'],
|
||||
'unionid' => $wechatUserInfo['unionid'],
|
||||
'openid' => $wechatUserInfo['openid'],
|
||||
'name' => $data['name'],
|
||||
'mobile' => $data['mobile'],
|
||||
'sn' => $data['sn'],
|
||||
'password' => $data['password'],
|
||||
];
|
||||
$userinfo = $logic->bindUser($uData);
|
||||
if ($userinfo === false) {
|
||||
throw new BusinessException('未查到用户信息');
|
||||
}
|
||||
|
||||
$jwt = new Jwt();
|
||||
$refreshToken = (new AuthLogic())->generateRefreshToken($userinfo->id, 'board');
|
||||
return array_merge($userinfo->toArray(), [
|
||||
'access_token' => $jwt->generateToken($logic->buildJwtPayload($userinfo)),
|
||||
'is_bind' => true,
|
||||
'refresh_token'=> $refreshToken,
|
||||
'expires_in' => config('jwt.jwt_expiration')
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
return $this->logic->getList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*/
|
||||
public function savePassword(int $uid, array $data)
|
||||
{
|
||||
// 对密码进行哈希处理
|
||||
$password = $data['password'];
|
||||
$user = User::find($uid);
|
||||
if (!password_verify($password, $user->password)) {
|
||||
throw new BusinessException('密码错误');
|
||||
}
|
||||
|
||||
$user = $this->logic->savePassword($uid,$data);
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*/
|
||||
public function save(int $uid, array $data)
|
||||
{
|
||||
// 对密码进行哈希处理
|
||||
$user = User::find($uid);
|
||||
$keysToKeep = ['name', 'nickname', 'avatar'];
|
||||
|
||||
$data = array_intersect_key($data, array_flip($keysToKeep));
|
||||
|
||||
$user = $user->update($data);
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信小程序用户信息(登录及获取手机号)
|
||||
*/
|
||||
public function wechatLogin(string $loginCode, string $phoneCode)
|
||||
{
|
||||
$logic = new UserLogic();
|
||||
//$accessToken = $logic->getAccessToken($code, $state);
|
||||
|
||||
$session = $logic->miniCode2Session($loginCode);
|
||||
if (!isset($session['openid'])) {
|
||||
throw new BusinessException('登录失败');
|
||||
// return json(['code'=>0, 'msg'=>'登录失败', 'data'=>$session]);
|
||||
}
|
||||
|
||||
$openid = $session['openid'];
|
||||
|
||||
$tokenData = $logic->getMiniAccessToken();
|
||||
$access_token = $tokenData['access_token'];
|
||||
|
||||
// 换手机号
|
||||
$phoneData = $logic->getMiniPhoneNumber($access_token, $phoneCode);
|
||||
|
||||
if (!isset($phoneData['phone_info']['phoneNumber'])) {
|
||||
throw new BusinessException('获取手机号失败');
|
||||
// return json(['code'=>0, 'msg'=>'获取手机号失败', 'data'=>$phoneData]);
|
||||
}
|
||||
|
||||
$phone = $phoneData['phone_info']['phoneNumber'];
|
||||
|
||||
$user = User::firstOrCreate(['phone' => $phone], [
|
||||
'openid' => $openid
|
||||
]);
|
||||
|
||||
// $userInfo = $logic->checkUser($accessToken['openid'], $accessToken['unionid']);
|
||||
//
|
||||
// if ($userInfo === false) {
|
||||
// return [
|
||||
// 'is_bind' => false,
|
||||
// 'access_token' => $accessToken['access_token'],
|
||||
// 'openid' => $accessToken['openid'],
|
||||
// 'unionid' => $accessToken['unionid'],
|
||||
// ];
|
||||
// }
|
||||
|
||||
$jwt = new Jwt();
|
||||
$JwtPayload = $logic->buildJwtPayload($user);
|
||||
$JwtPayload['exp'] = $JwtPayload['exp'] + (86400 * 30);
|
||||
$token = $jwt->generateToken($JwtPayload);
|
||||
$refreshToken = (new AuthLogic())->generateRefreshToken($user->id, 'info');
|
||||
return array_merge($user->toArray(), ['access_token' => $token, 'is_bind' => true, 'refresh_token'=> $refreshToken, 'expires_in' => config('jwt.jwt_expiration')]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 小程序登录
|
||||
*/
|
||||
public function miniappLogin(array $data)
|
||||
{
|
||||
$logic = new UserLogic();
|
||||
$wechatService = new WechatService();
|
||||
$wxinfo = $wechatService->xcxOpenid($data['code']);
|
||||
|
||||
$name = '微信用户_' . self::generate(8);
|
||||
// 用户信息
|
||||
$user = User::firstOrCreate(
|
||||
['openid' => $wxinfo['openid']],
|
||||
[
|
||||
'nickname' => $name,
|
||||
'unionid' => $wxinfo['unionid'],
|
||||
'name' => $name,
|
||||
'avatar' => 'bsh_datax/user/20251021/a4ee815405a1506abeec1af0f738f70f_68f6e76514b66.jpg'
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
$jwt = new Jwt();
|
||||
$JwtPayload = $logic->buildJwtPayload($user);
|
||||
$JwtPayload['exp'] = $JwtPayload['exp'] + (86400 * 30);
|
||||
$token = $jwt->generateToken($JwtPayload);
|
||||
$refreshToken = (new AuthLogic())->generateRefreshToken($user->id, 'info');
|
||||
|
||||
return array_merge($user->toArray(), ['token' => $token, 'is_bind' => true, 'refresh_token'=> $refreshToken, 'expires_in' => config('jwt.jwt_expiration')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取手机号
|
||||
*/
|
||||
public function miniappPhoneNumber(array $data,Request $request)
|
||||
{
|
||||
// 手机号
|
||||
$wechatService = new WechatService();
|
||||
$wxinfo = $wechatService->xcxPhoneNumber($data['phone_code']);
|
||||
|
||||
$uinfo = User::where('id', $request->user->uid)->first();
|
||||
$uinfo->mobile = $wxinfo['phone_info']['phoneNumber'];
|
||||
$uinfo->save();
|
||||
|
||||
return $wxinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机字符串编码
|
||||
*
|
||||
* @param int $length 字符串长度
|
||||
* @param bool $uppercaseOnly 是否只使用大写字母
|
||||
* @return string
|
||||
*/
|
||||
public static function generate(int $length = 8, bool $uppercaseOnly = false): string
|
||||
{
|
||||
$characters = self::$characters;
|
||||
|
||||
if ($uppercaseOnly) {
|
||||
$characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
}
|
||||
|
||||
$charactersLength = strlen($characters);
|
||||
$randomString = '';
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$randomString .= $characters[random_int(0, $charactersLength - 1)];
|
||||
}
|
||||
|
||||
return $randomString;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\User;
|
||||
|
||||
use EasyWeChat\MiniApp\Application as xcxApplication;
|
||||
use EasyWeChat\OpenPlatform\Application;
|
||||
use support\Redis;
|
||||
use GuzzleHttp\Client;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class WechatService
|
||||
{
|
||||
|
||||
protected array $web;
|
||||
protected array $mini;
|
||||
protected array $login;
|
||||
protected $app;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$cfg = config('wechat');
|
||||
$this->web = $cfg['web'];
|
||||
$this->mini = $cfg['mini'];
|
||||
$this->login = $cfg['login'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信二维码
|
||||
*/
|
||||
public function makeQrUrl()
|
||||
{
|
||||
try {
|
||||
$state = bin2hex(random_bytes(16));
|
||||
$ttl = (int)($this->login['state_ttl'] ?? 300);
|
||||
|
||||
// 记录 state
|
||||
Redis::setEx("wx:login:state:$state", $ttl, json_encode([
|
||||
'redirect' => $this->web['redirect'],
|
||||
'ts' => time(),
|
||||
], JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// 组装跳转地址
|
||||
$qrUrl = sprintf(
|
||||
'https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=%s&scope=%s&state=%s#wechat_redirect',
|
||||
$this->web['app_id'],
|
||||
urlencode($this->web['redirect']),
|
||||
'code',
|
||||
'snsapi_login',
|
||||
$state,
|
||||
);
|
||||
|
||||
$data = [
|
||||
'state' => $state,
|
||||
'qr_url' => $qrUrl
|
||||
];
|
||||
return $data;
|
||||
} catch (\Throwable $th) {
|
||||
// var_dump($th->getFile().'|'.$th->getLine().'|'.$th->getMessage());
|
||||
throw new BusinessException('获取微信二维码失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信access_token
|
||||
*/
|
||||
public function wechatWebAccessToken(string $code, string $state): array
|
||||
{
|
||||
try {
|
||||
// 校验 state
|
||||
$stateJson = Redis::get("wx:login:state:$state");
|
||||
if (!$stateJson) {
|
||||
throw new \RuntimeException('state 已过期或无效');
|
||||
}
|
||||
|
||||
// 拼接地址
|
||||
$tokenUrl = sprintf(
|
||||
'https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code',
|
||||
$this->web['app_id'],
|
||||
$this->web['app_secret'],
|
||||
$code
|
||||
);
|
||||
|
||||
// code 换 token
|
||||
$token = $this->httpGetJson($tokenUrl);
|
||||
if (!isset($token['access_token'], $token['openid'])) {
|
||||
throw new \RuntimeException('换取 access_token 失败:'. json_encode($token, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return $token;
|
||||
} catch (\Throwable $th) {
|
||||
throw new BusinessException('获取 access_token 失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信用户信息
|
||||
*
|
||||
* @param array $token
|
||||
* @return array
|
||||
*/
|
||||
public function wechatWebUserInfo(array $accessToken): array
|
||||
{
|
||||
try {
|
||||
// 拉取用户信息
|
||||
return $this->httpGetJson(sprintf(
|
||||
'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s',
|
||||
$accessToken['access_token'],
|
||||
$accessToken['openid']
|
||||
));
|
||||
} catch (\Throwable $th) {
|
||||
// var_dump($th->getFile().'|'.$th->getLine().'|'.$th->getMessage());
|
||||
throw new BusinessException('获取用户信息失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tools - httpGetJson
|
||||
*/
|
||||
protected function httpGetJson(string $url): array
|
||||
{
|
||||
$client = new Client([
|
||||
'verify' => false, // 禁用 SSL 验证
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$json = $client->get($url)->getBody()->getContents();
|
||||
return json_decode($json, true) ?: [];
|
||||
}
|
||||
|
||||
|
||||
//----------------------------小程序登录----------------------------------------
|
||||
|
||||
/**
|
||||
* 获取 openid / session_key
|
||||
* @param $code
|
||||
* @return mixed
|
||||
*/
|
||||
public function miniCode2Session($code)
|
||||
{
|
||||
$appid = $this->mini['app_id'];
|
||||
$secret = $this->mini['app_secret'];
|
||||
$url = "https://api.weixin.qq.com/sns/jscode2session?appid=$appid&secret=$secret&js_code=$code&grant_type=authorization_code";
|
||||
return json_decode(file_get_contents($url), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 access_token
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMiniAccessToken()
|
||||
{
|
||||
$appid = $this->mini['app_id'];
|
||||
$secret = $this->mini['app_secret'];
|
||||
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appid&secret=$secret";
|
||||
return json_decode(file_get_contents($url), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用微信接口取手机号
|
||||
* @param $access_token
|
||||
* @param $phone_code
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMiniPhoneNumber($access_token, $phone_code)
|
||||
{
|
||||
$url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={$access_token}";
|
||||
|
||||
$data = json_encode([
|
||||
'code' => $phone_code
|
||||
]);
|
||||
|
||||
$options = [
|
||||
'http' => [
|
||||
'header' => "Content-type: application/json",
|
||||
'method' => 'POST',
|
||||
'content' => $data,
|
||||
],
|
||||
];
|
||||
|
||||
return json_decode(file_get_contents($url, false, stream_context_create($options)), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序获取openid
|
||||
* @param string $code
|
||||
* @return array
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function xcxOpenid(string $code): array
|
||||
{
|
||||
|
||||
$config = [
|
||||
'app_id' => getenv('WECHAT_MINI_APPID'),
|
||||
'secret' => getenv('WECHAT_MINI_SECRET'),
|
||||
'response_type' => 'array',
|
||||
'log' => [
|
||||
'level' => 'debug',
|
||||
'file' => runtime_path().'/mzl/wechat.log',
|
||||
]
|
||||
];
|
||||
// 创建微信小程序对象
|
||||
$wechat = new xcxApplication($config);
|
||||
// 获取 session_key 和 openid
|
||||
return $wechat->getUtils()->codeToSession($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序获取手机号
|
||||
* @param string $phone_code
|
||||
* @return mixed
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function xcxPhoneNumber(string $phone_code)
|
||||
{
|
||||
$config = [
|
||||
'app_id' => getenv('WECHAT_MINI_APPID'),
|
||||
'secret' => getenv('WECHAT_MINI_SECRET'),
|
||||
'response_type' => 'array',
|
||||
'log' => [
|
||||
'level' => 'debug',
|
||||
'file' => runtime_path().'/mzl/wechat.log',
|
||||
]
|
||||
];
|
||||
// 创建微信小程序对象
|
||||
$wechat = new xcxApplication($config);
|
||||
// getPhoneNumber
|
||||
$data = ['code' => $phone_code];
|
||||
$result = $wechat->getClient()->postJson('wxa/business/getuserphonenumber', $data);
|
||||
if (isset($result['phone_info'])) {
|
||||
// 业务处理 $result['phone_info']['phoneNumber']
|
||||
return $result;
|
||||
} else {
|
||||
throw new BusinessException($result['errmsg']);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user