样机小程序
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
/runtime
|
||||
/.idea
|
||||
/.vscode
|
||||
/vendor
|
||||
*.log
|
||||
.env
|
||||
/tests/tmp
|
||||
/tests/.phpunit.result.cache
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 walkor<walkor@workerman.net> and contributors (see https://github.com/walkor/webman/contributors)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\AgreementService;
|
||||
|
||||
class AgreementController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new AgreementService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\BannerService;
|
||||
|
||||
class BannerController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new BannerService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮播图模块
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getBannerModule()
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->getBannerModule();
|
||||
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
|
||||
? [$this, 'indexFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (isset($data['image_url']) && !empty($data['image_url'])){
|
||||
$ossservice = new OssService();
|
||||
$data['image_url_pull'] = $ossservice->generatePrivateUrl($data['image_url']);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\MessageNoticeService;
|
||||
|
||||
class MessageNoticeController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new MessageNoticeService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostCategoryService;
|
||||
use support\Request;
|
||||
|
||||
class PostCategoryController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostCategoryService();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分类树
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function tree(Request $request)
|
||||
{
|
||||
try {
|
||||
$params = $request->all();
|
||||
$result = $this->service->getList($params);
|
||||
return $this->success($result, '获取分类列表');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
$ossservice = new OssService();
|
||||
if (!empty($data['icon_active'])){
|
||||
$data['icon_active_pull'] = $ossservice->generatePrivateUrl($data['icon_active']);
|
||||
}
|
||||
if (!empty($data['icon_inactive'])){
|
||||
$data['icon_inactive_pull'] = $ossservice->generatePrivateUrl($data['icon_inactive']);
|
||||
}
|
||||
if (!empty($data['icon_preset'])){
|
||||
$data['icon_preset_pull'] = $ossservice->generatePrivateUrl($data['icon_preset']);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\model\PostComment;
|
||||
use app\common\model\User;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostCommentService;
|
||||
|
||||
class PostCommentController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostCommentService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (isset($data['id'])){
|
||||
$data['child'] = [];
|
||||
$child = PostComment::where(['parent_id' => $data['id']])->first();
|
||||
if(!empty($child)){
|
||||
$child = $child->toArray();
|
||||
}
|
||||
$data['count'] = PostComment::where(['parent_id' => $data['id']])->count();
|
||||
if (isset($child['user_id'])){
|
||||
$ossservice = new OssService();
|
||||
$child['user'] = User::where('id', $child['user_id'])->select(['nickname', 'avatar', 'openid'])->first();
|
||||
if(!str_contains($child['user']['avatar'], 'http') && !empty($child['user']['avatar'])){
|
||||
$child['user']['avatar_pull'] = $ossservice->generatePrivateUrl($child['user']['avatar']);
|
||||
}
|
||||
$child['created_at'] = date('Y-m-d H:i:s', strtotime($child['created_at']));
|
||||
$child['updated_at'] = date('Y-m-d H:i:s', strtotime($child['updated_at']));
|
||||
$data['child'][] = $child;
|
||||
}
|
||||
}
|
||||
if (isset($data['user_id'])){
|
||||
$ossservice = new OssService();
|
||||
$data['user'] = User::where('id', $data['user_id'])->select(['nickname', 'avatar', 'openid'])->first();
|
||||
|
||||
if(!str_contains($data['user']['avatar'], 'http') && !empty($data['user']['avatar'])){
|
||||
$data['user']['avatar_pull'] = $ossservice->generatePrivateUrl($data['user']['avatar']);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\model\PostCategory;
|
||||
use app\common\model\PostMedia;
|
||||
use app\common\model\User;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostService;
|
||||
|
||||
class PostController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (isset($data['id']))
|
||||
$data['media'] = PostMedia::where('post_id', $data['id'])->get();
|
||||
if (isset($data['category_id']))
|
||||
$data['category_name'] = PostCategory::where('id', $data['category_id'])->value('name')??'';
|
||||
|
||||
$ossservice = new OssService();
|
||||
if (isset($data['id'])){
|
||||
$data['media'] = PostMedia::where('post_id', $data['id'])->get()->toArray();
|
||||
foreach ($data['media'] as &$media) {
|
||||
$media['url_pull'] = $ossservice->generatePrivateUrl($media['url']);
|
||||
}
|
||||
}
|
||||
if (isset($data['user_id'])){
|
||||
$data['user'] = User::where('id', $data['user_id'])->first();
|
||||
unset($data['user']['password']);
|
||||
$data['user']['avatar_pull'] = $data['user']['avatar'];
|
||||
if(!str_contains($data['user']['avatar'], 'http') && !empty($data['user']['avatar'])){
|
||||
$data['user']['avatar_pull'] = $ossservice->generatePrivateUrl($data['user']['avatar']);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function showFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (isset($data['id']))
|
||||
$data['media'] = PostMedia::where('post_id', $data['id'])->get();
|
||||
if (isset($data['category_id']))
|
||||
$data['category_name'] = PostCategory::where('id', $data['category_id'])->value('name')??'';
|
||||
|
||||
$ossservice = new OssService();
|
||||
if (isset($data['id'])){
|
||||
$data['media'] = PostMedia::where('post_id', $data['id'])->get()->toArray();
|
||||
foreach ($data['media'] as &$media) {
|
||||
$media['url_pull'] = $ossservice->generatePrivateUrl($media['url']);
|
||||
}
|
||||
}
|
||||
if (isset($data['user_id'])){
|
||||
$data['user'] = User::where('id', $data['user_id'])->first();
|
||||
unset($data['user']['password']);
|
||||
$data['user']['avatar_pull'] = $data['user']['avatar'];
|
||||
if(!str_contains($data['user']['avatar'], 'http') && !empty($data['user']['avatar'])){
|
||||
$data['user']['avatar_pull'] = $ossservice->generatePrivateUrl($data['user']['avatar']);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostFavoriteService;
|
||||
|
||||
class PostFavoriteController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostFavoriteService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostLikeService;
|
||||
|
||||
class PostLikeController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostLikeService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostMediaService;
|
||||
|
||||
class PostMediaController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostMediaService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\admin\service\RoleService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use support\Request;
|
||||
|
||||
class RoleController extends BaseController
|
||||
{
|
||||
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new RoleService();
|
||||
}
|
||||
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function menuResource(Request $request)
|
||||
{
|
||||
try {
|
||||
// $data = $this->validate($this->service->getValidator(), $request->post(), 'allocation');
|
||||
$data = $request->post();
|
||||
$res = $this->service->menuResource($request, $data);
|
||||
return $this->success($res);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\SkuAttributeService;
|
||||
|
||||
class SkuAttributeController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new SkuAttributeService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\SkuAttributeValueService;
|
||||
|
||||
class SkuAttributeValueController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new SkuAttributeValueService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\SkuService;
|
||||
|
||||
class SkuController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new SkuService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\admin\service\SystemsService;
|
||||
|
||||
class SystemsController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new SystemsService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\model\Corp;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\admin\service\UserService;
|
||||
use app\crm\model\Customer;
|
||||
use support\Request;
|
||||
|
||||
class UserController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new UserService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回更新成功的数据或信息
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
if(mb_strlen($data['mobile']) < 11){
|
||||
return $this->error('手机号错误');
|
||||
}
|
||||
$res = $this->service->serviceCreateUser($request, $data);
|
||||
return $this->success([], '添加成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回更新成功的数据或信息
|
||||
*/
|
||||
public function update(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
$res = $this->service->serviceUpdateUser($request, $data);
|
||||
return $this->success([], '更新成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \Random\RandomException
|
||||
*/
|
||||
public function savePassword(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
if(empty($data['password'])){
|
||||
return $this->error('密码不能为空');
|
||||
}
|
||||
$result = $this->service->savePassword($request,$data);;
|
||||
return $this->success($result, '编辑成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回更新成功的数据或信息
|
||||
*/
|
||||
public function edit(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
$data['id'] = $data['id']??$request->user->uid;
|
||||
$res = $this->service->serviceUpdate($request, $data);
|
||||
return $this->success([], '更新成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if(isset($data['records'])){
|
||||
return $data;
|
||||
}
|
||||
$data['sex_txt'] = '';
|
||||
if (isset($data['sex']) && $data['sex'] == 1){
|
||||
$data['sex_txt'] = '男';
|
||||
}elseif(isset($data['sex']) && $data['sex'] == 2){
|
||||
$data['sex_txt'] = '女';
|
||||
}
|
||||
|
||||
$ossservice = new OssService();
|
||||
if(isset($data['avatar']) && !empty($data['avatar']) && strpos($data['avatar'], 'http') === false){
|
||||
//$data['avatar_pull'] = $ossservice->generatePrivateUrl($data['avatar']);
|
||||
$data['avatar_pull'] = '/proxy/ossurl?file='.$data['avatar'];
|
||||
}else{
|
||||
$data['avatar_pull'] = $data['avatar'];
|
||||
}
|
||||
|
||||
switch ($data['status']){
|
||||
case 1:
|
||||
$data['status_txt'] = '正常';
|
||||
break;
|
||||
case 2:
|
||||
$data['status_txt'] = '离职';
|
||||
break;
|
||||
default:
|
||||
$data['status_txt'] = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$data['role_ids'] = [];
|
||||
$data['system_ids'] = [];
|
||||
if (isset($data['roles']) && count($data['roles']) > 0) {
|
||||
foreach ($data['roles'] as $role) {
|
||||
$data['role_ids'][] = $role['id'];
|
||||
}
|
||||
}
|
||||
if (isset($data['systems']) && count($data['systems']) > 0) {
|
||||
foreach ($data['systems'] as $system) {
|
||||
$data['system_ids'][] = $system['id'];
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function authorize(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
$res = $this->service->authorize($request, $data);
|
||||
return $this->success([], '分配成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接授权
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateResources(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
$res = $this->service->updateResources($request, $data);
|
||||
return $this->success([], '分配成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function updateSign(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
$this->service->serviceUpdateSign($request, $data);
|
||||
return $this->success([], '签名成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\User;
|
||||
use support\Db;
|
||||
|
||||
class UserLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = User::class;
|
||||
|
||||
|
||||
public function updateRoleAndSystem(array $data): bool
|
||||
{
|
||||
$roleIds = $data['role_ids'] ?? [];
|
||||
$systemIds = $data['system_ids'] ?? [];
|
||||
$userId = $data['user_id'] ?? 0;
|
||||
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
Db::table('user_roles')->where('user_id', $userId)->delete();
|
||||
if (count($roleIds) > 0) {
|
||||
$insertDataRole = [];
|
||||
foreach ($roleIds as $roleId) {
|
||||
$insertDataRole[] = [
|
||||
'role_id' => $roleId,
|
||||
'user_id' => $userId
|
||||
];
|
||||
}
|
||||
$res = Db::table('user_roles')->insert($insertDataRole);
|
||||
var_dump($res);
|
||||
}
|
||||
|
||||
Db::table('user_systems')->where('user_id', $userId)->delete();
|
||||
if (count($systemIds) > 0) {
|
||||
$insertDataSystem = [];
|
||||
foreach ($systemIds as $systemId) {
|
||||
$insertDataSystem[] = [
|
||||
'system_id' => $systemId,
|
||||
'user_id' => $userId
|
||||
];
|
||||
}
|
||||
Db::table('user_systems')->insert($insertDataSystem);
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
return true;
|
||||
} catch (\Throwable $exception) {
|
||||
Db::rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function updateUserResources(array $data): bool
|
||||
{
|
||||
$userId = $data['user_id'] ?? 0;
|
||||
$resources = $data['resources'] ?? [];
|
||||
|
||||
if (empty($userId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
// 删除原有资源关联
|
||||
Db::table('user_resources')->where('user_id', $userId)->delete();
|
||||
|
||||
// 批量插入新角色资源关联
|
||||
if (!empty($resources)) {
|
||||
$insertData = [];
|
||||
foreach ($resources as $resourceId) {
|
||||
$insertData[] = [
|
||||
'user_id' => $userId,
|
||||
'resource_id' => $resourceId
|
||||
];
|
||||
}
|
||||
Db::table('user_resources')->insert($insertData);
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
return true;
|
||||
} catch (\Throwable $exception) {
|
||||
Db::rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\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\admin\service;
|
||||
|
||||
use app\common\validate\SystemsValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Systems;
|
||||
|
||||
class SystemsService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Systems::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = SystemsValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\service;
|
||||
|
||||
use app\admin\logic\UserLogic;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\User;
|
||||
use app\common\validate\UserValidate;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
class UserService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = User::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = UserValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/** 更新 */
|
||||
public function serviceCreateUser(Request $request, array $data = [])
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'create');
|
||||
if(isset($data['avatar']) && empty($data['avatar'])){
|
||||
$data['avatar'] = 'bsh_datax/user/20251021/a4ee815405a1506abeec1af0f738f70f_68f6e76514b66.jpg';
|
||||
}
|
||||
if(empty($data['password'])){
|
||||
$data['password'] = password_hash('12345678', PASSWORD_DEFAULT);
|
||||
}else{
|
||||
$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
}
|
||||
$created = $this->logicCreate($data);
|
||||
return $this->postProcess('Create', $data);
|
||||
}
|
||||
|
||||
/** 更新 */
|
||||
public function serviceUpdateUser(Request $request, array $data = [])
|
||||
{
|
||||
$data = $this->preProcess('Update', $data, $request);
|
||||
$config = $this->buildQueryConfig($request, 'update');
|
||||
$updated = $this->logicUpdateBy($config, $data);
|
||||
return $this->postProcess('Update', $data);
|
||||
}
|
||||
|
||||
/** 更新 */
|
||||
public function serviceUpdate(Request $request, array $data = [])
|
||||
{
|
||||
unset($data['roles']);
|
||||
unset($data['avatar_pull']);
|
||||
$data = $this->preProcess('Update', $data, $request);
|
||||
$config = $this->buildQueryConfig($request, 'edit');
|
||||
$updated = $this->logicUpdateBy($config, $data);
|
||||
return $this->postProcess('Update', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 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['keyword']) && $p['keyword']) {
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
$config['where']['name'] = ['like', $k];
|
||||
}
|
||||
if (isset($p['status']) && $p['status']) {
|
||||
$config['where']['status'] = $p['status'];
|
||||
}
|
||||
if (isset($p['user_id']) && $p['user_id']) {
|
||||
$config['where']['user_id'] = $p['user_id'];
|
||||
}
|
||||
if (isset($p['id']) && $p['id']) {
|
||||
$config['where']['id'] = $p['id'];
|
||||
}
|
||||
if (isset($p['corp_id']) && $p['corp_id']) {
|
||||
$config['where']['corp_id'] = $p['corp_id'];
|
||||
}
|
||||
|
||||
$config['fields'] = ['id','sn', 'name', 'email', 'mobile', 'avatar', 'nickname', 'is_release', 'status', 'created_at'];
|
||||
|
||||
$config['with']['roles'][] = 'id';
|
||||
$config['with']['roles'][] = 'name';
|
||||
$config['with']['systems'][] = 'id';
|
||||
$config['with']['systems'][] = 'name';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'savePassword':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'edit':
|
||||
case 'updateSign':
|
||||
$config['where']['id'] = $request->user->uid;
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(Request $request, array $data = [])
|
||||
{
|
||||
return (new UserLogic())->updateRoleAndSystem($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户资源权限
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function updateResources(Request $request, array $data = [])
|
||||
{
|
||||
return (new UserLogic())->updateUserResources($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*/
|
||||
public function savePassword(Request $request, array $data)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'savePassword');
|
||||
$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
$user = $this->logicUpdateBy($config,$data);
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function serviceUpdateSign(Request $request, array $data)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'updateSign');
|
||||
$user = $this->logicUpdateBy($config,$data);
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\AgreementService;
|
||||
|
||||
class AgreementController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new AgreementService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\service\AuthService;
|
||||
use app\common\validate\UserValidate;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class AuthController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* 不需要头信息的方法
|
||||
*/
|
||||
protected $noNeedHeaderData = ['feishuAuth'];
|
||||
|
||||
protected $noNeedLogin = ['feishuScope', 'login', 'register', 'feishuAuth'];
|
||||
|
||||
|
||||
// 调试
|
||||
public function feishuAuth(Request $request)
|
||||
{
|
||||
try {
|
||||
$code = $request->all();
|
||||
return $this->success($code);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function feishuScope(Request $request)
|
||||
{
|
||||
try {
|
||||
$result = (new AuthService())->feishuAuthorize($request->corp_abbr, $request->system_code);
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $this->validate(new UserValidate(), $this->requestData($request), $request->login_type.'_login');
|
||||
$result = (new AuthService())->login($data);
|
||||
return $this->success($result, '登录成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function register(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $this->validate(new UserValidate(), $this->requestData($request), $request->login_type.'_register');
|
||||
$result = (new AuthService())->register($data);
|
||||
return $this->success($result, '注册成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function refresh(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $this->requestData($request);
|
||||
if (!$data['refresh_token'] || !$data['system_code']) return $this->error('参数缺失', 422);
|
||||
$result = (new AuthService())->refreshToken($data['refresh_token'], $data['system_code']);
|
||||
return $this->success($result, '刷新成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage(), 401);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// public function perm(Request $request)
|
||||
// {
|
||||
// try {
|
||||
// $data = $this->requestData($request);
|
||||
// if (!$data['access_token'] || !$data['system_code']) return $this->error('参数缺失', 422);
|
||||
// $result = (new AuthService())->logout($data['access_token'], $data['system_code']);
|
||||
// return $this->success($result, '已登出');
|
||||
// } catch (\Throwable $e) {}
|
||||
// }
|
||||
|
||||
// public function verify(Request $request)
|
||||
// {
|
||||
// try {
|
||||
// $token = $request->post('access_token') ?: $request->header('authorization');
|
||||
// $systemCode = $request->post('system_code');
|
||||
// if (!$token || !$systemCode) return $this->error('参数缺失', 422);
|
||||
// $payload = (new AuthService())->verifyToken($token, $systemCode);
|
||||
// return $this->success($payload, '验证成功');
|
||||
// } catch (\Throwable $e) {
|
||||
// return $this->error($e->getMessage() ?: '无效或过期的token', 401);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public function logout(Request $request)
|
||||
// {
|
||||
// $token = $request->post('access_token') ?: $request->header('Authorization');
|
||||
// $systemCode = $request->post('system_code') ?: $request->header('system_code');
|
||||
// (new AuthService())->logout($token, $systemCode);
|
||||
// return $this->success([], '已登出');
|
||||
// }
|
||||
|
||||
// public function blockToken(Request $request)
|
||||
// {
|
||||
// $token = $request->post('token');
|
||||
// $systemCode = $request->post('system_code');
|
||||
// if (!$token || !$systemCode) return $this->error('参数缺失', 422);
|
||||
// (new AuthService())->blockToken($token, $systemCode);
|
||||
// return $this->success([], '已强制停用该token');
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\BannerService;
|
||||
use support\Request;
|
||||
|
||||
class BannerController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $noNeedLogin = ['getAll'];
|
||||
|
||||
protected $noNeedHeaderData = ['getAll'];
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new BannerService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮播
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getAll(Request $request)
|
||||
{
|
||||
try {
|
||||
$params = $request->all();
|
||||
$result = $this->service->getBanner($params);
|
||||
foreach ($result as $key => $value) {
|
||||
if (isset($value['image_url']) && !empty($value['image_url'])){
|
||||
$ossservice = new OssService();
|
||||
$result[$key]['image_url_pull'] = $ossservice->generatePrivateUrl($value['image_url']);
|
||||
}
|
||||
}
|
||||
return $this->success($result, '获取轮播列表');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (isset($data['image_url']) && !empty($data['image_url'])){
|
||||
$ossservice = new OssService();
|
||||
$data['image_url_pull'] = $ossservice->generatePrivateUrl($data['image_url']);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\controller;
|
||||
|
||||
use support\exception\BusinessException;
|
||||
use app\common\traits\ResponseTrait;
|
||||
use app\common\traits\DataTransformer;
|
||||
use think\Validate;
|
||||
use support\Request;
|
||||
|
||||
class BaseController
|
||||
{
|
||||
/**
|
||||
* 响应处理、数据格式化处理
|
||||
*/
|
||||
use ResponseTrait, DataTransformer;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
* @var Validate
|
||||
*/
|
||||
protected mixed $validator = null;
|
||||
|
||||
/**
|
||||
* @var Model
|
||||
*/
|
||||
protected $model = null;
|
||||
|
||||
/**
|
||||
* 不登录不鉴权
|
||||
* @var array
|
||||
*/
|
||||
protected $noNeedLogin = [];
|
||||
|
||||
/**
|
||||
* 登录不鉴权
|
||||
* @var array
|
||||
*/
|
||||
protected $noNeedAuth = [];
|
||||
|
||||
/**
|
||||
* 不用头部数据
|
||||
* @var array
|
||||
*/
|
||||
protected $noNeedHeaderData = [];
|
||||
|
||||
/**
|
||||
* 数据限制
|
||||
* null 不做限制,任何管理员都可以查看该表的所有数据
|
||||
* auth 管理员能看到自己以及自己的子管理员插入的数据
|
||||
* personal 管理员只能看到自己插入的数据
|
||||
* @var string
|
||||
*/
|
||||
protected $dataLimit = null;
|
||||
|
||||
/**
|
||||
* 数据限制字段
|
||||
*/
|
||||
protected $dataLimitField = 'admin_id';
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
*
|
||||
* @param Validate $validator 验证器实例
|
||||
* @param array $data 待验证的数据
|
||||
* @param string $scene 验证场景
|
||||
* @return array 验证后的数据
|
||||
* @throws BusinessException 验证失败时抛出业务异常
|
||||
*/
|
||||
public function validate(Validate $validator, array $data, string $scene = ''): array
|
||||
{
|
||||
// 如果指定了验证场景,并且验证器支持场景方法,则设置验证场景
|
||||
if ($scene && method_exists($validator, 'scene')) {
|
||||
$validator->scene($scene);
|
||||
}
|
||||
// 执行数据验证
|
||||
if (!$validator->check($data)) {
|
||||
// 验证失败,抛出业务异常,异常信息为验证器返回的错误信息
|
||||
throw new BusinessException($validator->getError());
|
||||
}
|
||||
// 验证成功,返回原始数据
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数处理
|
||||
*/
|
||||
public function requestData(Request $request)
|
||||
{
|
||||
return $request->all() + $request->basic_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\model\Post;
|
||||
use app\common\model\PostComment;
|
||||
use app\common\model\PostMedia;
|
||||
use app\common\model\User;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\MessageNoticeService;
|
||||
use support\Request;
|
||||
|
||||
class MessageNoticeController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new MessageNoticeService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回分页数据及总数
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceSelfList($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
|
||||
? [$this, 'indexFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (isset($data['post_id'])){
|
||||
$data['post'] = Post::where('id', $data['post_id'])->first();
|
||||
$data['post']['media'] = PostMedia::where('post_id', $data['post_id'])->get();
|
||||
}
|
||||
if (isset($data['sender_user_id'])){
|
||||
$ossservice = new OssService();
|
||||
$data['sender_user'] = User::where('id', $data['sender_user_id'])->select(['nickname', 'avatar', 'openid'])->first();
|
||||
|
||||
if(!str_contains($data['sender_user']['avatar'], 'http') && !empty($data['sender_user']['avatar'])){
|
||||
$data['sender_user']['avatar_pull'] = $ossservice->generatePrivateUrl($data['sender_user']['avatar']);
|
||||
}
|
||||
}
|
||||
if (!empty($data['comment_id'])){
|
||||
$data['comment'] = PostComment::where('id', $data['comment_id'])->first();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostCategoryService;
|
||||
|
||||
class PostCategoryController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostCategoryService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (!empty($data['icon'])){
|
||||
$ossservice = new OssService();
|
||||
$data['icon_pull'] = $ossservice->generatePrivateUrl($data['icon']);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\model\PostComment;
|
||||
use app\common\model\User;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostCommentService;
|
||||
use support\Request;
|
||||
|
||||
class PostCommentController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostCommentService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (isset($data['id'])){
|
||||
$data['child'] = [];
|
||||
$child = PostComment::where(['parent_id' => $data['id']])->first();
|
||||
if(!empty($child)){
|
||||
$child = $child->toArray();
|
||||
}
|
||||
$data['count'] = PostComment::where(['parent_id' => $data['id']])->count();
|
||||
if (isset($child['user_id'])){
|
||||
$ossservice = new OssService();
|
||||
$child['user'] = User::where('id', $child['user_id'])->select(['nickname', 'avatar', 'openid'])->first();
|
||||
if(!str_contains($child['user']['avatar'], 'http') && !empty($child['user']['avatar'])){
|
||||
$child['user']['avatar_pull'] = $ossservice->generatePrivateUrl($child['user']['avatar']);
|
||||
}
|
||||
$child['created_at'] = date('Y-m-d H:i:s', strtotime($child['created_at']));
|
||||
$child['updated_at'] = date('Y-m-d H:i:s', strtotime($child['updated_at']));
|
||||
$data['child'][] = $child;
|
||||
}
|
||||
}
|
||||
if (isset($data['user_id'])){
|
||||
$ossservice = new OssService();
|
||||
$data['user'] = User::where('id', $data['user_id'])->select(['nickname', 'avatar', 'openid'])->first();
|
||||
|
||||
if(!str_contains($data['user']['avatar'], 'http') && !empty($data['user']['avatar'])){
|
||||
$data['user']['avatar_pull'] = $ossservice->generatePrivateUrl($data['user']['avatar']);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回删除操作结果
|
||||
*/
|
||||
public function delete(Request $request)
|
||||
{
|
||||
try {
|
||||
$count = $this->service->serviceDelete($request);
|
||||
return $this->success([], "删除评论成功");
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage().$e->getLine().$e->getFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\model\Post;
|
||||
use app\common\model\PostComment;
|
||||
use app\common\model\PostFavorite;
|
||||
use app\common\model\PostLike;
|
||||
use app\common\model\PostMedia;
|
||||
use app\common\model\User;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostService;
|
||||
use support\Request;
|
||||
|
||||
class PostController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
// protected $noNeedLogin = ['index'];
|
||||
//
|
||||
// protected $noNeedHeaderData = ['index'];
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostService();
|
||||
}
|
||||
/**
|
||||
* 获取列表
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回分页数据及总数
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceList($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
|
||||
? [$this, 'indexFormat']
|
||||
: null);
|
||||
$records = $data['records'];
|
||||
foreach ($records as &$record) {
|
||||
if (!isset($record['id']))
|
||||
break;
|
||||
if(!empty($request->user) && !empty($request->user->uid)){
|
||||
$where = [
|
||||
'post_id' => $record['id'],
|
||||
'user_id' => $request->user->uid
|
||||
];
|
||||
$record['is_like'] = PostLike::where($where)->count();
|
||||
$record['is_favorite'] = PostFavorite::where($where)->count();
|
||||
$record['is_comment'] = PostComment::where($where)->count();
|
||||
}else{
|
||||
$record['is_like'] = 0;
|
||||
$record['is_favorite'] = 0;
|
||||
$record['is_comment'] = 0;
|
||||
}
|
||||
$created_at = strtotime($record['created_at']);
|
||||
$record['year'] = date('Y', $created_at);
|
||||
$record['month'] = date('m', $created_at);
|
||||
$record['day'] = date('d', $created_at);
|
||||
}
|
||||
$data['records'] = $records;
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage().$e->getFile().$e->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
$ossservice = new OssService();
|
||||
if (isset($data['id'])){
|
||||
$data['media'] = PostMedia::where('post_id', $data['id'])->get()->toArray();
|
||||
foreach ($data['media'] as &$media) {
|
||||
$media['url_pull'] = $ossservice->generatePrivateUrl($media['url']);
|
||||
}
|
||||
}
|
||||
if (isset($data['user_id'])){
|
||||
$data['user'] = User::where('id', $data['user_id'])->first();
|
||||
unset($data['user']['password']);
|
||||
$data['user']['avatar_pull'] = $data['user']['avatar'];
|
||||
if(!str_contains($data['user']['avatar'], 'http') && !empty($data['user']['avatar'])){
|
||||
$data['user']['avatar_pull'] = $ossservice->generatePrivateUrl($data['user']['avatar']);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取评论,点赞,收藏数量
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @param int|string $id 资源 ID
|
||||
* @return mixed 返回资源详情数据
|
||||
*/
|
||||
public function interaction(Request $request)
|
||||
{
|
||||
try {
|
||||
$param = $request->all();
|
||||
$data = Post::where('id', $param['id'])->select(['like','favorite','comment'])->first();
|
||||
|
||||
if(!empty($request->user) && !empty($request->user->uid)){
|
||||
$where = [
|
||||
'post_id' => $data['id'],
|
||||
'user_id' => $request->user->uid
|
||||
];
|
||||
$data['is_like'] = PostLike::where($where)->count();
|
||||
$data['is_favorite'] = PostFavorite::where($where)->count();
|
||||
$data['is_comment'] = PostComment::where($where)->count();
|
||||
}else{
|
||||
$data['is_like'] = 0;
|
||||
$data['is_favorite'] = 0;
|
||||
$data['is_comment'] = 0;
|
||||
}
|
||||
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage().$e->getFile().$e->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取详情
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @param int|string $id 资源 ID
|
||||
* @return mixed 返回资源详情数据
|
||||
*/
|
||||
public function show(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceShow($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'showFormat')
|
||||
? [$this, 'showFormat']
|
||||
: null);
|
||||
|
||||
if(!empty($request->user) && !empty($request->user->uid)){
|
||||
$where = [
|
||||
'post_id' => $data['id'],
|
||||
'user_id' => $request->user->uid
|
||||
];
|
||||
$data['is_like'] = PostLike::where($where)->count();
|
||||
$data['is_favorite'] = PostFavorite::where($where)->count();
|
||||
$data['is_comment'] = PostComment::where($where)->count();
|
||||
}else{
|
||||
$data['is_like'] = 0;
|
||||
$data['is_favorite'] = 0;
|
||||
$data['is_comment'] = 0;
|
||||
}
|
||||
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage().$e->getFile().$e->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function showFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
$ossservice = new OssService();
|
||||
if (isset($data['id'])){
|
||||
$data['media'] = PostMedia::where('post_id', $data['id'])->get()->toArray();
|
||||
foreach ($data['media'] as &$media) {
|
||||
$media['url_pull'] = $ossservice->generatePrivateUrl($media['url']);
|
||||
}
|
||||
}
|
||||
if (isset($data['user_id'])){
|
||||
$data['user'] = User::where('id', $data['user_id'])->first();
|
||||
unset($data['user']['password']);
|
||||
$data['user']['avatar_pull'] = $data['user']['avatar'];
|
||||
if(!str_contains($data['user']['avatar'], 'http') && !empty($data['user']['avatar'])){
|
||||
$data['user']['avatar_pull'] = $ossservice->generatePrivateUrl($data['user']['avatar']);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\model\Post;
|
||||
use app\common\model\PostMedia;
|
||||
use app\common\model\User;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostFavoriteService;
|
||||
use support\Request;
|
||||
|
||||
class PostFavoriteController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostFavoriteService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回分页数据及总数
|
||||
*/
|
||||
public function self(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceSelfList($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
|
||||
? [$this, 'indexFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
if (isset($data['post_id'])){
|
||||
$ossservice = new OssService();
|
||||
$post = Post::where('id', $data['post_id'])->first()->toArray();
|
||||
|
||||
if (isset( $post['user_id'])){
|
||||
$user = User::where('id', $post['user_id'])->first();
|
||||
$postUser = [];
|
||||
$postUser['name'] = $user['name'];
|
||||
$postUser['nickname'] = $user['nickname'];
|
||||
$postUser['avatar'] = $user['avatar'];
|
||||
$postUser['avatar_pull'] = $user['avatar'];
|
||||
if(!str_contains($postUser['avatar'], 'http') && !empty($postUser['avatar'])){
|
||||
$postUser['avatar_pull'] = $ossservice->generatePrivateUrl($postUser['avatar']);
|
||||
}
|
||||
$post['user'] = $postUser;
|
||||
}
|
||||
|
||||
$ossservice = new OssService();
|
||||
if (isset($post['id'])){
|
||||
$post['media'] = PostMedia::where('post_id', $post['id'])->get()->toArray();
|
||||
foreach ($post['media'] as &$media) {
|
||||
$media['url_pull'] = $ossservice->generatePrivateUrl($media['url']);
|
||||
}
|
||||
}
|
||||
|
||||
$data['post'] = $post;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回删除操作结果
|
||||
*/
|
||||
public function delete(Request $request)
|
||||
{
|
||||
try {
|
||||
$count = $this->service->serviceDelete($request);
|
||||
return $this->success([], "取消收藏成功");
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostLikeService;
|
||||
use support\Request;
|
||||
|
||||
class PostLikeController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostLikeService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回分页数据及总数
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceSelfList($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
|
||||
? [$this, 'indexFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回删除操作结果
|
||||
*/
|
||||
public function delete(Request $request)
|
||||
{
|
||||
try {
|
||||
$count = $this->service->serviceDelete($request);
|
||||
return $this->success([], "取消点赞成功");
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\PostMediaService;
|
||||
|
||||
class PostMediaController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new PostMediaService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\admin\service\RoleService;
|
||||
use app\common\service\BrandSeriesService;
|
||||
use app\common\service\BrandService;
|
||||
use app\common\service\SysAccountService;
|
||||
use app\common\service\SysCurrencyService;
|
||||
use app\common\service\SysDictItemService;
|
||||
use app\common\service\SysDictService;
|
||||
use app\common\service\SysPortService;
|
||||
use app\common\service\VehColorService;
|
||||
use app\common\service\VehModificationService;
|
||||
use support\Request;
|
||||
use app\common\service\CorpService;
|
||||
use app\common\service\CorpFeishuAppService;
|
||||
use app\common\service\SystemsService;
|
||||
use app\common\service\UserService;
|
||||
use support\Cache;
|
||||
use app\common\service\PermService;
|
||||
use app\common\service\UserGroupService;
|
||||
|
||||
class PresetController extends BaseController
|
||||
{
|
||||
|
||||
protected $noNeedLogin = ['systems'];
|
||||
|
||||
protected $noNeedHeaderData = ['systems'];
|
||||
|
||||
|
||||
public function systems()
|
||||
{
|
||||
try {
|
||||
$result = (new SystemsService())->getList();
|
||||
return $this->success($result, '获取系统列表');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function users()
|
||||
{
|
||||
try {
|
||||
$result = (new UserService())->getList();
|
||||
return $this->success($result, '获取用户列表');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function roles()
|
||||
{
|
||||
try {
|
||||
$result = (new RoleService)->getList();
|
||||
return $this->success($result, '获取角色列表');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function cacheClear()
|
||||
{
|
||||
try {
|
||||
Cache::clear();
|
||||
return $this->success([], '操作成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function menus(Request $request)
|
||||
{
|
||||
try {
|
||||
$uid = $request->user->uid;
|
||||
$systemCode = $request->system_code;
|
||||
$permService = new PermService();
|
||||
$menuTree = $permService->getMenuTree($uid, $systemCode);
|
||||
$permissionCodes = $permService->getPermissionCodes($uid, $systemCode);
|
||||
$result = [
|
||||
'menu' => $menuTree,
|
||||
'permissions' => $permissionCodes
|
||||
];
|
||||
return $this->success($result, '获取菜单权限');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\ResourceService;
|
||||
use support\Request;
|
||||
|
||||
class ResourceController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new ResourceService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function allFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源树形结构
|
||||
*/
|
||||
public function listTree(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceListAll($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'allFormat')
|
||||
? [$this, 'allFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单
|
||||
*/
|
||||
public function menuList(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceMenuList($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'allFormat')
|
||||
? [$this, 'allFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单
|
||||
*/
|
||||
public function menuTreeList(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceMenuTreeList($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'allFormat')
|
||||
? [$this, 'allFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage().$e->getFile().$e->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\SkuAttributeService;
|
||||
|
||||
class SkuAttributeController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new SkuAttributeService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\SkuAttributeValueService;
|
||||
|
||||
class SkuAttributeValueController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new SkuAttributeValueService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\SkuService;
|
||||
|
||||
class SkuController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new SkuService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\service\OssService;
|
||||
use app\common\service\UploadedFilesService;
|
||||
use app\common\service\UploadService;
|
||||
use app\common\traits\ResponseTrait;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
use support\exception\BusinessException;
|
||||
use Shopwwi\WebmanFilesystem\Facade\Storage;
|
||||
|
||||
class UploadController
|
||||
{
|
||||
|
||||
use ResponseTrait;
|
||||
|
||||
protected $noNeedLogin = ['proxy'];
|
||||
|
||||
protected $noNeedHeaderData = ['proxy'];
|
||||
|
||||
public function upload(Request $request)
|
||||
{
|
||||
try {
|
||||
$scene = $request->input('scene', 'image');
|
||||
$file = $request->file('file');
|
||||
if ($file && $file->isValid()) {
|
||||
$fileName = md5($file->getUploadName() . time()).'.'.$file->getUploadExtension();
|
||||
$pathUrl = '/bsh_sample/'.$scene.'/'.date('Ymd').'/'.$fileName;
|
||||
$fullPathUrl = public_path() . $pathUrl;
|
||||
$file->move($fullPathUrl);
|
||||
|
||||
$data = [
|
||||
'domain' => getenv('MAIN_DOMAIN'),
|
||||
'file_url' => $pathUrl,
|
||||
'full_url' => getenv('MAIN_DOMAIN') . $pathUrl,
|
||||
'scene' => $scene,
|
||||
];
|
||||
|
||||
// 记录文件信息到数据库
|
||||
try {
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
$partition = $scene;
|
||||
$category = $request->input('category', 'general');
|
||||
|
||||
$fileInfo = [
|
||||
'file_name' => basename($fileName),
|
||||
'file_path' => $pathUrl,
|
||||
'file_size' => $file->getSize(),
|
||||
'file_type' => $file->getUploadMimeType(),
|
||||
'original_name' => $file->getUploadName(),
|
||||
];
|
||||
|
||||
$recordResult = $uploadedFilesService->recordFileInfo($fileInfo, $request, $partition, $category);
|
||||
$data['file_id'] = $recordResult['id'];
|
||||
$data['partition'] = $partition;
|
||||
$data['category'] = $category;
|
||||
} catch (\Throwable $e) {
|
||||
// 记录失败不影响上传结果,只记录日志
|
||||
Log::error('记录文件信息失败: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->success($data, 'upload success');
|
||||
}
|
||||
return $this->error('file not found');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 上传单文件附件
|
||||
public function uploadFile(Request $request)
|
||||
{
|
||||
try {
|
||||
$scene = $request->input('scene');
|
||||
$file = $request->file('file');
|
||||
|
||||
if (!$file || !$file->isValid()) {
|
||||
return $this->error('上传失败');
|
||||
}
|
||||
if (empty($scene)) {
|
||||
// return $this->error('上传场景不能为空');
|
||||
$sceneUrl = '';
|
||||
}else{
|
||||
$sceneUrl = $scene . '/';
|
||||
}
|
||||
$originalName = $file->getUploadName();
|
||||
|
||||
$result = Storage::adapter('oss')
|
||||
->path('bsh_sample/' . $sceneUrl . date('Ymd'))
|
||||
->size(1024*1024*100)
|
||||
->upload($file);
|
||||
|
||||
$ossservice = new OssService();
|
||||
|
||||
$data = [
|
||||
'original_name' => $originalName,
|
||||
'file_name' => $result->file_name,
|
||||
'file_url' => $ossservice->generatePrivateUrl($result->file_name)
|
||||
];
|
||||
|
||||
// 记录文件信息到数据库
|
||||
$category = $request->input('category', 'general');
|
||||
$res = $this->recordFileInfo($result,$request,$file,$scene,$category);
|
||||
$data = array_merge($data, $res);
|
||||
|
||||
return $this->success($data);
|
||||
}catch (\Throwable $e){
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 上传单文件图片
|
||||
public function uploadImage(Request $request)
|
||||
{
|
||||
try {
|
||||
$scene = $request->input('scene');
|
||||
$file = $request->file('image');
|
||||
|
||||
if (!$file || !$file->isValid()) {
|
||||
return $this->error('上传失败');
|
||||
}
|
||||
if (empty($scene)) {
|
||||
// return $this->error('上传场景不能为空');
|
||||
$sceneUrl = '';
|
||||
}else{
|
||||
$sceneUrl = $scene . '/';
|
||||
}
|
||||
|
||||
$result = Storage::adapter('oss')
|
||||
->path('bsh_sample/' . $sceneUrl . date('Ymd'))
|
||||
->size(1024*1024*100)
|
||||
->extYes(['image/jpeg','image/png'])
|
||||
->extNo(['image/gif'])
|
||||
->upload($file);
|
||||
|
||||
$ossservice = new OssService();
|
||||
|
||||
$data = [
|
||||
'href' => $result->file_name,
|
||||
'alt' => '',
|
||||
'url' => $ossservice->generatePrivateUrl($result->file_name)
|
||||
];
|
||||
|
||||
// 记录文件信息到数据库
|
||||
$category = $request->input('category', 'general');
|
||||
$res = $this->recordFileInfo($result,$request,$file,$scene,$category);
|
||||
$data = array_merge($data, $res);
|
||||
|
||||
return json(['errno' => 0, 'data' => $data]);
|
||||
// return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return json(['errno' => 1, 'message' => $e->getMessage()]);
|
||||
// return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function recordFileInfo($result, $request, $file, $scene, $category)
|
||||
{
|
||||
try {
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
$partition = $scene;
|
||||
|
||||
$fileInfo = [
|
||||
'file_name' => basename($result->file_name),
|
||||
'file_path' => $result->file_name, // OSS存储路径
|
||||
'file_size' => $file->getSize(),
|
||||
'file_type' => $file->getUploadMimeType(),
|
||||
'original_name' => $file->getUploadName(),
|
||||
];
|
||||
|
||||
$partition = !empty($partition)?$partition:'other';
|
||||
$category = !empty($category)?$category:'other';
|
||||
$recordResult = $uploadedFilesService->recordFileInfo($fileInfo, $request, $partition, $category);
|
||||
$data = [];
|
||||
$data['file_id'] = $recordResult['id'];
|
||||
$data['partition'] = $partition;
|
||||
$data['category'] = $category;
|
||||
return $data;
|
||||
} catch (\Throwable $e) {
|
||||
// 记录失败不影响上传结果,只记录日志
|
||||
Log::error('记录文件信息失败: ' . $e->getMessage());
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getFileInfo(Request $request)
|
||||
{
|
||||
try {
|
||||
$fileId = $request->input('id');
|
||||
|
||||
if (!$fileId) {
|
||||
return $this->error('文件ID不能为空');
|
||||
}
|
||||
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
$fileInfo = $uploadedFilesService->getFileInfo($fileId);
|
||||
|
||||
if (!$fileInfo) {
|
||||
return $this->error('文件不存在');
|
||||
}
|
||||
|
||||
return $this->success($fileInfo);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error('获取文件信息失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function deleteFile(Request $request)
|
||||
{
|
||||
try {
|
||||
$fileId = $request->input('id');
|
||||
$path = $request->input('path');
|
||||
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
if(!empty($path) && empty($fileId)){
|
||||
$where = ['file_path' => $path];
|
||||
$file = $uploadedFilesService->getFile($where);
|
||||
$fileId = $file->id;
|
||||
}elseif(empty($path) && !empty($fileId)){
|
||||
$where = ['id' => $fileId];
|
||||
$file = $uploadedFilesService->getFile($where);
|
||||
$path = $file->file_path;
|
||||
}
|
||||
if (!$fileId) {
|
||||
return $this->error('文件ID与路径不能为空');
|
||||
}
|
||||
|
||||
// 删除 OSS 上的文件
|
||||
$ossService = new OssService();
|
||||
$ossService->deleteFile($path);
|
||||
|
||||
$result = $uploadedFilesService->deleteFile($fileId);
|
||||
|
||||
if ($result) {
|
||||
return $this->success([], '文件删除成功');
|
||||
} else {
|
||||
return $this->error('文件删除失败');
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error('文件删除失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分区配置
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getPartitionConfig(Request $request)
|
||||
{
|
||||
try {
|
||||
$uploadedFilesService = new UploadedFilesService();
|
||||
$config = $uploadedFilesService->getPartitionConfig();
|
||||
|
||||
return $this->success($config);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error('获取分区配置失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function proxy(Request $request)
|
||||
{
|
||||
$filePath = $request->get('file'); // 原OSS文件路径
|
||||
try {
|
||||
// 生成签名URL
|
||||
$signedUrl = (new \app\common\service\OssService())->generatePrivateUrl($filePath);
|
||||
|
||||
// 获取图片数据并返回
|
||||
$imageData = file_get_contents($signedUrl);
|
||||
|
||||
// 根据文件类型设置Content-Type
|
||||
$mime = mime_content_type('data://application/octet-stream;base64,'.base64_encode($imageData));
|
||||
|
||||
return response($imageData, 200, [
|
||||
'Content-Type' => $mime,
|
||||
'Cache-Control' => 'public, max-age=600' // 客户端缓存10分钟
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response('Image not found '.$e->getMessage(), 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\service\OssService;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\UserService;
|
||||
use app\common\service\WechatService;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
|
||||
class UserController extends BaseController
|
||||
{
|
||||
protected $noNeedLogin = ['getQrUrl', 'getUserInfo', 'bindUser', 'miniappLogin'];
|
||||
|
||||
protected $noNeedHeaderData = ['getQrUrl', 'getUserInfo', 'bindUser', 'miniappLogin'];
|
||||
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new UserService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信二维码
|
||||
*/
|
||||
public function getQrUrl()
|
||||
{
|
||||
try {
|
||||
$result = $this->service->makeQrUrl();
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
public function getUserInfo(Request $request)
|
||||
{
|
||||
try {
|
||||
$params = $request->all();
|
||||
$result = $this->service->userInfo($params['code'], $params['state']);
|
||||
unset($result['password']);
|
||||
|
||||
if (!isset($result['avatar'])){
|
||||
return $this->success($result);
|
||||
}
|
||||
|
||||
$ossservice = new OssService();
|
||||
$result['avatar_pull'] = $result['avatar'];
|
||||
if(strpos($result['avatar'], 'http') === false && !empty($result['avatar'])){
|
||||
$result['avatar_pull'] = $ossservice->generatePrivateUrl($result['avatar']);
|
||||
}
|
||||
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户信息(登录后调用)
|
||||
*/
|
||||
public function info(Request $request)
|
||||
{
|
||||
try {
|
||||
$uid = $request->user->uid;
|
||||
$result = (new UserService())->getUserInfo($uid);
|
||||
return $this->success($result, '获取用户信息');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定用户
|
||||
*/
|
||||
public function bindUser(Request $request)
|
||||
{
|
||||
try {
|
||||
$params = $request->all();
|
||||
$result = $this->service->bindUser($params);
|
||||
unset($result['password']);
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \Random\RandomException
|
||||
*/
|
||||
public function savePassword(Request $request)
|
||||
{
|
||||
try {
|
||||
$uid = $request->user->uid;
|
||||
$data = $request->all();
|
||||
$result = (new UserService())->savePassword($uid,$data);;
|
||||
return $this->success($result, '编辑成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改名字与头像
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \Random\RandomException
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
try {
|
||||
$uid = $request->user->uid;
|
||||
$data = $request->all();
|
||||
$result = (new UserService())->save($uid,$data);;
|
||||
return $this->success($result, '编辑成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public function wechatLogin($request)
|
||||
{
|
||||
try {
|
||||
$params = $request->all();
|
||||
$result = $this->service->wechatLogin($params['login_code'], $params['phone_code']);
|
||||
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 小程序登录
|
||||
*/
|
||||
public function miniappLogin(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$result = $this->service->miniappLogin($request->all());
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取手机号
|
||||
*/
|
||||
public function miniappPhoneNumber(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$result = $this->service->miniappPhoneNumber($request->all(),$request);
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\Agreement;
|
||||
|
||||
class AgreementLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Agreement::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,572 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\model\Corp;
|
||||
use app\common\model\CorpFeishuApp;
|
||||
use app\common\model\Resource;
|
||||
use app\common\model\UserTokenLog;
|
||||
use app\common\model\Systems;
|
||||
use app\common\model\User;
|
||||
use app\common\model\UserSn;
|
||||
use app\common\utils\Feishu;
|
||||
use app\common\utils\Jwt;
|
||||
use support\Redis;
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
|
||||
class AuthLogic
|
||||
{
|
||||
/**
|
||||
* 账号密码登录
|
||||
*/
|
||||
public function uPwdLogin(array $data): array
|
||||
{
|
||||
$user = $this->validateUser($data['account'], $data['password']);
|
||||
$system = $this->validateSystem($data['system_code']);
|
||||
$this->validateSystemPermission($user, $system);
|
||||
|
||||
return $this->generateTokensAndReturn($user, $system, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 飞书登录
|
||||
* 如果用户不存在则新增用户信息
|
||||
*/
|
||||
public function feishuLogin(array $data): array
|
||||
{
|
||||
$feishuUserInfo = $this->getFeishuUserInfo($data);
|
||||
$user = $this->getOrCreateUser($feishuUserInfo);
|
||||
|
||||
$system = $this->validateSystem($data['system_code']);
|
||||
if ($user->isLogin) {
|
||||
$this->validateSystemPermission($user, $system);
|
||||
}
|
||||
|
||||
return $this->generateTokensAndReturn($user, $system, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
public function register(array $data)
|
||||
{
|
||||
try {
|
||||
// 获取可用用户编号
|
||||
$sn = $this->getAvailableUserSn();
|
||||
$data['sn'] = $sn->user_sn;
|
||||
|
||||
// 对密码进行哈希处理
|
||||
$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
|
||||
// 处理账户
|
||||
$data = $data + normalizeAccount($data['account']);
|
||||
|
||||
// 创建用户记录
|
||||
$user = $this->createUser($data);
|
||||
|
||||
// 更新用户编号的用户 ID
|
||||
$this->updateUserId($user->id, $sn->user_sn);
|
||||
|
||||
$system = $this->validateSystem($data['system_code']);
|
||||
return $this->generateTokensAndReturn($user, $system, $data);
|
||||
} catch (\Throwable $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找或创建飞书用户
|
||||
*/
|
||||
private function getOrCreateUser(array $feishuUserInfo)
|
||||
{
|
||||
try {
|
||||
$phone = $this->sanitizePhone($feishuUserInfo['mobile'] ?? '');
|
||||
$email = $feishuUserInfo['enterprise_email'];
|
||||
// $user = User::where('corp_id', $feishuUserInfo['corp_id'])
|
||||
// ->where(function($query) use ($phone, $email) {
|
||||
// $query->where('phone', $phone)
|
||||
// ->orWhere('email', $email);
|
||||
// })
|
||||
// ->first();
|
||||
$userByPhone = User::where('corp_id', $feishuUserInfo['corp_id'])
|
||||
->where('phone', $phone)
|
||||
->where('phone', '!=', '')
|
||||
->first();
|
||||
$userByEmail = User::where('corp_id', $feishuUserInfo['corp_id'])
|
||||
->where('email', $email)
|
||||
->where('email', '!=', '')
|
||||
->first();
|
||||
$user = $userByPhone ?: $userByEmail;
|
||||
if (!$user) {
|
||||
// 获取编号
|
||||
$userSn = $this->getAvailableUserSn();
|
||||
// 创建用户
|
||||
$user = User::create([
|
||||
'name' => $feishuUserInfo['name'],
|
||||
'avatar' => $feishuUserInfo['avatar_middle'],
|
||||
'phone' => $this->sanitizePhone($feishuUserInfo['mobile'] ?? ''),
|
||||
'email' => $feishuUserInfo['enterprise_email'],
|
||||
'union_id' => $feishuUserInfo['union_id'],
|
||||
'user_id' => $feishuUserInfo['user_id'],
|
||||
'open_id' => $feishuUserInfo['open_id'],
|
||||
'tenant_key' => $feishuUserInfo['tenant_key'],
|
||||
'corp_id' => $feishuUserInfo['corp_id'],
|
||||
'password' => password_hash($userSn->user_sn, PASSWORD_DEFAULT)
|
||||
]);
|
||||
// 更新使用
|
||||
$this->updateUserId($user->id, $userSn->user_sn);
|
||||
// 更新编号
|
||||
if (!$user->update(['sn'=>$userSn->user_sn])) {
|
||||
throw new BusinessException('编号绑定失败');
|
||||
}
|
||||
// 是否登陆
|
||||
$user->isLogin = false;
|
||||
|
||||
$options = [
|
||||
'corp_id' => $user->corp_id,
|
||||
'user_id' => $user->id
|
||||
];
|
||||
\Webman\RedisQueue\Redis::send('perm-agt', $options);
|
||||
} else {
|
||||
$updated = [
|
||||
'union_id' => $feishuUserInfo['union_id'],
|
||||
'user_id' => $feishuUserInfo['user_id'],
|
||||
'open_id' => $feishuUserInfo['open_id'],
|
||||
'tenant_key' => $feishuUserInfo['tenant_key']
|
||||
];
|
||||
if ($phone && $phone == $user->phone) {
|
||||
$updated['phone'] = $phone;
|
||||
}
|
||||
if ($phone && $phone == $user->phone) {
|
||||
$updated['email'] = $email;
|
||||
}
|
||||
// 更新飞书信息
|
||||
$user->update($updated);
|
||||
// 是否登陆
|
||||
$user->isLogin = true;
|
||||
}
|
||||
return $user;
|
||||
} catch (\Throwable $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤和格式化手机号
|
||||
*/
|
||||
private function sanitizePhone($mobile)
|
||||
{
|
||||
return isset($mobile) ? str_replace('+86', '', $mobile) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成并记录token,返回包含token的响应数据
|
||||
*/
|
||||
private function generateTokensAndReturn(User $user, Systems $system, array $data): array
|
||||
{
|
||||
$payload = $this->buildJwtPayload($user, $system);
|
||||
$token = $this->generateAccessToken($payload);
|
||||
$refreshToken = $this->generateRefreshToken($user->id, $data['system_code']);
|
||||
$homeUrl = $this->getHome($system->id);
|
||||
|
||||
// 记录 token 到 Redis 和 MySQL
|
||||
$this->recordUserToken($user->id, $token, $data['system_code']);
|
||||
|
||||
return [
|
||||
'access_token' => $token,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_in' => config('jwt.jwt_expiration'),
|
||||
'system_code' => $data['system_code'],
|
||||
'login_type' => $data['login_type'],
|
||||
'home_url' => $homeUrl,
|
||||
// 'payload' => $payload,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取飞书用户信息
|
||||
*/
|
||||
private function getFeishuUserInfo(array $data)
|
||||
{
|
||||
$certificate = $this->feishuAppInfo($data['corp_abbr'], $data['system_code']);
|
||||
$feishu = new Feishu($certificate['app_id'], $certificate['app_secret'], $certificate['abbr']);
|
||||
$userAccessToken = $feishu->userAccessToken($data['feishu_code'], $certificate['r_url']);
|
||||
$userInfo = $feishu->userInfo($userAccessToken['access_token']);
|
||||
|
||||
if ($userInfo['code'] != 0) {
|
||||
throw new BusinessException('授权失败,请重试');
|
||||
}
|
||||
|
||||
return $userInfo['data'] + $data + $certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户编号
|
||||
*/
|
||||
private function updateUserId($userId, $userSn)
|
||||
{
|
||||
$updated = UserSn::where('user_sn', $userSn)
|
||||
->update(['user_id' => $userId]);
|
||||
|
||||
if ($updated === 0) {
|
||||
throw new BusinessException('用户编号不存在或更新失败');
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录用户token到 Redis 和 MySQL
|
||||
*/
|
||||
protected function recordUserToken(int $userId, string $token, string $systemCode)
|
||||
{
|
||||
$request = request();
|
||||
$ip = $request ? $request->getRealIp() : '';
|
||||
$ua = $request ? $request->header('user-agent', '') : '';
|
||||
$now = time();
|
||||
$expireAt = $now + config('jwt.jwt_expiration');
|
||||
|
||||
// Redis Set 用户token集合
|
||||
Redis::sAdd("user_tokens:{$userId}:{$systemCode}", $token);
|
||||
Redis::expire("user_tokens:{$userId}:{$systemCode}", config('jwt.jwt_expiration'));
|
||||
|
||||
// Redis Hash token元信息
|
||||
$meta = [
|
||||
'system_code' => $systemCode,
|
||||
'login_ip' => $ip,
|
||||
'user_agent' => $ua,
|
||||
'login_time' => $now,
|
||||
'expired_at' => $expireAt,
|
||||
];
|
||||
Redis::hMSet("user_token_meta:{$token}", $meta);
|
||||
Redis::expire("user_token_meta:{$token}", config('jwt.jwt_expiration'));
|
||||
|
||||
// 可选:MySQL 持久化
|
||||
try {
|
||||
UserTokenLog::create([
|
||||
'user_id' => $userId,
|
||||
'token' => $token,
|
||||
'system_code'=> $systemCode,
|
||||
'login_ip' => $ip,
|
||||
'user_agent' => $ua,
|
||||
'login_time' => $now,
|
||||
'expired_at' => $expireAt,
|
||||
'is_valid' => 1,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Token log write failed: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验token有效性
|
||||
*/
|
||||
public function verifyToken(string $token, string $systemCode): array
|
||||
{
|
||||
if (!$systemCode) throw new BusinessException('缺少system_code', 422);
|
||||
|
||||
$payload = (new Jwt())->verifyToken($token);
|
||||
|
||||
// 校验黑名单
|
||||
if (Redis::has("token_blacklist:{$token}")) {
|
||||
throw new BusinessException('token已失效', 403);
|
||||
}
|
||||
|
||||
// 强制校验aud(系统隔离)
|
||||
if ($systemCode && $payload['aud'] != $systemCode && $payload['aud'] != ($payload['system_code'] ?? '')) {
|
||||
throw new BusinessException('token不属于当前系统', 403);
|
||||
}
|
||||
|
||||
return (array)$payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取飞书应用信息
|
||||
*/
|
||||
public function feishuAppInfo(string $corpAbbr, string $systemCode)
|
||||
{
|
||||
$corpInfo = $this->validateCorp($corpAbbr);
|
||||
$systemInfo = $this->validateSystem($systemCode);
|
||||
$fsAppInfo = $this->validateFeishuApp($corpInfo->id, $systemInfo->id);
|
||||
return [
|
||||
'app_id' => $fsAppInfo->app_id,
|
||||
'app_secret' => $fsAppInfo->app_secret,
|
||||
'r_url' => $fsAppInfo->r_url,
|
||||
'scope' => $fsAppInfo->scopes,
|
||||
'state' => $fsAppInfo->state,
|
||||
'abbr' => $corpAbbr,
|
||||
'corp_id' => $corpInfo->id,
|
||||
'system_id' => $systemInfo->id
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户信息
|
||||
*/
|
||||
private function validateUser(string $account, string $password)
|
||||
{
|
||||
// $user = User::byAccount($account)->first();
|
||||
$user = User::byAccount($account)->first();
|
||||
if (!$user || !password_verify($password, $user->password)) {
|
||||
throw new BusinessException('账号或密码错误', 401);
|
||||
}
|
||||
if ($user->status != 1) {
|
||||
throw new BusinessException('账号已禁用', 403);
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证系统信息
|
||||
*/
|
||||
private function validateSystem(string $systemCode)
|
||||
{
|
||||
$system = Systems::where('code', $systemCode)->first();
|
||||
if (!$system) {
|
||||
throw new BusinessException('系统不存在', 403);
|
||||
}
|
||||
return $system;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证公司信息
|
||||
*/
|
||||
private function validateCorp(string $corpAbbr)
|
||||
{
|
||||
$corp = Corp::where('abbr', $corpAbbr)->first();
|
||||
if (!$corp) {
|
||||
throw new BusinessException('公司不存在', 403);
|
||||
}
|
||||
return $corp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证飞书应用信息
|
||||
*/
|
||||
private function validateFeishuApp(int $corpId, int $systemId)
|
||||
{
|
||||
$feishuAppInfo = CorpFeishuApp::where('corp_id', $corpId)->where('system_id', $systemId)->first();
|
||||
if (!$feishuAppInfo) {
|
||||
throw new BusinessException('飞书应用不存在', 403);
|
||||
}
|
||||
return $feishuAppInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户系统权限
|
||||
*/
|
||||
private function validateSystemPermission(User $user, Systems $system)
|
||||
{
|
||||
if ($system->is_role) {
|
||||
$systemIds = $user->systems->pluck('id')->toArray();
|
||||
if (!in_array($system->id, $systemIds)) {
|
||||
throw new BusinessException('无该系统权限', 403);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用的用户编号
|
||||
*
|
||||
* @return \app\common\model\UserSn 用户编号模型实例
|
||||
* @throws BusinessException 当未找到适用编号时抛出
|
||||
*/
|
||||
private function getAvailableUserSn(): \app\common\model\UserSn
|
||||
{
|
||||
$userSnModel = new UserSn();
|
||||
$sn = $userSnModel->where('user_id', '=', 0)->inRandomOrder()->first();
|
||||
if (!$sn) {
|
||||
Log::error('用户注册时未找到适用编号');
|
||||
throw new BusinessException('未找到适用编号');
|
||||
}
|
||||
return $sn;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户记录
|
||||
*
|
||||
* @param array $data 包含用户信息的数组
|
||||
* @return \app\common\model\User 用户模型实例
|
||||
*/
|
||||
private function createUser(array $data): \app\common\model\User
|
||||
{
|
||||
try {
|
||||
return User::create($data);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('用户注册时创建用户记录失败', [
|
||||
'data' => $data,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw new BusinessException('用户注册失败,请稍后重试', 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT payload 构建
|
||||
* 可扩展 payload 字段
|
||||
*/
|
||||
private function buildJwtPayload(User $user, ?Systems $system = null): array
|
||||
{
|
||||
$now = time();
|
||||
$exp = $now + config('jwt.jwt_expiration');
|
||||
$system_ids = $user->systems ? $user->systems->pluck('id')->toArray() : [];
|
||||
$role_ids = $user->roles ? $user->roles->pluck('id')->toArray() : [];
|
||||
|
||||
return [
|
||||
'sub' => 'user_' . $user->id,
|
||||
'aud' => $system->code,
|
||||
'iat' => $now,
|
||||
'nbf' => $now,
|
||||
'exp' => $exp,
|
||||
'typ' => 'access',
|
||||
'uid' => $user->id,
|
||||
'uname' => $user->name,
|
||||
'role_ids' => $role_ids,
|
||||
'system_ids' => $system_ids
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT签发
|
||||
*/
|
||||
private function generateAccessToken(array $payload)
|
||||
{
|
||||
return (new Jwt())->generateToken($payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新令牌生成
|
||||
*/
|
||||
public function generateRefreshToken(int $userId, string $systemCode)
|
||||
{
|
||||
$refreshToken = bin2hex(random_bytes(32));
|
||||
// user_id+system_code只允许一个refresh_token生效
|
||||
Redis::set("refresh_token:{$userId}:{$systemCode}", $refreshToken, config('jwt.jwt_refresh_token_expiration'));
|
||||
// 建立refresh_token到user_id+system_code映射,便于校验
|
||||
Redis::set("refresh_token_map:{$refreshToken}:{$systemCode}", $userId, config('jwt.jwt_refresh_token_expiration'));
|
||||
return $refreshToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 刷新token
|
||||
* @param string $refreshToken
|
||||
* @param string|null $systemCode 可选,指定系统
|
||||
* @return array
|
||||
*/
|
||||
public function refreshToken(string $refreshToken, ?string $systemCode = null): array
|
||||
{
|
||||
if (!$systemCode) throw new BusinessException('缺少system_code', 422);
|
||||
|
||||
// 校验refresh_token
|
||||
$userId = Redis::get("refresh_token_map:{$refreshToken}:{$systemCode}");
|
||||
if (!$userId) {
|
||||
throw new BusinessException('refresh_token无效或已过期', 401);
|
||||
}
|
||||
|
||||
$validToken = Redis::get("refresh_token:{$userId}:{$systemCode}");
|
||||
if ($validToken !== $refreshToken) {
|
||||
throw new BusinessException('refresh_token无效或已过期', 401);
|
||||
}
|
||||
|
||||
$user = User::find($userId);
|
||||
if (!$user || $user->status != 1) {
|
||||
throw new BusinessException('用户无效', 403);
|
||||
}
|
||||
|
||||
$system = $this->validateSystem($systemCode);
|
||||
$this->validateSystemPermission($user, $system);
|
||||
|
||||
$payload = $this->buildJwtPayload($user, $system);
|
||||
$token = $this->generateAccessToken($payload);
|
||||
$refreshToken = $this->generateRefreshToken($user->id, $systemCode);
|
||||
$this->recordUserToken($user->id, $token, $systemCode);
|
||||
|
||||
return [
|
||||
'access_token' => $token,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_in' => config('jwt.jwt_expiration'),
|
||||
// 'payload' => $payload,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出/失效token
|
||||
*/
|
||||
public function logout(?string $token, ?string $systemCode = null)
|
||||
{
|
||||
if ($token) {
|
||||
Redis::set("token_blacklist:{$token}", 1, config('jwt.jwt_expiration'));
|
||||
$payload = null;
|
||||
try { $payload = (new Jwt())->verifyToken($token); } catch (\Throwable $e) {}
|
||||
$userId = $payload['uid'] ?? null;
|
||||
$aud = $payload['aud'] ?? null;
|
||||
$sc = $systemCode ?? $aud;
|
||||
if ($userId && $sc) {
|
||||
Redis::sRem("user_tokens:{$userId}:{$sc}", $token);
|
||||
}
|
||||
Redis::del("user_token_meta:{$token}");
|
||||
UserTokenLog::where('token', $token)->update(['is_valid'=>0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制拉黑token
|
||||
*/
|
||||
public function blockToken(string $token, ?string $systemCode = null)
|
||||
{
|
||||
if (!$token) {
|
||||
throw new BusinessException('token不能为空', 422);
|
||||
}
|
||||
Redis::set("token_blacklist:{$token}", 1, config('jwt.jwt_expiration'));
|
||||
$payload = null;
|
||||
try { $payload = (new Jwt())->verifyToken($token); } catch (\Throwable $e) {}
|
||||
$userId = $payload['uid'] ?? null;
|
||||
$aud = $payload['aud'] ?? null;
|
||||
$sc = $systemCode ?? $aud;
|
||||
if ($userId && $sc) {
|
||||
Redis::sRem("user_tokens:{$userId}:{$sc}", $token);
|
||||
}
|
||||
Redis::del("user_token_meta:{$token}");
|
||||
UserTokenLog::where('token', $token)->update(['is_valid'=>0]);
|
||||
}
|
||||
|
||||
|
||||
public function getHome($systemId)
|
||||
{
|
||||
$info = Resource::where('system_id', $systemId)
|
||||
->where('is_home', 1)
|
||||
->first();
|
||||
|
||||
if (!$info) {
|
||||
return '/dashboard/console';
|
||||
}
|
||||
|
||||
// 递归拼接 URL
|
||||
$url = $this->buildParentUrl($info);
|
||||
|
||||
return $url ?: '/dashboard/console';
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归构建父级 URL
|
||||
* @param Resource $resource
|
||||
* @return string
|
||||
*/
|
||||
protected function buildParentUrl(Resource $resource)
|
||||
{
|
||||
$url = $resource->url ?? '';
|
||||
|
||||
// 如果存在父级,则递归拼接
|
||||
if ($resource->parent_id != 0) {
|
||||
$parent = Resource::find($resource->parent_id);
|
||||
if ($parent) {
|
||||
$parentUrl = $this->buildParentUrl($parent);
|
||||
$url = $parentUrl . ($url ? '/' . ltrim($url, '/') : '');
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\Banner;
|
||||
|
||||
class BannerLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Banner::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\MessageNotice;
|
||||
|
||||
class MessageNoticeLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = MessageNotice::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\model\User;
|
||||
use app\common\model\Resource;
|
||||
use app\common\model\Systems;
|
||||
|
||||
class PermLogic
|
||||
{
|
||||
/**
|
||||
* 获取用户所有资源(合并角色+直接分配),并加入公共菜单,排序按sort字段
|
||||
*/
|
||||
public function getUserResources(int $userId, string $systemCode)
|
||||
{
|
||||
$system = Systems::where('code', $systemCode)->first();
|
||||
|
||||
// 获取用户及其关联角色资源和直接分配的资源
|
||||
$user = User::with(['roles.resources', 'resources'])->find($userId);
|
||||
|
||||
if (!$user) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$all = collect();
|
||||
// 遍历用户的所有角色,合并每个角色所拥有的资源
|
||||
foreach ($user->roles as $role) {
|
||||
$all = $all->merge(
|
||||
// 过滤当前角色的资源列表
|
||||
$role->resources->filter(function ($resource) use($system) {
|
||||
// 资源过滤条件:
|
||||
// 1. !$resource->no_auth:资源需要权限认证(排除公共资源)
|
||||
// 2. 系统匹配条件:
|
||||
// - $system->id == $resource->system_id:资源属于当前系统
|
||||
// - $resource->system_id == 0:资源为全局公共资源(所有系统可用)
|
||||
return !$resource->no_auth && ($system->id == $resource->system_id || $resource->system_id == 0);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// 合并用户直接分配的资源,排除不需要权限认证的资源
|
||||
$all = $all->merge(
|
||||
$user->resources->filter(function ($resource) {
|
||||
// 只保留需要权限认证的资源(或公共资源)
|
||||
return !$resource->no_auth;
|
||||
})
|
||||
);
|
||||
|
||||
// 加入公共菜单,公共菜单不管是否授权,所有人都能访问
|
||||
$publicResources = Resource::where('no_auth', 1)
|
||||
->orderBy('sort', 'asc') // 按 sort 字段升序排序
|
||||
->get();
|
||||
|
||||
// 合并所有公共资源
|
||||
$all = $all->merge($publicResources);
|
||||
|
||||
// 返回唯一的资源列表,并按 id 排序
|
||||
// 使用 sortBy('sort') 来确保最终结果根据 'sort' 字段排序
|
||||
return $all->unique('id')->values()->sortBy('sort');
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建目录/菜单树
|
||||
*
|
||||
* @param \Illuminate\Support\Collection $resources 全部资源集合
|
||||
* @param int $parentId 当前父级资源 ID
|
||||
* @param string $parentPath 父级完整路径(用于递归)
|
||||
* @return array
|
||||
*/
|
||||
public function buildTree($resources, int $parentId = 0, string $parentPath = ''): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($resources as $node) {
|
||||
if ($node->parent_id !== $parentId) continue;
|
||||
|
||||
// 拼接完整路径
|
||||
$currentPath = $parentPath;
|
||||
if ($currentPath && substr($currentPath, -1) === '/') {
|
||||
$currentPath = rtrim($currentPath, '/');
|
||||
}
|
||||
if (!empty($node->url)) {
|
||||
if (!$currentPath) {
|
||||
$currentPath = $node->url;
|
||||
} else {
|
||||
$url = ltrim($node->url, '/');
|
||||
$currentPath = $currentPath . '/' . $url;
|
||||
}
|
||||
}
|
||||
|
||||
// 子节点递归
|
||||
$children = [];
|
||||
if ($node->type === 'directory') {
|
||||
$children = $this->buildTree($resources, $node->id, $currentPath);
|
||||
}
|
||||
|
||||
// 权限
|
||||
$authList = $resources
|
||||
->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id)
|
||||
->map(fn($r) => [
|
||||
'id' => $r->id,
|
||||
'title' => $r->name,
|
||||
'auth_mark' => $r->code,
|
||||
])->values()->all();
|
||||
|
||||
// 判断是否有子级菜单(非权限)
|
||||
$hasChildrenMenu = collect($resources)->where('parent_id', $node->id)
|
||||
->whereIn('type', ['directory', 'menu'])->isNotEmpty();
|
||||
|
||||
$componentValue = $hasChildrenMenu ? '/index/index' : $currentPath;
|
||||
|
||||
$tree[] = [
|
||||
'id' => $node->id,
|
||||
'name' => $node->name,
|
||||
'path' => $node->url,
|
||||
'component' => $componentValue,
|
||||
'meta' => [
|
||||
'title' => $node->name,
|
||||
'icon' => $node->icon,
|
||||
'keepAlive' => $node->keep_alive == 1 ? true : false,
|
||||
'authList' => $authList,
|
||||
'openType' => $node->open_type,
|
||||
'isHide' => $node->is_hide == 0 ? false : true,
|
||||
'isHideTab' => $node->is_hide_tab == 0 ? false : true
|
||||
],
|
||||
'children' => $children,
|
||||
];
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有权限code
|
||||
*/
|
||||
public function getPermissionCodes(int $userId, string $systemCode): array
|
||||
{
|
||||
$resources = $this->getUserResources($userId, $systemCode);
|
||||
return $resources
|
||||
->filter(fn($res) => $res->type === 'permission')
|
||||
->pluck('code')
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\PostCategory;
|
||||
|
||||
class PostCategoryLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostCategory::class;
|
||||
|
||||
public function getList($where)
|
||||
{
|
||||
return PostCategory::where('status', 1)->where($where)->orderBy('sort','desc')->get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\PostComment;
|
||||
|
||||
class PostCommentLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostComment::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\PostFavorite;
|
||||
|
||||
class PostFavoriteLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostFavorite::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\PostLike;
|
||||
|
||||
class PostLikeLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostLike::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\Post;
|
||||
|
||||
class PostLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Post::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\PostMedia;
|
||||
|
||||
class PostMediaLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = PostMedia::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\Resource;
|
||||
use support\Request;
|
||||
|
||||
class ResourceLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Resource::class;
|
||||
|
||||
|
||||
public function logicListAllResources(Request $request, array $config)
|
||||
{
|
||||
$data = $this->logicListAll($config);
|
||||
|
||||
if ($request->get('role_id')) {
|
||||
$selected = (new RoleLogic())->getRoleResources($request->get('role_id'));
|
||||
} else if ($request->get('user_id')) {
|
||||
$selected = (new RoleLogic())->getUserResources($request->get('user_id'));
|
||||
} else {
|
||||
$selected = [];
|
||||
}
|
||||
|
||||
foreach ($data as &$item) {
|
||||
$item['selected'] = in_array($item['id'], $selected) ? true : false;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use support\Db;
|
||||
|
||||
class RoleLogic
|
||||
{
|
||||
|
||||
/**
|
||||
* 更新角色资源权限
|
||||
*
|
||||
* @param array $data 包含 role_id 和 resources 的数据
|
||||
* @return bool 操作是否成功
|
||||
*/
|
||||
public function updateRoleResources(array $data): bool
|
||||
{
|
||||
$roleId = $data['role_id'] ?? 0;
|
||||
$resources = $data['resources'] ?? [];
|
||||
|
||||
if (empty($roleId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Db::beginTransaction();
|
||||
try {
|
||||
// 删除原有角色资源关联
|
||||
Db::table('role_resources')->where('role_id', $roleId)->delete();
|
||||
|
||||
// 批量插入新角色资源关联
|
||||
if (!empty($resources)) {
|
||||
$insertData = [];
|
||||
foreach ($resources as $resourceId) {
|
||||
$insertData[] = [
|
||||
'role_id' => $roleId,
|
||||
'resource_id' => $resourceId
|
||||
];
|
||||
}
|
||||
Db::table('role_resources')->insert($insertData);
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
return true;
|
||||
} catch (\Throwable $exception) {
|
||||
Db::rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色资源
|
||||
*
|
||||
* @param int $roleId 角色ID
|
||||
* @return array 资源ID列表
|
||||
*/
|
||||
public function getRoleResources(int $roleId): array
|
||||
{
|
||||
if (empty($roleId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Db::table('role_resources')
|
||||
->where('role_id', $roleId)
|
||||
->pluck('resource_id')
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户资源
|
||||
*
|
||||
* @param int $userId 用户ID
|
||||
* @return array 资源ID列表
|
||||
*/
|
||||
public function getUserResources(int $userId): array
|
||||
{
|
||||
if (empty($userId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Db::table('user_resources')
|
||||
->where('user_id', $userId)
|
||||
->pluck('resource_id')
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\SkuAttribute;
|
||||
|
||||
class SkuAttributeLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = SkuAttribute::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\SkuAttributeValue;
|
||||
|
||||
class SkuAttributeValueLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = SkuAttributeValue::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\Sku;
|
||||
|
||||
class SkuLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Sku::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\Systems;
|
||||
|
||||
class SystemsLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Systems::class;
|
||||
|
||||
public function getList()
|
||||
{
|
||||
return Systems::where('status', 1)->orderBy('sort', 'asc')->get(['id', 'name', 'code', 'type', 'type']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\UploadedFiles;
|
||||
|
||||
class UploadedFilesLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = UploadedFiles::class;
|
||||
|
||||
/**
|
||||
* 根据分区获取文件列表
|
||||
*
|
||||
* @param string $partition
|
||||
* @param int $limit
|
||||
* @param int $page
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFilesByPartition(string $partition, int $limit = 15, int $page = 1)
|
||||
{
|
||||
$config = [
|
||||
'model' => $this->modelClass,
|
||||
'where' => ['partition' => $partition],
|
||||
'order' => ['created_at' => 'desc', 'id' => 'desc']
|
||||
];
|
||||
|
||||
return $this->logicList($config, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分类获取文件列表
|
||||
*
|
||||
* @param string $category
|
||||
* @param int $limit
|
||||
* @param int $page
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFilesByCategory(string $category, int $limit = 15, int $page = 1)
|
||||
{
|
||||
$config = [
|
||||
'model' => $this->modelClass,
|
||||
'where' => ['category' => $category],
|
||||
'order' => ['created_at' => 'desc', 'id' => 'desc']
|
||||
];
|
||||
|
||||
return $this->logicList($config, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件类型获取文件列表
|
||||
*
|
||||
* @param string $fileType
|
||||
* @param int $limit
|
||||
* @param int $page
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFilesByType(string $fileType, int $limit = 15, int $page = 1)
|
||||
{
|
||||
$config = [
|
||||
'model' => $this->modelClass,
|
||||
'where' => ['file_type' => $fileType],
|
||||
'order' => ['created_at' => 'desc', 'id' => 'desc']
|
||||
];
|
||||
|
||||
return $this->logicList($config, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索文件
|
||||
*
|
||||
* @param string $keyword
|
||||
* @param int $limit
|
||||
* @param int $page
|
||||
* @return mixed
|
||||
*/
|
||||
public function searchFiles(string $keyword, int $limit = 15, int $page = 1)
|
||||
{
|
||||
$config = [
|
||||
'model' => $this->modelClass,
|
||||
'where' => [
|
||||
'or' => [
|
||||
['file_name', 'like', '%' . $keyword . '%'],
|
||||
['original_name', 'like', '%' . $keyword . '%'],
|
||||
['category', 'like', '%' . $keyword . '%']
|
||||
]
|
||||
],
|
||||
'order' => ['created_at' => 'desc', 'id' => 'desc']
|
||||
];
|
||||
|
||||
return $this->logicList($config, $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件统计信息
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFileStatistics(): array
|
||||
{
|
||||
$model = new $this->modelClass();
|
||||
|
||||
$totalFiles = $model->count();
|
||||
$totalSize = $model->sum('file_size');
|
||||
|
||||
$partitionStats = $model->selectRaw('partition, COUNT(*) as count, SUM(file_size) as size')
|
||||
->groupBy('partition')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$categoryStats = $model->selectRaw('category, COUNT(*) as count, SUM(file_size) as size')
|
||||
->groupBy('category')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$typeStats = $model->selectRaw('file_type, COUNT(*) as count, SUM(file_size) as size')
|
||||
->groupBy('file_type')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
return [
|
||||
'total_files' => $totalFiles,
|
||||
'total_size' => $totalSize,
|
||||
'partition_stats' => $partitionStats,
|
||||
'category_stats' => $categoryStats,
|
||||
'type_stats' => $typeStats
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期文件
|
||||
*
|
||||
* @param int $days 保留天数
|
||||
* @return int 清理的文件数量
|
||||
*/
|
||||
public function cleanExpiredFiles(int $days = 30): int
|
||||
{
|
||||
$expiredTime = time() - ($days * 24 * 60 * 60);
|
||||
|
||||
$config = [
|
||||
'model' => $this->modelClass,
|
||||
'where' => [
|
||||
['created_at', '<', $expiredTime]
|
||||
]
|
||||
];
|
||||
|
||||
$files = $this->logicListAll($config);
|
||||
$count = 0;
|
||||
|
||||
foreach ($files as $file) {
|
||||
// 删除物理文件
|
||||
$fullPath = public_path() . $file->file_path;
|
||||
if (file_exists($fullPath)) {
|
||||
unlink($fullPath);
|
||||
}
|
||||
|
||||
// 删除数据库记录
|
||||
$this->logicDeleteBy(['where' => ['id' => $file->id]]);
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\User;
|
||||
use app\common\service\WechatService;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class UserLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = User::class;
|
||||
|
||||
|
||||
/**
|
||||
* 构建 JWT 令牌有效载荷
|
||||
*
|
||||
* @param User $user
|
||||
* @return array
|
||||
*/
|
||||
public function buildJwtPayload(User $user): array
|
||||
{
|
||||
$now = time();
|
||||
return [
|
||||
'sub' => 'user_' . $user->id,
|
||||
'aud' => 'bsh.yw.hnzhwlkj.cn',
|
||||
'iat' => $now,
|
||||
'nbf' => $now,
|
||||
'exp' => $now + config('jwt.jwt_expiration'),
|
||||
'typ' => 'access',
|
||||
'user_id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'meta' => $user->toArray(),
|
||||
'uid' => $user->id,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
public function userInfo(int $uid)
|
||||
{
|
||||
$user = User::find($uid);
|
||||
|
||||
if (!$user) {
|
||||
throw new BusinessException('账户不存在', 404);
|
||||
}
|
||||
|
||||
if ($user->status != 1) {
|
||||
throw new BusinessException('账号已禁用', 403);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测用户是否存在
|
||||
*
|
||||
* @param string $openid
|
||||
* @param string $unionid
|
||||
* @return User|bool
|
||||
*/
|
||||
public function checkUser(string $openid, string $unionid): User|bool
|
||||
{
|
||||
$uinfo = User::where('status', 1)
|
||||
->where('openid', $openid)
|
||||
->where('unionid', $unionid)
|
||||
->first();
|
||||
return $uinfo === null ? false : $uinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定用户
|
||||
*
|
||||
* @param array $data
|
||||
* @return User|bool
|
||||
*/
|
||||
public function bindUser(array $data): User|bool
|
||||
{
|
||||
$uinfo = User::where('status', 1)
|
||||
->where('name', $data['name'])
|
||||
->where('mobile', $data['mobile'])
|
||||
->where('sn', $data['sn'])
|
||||
->first();
|
||||
|
||||
if ($uinfo !== null) {
|
||||
$uinfo->update([
|
||||
'openid' => $data['openid'],
|
||||
'unionid' => $data['unionid'],
|
||||
'nickname' => $data['nickname'],
|
||||
'avatar' => $data['avatar'],
|
||||
'password' => password_hash($data['password'], PASSWORD_DEFAULT)
|
||||
]);
|
||||
return $uinfo;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*
|
||||
* @param array $data
|
||||
* @return User
|
||||
*/
|
||||
public function createUser(array $data): User
|
||||
{
|
||||
return User::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信access_token
|
||||
*
|
||||
* @param string $code
|
||||
* @param string $state
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken(string $code, string $state): array
|
||||
{
|
||||
$wechat = new WechatService();
|
||||
return $wechat->wechatWebAccessToken($code, $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信用户信息
|
||||
*
|
||||
* @param array $token
|
||||
* @return array
|
||||
*/
|
||||
public function getWechatUserInfo(array $token)
|
||||
{
|
||||
$wechat = new WechatService();
|
||||
return $wechat->wechatWebUserInfo($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
public function getList()
|
||||
{
|
||||
$list = User::where('status', 1)->orderBy('id', 'desc')->get();
|
||||
$arr = [];
|
||||
foreach ($list->toArray() as $item) {
|
||||
$arr[] = [
|
||||
'name' => $item['name'],
|
||||
'id' => $item['id'],
|
||||
];
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
public function savePassword(int $uid, array $data)
|
||||
{
|
||||
$password = password_hash($data['password_new'], PASSWORD_DEFAULT);
|
||||
$res = User::where('id',$uid)->update(['password' => $password]);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
//---------------------------------------------小程序------------------------------------------------------------
|
||||
/**
|
||||
* 获取微信小程序access_token
|
||||
*
|
||||
* @param string $code
|
||||
* @param string $state
|
||||
* @return array
|
||||
*/
|
||||
public function getMiniAccessToken(): array
|
||||
{
|
||||
$wechat = new WechatService();
|
||||
return $wechat->getMiniAccessToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 openid / session_key
|
||||
*
|
||||
* @param string $code
|
||||
* @param string $state
|
||||
* @return array
|
||||
*/
|
||||
public function miniCode2Session($loginCode): array
|
||||
{
|
||||
$wechat = new WechatService();
|
||||
return $wechat->miniCode2Session($loginCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 openid / session_key
|
||||
*
|
||||
* @param string $code
|
||||
* @param string $state
|
||||
* @return array
|
||||
*/
|
||||
public function getMiniPhoneNumber($access_token, $phone_code): array
|
||||
{
|
||||
$wechat = new WechatService();
|
||||
return $wechat->getMiniPhoneNumber($access_token, $phone_code);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Agreement extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'agreement';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'title', 'type', 'content', 'sort', 'status', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Banner extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'banner';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class BannerModule extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'banner_module';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class MessageNotice extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'message_notice';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'receiver_user_id', 'sender_user_id', 'post_id', 'comment_id', 'type', 'content', 'is_read', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Post extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'post';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'user_id', 'category_id', 'content', 'location_name', 'latitude', 'longitude', 'status', 'sort', 'like', 'favorite', 'comment', 'browse', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class PostCategory extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'post_category';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'parent_id', 'icon_active', 'icon_inactive', 'icon_preset', 'name', 'level', 'path', 'sort', 'status', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class PostComment extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'post_comment';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'post_id', 'user_id', 'parent_id', 'root_id', 'content', 'status', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class PostFavorite extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'post_favorite';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'post_id', 'user_id', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class PostLike extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'post_like';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'post_id', 'user_id', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class PostMedia extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'post_media';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'post_id', 'media_type', 'url', 'sort', 'updated_at', 'created_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Resource extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'resources';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'system_id', 'name', 'desc', 'type', 'code', 'parent_id', 'url', 'icon', 'open_type', 'is_hide', 'is_hide_tab', 'no_auth', 'is_home', 'instance', 'sort', 'status', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
/**
|
||||
* roles 角色表
|
||||
* @property integer $id 角色ID(主键)
|
||||
* @property string $name 角色名称
|
||||
* @property string $desc 角色描述
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Role extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'roles';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
protected $fillable = [
|
||||
'system_id',
|
||||
'name',
|
||||
'desc',
|
||||
'sort',
|
||||
'status'
|
||||
];
|
||||
|
||||
// 角色下所有用户
|
||||
public function users()
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'user_roles', 'role_id', 'user_id');
|
||||
}
|
||||
|
||||
// 角色拥有的资源(权限点、菜单)
|
||||
public function resources()
|
||||
{
|
||||
return $this->belongsToMany(Resource::class, 'role_resources', 'role_id', 'resource_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Sku extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'sku';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class SkuAttribute extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'sku_attribute_definition';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class SkuAttributeValue extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'sku_attribute_value';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Systems extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'systems';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'code', 'name', 'type', 'desc', 'icon', 'domain_url', 'is_role', 'sort', 'status', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class UploadedFiles extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'uploaded_files';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'file_name',
|
||||
'file_path',
|
||||
'file_size',
|
||||
'file_type',
|
||||
'category',
|
||||
'original_name',
|
||||
'extension',
|
||||
'partition',
|
||||
'upload_ip',
|
||||
'user_agent',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class User extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'user';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'password', 'name', 'email', 'mobile', 'avatar', 'sn', 'status', 'is_release', 'nickname', 'openid', 'unionid', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
// 用户所有角色
|
||||
public function roles()
|
||||
{
|
||||
return $this->belongsToMany(Role::class, 'user_roles', 'user_id', 'role_id');
|
||||
}
|
||||
|
||||
// 用户直接拥有的资源(用于特殊补权)
|
||||
public function resources()
|
||||
{
|
||||
return $this->belongsToMany(Resource::class, 'user_resources', 'user_id', 'resource_id')->orderBy('sort', 'asc');
|
||||
}
|
||||
|
||||
// 用户可访问的系统
|
||||
public function systems()
|
||||
{
|
||||
return $this->belongsToMany(Systems::class, 'user_systems', 'user_id', 'system_id');
|
||||
}
|
||||
|
||||
// 账号查询的作用域
|
||||
public function scopeByAccount($query, $account)
|
||||
{
|
||||
return $query->where('sn', $account)
|
||||
->orWhere('mobile', $account)
|
||||
->orWhere('email', $account);
|
||||
}
|
||||
}
|
||||
@@ -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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace app\common\traits;
|
||||
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* 数据转换器 Trait
|
||||
* 用于将原始数据(如模型、集合、分页等)统一转换为数组格式,
|
||||
* 并支持字段级与结果级的灵活后置加工。
|
||||
*/
|
||||
trait DataTransformer
|
||||
{
|
||||
/**
|
||||
* 核心转换方法
|
||||
*
|
||||
* @param mixed $rawData 原始数据:Model、Collection、Paginator、数组等
|
||||
* @param array $opts 可选配置:
|
||||
* - 'fieldFormatter' => callable 字段名格式化回调,如 fn($f)=>snake_case($f)
|
||||
* - 'postFormatter' => callable 结果级加工回调,接收整个数组并返回
|
||||
*
|
||||
* @return array 转换并加工后的纯 PHP 数组
|
||||
*/
|
||||
protected function transformData(
|
||||
mixed $rawData,
|
||||
?callable $postFormatter = null,
|
||||
?callable $fieldFormatter = null
|
||||
): array {
|
||||
try {
|
||||
$fieldFormatter = $fieldFormatter ?: fn($field) => $field;
|
||||
if ($rawData instanceof LengthAwarePaginator) {
|
||||
$arr = $this->formatPaginated($rawData, $postFormatter, $fieldFormatter);
|
||||
} elseif ($rawData instanceof Model) {
|
||||
$arr = $this->formatModel($rawData, $fieldFormatter);
|
||||
} elseif ($rawData instanceof Collection) {
|
||||
$arr = $this->formatCollection($rawData, $fieldFormatter);
|
||||
} elseif (is_array($rawData)) {
|
||||
$arr = $this->formatArray($rawData, $fieldFormatter);
|
||||
} else {
|
||||
$arr = (array)$rawData;
|
||||
}
|
||||
|
||||
if (is_callable($postFormatter)) {
|
||||
$arr = $postFormatter($arr);
|
||||
}
|
||||
|
||||
return $arr;
|
||||
} catch (\Throwable $e) {
|
||||
return [
|
||||
'error' => true,
|
||||
'message' => $e->getMessage(),
|
||||
// 'message' => $e->getMessage()."\n".$e->getLine()."\n".$e->getFile(),
|
||||
'code' => $e->getCode(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化分页数据:转换每条记录
|
||||
*
|
||||
* @param LengthAwarePaginator $p
|
||||
* @param callable $fmt
|
||||
* @return array{records: array, total: int, current: int, size: int}
|
||||
*/
|
||||
protected function formatPaginated(
|
||||
LengthAwarePaginator $p,
|
||||
?callable $postFormatter,
|
||||
callable $fmt
|
||||
): array {
|
||||
$records = $p->getCollection()
|
||||
->map(fn($item) => $this->transformData($item, $postFormatter, $fmt))
|
||||
->toArray();
|
||||
|
||||
return [
|
||||
'records' => $records,
|
||||
'total' => $p->total(),
|
||||
'current' => $p->currentPage(),
|
||||
'size' => $p->perPage(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化 Eloquent 模型:主表属性 + 关联递归
|
||||
*
|
||||
* @param Model $model
|
||||
* @param callable $fmt
|
||||
* @return array
|
||||
*/
|
||||
protected function formatModel(
|
||||
Model $model,
|
||||
callable $fmt
|
||||
): array {
|
||||
$out = [];
|
||||
// 1) 主表字段
|
||||
foreach ($model->getAttributes() as $key => $value) {
|
||||
$out[$fmt($key)] = $value;
|
||||
}
|
||||
// 2) 关联递归
|
||||
foreach ($model->getRelations() as $rel => $relData) {
|
||||
if ($relData instanceof Model) {
|
||||
$out[$rel] = $this->formatModel($relData, $fmt);
|
||||
} elseif ($relData instanceof Collection) {
|
||||
$out[$rel] = $relData
|
||||
->map(fn($item) => $this->transformData($item, null, $fmt))
|
||||
->toArray();
|
||||
} else {
|
||||
$out[$rel] = $relData;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化集合数据:对每个元素递归调用 transformData
|
||||
*
|
||||
* @param Collection $c
|
||||
* @param callable $fmt
|
||||
* @return array
|
||||
*/
|
||||
protected function formatCollection(
|
||||
Collection $c,
|
||||
callable $fmt
|
||||
): array {
|
||||
return $c
|
||||
->map(fn($item) => $this->transformData($item, null, $fmt))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化普通数组:递归处理可能出现的模型或集合
|
||||
*
|
||||
* @param array $arr
|
||||
* @param callable $fmt
|
||||
* @return array
|
||||
*/
|
||||
protected function formatArray(
|
||||
array $arr,
|
||||
callable $fmt
|
||||
): array {
|
||||
return array_map(function($item) use ($fmt) {
|
||||
if (is_array($item)
|
||||
|| $item instanceof Model
|
||||
|| $item instanceof Collection
|
||||
|| $item instanceof LengthAwarePaginator
|
||||
) {
|
||||
return $this->transformData($item, null, $fmt);
|
||||
}
|
||||
return $item;
|
||||
}, $arr);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user