Initial commit

This commit is contained in:
php_Team 2023-04-16 23:05:17 +08:00
commit dd44cab777
224 changed files with 90196 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
/.idea
/.vscode
/vendor
/public/uploads/**
*.log
.env
*.http
runtime/*

42
.travis.yml Normal file
View File

@ -0,0 +1,42 @@
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true

32
LICENSE.txt Normal file
View File

@ -0,0 +1,32 @@
ThinkPHP遵循Apache2开源协议发布并提供免费使用。
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
Apache Licence是著名的非盈利开源组织Apache采用的协议。
该协议和BSD类似鼓励代码共享和尊重原作者的著作权
允许代码修改,再作为开源或商业软件发布。需要满足
的条件:
1 需要给代码的用户一份Apache Licence
2 如果你修改了代码,需要在被修改的文件中说明;
3 在延伸的代码中(修改和有源代码衍生的代码中)需要
带有原来代码中的协议,商标,专利声明和其他原来作者规
定需要包含的说明;
4 如果再发布的产品中包含一个Notice文件则在Notice文
件中需要带有本协议内容。你可以在Notice中增加自己的
许可但不可以表现为对Apache Licence构成更改。
具体的协议参考http://www.apache.org/licenses/LICENSE-2.0
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

56
README.md Normal file
View File

@ -0,0 +1,56 @@
ThinkPHP 6.0
===============
> 运行环境要求PHP7.1+兼容PHP8.0。
[官方应用服务市场](https://market.topthink.com) | [`ThinkAPI`——官方统一API服务](https://docs.topthink.com/think-api)
ThinkPHPV6.0版本由[亿速云](https://www.yisu.com/)独家赞助发布。
## 主要新特性
* 采用`PHP7`强类型(严格模式)
* 支持更多的`PSR`规范
* 原生多应用支持
* 更强大和易用的查询
* 全新的事件系统
* 模型事件和数据库事件统一纳入事件系统
* 模板引擎分离出核心
* 内部功能中间件化
* SESSION/Cookie机制改进
* 对Swoole以及协程支持改进
* 对IDE更加友好
* 统一和精简大量用法
## 安装
~~~
composer create-project topthink/think tp 6.0.*
~~~
如果需要更新框架使用
~~~
composer update topthink/framework
~~~
## 文档
[完全开发手册](https://www.kancloud.cn/manual/thinkphp6_0/content)
## 参与开发
请参阅 [ThinkPHP 核心框架包](https://github.com/top-think/framework)。
## 版权信息
ThinkPHP遵循Apache2开源协议发布并提供免费使用。
本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2006-2020 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
更多细节参阅 [LICENSE.txt](LICENSE.txt)

1
app/.htaccess Normal file
View File

@ -0,0 +1 @@
deny from all

22
app/AppService.php Normal file
View File

@ -0,0 +1,22 @@
<?php
declare (strict_types = 1);
namespace app;
use think\Service;
/**
* 应用服务类
*/
class AppService extends Service
{
public function register()
{
// 服务注册
}
public function boot()
{
// 服务启动
}
}

138
app/BaseController.php Normal file
View File

@ -0,0 +1,138 @@
<?php
declare(strict_types=1);
namespace app;
use think\App;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Request;
use think\Validate;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = true)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
/**
* 开启事务
*
* @param callable $cb
* @param array $args
* @return mixed
* @date 2022-07-22
* @example
* @author admin
* @since 1.0.0
*/
protected static function transaction(callable $cb, array $args = [])
{
Db::startTrans();
try {
$result = invoke($cb, $args);
Db::commit();
return $result;
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 分页包装器
*
* @param $query
* @date 2022-03-03
* @example
* @author admin
* @since 1.0.0
*/
protected static function pageWrapper($query)
{
return (clone $query)->page(
(int) Request::param('page', 1),
(int) Request::param('limit', 10)
);
}
}

16
app/BaseModel.php Normal file
View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace app;
use app\common\traits\Model as TraitsModel;
use think\Model;
/**
* 模型层基础类
*/
abstract class BaseModel extends Model
{
use TraitsModel;
}

16
app/BasePivot.php Normal file
View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace app;
use app\common\traits\Model as TraitsModel;
use think\model\Pivot;
/**
* 模型层基础类
*/
abstract class BasePivot extends Pivot
{
use TraitsModel;
}

133
app/ExceptionHandle.php Normal file
View File

@ -0,0 +1,133 @@
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
use app\common\exception\LoginTimeOut;
use app\common\exception\NotAuthApi;
use think\facade\Env;
use app\common\arw\adjfut\src\Exception\ErrorMsg as ExceptionErrorMsg;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
LoginTimeOut::class,
NotAuthApi::class,
ErrorMsg::class,
ExceptionErrorMsg::class
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \app\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
// 未授权接口
if ($e instanceof NotAuthApi) {
return $this->respone([
'code' => 40050,
'msg' => $e->getMessage(),
]);
}
// 登录超时
if ($e instanceof LoginTimeOut) {
return $this->respone([
'code' => 40026,
'msg' => $request->isDev() ? $e->getMessage() : '登录超时',
]);
}
// 参数验证不通过
if ($e instanceof ValidateException) {
return $this->respone([
'code' => 40030,
'msg' => $e->getMessage()
]);
}
// 业务异常
if ($e instanceof ErrorMsg || $e instanceof ExceptionErrorMsg) {
$code = $e->getCode();
return $this->respone([
'code' => $code == 0 ? 40052 : $code,
'msg' => $e->getMessage(),
], $e);
}
// 服务器异常
// if ($e instanceof Exception) {
// return $this->respone([
// 'code' => 40051,
// 'msg' => '服务器异常',
// ], $e);
// }
// 其他错误交给系统处理
return parent::render($request, $e);
}
/**
* 返回
*
* @param array $data
* @param Throwable $e
* @return Response
* @date 2022-04-15
* @example
* @author admin
* @since 1.0.0
*/
private function respone(array $data, $e = null): Response
{
$request = $this->app->request;
if ($e && Env::get('app_show_error')) {
$data['__error'] = [
'File' => $e->getFile(),
'Line' => $e->getLine(),
'Message' => $e->getMessage(),
'Trace' => $e->getTrace()
];
$data['__param'] = $request->param();
}
if ($request->isAjax()) {
return Response::create($data, 'json');
} else {
return Response::create(json_encode($data), 'html');
}
}
}

80
app/Request.php Normal file
View File

@ -0,0 +1,80 @@
<?php
namespace app;
use app\common\model\Token;
use app\common\model\User\User;
use think\facade\Env;
// 应用请求对象类
class Request extends \think\Request
{
/**
* 获取当前用户
*
* @return User
* @date 2023-01-03
* @example
* @author admin
* @since 1.0.0
*/
public static function getCurrentUser(): User
{
return Token::getCurrentUser();
}
/**
* 获取当前token
*
* @return Token
* @date 2023-01-03
* @example
* @author admin
* @since 1.0.0
*/
public static function getCurrentToken(): Token
{
return Token::getCurrent();
}
/**
* 是否登陆
*
* @return boolean
* @date 2022-12-30
* @example
* @author admin
* @since 1.0.0
*/
public static function isLogin(): bool
{
return Token::isLogin();
}
/**
* 是否开发模式
*
* @date 2022-04-07
* @example
* @author admin
* @since 1.0.0
*/
public static function isDev(): bool
{
return !self::isProd();
}
/**
* 是否生产环境
*
* @date 2022-04-07
* @example
* @author admin
* @since 1.0.0
*/
public static function isProd(): bool
{
return Env::get('app_mode') === 'production';
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace app\admin\controller;
use app\model\Banner as ModelBanner;
use app\BaseController;
use app\Request;
use app\exception\ErrorMsg;
use think\facade\Validate;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use think\facade\Db;
use think\facade\Env;
class Common extends BaseController
{
/**
* 上传图片
*/
public function uploadImg(Request $request)
{
$dirName = $request->param('dirName');
$upload = new UploadFile('uploads', 'file');
$path = $upload->putFile($dirName . 'Img');
return [
'code' => 0,
'data' => [
"name" => $path,
"url" => "/uploads/" . $path,
],
'msg' => '上传成功!'
];
}
/**
* 上传文件
*/
public function uploadFile(Request $request)
{
$dirName = $request->param('dirName');
$upload = new UploadFile('uploads', 'file');
$path = $upload->putFile($dirName . 'File');
return [
'code' => 0,
'data' => [
"name" => $path,
"url" => "/uploads/" . $path,
],
'msg' => '上传成功!'
];
}
}

View File

@ -0,0 +1,234 @@
<?php
namespace app\admin\controller\Dictionary;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use app\common\arw\adjfut\src\Traverse;
use app\BaseController;
use app\exception\ErrorMsg;
use app\common\model\Dictionary\Dictionary as ModelDictionary;
use app\Request;
class Dictionary extends BaseController
{
/**
* 获取字典列表
*
* @param Request $request
* @date 2022-03-14
* @example
* @author admin
* @since 1.0.0
*/
public function getDictionaryList(Request $request): array
{
$select = ModelDictionary::where('dictionary_parent_guid', 0)->order([
'dictionary_index',
'dictionary_order' => 'desc',
])->select();
return [
'code' => 0,
'msg' => 'ok',
'data' => $select
];
}
/**
* 获取菜单树
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function getDictionaryTree(Request $request)
{
$dictionary = ModelDictionary::withoutGlobalScope(['status'])->order([
'dictionary_index',
'dictionary_order' => 'desc',
])->field([
'dictionary_parent_guid',
'dictionary_name',
'dictionary_index',
'dictionary_value',
'dictionary_order',
'dictionary_status',
'dictionary_allow_update',
'dictionary_list_class',
'dictionary_guid',
])->select()->toArray();
array_unshift($dictionary, [
'dictionary_guid' => '0',
'dictionary_parent_guid' => '-1',
'dictionary_name' => '系统字典',
'dictionary_index' => 0,
'dictionary_value' => '',
'dictionary_order' => 0,
'dictionary_status' => 0,
'dictionary_allow_update' => 2,
'dictionary_list_class' => '',
]);
$Traverse = new Traverse('dictionary_guid', 'dictionary_parent_guid');
$dictionaryTree = $Traverse->tree($dictionary, '-1', function ($v) {
return [
'label' => $v['dictionary_name'],
'id' => $v['dictionary_guid'],
'parent_id' => $v['dictionary_parent_guid'],
'index' => $v['dictionary_index'],
'order' => $v['dictionary_order'],
'status' => $v['dictionary_status'],
'allow' => $v['dictionary_allow_update'],
'value' => $v['dictionary_value'],
'list_class' => $v['dictionary_list_class']
];
});
return [
'code' => 0,
'msg' => 'ok',
'data' => $dictionaryTree
];
}
/**
* 添加字典
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function addDictionary(Request $request)
{
$params = $request->param();
$this->validate($params, [
'dictionary_name' => 'require',
'dictionary_index' => 'require',
'dictionary_order' => 'require',
'dictionary_parent_guid' => 'require',
]);
if (isset($params['dictionary_guid'])) {
unset($params['dictionary_guid']);
}
ModelDictionary::create($params);
return [
'code' => 0,
'msg' => '添加成功'
];
}
/**
* 更新部门
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function updateDictionary(Request $request)
{
$params = $request->param();
$this->validate($params, [
'dictionary_guid' => 'require'
]);
ModelDictionary::withoutGlobalScope(['status'])->update($params, [
'dictionary_guid' => $params['dictionary_guid']
]);
return [
'code' => 0,
'msg' => '更新成功'
];
}
/**
* 删除菜单
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function deleteDictionary(Request $request)
{
$params = $request->param();
$this->validate($params, [
'dictionary_guid' => 'require'
]);
ModelDictionary::find($params['dictionary_guid'])->delete();
return [
'code' => 0,
'msg' => '删除成功'
];
}
// 获取字典
public function getDictionary(Request $request)
{
$dictionary_value = $request->param('dictionary_value');
$dictionary_guid = ModelDictionary::where('dictionary_value', $dictionary_value)->find()['dictionary_guid'];
$res = ModelDictionary::field([
'dictionary_guid',
'dictionary_parent_guid',
'dictionary_name',
'dictionary_value',
'dictionary_list_class',
])->where('dictionary_parent_guid', $dictionary_guid)
->where('dictionary_status', 1)->select();
if (!$res) throwErrorMsg("字典不存在");
else return $res;
}
/**
* 下载导入模板
*/
public function downloadTemplate(Request $request)
{
$params = $request->param();
$data = [
[
'上级字典',
'名称',
'值',
'层级',
'排序',
'回显',
]
];
$data[] = ['','状态','status','1','0','',];
$data[] = ['状态','启用','1','2','1','primary'];
$data[] = ['状态','禁用','2','2','2','danger',];
$excel = (new Excel())->exporTsheet($data);
$excel->save('字典导入模板.xlsx');
}
/**
* 导入excel
*/
public function importExcel(Request $request)
{
$file = new UploadFile('uploads', 'fileExt:xlsx');
$file->putFile('Dictionary');
$msg = ModelDictionary::importExcel($file);
return [
'code' => 0,
'msg' => $msg
];
}
}

View File

@ -0,0 +1,307 @@
<?php
namespace app\admin\controller\Flow;
use app\Request;
use app\common\model\Flow\Flow as ModelFlow;
use think\db\Where;
use think\facade\Validate;
use app\BaseController;
use app\exception\ErrorMsg;
use think\facade\Filesystem;
class Flow extends BaseController
{
// (new ModelFlow)->track();
/**
* 查询流量访问记录
* @throws \think\db\exception\DbException
*/
public function getFlowRecord(Request $request): array
{
$query = ModelFlow::where([]);
$select = self::pageWrapper($query)
->field([
'flow_id',
'flow_record_no',
'flow_visitor_ip',
'flow_location',
'flow_create_time',
'flow_source',
'flow_target',
'flow_os',
'flow_browser'
])
->order('flow_id', 'desc')
->select();
$count = $query->count();
return [
'msg' => '查询成功',
'code' => 0,
'data' => $select,
'count' => $count
];
}
/**
* 查询流量来源统计
*/
public function getFlowSourceCount(): array
{
$query = ModelFlow::where([]);
$count = $query->count();
$select = $query->field([
'flow_id',
'flow_source',
])->select();
$GDP = $query->field([
'flow_source',
])->group('flow_source')->select();
foreach ($GDP as $k => &$i) {
$i['number'] = 0;
$i['percentage'] = 0;
}
foreach ($select as $key => &$item) {
foreach ($GDP as $k => &$i) {
if ($item['flow_source'] === $i['flow_source']) {
$i['number'] += 1;
}
}
}
foreach ($GDP as $k => $i) {
$i['percentage'] = round($i['number'] / $count * 100);
}
return [
'msg' => '查询完成',
'code' => 0,
'count' => $count,
'data' => [
'GDP' => $GDP,
'select' => $select
]
];
}
/**
* 查询流量浏览器统计
*/
public function getFlowBrowserCount(): array
{
$query = ModelFlow::where([]);
$count = $query->count();
$select = $query->field([
'flow_id',
'flow_browser',
])->select();
$GDP = $query->field([
'flow_browser',
])->group('flow_browser')->select();
foreach ($GDP as $k => &$i) {
$i['number'] = 0;
$i['percentage'] = 0;
}
foreach ($select as $key => &$item) {
foreach ($GDP as $k => &$i) {
if ($item['flow_browser'] === $i['flow_browser']) {
$i['number'] += 1;
}
}
}
foreach ($GDP as $k => $i) {
$i['percentage'] = round($i['number'] / $count * 100);
}
return [
'msg' => '查询完成',
'code' => 0,
'count' => $count,
'data' => [
'select' => $select,
'GDP' => $GDP
]
];
}
/**
* 查询流量月统计
*/
public function getFlowMonthCount(Request $request): array
{
$current_year = input('post.current_year') ?? 0;
$query = ModelFlow::where([]);
$current_year = date('Y', strtotime("$current_year year"));
$count = $query->whereYear('flow_create_time', $current_year)
->field([
'flow_create_time',
])
->select()->count();
$select = $query->whereYear('flow_create_time', $current_year)
->field([
'flow_id',
'flow_record_no',
'flow_visitor_ip',
'flow_location',
'flow_create_time',
'flow_source',
'flow_target',
'flow_os',
'flow_browser'
])
->order('flow_id', 'desc')
->select()->toArray();
$res_select = [];
for ($i = 1; $i <= 12; $i++) {
array_push($res_select, [
'flow_Date' => $current_year .
'-' .
date('m', strtotime($current_year . '-' . $i)),
'number' => 0,
'percentage' => 0
]);
}
foreach ($select as $key => &$item) {
$date_format = explode('-', explode(' ', $item['flow_create_time'])[0]);
$item['flow_Date'] = $date_format[0] . '-' . $date_format[1];
foreach ($res_select as $k => &$it) {
if ($item['flow_Date'] == $it['flow_Date']) {
$it['number'] += 1;
}
}
foreach ($res_select as $k => &$it) {
$it['percentage'] = round($it['number'] / $count * 100);
}
};
foreach ($res_select as $k => &$it) {
foreach ($select as $key => &$item) {
if ($it['flow_Date'] === $item['flow_Date']) {
$it = array_merge($it, $item);
}
}
}
return [
'code' => 0,
'msg' => '查询成功',
'count' => $count,
'data' => [
'current_date' => ['y' => $current_year],
'select' => $res_select
]
];
}
/**
* 查询流量日统计
*/
public function getFlowDayCount(Request $request)
{
$current_month = input('post.current_month') ?? 0;
// return ['a'=>$current_month];
$query = ModelFlow::where([]);
$current_month_date = date('Y-m', strtotime(date('Y-m-01') . "$current_month month"));
// return ['a'=>$current_month_date];
$count = $query->whereMonth('flow_create_time', $current_month_date)
->field([
'flow_create_time',
])
->select()->count();
// $select = $query->whereMonth('flow_create_time', $current_month_date)
// ->field([
// 'flow_create_time',
// ])
// ->order('flow_id', 'desc')
// ->select()->toArray();
$select = $query->whereMonth('flow_create_time', $current_month_date)
->field([
'flow_create_time',
])
->buildSql();
return $select;
$GDP = [];
$res_select = [];
for ($i = 1; $i <= date('t', strtotime(date('Y-m-01') . "$current_month month")); $i++) {
array_push($res_select, [
'week' => $this->getWeek(date('Y-m', strtotime(date('Y-m-01') . "$current_month month"))
. '-'
. date('d', strtotime(date('Y-m', strtotime(date('Y-m-01') . "$current_month month")) . "-$i"))),
'flow_Date' => date('Y-m', strtotime(date('Y-m-01') . "$current_month month"))
. '-'
. date('d', strtotime(date('Y-m', strtotime(date('Y-m-01') . "$current_month month")) . "-$i")),
'number' => 0, 'percentage' => 0
]);
}
foreach ($select as $key => &$item) {
$item['flow_Date'] = explode(' ', $item['flow_create_time'])[0];
foreach ($res_select as $k => &$it) {
if ($item['flow_Date'] == $it['flow_Date']) {
$it['number'] += 1;
}
}
foreach ($res_select as $k => &$it) {
$it['percentage'] = round($it['number'] / $count * 100);
}
};
foreach ($res_select as $k => &$it) {
foreach ($select as $key => &$item) {
if ($it['flow_Date'] === $item['flow_Date']) {
$it = array_merge($it, $item);
}
}
}
return [
'code' => 0,
'msg' => '查询成功',
'count' => $count,
'data' => [
'current_date' => ['y' => date('Y', strtotime(date('Y-m-01') . "$current_month month")), 'm' => date('m', strtotime(date('Y-m-01') . "$current_month month"))],
'select' => $res_select
]
];
}
/**
* @param $date
* @return string
* @descript 获取指定日期星期
*/
private function getWeek($date): string
{
//强制转换日期格式
$date_str = date('Y-m-d', strtotime($date));
//封装成数组
$arr = explode("-", $date_str);
//参数赋值
//年
$year = $arr[0];
//月输出2位整型不够2位右对齐
$month = sprintf('%02d', $arr[1]);
//日输出2位整型不够2位右对齐
$day = sprintf('%02d', $arr[2]);
//时分秒默认赋值为0
$hour = $minute = $second = 0;
//转换成时间戳
$strap = mktime($hour, $minute, $second, $month, $day, $year);
//获取数字型星期几
$number_wk = date("w", $strap);
//自定义星期数组
$weekArr = array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六");
//获取数字对应的星期
return $weekArr[$number_wk];
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,145 @@
<?php
namespace app\admin\controller;
use app\common\arw\adjfut\src\Validate;
use app\BaseController;
use app\common\logic\Login as LogicLogin;
use app\Request;
use think\captcha\facade\Captcha;
use think\middleware\SessionInit;
use think\Response;
class Login extends BaseController
{
/**
* 初始化
*
* @date 2022-03-15
* @example
* @author admin
* @since 1.0.0
*/
protected function initialize(): void
{
$this->middleware[SessionInit::class] = [
'only' => ['accountLogin', 'getCaptcha']
];
}
/**
* 验证token
*
* @param Request $request
* @return void
*/
public function validateToken(Request $request)
{
$token = $request->getCurrentToken();
return [
'code' => 0,
'data' => [
'exp_time' => $token->token_exp_time,
],
'msg' => 'ok'
];
}
/**
* 西北政法大学单点登陆
*
* @param Request $request
* @return Response
* @date 2023-01-04
* @example
* @author admin
* @since 1.0.0
*/
public function casOauthLogin(Request $request): Response
{
$url = $request->param('url');
return LogicLogin::casOauthLogin(
LogicLogin::casOauthLoginHandle($url)
);
}
/**
* 西北政法大学单点登出
*
* @param Request $request
* @return Response
* @date 2023-01-04
* @example
* @author admin
* @since 1.0.0
*/
public function casOauthLogout(Request $request): Response
{
$url = $request->param('url');
return LogicLogin::casOauthLogout($url);
}
/**
* 用户账号登录
*
* @param Request $request
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function accountLogin(Request $request): array
{
$param = Validate::param([
'account|账号' => 'require',
'password|密码' => 'require',
// 'captcha|验证码' => $request->isProd() ? 'require|captcha' : false
]);
$token = LogicLogin::accountLogin(
$param['account'],
$param['password']
);
return [
'code' => 0,
'data' => [
'token' => $token->token_content,
'exp_time' => $token->token_exp_time,
],
'msg' => 'ok'
];
}
/**
* 生成验证码
*
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function getCaptcha()
{
return Captcha::create();
}
/**
* 用户登出
*
* @param Request $request
* @date 2022-03-09
* @example
* @author admin
* @since 1.0.0
*/
public function userLogout(Request $request): array
{
$token = $request->getCurrentToken();
$token->logout();
return [
'code' => 0,
'msg' => '登出成功'
];
}
}

View File

@ -0,0 +1,368 @@
<?php
namespace app\admin\controller\Menu;
use app\common\arw\adjfut\src\Traverse;
use app\BaseController;
use app\common\model\Menu\Menu as ModelMenu;
use app\common\model\Menu\MenuApi;
use app\common\model\Role\Role;
use app\common\model\Role\RoleMenu;
use app\Request;
use think\facade\Db;
class Menu extends BaseController
{
/**
* 获取菜单接口树
*
* @param Request $request
* @return array
* @date 2022-03-07
* @example
* @author admin
* @since 1.0.0
*/
public function getMenuApiTree(Request $request)
{
$menu = ModelMenu::order([
'menu_index',
'menu_order' => 'desc',
])->field([
'menu_guid',
'menu_parent_guid',
'menu_name',
'menu_url',
])->select()->toArray();
$menuApi = [];
foreach (MenuApi::select() as $value) {
if (!isset($menuApi[$value->menu_guid])) {
$menuApi[$value->menu_guid] = [];
}
$menuApi[$value->menu_guid][] = $value->menu_api_url;
}
$Traverse = new Traverse('menu_guid', 'menu_parent_guid');
$menuTree = $Traverse->tree($menu, '0', function ($v) use ($menuApi) {
return [
'menu_api_url' => isset($menuApi[$v['menu_guid']]) ? $menuApi[$v['menu_guid']] : [],
'menu_name' => $v['menu_name'],
'menu_guid' => $v['menu_guid'],
'menu_parent_guid' => $v['menu_parent_guid'],
'menu_url' => $v['menu_url'],
];
}, function ($v) {
$v['hasChildren'] = isset($value['children']) && count($value['children']);
return $v;
});
return [
'code' => 0,
'msg' => 'ok',
'data' => $menuTree,
];
}
/**
* 添加菜单接口
*
* @param Request $request
* @return array
* @date 2022-03-08
* @example
* @author admin
* @since 1.0.0
*/
public function addMenuApi(Request $request)
{
Db::startTrans();
try {
$params = $request->param();
$this->validate($params, [
'menu_guid' => 'require',
'menu_api_url' => 'require'
]);
foreach (explode(',', $params['menu_api_url']) as $menu_api_url) {
MenuApi::create([
'menu_guid' => $params['menu_guid'],
'menu_api_url' => $menu_api_url,
]);
}
Db::commit();
return [
'code' => 0,
'msg' => '添加成功',
];
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 删除菜单接口
*
* @param Request $request
* @return array
* @date 2022-03-08
* @example
* @author admin
* @since 1.0.0
*/
public function deleteMenuApi(Request $request)
{
$params = $request->param();
$this->validate($params, [
'menu_api_guid' => 'require'
]);
MenuApi::where([
'menu_api_guid' => explode(',', $params['menu_api_guid'])
])->select()->delete();
return [
'code' => 0,
'msg' => "删除成功"
];
}
/**
* 获取菜单接口列表
*
* @param Request $request
* @return array
* @date 2022-03-07
* @example
* @author admin
* @since 1.0.0
*/
public function getMenuApiList(Request $request)
{
$params = $request->param();
$this->validate($params, [
'menu_guid' => 'require'
]);
$query = ModelMenu::find($params['menu_guid'])->apis()->append([
'menu_api_status_text'
]);
$data = self::pageWrapper($query)->select();
$count = $query->count();
return [
'code' => 0,
'msg' => 'ok',
'data' => $data,
'count' => $count
];
}
/**
* 获取菜单树
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function getMenuTree(Request $request)
{
$menu = ModelMenu::order([
'menu_index',
'menu_order' => 'desc',
])->field([
'menu_parent_guid',
'menu_name',
'menu_url',
'menu_index',
'menu_order',
'menu_status',
'menu_show',
'menu_guid',
])->select()->toArray();
array_unshift($menu, [
'menu_guid' => '0',
'menu_parent_guid' => '-1',
'menu_name' => '系统菜单',
'menu_index' => 0,
'menu_order' => 0,
'menu_status' => 0,
'menu_show' => 0,
'menu_url' => '',
]);
$Traverse = new Traverse('menu_guid', 'menu_parent_guid');
$menuTree = $Traverse->tree($menu, '-1', function ($v) {
return [
'label' => $v['menu_name'],
'id' => $v['menu_guid'],
'parent_id' => $v['menu_parent_guid'],
'index' => $v['menu_index'],
'order' => $v['menu_order'],
'status' => $v['menu_status'],
'show' => $v['menu_show'],
'url' => $v['menu_url'],
];
});
return [
'code' => 0,
'msg' => 'ok',
'data' => $menuTree
];
}
/**
* 获取角色菜单
*
* @param Request $request
* @return array
* @date 2022-03-09
* @example
* @author admin
* @since 1.0.0
*/
public function getRoleMenu(Request $request)
{
$params = $request->param();
$this->validate($params, [
'role_guid' => 'require'
]);
$menus = Role::getByRoleGuid($params['role_guid'])->menus;
$menu_guids = [];
$menu_parent_guids = [];
foreach ($menus as $menu) {
if (!in_array($menu->menu_guid, $menu_guids)) {
$menu_guids[] = $menu->menu_guid;
}
if (!in_array($menu->menu_parent_guid, $menu_parent_guids)) {
$menu_parent_guids[] = $menu->menu_parent_guid;
}
}
// 去除父id 存在父id会全选子节点
$temp = [];
foreach ($menu_guids as $menu_guid) {
if (!in_array($menu_guid, $menu_parent_guids)) {
$temp[] = $menu_guid;
}
}
return [
'code' => 0,
'data' => $temp,
'msg' => 'ok'
];
}
/**
* 绑定角色菜单
*
* @param Request $request
* @return array
* @date 2022-03-09
* @example
* @author admin
* @since 1.0.0
*/
public function bindRoleMenu(Request $request)
{
$params = $request->param();
$this->validate($params, [
'role_guid' => 'require',
'menu_guid' => 'require'
]);
$menus = array_map(function ($v) {
return ModelMenu::find($v);
}, explode(',', $params['menu_guid']));
RoleMenu::rebindRoleMenu(
[
Role::getByRoleGuid($params['role_guid']),
],
array_filter($menus)
);
return [
'code' => 0,
'msg' => '绑定成功'
];
}
/**
* 添加菜单
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function addMenu(Request $request)
{
$params = $request->param();
$this->validate($params, [
'menu_name' => 'require',
'menu_index' => 'require',
'menu_order' => 'require',
'menu_show' => 'require',
'menu_parent_guid' => 'require',
]);
if (isset($params['menu_guid'])) {
unset($params['menu_guid']);
}
ModelMenu::create($params);
return [
'code' => 0,
'msg' => '添加成功'
];
}
/**
* 更新菜单
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function updateMenu(Request $request)
{
$params = $request->param();
$this->validate($params, [
'menu_guid' => 'require'
]);
ModelMenu::withoutGlobalScope(['status'])->update($params, [
'menu_guid' => $params['menu_guid']
]);
return [
'code' => 0,
'msg' => '更新成功'
];
}
/**
* 删除菜单
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function deleteMenu(Request $request)
{
$params = $request->param();
$this->validate($params, [
'menu_guid' => 'require'
]);
ModelMenu::where([
'menu_guid' => explode(',', $params['menu_guid'])
])->select()->delete();
return [
'code' => 0,
'msg' => '删除成功'
];
}
}

View File

@ -0,0 +1,291 @@
<?php
namespace app\admin\controller\News;
use app\BaseController;
use app\common\model\News\News as ModelNews;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use think\facade\Db;
use think\facade\Env;
class News extends BaseController
{
/**
* 获取新闻列表
*/
public function getNewsList(Request $request): array
{
$params = $request->param();
$con = [];
if (isset($params['news_title']) && $params['news_title']) {
$con[] = ['news_title', 'LIKE', '%' . $params['news_title'] . '%'];
};
if (isset($params['news_type']) && $params['news_type']) {
$con[] = ['news_type', '=', $params['news_type']];
};
$query = ModelNews::where($con);
$select = self::pageWrapper($query)
->field([
'news_id',
'news_guid',
'news_title',
'news_author',
'news_intro',
'news_type',
'news_img',
'news_content',
'news_num'
])
->order('news_update_time', 'desc')
->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 编辑新闻
*/
public function editNews(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'news_title|新闻标题' => 'require',
'news_author|新闻作者' => 'require',
'news_intro|新闻简介' => 'require',
'news_type|新闻类型' => 'require',
'news_img|新闻封面' => 'require',
]);
$model = ModelNews::where('news_guid', $params['news_guid'])->find();
if (!$model) throwErrorMsg("该新闻不存在", 1);
$model->allowField([
'news_update_user_guid',
'news_title',
'news_author',
'news_intro',
'news_type',
'news_img',
'news_content',
'news_num'
])->save($params);
return [
'code' => 0,
'msg' => '编辑成功'
];
}
/**
* 添加新闻
*/
public function addNews(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'news_title|新闻标题' => 'require',
'news_author|新闻作者' => 'require',
'news_intro|新闻简介' => 'require',
'news_type|新闻类型' => 'require',
'news_img|新闻封面' => 'require',
]);
$model = ModelNews::create($params, [
'news_guid',
'news_create_user_guid',
'news_update_user_guid',
'news_title',
'news_author',
'news_intro',
'news_type',
'news_img',
'news_content',
'news_num'
]);
return [
'code' => 0,
'msg' => '添加成功'
];
}
/**
* 删除新闻
*/
public function deleteNews(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'news_guid' => 'require',
]);
$news = ModelNews::where([
'news_guid' => explode(',', $params['news_guid'])
])->select();
$news->delete();
return [
'code' => 0,
'msg' => "删除成功"
];
}
/**
* 导出Excel
*/
public function exportExcel(Request $request)
{
$params = $request->param();
$select = ModelNews::field([
'news_title',
'news_author',
'news_intro',
'news_type',
'news_img',
'news_content',
'news_num'
])
->order('news_update_time', 'desc')
->select();
$data = [[
'新闻标题',
'新闻作者',
'新闻简介',
'新闻类型',
'新闻封面',
'新闻内容',
'新闻数量'
]];
foreach ($select as $key => $val) {
$data[] = [
$val['news_title'],
$val['news_author'],
$val['news_intro'],
$val['news_type'],
$val['news_img'],
$val['news_content'],
$val['news_num'],
];
}
$excel = (new Excel())->exporTsheet($data);
$excel->save('新闻.xlsx');
}
/**
* 下载导入模板
*/
public function downloadTemplate(Request $request)
{
$params = $request->param();
$data = [
'新闻标题',
'新闻作者',
'新闻简介',
'新闻类型',
'新闻封面',
'新闻内容',
'新闻数量'
];
$excel = (new Excel())->exporTsheet($data);
$excel->save('新闻导入模板.xlsx');
}
/**
* 导入excel
*/
public function importExcel(Request $request)
{
$file = new UploadFile('uploads', 'fileExt:xlsx');
$file->putFile('news');
Db::startTrans();
try {
$excel = new Excel($file);
$data = $excel->parseExcel(
[[
'title' => '新闻标题',
'validate' => 'require',
'field' => 'news_title',
], [
'title' => '新闻作者',
'validate' => 'require',
'field' => 'news_author',
], [
'title' => '新闻简介',
'validate' => 'require',
'field' => 'news_intro',
], [
'title' => '新闻类型',
'validate' => 'require',
'field' => 'news_type',
], [
'title' => '新闻封面',
'validate' => 'require',
'field' => 'news_img',
], [
'title' => '新闻内容',
'validate' => 'require',
'field' => 'news_content',
], [
'title' => '新闻数量',
'validate' => 'require',
'field' => 'news_num',
],],
[
'titleLine' => [1]
]
);
if (!$data) throwErrorMsg('excel无数据', 1);
$error = [];
foreach ($data as $line => $value) {
try {
$news_title = $value['news_title'];
$news_author = $value['news_author'];
$news_intro = $value['news_intro'];
$news_type = $value['news_type'];
$news_img = $value['news_img'];
$news_content = $value['news_content'];
$news_data = $value['news_data'];
$news_time = $value['news_time'];
$news_num = $value['news_num'];
ModelNews::create([
'news_title' => $news_title,
'news_author' => $news_author,
'news_intro' => $news_intro,
'news_type' => $news_type,
'news_img' => $news_img,
'news_content' => $news_content,
'news_num' => $news_num,
]);
} catch (\Throwable $th) {
$error[] = $line . '' . $th->getMessage();
}
}
if ($error) throwErrorMsg(implode(', ', $error), 1);
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
return [
'code' => 0,
'msg' => '导入成功!'
];
}
}

View File

@ -0,0 +1,220 @@
<?php
namespace app\admin\controller\Product;
use app\BaseController;
use app\common\model\Product\Product as ModelProduct;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use app\common\exception\Tool;
use think\facade\Db;
use think\facade\Env;
class Product extends BaseController
{
/**
* 获取产品列表接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function getProductList(Request $request): array
{
Db::startTrans();
try {
$params = $request->param();
$con = [];
$con = Tool::getOptionalQuery(
['product.product_name', 'LIKE'],
['product.product_type_guid'],
);
$query = ModelProduct::where($con)
->leftJoin('product_type', 'product_type.product_type_guid = product.product_type_guid')
->field([
'product.product_id',
'product.product_guid',
'product.product_type_guid',
'product.product_name',
'product.product_img',
'product.product_params',
'product.product_details',
'product.product_price',
'product_type.product_type_name'
])
->order('product_id', 'desc');
return msg("获取产品列表成功!", $query);
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 编辑产品接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function editProduct(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'product_type_guid|产品系列guid' => 'require',
'product_name|名称' => 'require',
'product_img|图片' => 'require',
'product_details|详情' => 'require',
'product_price|价格' => 'require'
]);
$model = ModelProduct::where('product_guid', $params['product_guid'])->find();
if (!$model) throwErrorMsg("该产品不存在", 1);
// Tool::sortEditProc(
// new ModelProduct,
// ["product_guid" => $params['product_guid']],
// ["product_type_order" => $params['product_type_order']],
// );
$model->allowField([
'product_update_user_guid',
'product_type_guid',
'product_name',
'product_img',
'product_params',
'product_details',
'product_price'
])->save($params);
return msg('编辑成功!');
}
/**
* 添加产品接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function addProduct(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'product_type_guid|产品系列guid' => 'require',
'product_name|名称' => 'require',
'product_img|图片' => 'require',
'product_details|详情' => 'require',
'product_price|价格' => 'require'
]);
ModelProduct::create($params, [
'product_guid',
'product_create_user_guid',
'product_update_user_guid',
'product_type_guid',
'product_name',
'product_img',
'product_params',
'product_details',
'product_price'
]);
return msg('添加成功!');
}
/**
* 删除产品接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function deleteProduct(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'product_guid|产品系列' => 'require',
]);
$product = ModelProduct::where([
'product_guid' => explode(',', $params['product_guid'])
])->select();
$product->delete();
return msg('删除成功!');
}
/**
* 导出Excel接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function exportExcel(Request $request)
{
$params = $request->param();
$select = ModelProduct::field([
'product_type_guid',
'product_name',
'product_img',
'product_params',
'product_details',
'product_price'
])
->order('product_update_time', 'desc')
->select();
return ModelProduct::exportExcel($select);
}
/**
* 下载导入模板接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function downloadTemplate(Request $request)
{
$params = $request->param();
$data = array_values(ModelProduct::EXCELFIELD);
$excel = (new Excel())->exporTsheet($data);
$excel->save('产品导入模板.xlsx');
}
/**
* 导入excel接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function importExcel(Request $request)
{
$file = new UploadFile('uploads', 'fileExt:xlsx');
$file->putFile('product');
$msg = ModelProduct::importExcel($file);
return [
'code' => 0,
'msg' => $msg
];
}
}

View File

@ -0,0 +1,148 @@
<?php
namespace app\admin\controller\Product;
use app\BaseController;
use app\common\model\Product\ProductParam as ModelProductParam;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use app\common\exception\Tool;
use think\facade\Db;
use think\facade\Env;
class ProductParam extends BaseController
{
/**
* 获取产品参数列表接口
*
* @param Request request
* @date 2023-04-02
* @example
* @author xjh
* @since 1.0.0
*/
public function getProductParamList(Request $request): array
{
$con = Tool::getOptionalQuery(['product_param.product_type_guid', '=']);
$query = ModelProductParam::where($con)
->field([
'product_param.product_param_id',
'product_param.product_param_guid',
'product_param.product_param_name',
'product_param.product_type_guid',
'product_param.product_param_order',
'product_type.product_type_name'
])
->leftJoin('product_type', 'product_type.product_type_guid = product_param.product_type_guid')
->order('product_param_order', 'asc');
return msg("获取产品参数列表成功!", $query);
}
/**
* 获取指定系列参数模板接口
*
* @param Request request
* @date 2023-04-02
* @example
* @author xjh
* @since 1.0.0
*/
public function getProductParamTemplate(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'product_type_guid|产品系列guid' => 'require'
]);
$data = ModelProductParam::field(['product_param_name', 'product_param_order'])
->where('product_type_guid', $params['product_type_guid'])
->order('product_param_order', 'desc')
->append(['product_param_value'])
->select();
return msg(0, '获取指定系列参数模板成功!', ['data' => $data]);
}
/**
* 编辑产品参数接口
*
* @param Request request
* @date 2023-04-02
* @example
* @author xjh
* @since 1.0.0
*/
public function editProductParam(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'product_param_name|产品参数名称' => 'require',
'product_type_guid|产品系列guid' => 'require'
]);
$model = ModelProductParam::where('product_param_guid', $params['product_param_guid'])->find();
if (!$model) throwErrorMsg("该产品参数不存在", 1);
$model->allowField([
'product_param_update_user_guid',
'product_param_name',
'product_type_guid',
'product_param_order'
])->save($params);
return msg('编辑成功!');
}
/**
* 添加产品参数接口
*
* @param Request request
* @date 2023-04-02
* @example
* @author xjh
* @since 1.0.0
*/
public function addProductParam(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'product_param_name|产品参数名称' => 'require',
'product_type_guid|产品系列guid' => 'require'
]);
$model = ModelProductParam::create($params, [
'product_param_guid',
'product_param_create_user_guid',
'product_param_update_user_guid',
'product_param_name',
'product_param_order',
'product_type_guid'
]);
return msg('添加成功!');
}
/**
* 删除产品参数接口
*
* @param Request request
* @date 2023-04-02
* @example
* @author xjh
* @since 1.0.0
*/
public function deleteProductParam(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'product_param_guid' => 'require',
]);
$product_param = ModelProductParam::where([
'product_param_guid' => explode(',', $params['product_param_guid'])
])->select();
$product_param->delete();
return msg('删除成功!');
}
}

View File

@ -0,0 +1,271 @@
<?php
namespace app\admin\controller\Product;
use app\BaseController;
use app\common\model\Product\ProductType as ModelProductType;
use app\common\arw\adjfut\src\Traverse;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use app\common\exception\Tool;
use think\facade\Db;
use think\facade\Env;
class ProductType extends BaseController
{
/**
* 获取产品系列树形列表接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function getProductTypeTree(Request $request): array
{
$con = Tool::getOptionalQuery(
['b.product_delete_time', 'NULL'],
['a.product_type_name', 'LIKE']
);
$product_type = ModelProductType::field([
'a.product_type_parent_guid',
'a.product_type_name',
'b.product_type_name' => "product_type_parent_name",
'a.product_type_order',
'a.product_type_guid',
'a.product_type_icon',
'a.product_type_cover',
])
->alias('a')
->leftjoin('product_type b', 'a.product_type_parent_guid = b.product_type_guid')
->where($con)
->order(['product_type_order' => 'asc'])
->select()->toArray();
$Traverse = new Traverse('product_type_guid', 'product_type_parent_guid');
$product_type_tree = $Traverse->tree($product_type, '0', function ($v) {
return [
'product_type_name' => $v['product_type_name'],
'product_type_parent_name' => $v['product_type_parent_name'],
'product_type_guid' => $v['product_type_guid'],
'product_type_parent_guid' => $v['product_type_parent_guid'],
'product_type_order' => $v['product_type_order'],
'product_type_icon' => $v['product_type_icon'],
'product_type_cover' => $v['product_type_cover'],
];
});
return msg("获取产品系列列表成功!", $product_type_tree);
}
/**
* 编辑产品系列接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function editProductType(Request $request): array
{
Db::startTrans();
try {
$params = $request->param();
$this->validate($params, [
'product_type_name|产品系列名称' => 'require',
'product_type_icon|产品系列图标' => 'require',
'product_type_cover|产品系列封面' => 'require',
'product_type_guid|产品系列guid' => 'require',
'product_type_order|产品系列排序' => 'require',
]);
$model = ModelProductType::where('product_type_guid', $params['product_type_guid'])->find();
if (!$model) throwErrorMsg("该产品系列不存在", 1);
ModelProductType::isDuplicateName($params['product_type_name'], $params['product_type_guid']);
$params['product_type_ancestors_guid'] = ModelProductType::buildAncestorsGuid($params['product_type_parent_guid']);
Tool::sortEditProc(
new ModelProductType,
["product_type_order" => $params['product_type_order']],
["product_type_guid" => $params['product_type_guid']],
["product_type_parent_guid" => $params['product_type_parent_guid']],
);
$model->allowField([
'product_type_update_user_guid',
'product_type_title',
'product_type_icon',
'product_type_cover',
'product_type_ancestors_guid',
'product_type_parent_guid',
'product_type_order',
])->save($params);
Db::commit();
return msg('编辑成功!');
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 添加产品系列接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function addProductType(Request $request): array
{
Db::startTrans();
try {
$params = $request->param();
$this->validate($params, [
'product_type_name|产品类型名称' => 'require',
'product_type_icon|产品系列图标' => 'require',
'product_type_cover|产品系列封面' => 'require',
'product_type_order|产品系列排序' => 'require'
]);
ModelProductType::isDuplicateName($params['product_type_name']);
$product_type_parent_where = [];
if (!empty($params['product_type_parent_guid'])) {
$params['product_type_ancestors_guid'] = ModelProductType::buildAncestorsGuid($params['product_type_parent_guid']);
$product_type_parent_where['product_type_parent_guid'] = $params['product_type_parent_guid'];
}
Tool::sortInsertProc(
new ModelProductType,
["product_type_order" => $params['product_type_order']],
$product_type_parent_where,
);
ModelProductType::create($params, [
'product_type_guid',
'product_type_create_user_guid',
'product_type_update_user_guid',
'product_type_parent_guid',
'product_type_ancestors_guid',
'product_type_name',
'product_type_icon',
'product_type_cover',
'product_type_order'
]);
Db::commit();
return msg("添加成功!");
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 删除产品系列接口接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function deleteProductType(Request $request): array
{
Db::startTrans();
try {
$params = $request->param();
$this->validate($params, [
'product_type_guid|产品系列guid' => 'require',
]);
$guids = explode(',', $params['product_type_guid']);
Tool::sortDeleteProc(
new ModelProductType,
'product_type_order',
["product_type_guid" => $guids],
["product_type_parent_guid"],
);
ModelProductType::where(['product_type_guid' => $guids])->select()->delete();
Db::commit();
return msg('删除成功!');
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 导出Excel接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function exportExcel(Request $request)
{
$params = $request->param();
$select = ModelProductType::field([
'product_type_title',
'product_type_icon',
'product_type_cover'
])
->order('product_type_update_time', 'desc')
->select();
return ModelProductType::exportExcel($select);
}
/**
* 下载导入模板接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function downloadTemplate(Request $request)
{
$params = $request->param();
$data = array_values(ModelProductType::EXCELFIELD);
$excel = (new Excel())->exporTsheet($data);
$excel->save('产品系列导入模板.xlsx');
}
/**
* 导入excel接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function importExcel(Request $request)
{
$file = new UploadFile('uploads', 'fileExt:xlsx');
$file->putFile('product_type');
$msg = ModelProductType::importExcel($file);
return [
'code' => 0,
'msg' => $msg
];
}
}

View File

@ -0,0 +1,198 @@
<?php
namespace app\admin\controller\Role;
use app\BaseController;
use app\common\model\Role\Role as ModelRole;
use app\Request;
class Role extends BaseController
{
/**
* 获取用户角色列表
*
* @param Request $request
* @return array
* @date 2022-03-02
* @example
* @author admin
* @since 1.0.0
*/
public function getUserRoleList(Request $request)
{
}
/**
* 获取角色列表
*
* @param Request $request
* @date 2022-02-25
* @example
* @author admin
* @since 1.0.0
*/
public function getRoleList(Request $request): array
{
$role_status = $request->param('role_status');
$role = $request->param('role');
$scope = explode(',', $request->param('scope', ''));
$con = [
// 'role_status' => 1
];
if ($role) {
$con['role_name'] = $role;
}
if ($role_status) {
$con['role_status'] = $role_status;
}
$query = ModelRole::scope($scope)->withSearch(['role_name'], $con)->where($con);
$select = self::pageWrapper($query)->field([
'role_name',
'role_status',
'role_guid',
])->append([
'role_status_text'
])->order([
'role_id' => 'desc'
])->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 获取角色菜单
*
* @param Request $request
* @date 2022-03-08
* @example
* @author admin
* @since 1.0.0
*/
public function getRoleMenu(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'role_guid' => 'require'
]);
dump(ModelRole::getByRoleGuid($params['role_guid'])->menus);
return [
'code' => 0,
'msg' => 'ok',
// 'data' => $data
];
}
/**
* 编辑角色
*
* @param Request $request
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function editRole(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'role_guid' => 'require',
'role_name' => 'require',
]);
$role = ModelRole::where([
'role_guid' => $params['role_guid']
])->find();
if (!$role) {
throwErrorMsg("角色不存在", 1);
}
$role->save([
'role_name' => $params['role_name'],
]);
return [
'code' => 0,
'msg' => '编辑成功'
];
}
/**
* 添加角色
*
* @param Request $request
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function addRole(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'role_name' => 'require',
]);
ModelRole::create([
'role_name' => $params['role_name'],
]);
return [
'code' => 0,
'msg' => '添加成功'
];
}
/**
* 删除角色
*
* @param Request $request
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function deleteRole(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'role_guid' => 'require',
]);
$roles = ModelRole::where([
'role_guid' => ['in', $params['role_guid']]
])->select();
$roles->delete();
return [
'code' => 0,
'msg' => "删除成功"
];
}
/**
* 更新角色状态
*
* @param Request $request
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function updateRoleStatus(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'role_guid' => 'require',
'role_status' => 'require|in:1,2',
]);
$role_status = $params['role_status'];
$roles = ModelRole::where([
'role_guid' => explode(',', $params['role_guid'])
])->select();
$roles->update([
'role_status' => $role_status
]);
return [
'code' => 0,
'msg' => "更新成功"
];
}
}

View File

@ -0,0 +1,111 @@
<?php
namespace app\admin\controller\School;
use app\BaseController;
use app\common\model\School\Classes as ModelClasses;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use think\facade\Db;
use think\facade\Env;
class Classes extends BaseController
{
/**
* 获取班级列表
*/
public function getClassesList(Request $request): array
{
$params = $request->param();
$con = [];
if (isset($params['classes_name']) && $params['classes_name']) {
$con[] = ['classes_name', 'LIKE', '%' . $params['classes_name'] . '%'];
};
$query = ModelClasses::where($con);
$select = self::pageWrapper($query)
->field([
'classes_id',
'classes_guid',
'classes_name'
])
->order('classes_update_time', 'desc')
->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 编辑班级
*/
public function editClasses(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'classes_name|班级名称' => 'require'
]);
$model = ModelClasses::where('classes_guid', $params['classes_guid'])->find();
if (!$model) throwErrorMsg("该班级不存在", 1);
$model->allowField([
'classes_update_user_guid',
'classes_name'
])->save($params);
return [
'code' => 0,
'msg' => '编辑成功'
];
}
/**
* 添加班级
*/
public function addClasses(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'classes_name|班级名称' => 'require'
]);
$model = ModelClasses::create($params, [
'classes_guid',
'classes_create_user_guid',
'classes_update_user_guid',
'classes_name'
]);
return [
'code' => 0,
'msg' => '添加成功'
];
}
/**
* 删除班级
*/
public function deleteClasses(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'classes_guid' => 'require',
]);
$classes = ModelClasses::where([
'classes_guid' => explode(',', $params['classes_guid'])
])->select();
$classes->delete();
return [
'code' => 0,
'msg' => "删除成功"
];
}
}

View File

@ -0,0 +1,544 @@
<?php
namespace app\admin\controller\School;
use app\BaseController;
use app\common\model\School\Student as ModelStudent;
use app\common\model\School\StudentService as ModelStudentService;
use app\common\model\Product\Product as ModelProduct;
use app\common\model\Product\ProductType as ModelProductType;
use app\common\model\Product\ProductParts as ModelProductParts;
use app\common\model\User\User as ModelUser;
use app\Request;
use app\common\arw\adjfut\src\Traverse;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use think\facade\Db;
use think\facade\Env;
use app\common\exception\Map;
class Student extends BaseController
{
public function index()
{
return $user_guid = Request::getCurrentUser()->user_guid;
$jwd = Map::getLongitudeAndLatitude("广东省佛山市顺德区容桂街道保利·德胜湾保利外滩一号");
return $jwd;
// return date('Y-m-d H:i:s', strtotime('+3 month'));
}
/**
* 获取学生列表
*/
public function getStudentList(Request $request)
{
$params = $request->param();
$con = [];
$conOr = [];
if (isset($params['student_name']) && $params['student_name']) {
$con[] = ['student_name', 'LIKE', '%' . $params['student_name'] . '%'];
};
if (isset($params['studnet_phone']) && $params['studnet_phone']) {
$con[] = ['studnet_phone', 'LIKE', '%' . $params['studnet_phone'] . '%'];
};
if (isset($params['student_id_card']) && $params['student_id_card']) {
$con[] = ['student_id_card', 'LIKE', '%' . $params['student_id_card'] . '%'];
};
if (isset($params['student_email']) && $params['student_email']) {
$con[] = ['student_email', 'LIKE', '%' . $params['student_email'] . '%'];
};
if (isset($params['student_sex']) && $params['student_sex']) {
$con[] = ['student_sex', '=', $params['student_sex']];
};
if (isset($params['student_membe_type']) && $params['student_membe_type']) {
$con[] = ['student_membe_type', '=', $params['student_membe_type']];
};
if (isset($params['student_audit_status']) && $params['student_audit_status']) {
$con[] = ['student_audit_status', '=', $params['student_audit_status']];
};
if (isset($params['product_type']) && $params['product_type']) {
$con[] = ['a.product_type', '=', $params['product_type']];
$conOr[] = ['c.product_type_parent_guid', '=', $params['product_type']];
};
if (isset($params['product_guid']) && $params['product_guid']) {
$con[] = ['a.product_guid', '=', $params['product_guid']];
};
if (isset($params['product_parts_guid']) && $params['product_parts_guid']) {
$con[] = ['a.product_parts_guid', '=', $params['product_parts_guid']];
};
if (isset($params['student_brithday']) && $params['student_brithday']) {
$con[] = ['student_brithday', 'BETWEEN', implode(',', $params['student_brithday'])];
};
// return $con;
$query = ModelStudent::alias('a')
->leftjoin('user b', 'a.user_guid = b.user_guid')
->leftjoin('product_type c', 'a.product_type = c.product_type_guid')
->leftjoin('product d', 'a.product_guid = d.product_guid')
->leftjoin('product_parts e', 'a.product_parts_guid = e.product_parts_guid')
->leftjoin('classes f', 'a.classes_guid = f.classes_guid')
->where($con)
->whereOr(function ($query) use ($conOr) {
$query->whereOr($conOr);
});
if (isset($params['student_member_time']) && $params['student_member_time']) {
$query->where("
(
student_member_begin_time >= '{$params['student_member_time'][0]}'
AND
student_member_begin_time <= '{$params['student_member_time'][1]}'
)
OR
(
student_member_end_time >= '{$params['student_member_time'][0]}'
AND
student_member_end_time <= '{$params['student_member_time'][1]}'
)
OR
(
student_member_begin_time >= '{$params['student_member_time'][0]}'
AND
student_member_end_time <= '{$params['student_member_time'][1]}'
)
");
}
$select = self::pageWrapper($query)
->field([
'a.student_id',
'a.student_guid',
'a.student_name',
'a.user_guid',
'b.user_name',
'a.classes_guid',
'f.classes_name',
'a.studnet_phone',
'a.student_id_card',
'a.student_email',
'a.student_sex',
'a.student_price',
'a.student_brithday',
'a.product_type',
'c.product_type_name',
'a.product_guid',
'd.product_name',
'a.product_parts_guid',
'e.product_parts_name',
'a.student_img',
'a.student_banner_img',
'a.student_attachment',
'a.student_intro',
'a.student_location',
'a.longitude',
'a.latitude',
'a.student_membe_type',
'a.student_member_begin_time',
'a.student_member_end_time',
'a.student_audit_status',
'a.student_audit_user_guid',
"(SELECT `user`.`user_name` FROM `user` WHERE `user`.user_guid = `a`.`student_audit_user_guid`) as student_audit_user_name",
])
->append([
'student_member_time',
'student_service',
])
->order('student_update_time', 'desc')
->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 编辑学生
*/
public function editStudent(Request $request)
{
$params = $request->param();
$this->validate($params, [
'student_name|学生名称' => 'require',
'user_guid|用户' => 'require',
'classes_guid|班级' => 'require',
'studnet_phone|手机号' => 'require',
'student_id_card|身份证号' => 'require',
'student_sex|性别' => 'require',
'student_price|学生价格' => 'require',
'product_type|产品类型' => 'require',
'product_guid|产品' => 'require',
'product_parts_guid|产品零件' => 'require',
'student_img|头像' => 'require',
'student_intro|简介' => 'require',
'student_location|家庭住址' => 'require',
'longitude|经度' => 'require',
'latitude|纬度' => 'require'
]);
$model = ModelStudent::where('student_guid', $params['student_guid'])->find();
if (!$model) throwErrorMsg("该学生不存在", 1);
$student_member_time = $params['student_member_time'];
$params['student_member_begin_time'] = $student_member_time[0];
$params['student_member_end_time'] = $student_member_time[1];
// return $params;
$model->allowField([
'student_update_user_guid',
'student_name',
'user_guid',
'classes_guid',
'studnet_phone',
'student_id_card',
'student_email',
'student_sex',
'student_price',
'student_brithday',
'product_type',
'product_guid',
'product_parts_guid',
'student_img',
'student_banner_img',
'student_attachment',
'student_intro',
'student_location',
'longitude',
'latitude',
'student_membe_type',
'student_member_begin_time',
'student_member_end_time',
'student_audit_status',
'student_audit_user_guid'
])->save($params);
// 学生服务编辑
ModelStudent::editStudentService($params);
return [
'code' => 0,
'msg' => '编辑成功'
];
}
/**
* 添加学生
*/
public function addStudent(Request $request)
{
$params = $request->param();
$this->validate($params, [
'student_name|学生名称' => 'require',
'user_name|用户' => 'require',
'classes_guid|班级' => 'require',
'studnet_phone|手机号' => 'require',
'student_id_card|身份证号' => 'require',
'student_sex|性别' => 'require',
'student_price|学生价格' => 'require',
'product_type|产品类型' => 'require',
'product_guid|产品' => 'require',
'product_parts_guid|产品零件' => 'require',
'student_img|头像' => 'require',
'student_intro|简介' => 'require',
'student_location|家庭住址' => 'require',
'longitude|经度' => 'require',
'latitude|纬度' => 'require',
'student_membe_type|会员类型' => 'require',
]);
$params = ModelStudent::initAdd($params);
$model = ModelStudent::create($params, [
'student_guid',
'student_create_user_guid',
'student_update_user_guid',
'student_name',
'user_guid',
'classes_guid',
'studnet_phone',
'student_id_card',
'student_email',
'student_sex',
'student_price',
'student_brithday',
'product_type',
'product_guid',
'product_parts_guid',
'student_img',
'student_banner_img',
'student_attachment',
'student_intro',
'student_location',
'longitude',
'latitude',
'student_membe_type',
'student_member_begin_time',
'student_member_end_time',
'student_audit_status',
'student_audit_user_guid'
]);
if (!$model) throwErrorMsg("添加失败");
$student_guid = $model->student_guid;
// 添加学生服务
ModelStudent::addStudentService($student_guid, $params);
return [
'code' => 0,
'msg' => '添加成功'
];
}
/**
* 删除学生
*/
public function deleteStudent(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'student_guid' => 'require',
]);
$student = ModelStudent::where([
'student_guid' => explode(',', $params['student_guid'])
])->select();
$student->delete();
// 从学生服务(副表)查询出所有当前学生的服务,进行删除
ModelStudentService::where('student_guid', $params['student_guid'])->select()->delete();
return [
'code' => 0,
'msg' => "删除成功"
];
}
/**
* 查找未绑定用户列表
*/
public function notBindUserList(Request $request)
{
$user = $request->param('user');
$con = [
'user_status' => 1,
];
$search = [];
if ($user) {
$search['user_name'] = $user;
}
$query = ModelUser::alias('a')
->join('student b', 'a.user_guid != b.user_guid')
->withSearch(array_keys($search), $search)->where($con)
->whereNotExists(function ($query) {
$query->table('student')->alias('b')->where("a.user_guid = b.user_guid");
});
$select = self::pageWrapper($query)->field([
'a.user_name',
])
->group('user.user_guid')->order([
'user.user_update_time' => 'desc'
])->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 审核学生
*/
public function auditStudent(Request $request)
{
$params = $request->param();
$this->validate($params, [
'student_guid|学生guid' => 'require',
'student_audit_status|审核状态' => 'require|in:2,3',
]);
ModelStudent::auditStudent($params);
return [
'code' => 0,
'msg' => '审核成功'
];
}
/**
* 导出Excel
*/
public function exportExcel(Request $request)
{
$params = $request->param();
return ModelStudent::exportStudent();
}
/**
* 下载导入模板
*/
public function downloadTemplate(Request $request)
{
$params = $request->param();
$data = [
['学生名称', '用户', '班级', '手机号', '身份证号', '邮箱', '性别', '学生价格', '生日', '产品类型', '产品', '产品零件', '头像', '轮播图片', '简介', '家庭住址', '会员类型',]
];
$data[] = ['张思', '负责人', '网络3+2', '19882556281', '110223790813697', '2679599887@163.com', '男', '99.99', '2023-02-19', '小米10', '小米10代手机 全面屏 3亿像素', '小米专属钢化膜', 'https://hjczx.net/intelligent_clique/public/uploads/hjczx//student_img/2022/459/210744-compression.jpg', 'http://aerwen.net/prod-api/student/20230218/C9B76FC1E616EE6A.jpg,http://aerwen.net/prod-api/key/20230217/628A9C1A391ABD61.jpg', '我是三好学生', '广东省佛山市顺德区容桂街道胡锦超职业技术学校', '季卡'];
$excel = (new Excel())->exporTsheet($data);
$excel->save('学生导入模板.xlsx');
}
/**
* 导入excel
*/
public function importExcel(Request $request)
{
$file = new UploadFile('uploads', 'fileExt:xlsx');
$file->putFile('student');
$msg = ModelStudent::ImportStudent($file);
return [
'code' => 0,
'msg' => $msg
];
}
/**
* 获取点击后的产品列表
*/
public function getClickProduct(Request $request)
{
$params = $request->param();
$this->validate($params, [
'product_type_guid|产品类型' => 'require',
]);
$product_type_guid = $params['product_type_guid'];
$products = ModelProduct::alias('a')
->leftjoin('product_type b', "a.product_type_guid = b.product_type_guid")
->where("a.product_type_guid = '$product_type_guid' or b.product_type_parent_guid = '$product_type_guid'")->select();
return [
'code' => 0,
'data' => $products,
'msg' => "获取点击后的产品列表成功"
];
}
/**
* 获取点击后的产品零件列表
*/
public function getClickProductParts(Request $request)
{
$params = $request->param();
$this->validate($params, [
'product_guid|产品' => 'require',
]);
$products_parts = ModelProductParts::where('product_guid', $params['product_guid'])->select();
return [
'code' => 0,
'data' => $products_parts,
'msg' => "获取点击后的产品零件列表成功"
];
}
/**
* 获取侧边产品数据
*/
public function getProductTree(): array
{
$data = [];
$product_types = ModelProductType::field([
'product_type_name',
'product_type_guid',
'product_type_parent_guid',
])->select();
foreach ($product_types as $key => $value) {
$product_type_guid = $value['product_type_guid'];
$product_type_parent_guid = $value['product_type_parent_guid'];
$data[] = [
'id' => $product_type_guid,
'parent_id' => $product_type_parent_guid,
'name' => $value['product_type_name'],
'type' => 'product_type',
'data' => [
'parent_id' => $product_type_parent_guid,
'product_type_guid' => $value['product_type_guid']
],
];
}
$products = ModelProduct::field([
'product_name',
'product_guid',
'product_type_guid',
])->select();
foreach ($products as $value) {
$product_guid = $value['product_guid'];
$product_type_guid = $value['product_type_guid'];
$id = $product_guid;
$data[] = [
'id' => $id,
'parent_id' => $product_type_guid,
'name' => $value['product_name'],
'type' => 'product',
'data' => [
'product_type_guid' => $product_type_guid,
'product_guid' => $product_guid
],
];
$product_parts = ModelProductParts::field([
'product_parts_name',
'product_parts_guid',
'product_guid',
])->where('product_guid', $product_guid)->select();
foreach ($product_parts as $value) {
$product_parts_guid = $value['product_parts_guid'];
$product_guid = $value['product_guid'];
$id = $product_parts_guid;
$data[] = [
'id' => $id,
'parent_id' => $product_guid,
'name' => $value['product_parts_name'],
'type' => 'product_parts',
'data' => [
'product_type_guid' => $product_type_guid,
'product_guid' => $product_guid,
'product_parts_guid' => $product_parts_guid
],
];
}
}
// return $data;
$Traverse = new Traverse('id', 'parent_id');
return $Traverse->tree($data, '0', function (array $value) {
return $value;
});
return [
'code' => 0,
'data' => $data,
'msg' => 'ok'
];
}
}

View File

@ -0,0 +1,133 @@
<?php
namespace app\admin\controller\Tdk;
use app\BaseController;
use app\common\model\Tdk\Tdk as ModelTdk;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use think\facade\Db;
use think\facade\Env;
class Tdk extends BaseController
{
/**
* 获取网站tdk列表
*/
public function getTdkList(Request $request): array
{
$params = $request->param();
$con = [];
if (isset($params['tdk_type']) && $params['tdk_type']) {
$con[] = ['tdk_type', '=', $params['tdk_type']];
};
if (isset($params['tdk_title']) && $params['tdk_title']) {
$con[] = ['tdk_title', 'LIKE', '%' . $params['tdk_title'] . '%'];
};
$query = ModelTdk::where($con);
$select = self::pageWrapper($query)
->field([
'tdk_id',
'tdk_guid',
'tdk_type',
'tdk_title',
'tdk_description',
'tdk_keyword'
])
->order('tdk_update_time', 'desc')
->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 编辑网站tdk
*/
public function editTdk(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'tdk_type|tdk所属模块' => 'require',
'tdk_title|网页标题' => 'require',
'tdk_description|网页简介' => 'require',
'tdk_keyword|网页关键词' => 'require'
]);
$model = ModelTdk::where('tdk_guid', $params['tdk_guid'])->find();
if (!$model) throwErrorMsg("该网站tdk不存在", 1);
$model->allowField([
'tdk_update_user_guid',
'tdk_type',
'tdk_title',
'tdk_description',
'tdk_keyword'
])->save($params);
return [
'code' => 0,
'msg' => '编辑成功'
];
}
/**
* 添加网站tdk
*/
public function addTdk(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'tdk_type|tdk所属模块' => 'require',
'tdk_title|网页标题' => 'require',
'tdk_description|网页简介' => 'require',
'tdk_keyword|网页关键词' => 'require'
]);
$type = ModelTdk::where('tdk_type',$params['tdk_type'])->find();
if($type) throwErrorMsg("{$type->title} 已设置,请勿重复设置!");
$model = ModelTdk::create($params, [
'tdk_guid',
'tdk_create_user_guid',
'tdk_update_user_guid',
'tdk_type',
'tdk_title',
'tdk_description',
'tdk_keyword'
]);
return [
'code' => 0,
'msg' => '添加成功'
];
}
/**
* 删除网站tdk
*/
public function deleteTdk(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'tdk_guid' => 'require',
]);
$tdk = ModelTdk::where([
'tdk_guid' => explode(',', $params['tdk_guid'])
])->select();
$tdk->delete();
return [
'code' => 0,
'msg' => "删除成功"
];
}
}

View File

@ -0,0 +1,371 @@
<?php
namespace app\admin\controller\User;
use app\common\arw\adjfut\src\Traverse;
use app\BaseController;
use app\exception\ErrorMsg;
use app\model\Role;
use app\common\model\Token;
use app\common\model\User\User as ModelUser;
use app\common\model\Role\Role as ModelRole;
use app\common\model\User\UserRole as ModelUserRole;
use app\model\UserRole;
use app\Request;
use think\db\Query;
use think\Exception;
use think\facade\Db;
use app\common\arw\adjfut\src\Validate;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
class User extends BaseController
{
/**
* 获取用户信息
*
* @param Request $request
* @date 2022-03-09
* @example
* @author admin
* @since 1.0.0
*/
public function getUserInfo(Request $request): array
{
$user = $request->getCurrentUser();
return [
'code' => 0,
'data' => [
'user_name' => $user['user_name']
],
'msg' => 'ok'
];
}
/**
* 获取用户菜单
*
* @param Request $request
* @return array
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function getUserMenu(Request $request)
{
// $user = $request->getCurrentUser();
// $menus = [];
// foreach ($user->roles as $role) {
// $menus = array_merge($menus, $role->menus->toArray());
// }
// array_multisort(array_column($menus, 'menu_order'), SORT_DESC, $menus);
// var_dump($menus);
$token = Token::getCurrent();
$menus = $token->token_menu;
$Traverse = new Traverse('menu_guid', 'menu_parent_guid');
$tree = $Traverse->tree($menus, '0', function ($v) {
return [
'key' => $v['menu_guid'],
'name' => $v['menu_name'],
'url' => $v['menu_url'],
'show' => $v['menu_show'],
'icon' => $v['menu_icon'],
];
});
return [
'code' => 0,
'msg' => 'ok',
'data' => $tree
];
}
/**
* 获取用户列表
*
* @param Request $request
* @date 2022-02-25
* @example
* @author admin
* @since 1.0.0
*/
public function getUserList(Request $request): array
{
$user = $request->param('user');
$con = [
// 'user_status' => 1
];
$search = [];
if ($user) {
$search['user_name'] = $user;
}
$query = ModelUser::scope(['admin'])
->withSearch(array_keys($search), $search)->where($con)
->leftjoin('user_role', 'user_role.user_guid = user.user_guid')
->join('role', join(' AND ', [
'role.role_guid = user_role.role_guid',
'role.role_status = 1',
'role.role_delete_time IS NULL',
]), 'left')->where($con);
$select = self::pageWrapper($query)->field([
'user.user_guid',
'user.user_name',
'user.user_phone',
'user.user_position',
'user.user_department',
'user.user_img',
'user.user_status',
'role.role_name',
])
->append([
'roles',
])
->group('user.user_guid')->order([
'user.user_update_time' => 'desc'
])->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 编辑用户
*
* @param Request $request
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function editUser(Request $request): array
{
$params = Validate::param([
'user_guid' => 'require',
'user_name' => 'require',
'roles|角色' => 'require',
]);
$model = ModelUser::where([
'user_guid' => $params['user_guid']
])->find();
if (!$model) {
throwErrorMsg("用户不存在", 1);
}
$model->save($params);
ModelUser::editUserRole($params);
return [
'code' => 0,
'msg' => '编辑成功'
];
}
/**
* 添加用户
*
* @param Request $request
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function addUser(Request $request): array
{
$params = Validate::param([
'user_name' => 'require',
'user_password' => 'require',
'roles|角色' => 'require',
]);
$params['user_status'] = 1;
$model = ModelUser::create($params);
$user_guid = $model->user_guid;
ModelUser::addUserRole($user_guid, $params);
return [
'code' => 0,
'msg' => '添加成功'
];
}
/**
* 删除用户
*
* @param Request $request
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function deleteUser(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'user_guid' => 'require',
]);
$users = ModelUser::where([
'user_guid' => explode(',', $params['user_guid'])
])->select();
$users->delete();
return [
'code' => 0,
'msg' => "删除成功"
];
}
/**
* 更新用户状态
*
* @param Request $request
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function updateUserStatus(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'user_guid' => 'require',
'user_status' => 'require|in:1,2',
]);
$user_status = $params['user_status'];
$users = ModelUser::where([
'user_guid' => explode(',', $params['user_guid'])
])->select();
$users->update([
'user_status' => $user_status
]);
return [
'code' => 0,
'msg' => "更新成功"
];
}
/**
* 重置用户密码
*
* @param Request $request
* @date 2022-02-25
* @example
* @author admin
* @since 1.0.0
*/
public function resetUserPassword(Request $request): array
{
$params = Validate::param([
'user_guid' => 'require',
'password' => 'require',
]);
$password = $params['password'];
$users = ModelUser::select(explode(',', $params['user_guid']));
// $users = ModelUser::where([
// 'user_guid' => ['in', $params['user_guid']]
// ])->select();
$users->update([
'user_password' => $password
]);
return [
'code' => 0,
'msg' => "密码已重置为:$password ,请及时修改密码"
];
}
/**
* 导出Excel
*/
public function exportExcel(Request $request)
{
$user = $request->param('user');
$con = [
// 'user_status' => 1
];
$search = [];
if ($user) {
$search['user_name'] = $user;
}
$select = ModelUser::scope(['admin'])
->where($con)->field([
'user.user_guid',
'user.user_name',
'user.user_phone',
'user.user_position',
'user.user_department',
'user.user_img',
'role.role_name',
])
->append([
'roles',
])
->withSearch(array_keys($search), $search)->where($con)
->leftjoin('user_role', 'user_role.user_guid = user.user_guid')
->join('role', join(' AND ', [
'role.role_guid = user_role.role_guid',
'role.role_status = 1',
'role.role_delete_time IS NULL',
]), 'left')
->group('user.user_guid')->order([
'user.user_update_time' => 'desc'
])->select();
return ModelUser::exportExcel($select);
}
/**
* 下载导入模板
*/
public function downloadTemplate(Request $request)
{
$params = $request->param();
$data = [
[
'用户名',
'头像',
'角色',
'手机号',
'密码',
]
];
$data[] = [
'负责人',
'https://img13.360buyimg.com/n5/jfs/t1/195344/2/24691/95759/6295e145E6fae20b9/1172b44c351eeaab.jpg.avif',
'管理员,部门负责人',
'10086',
'123456@aerwen',
];
$excel = (new Excel())->exporTsheet($data);
$excel->save('用户导入模板.xlsx');
}
/**
* 导入excel
*/
public function importExcel(Request $request)
{
$file = new UploadFile('uploads', 'fileExt:xlsx');
$file->putFile('User');
$msg = ModelUser::importExcel($file);
return [
'code' => 0,
'msg' => $msg
];
}
}

View File

@ -0,0 +1,153 @@
<?php
namespace app\admin\controller\User;
use app\BaseController;
use app\common\model\Role\Role as ModelRole;
use app\common\model\User\User as ModelUser;
use app\common\model\User\UserRole as ModelUserRole;
use app\Request;
class UserRole extends BaseController
{
/**
* 获取未绑定角色用户列表
*
* @param Request $request
* @return void
* @date 2022-03-02
* @example
* @author admin
* @since 1.0.0
*/
public function getUnbindUserList(Request $request): array
{
$role_guid = $request->param('role_guid');
$user = $request->param('user');
$this->validate($request->param(), [
'role_guid' => 'require'
]);
$user_guids = [];
$con = [];
$users = ModelRole::getByRoleGuid($role_guid)->users;
if ($users) {
$user_guids = $users->column('user_guid');
}
if ($user) {
$con['user_name'] = $user;
}
$query = ModelUser::withSearch(['user_name'], $con)->where($con)->where('user_guid', 'not in', $user_guids);
$select = self::pageWrapper($query)->field([
'user_name',
'user_guid',
])->order([
'user_id' => 'desc'
])->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 获取绑定角色用户列表
*
* @param Request $request
* @return void
* @date 2022-03-02
* @example
* @author admin
* @since 1.0.0
*/
public function getBindUserList(Request $request): array
{
$role_guid = $request->param('role_guid');
$user = $request->param('user');
$this->validate($request->param(), [
'role_guid' => 'require'
]);
$user_ids = [];
$con = [];
$users = ModelRole::getByRoleGuid($role_guid)->users;
if ($users) {
$user_ids = $users->column('user_id');
}
if ($user) {
$con['user_name'] = $user;
}
$query = ModelUser::withSearch(['user_name'], $con)->where($con)->where('user_id', 'in', $user_ids);
$select = self::pageWrapper($query)->field([
'user_name',
'user_guid',
])->order([
'user_id' => 'desc'
])->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 绑定用户角色
*
* @param Request $request
* @date 2022-03-02
* @example
* @author admin
* @since 1.0.0
*/
public function bindUserRole(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'user_guid' => 'require',
'role_guid' => 'require',
]);
$users = array_map(function ($v) {
return ModelUser::getByUserGuid($v);
}, explode(',', $params['user_guid']));
$roles = array_map(function ($v) {
return ModelRole::getByRoleGuid($v);
}, explode(',', $params['role_guid']));
ModelUserRole::bindUserRole($users, $roles);
return [
'code' => 0,
'msg' => '绑定成功'
];
}
/**
* 绑定用户角色
*
* @param Request $request
* @date 2022-03-02
* @example
* @author admin
* @since 1.0.0
*/
public function unBindUserRole(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'user_guid' => 'require',
'role_guid' => 'require',
]);
$users = array_map(function ($v) {
return ModelUser::getByUserGuid($v);
}, explode(',', $params['user_guid']));
$roles = array_map(function ($v) {
return ModelRole::getByRoleGuid($v);
}, explode(',', $params['role_guid']));
ModelUserRole::unbindUserRole($users, $roles);
return [
'code' => 0,
'msg' => '解绑成功'
];
}
}

View File

@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
namespace app\admin\middleware;
use app\common\exception\NotAuthApi;
use app\common\model\Token;
use app\common\traits\Auth as TraitsAuth;
use app\Request;
use think\Response;
class Auth
{
use TraitsAuth;
/**
* 忽略登录
*
* @var array
* @date 2023-01-07
* @example
* @author admin
* @since 1.0.0
*/
private $ignoreLogin = [
'Login' => ['*'],
'admin' => ['*'],
];
/**
* 处理请求
*
* @param \app\Request $request
* @param \Closure $next
* @return Response
*/
public function handle(Request $request, \Closure $next): Response
{
$this->request = $request;
if ($this->isIgnoreLogin()) {
return $next($request);
}
if ($request->isLogin()) {
$user = $request->getCurrentUser();
if ($user->user_admin) {
return $next($request);
}
}
$api = join('/', [
$request->controller(),
$request->action()
]);
$token = Token::getCurrent();
/**
* 缓存接口权限验证
*/
$validate = $this->validateApi($token->token_api);
/**
* 缓存权限验证不通过
*/
if ($validate === false) {
/**
* 自定义验证权限
* 如果验证通过刷新缓存接口
*/
$validate = $this->validateUser();
if ($validate) {
Token::getCurrentUser()->login();
}
}
/**
* 权限验证通过
*/
if ($validate) {
return $next($request);
}
throw new NotAuthApi("未授权接口 [ $api ]", 1);
}
}

12
app/admin/route.php Normal file
View File

@ -0,0 +1,12 @@
<?php
// +----------------------------------------------------------------------
// | 路由设置
// +----------------------------------------------------------------------
return [
// 中间件
'middleware' => [
// 接口鉴权
\app\admin\middleware\Auth::class
],
];

View File

@ -0,0 +1,112 @@
<?php
namespace app\api\controller\Crawler;
use app\Request;
use app\common\model\Flow\Flow as ModelFlow;
use think\db\Where;
use think\facade\Validate;
use app\BaseController;
use app\exception\ErrorMsg;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\UploadFile;
use app\common\exception\Tool;
use Goutte\Client;
class Crawler extends BaseController
{
/**
* 爬虫测试
*/
public function Test(Request $request)
{
// return 1;
// 创建Goutte客户端对象
$client = new Client();
// 获取目标网站的URL
$base_url = 'http://avers.fszhijun.com/';
$url = 'http://avers.fszhijun.com/product/1/117.html';
// return $url;
// 发起请求并获取响应对象
$crawler = $client->request('GET', $url);
// 选择要解析的HTML元素
$titles = $crawler->filter('.productsBody .productItem .products');
$imgs = $crawler->filter('.productsBody .productItem .products .productImg');
// return $titles;
// dump($titles);
// die;
$title111 = $titles->filter('.productType')->text();
$img111 = $titles->filter('.productImg')->eq(2)->attr('lazyload');
// return $img111;
// return $title111;
// 在全部元素中筛选
// $products = $crawler->filter('.productsBody .productItem .products');
// foreach ($products as $key => $value) {
// // dump($value->filter('.productType')->eq($key)->text());
// // die;
// foreach ($titles->filter('.productType')->eq($key) as $key => $value) {
// $title = $value->textContent;
// }
// // return $title;
// }
$titleArr = [];
// 遍历元素并输出结果
foreach ($titles as $title) {
$titleArr[] = $title->textContent;
}
return $titleArr;
// $imgArr = [];
foreach ($imgs as $img) {
// var_dump($img->getAttribute('lazyload'));
// die;
// return $img->getAttribute('lazyload');
$src = $img->getAttribute('lazyload');
if (strpos($src, 'http') === 0) {
$img_url = $src;
} else {
$img_url = $base_url . $src;
}
// return $img_url;
// 文件夹名称
$dirName = "product" . "Img";
// 文件保存位置
$fileSaveLocation = public_path('uploads') . $dirName . "\\";
// return $fileSaveLocation;
if (true !== $res = Tool::mkdir($fileSaveLocation)) {
return $res;
}
// 获取图片二进制数据
$imageContent = file_get_contents($img_url);
// var_dump($imageContent);
// die;
// return $imageContent;
// 保存图片到本地文件系统
file_put_contents($fileSaveLocation . basename($img_url), $imageContent);
$res_img_url = "/uoloads" . "/" . $dirName . "/" . basename($img_url);
return $res_img_url;
}
// return $imgArr;
return $titleArr;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace app\api\controller\Flow;
use app\Request;
use app\common\model\Flow\Flow as ModelFlow;
use think\db\Where;
use think\facade\Validate;
use app\BaseController;
use app\exception\ErrorMsg;
use think\facade\Filesystem;
class Flow extends BaseController
{
/**
* 添加流量访问记录
*/
public function AddFlowRecord(Request $request)
{
$params = $request->param();
$this->validate($params, ['flow_target' => 'require']);
$flow_target = $params['flow_target'];
try {
return (new ModelFlow)->track($flow_target);
return json(msg("添加流量访问记录成功"));
} catch (\Throwable $th) {
throwErrorMsg("错误信息:" . $th);
}
}
}

View File

@ -0,0 +1,144 @@
<?php
namespace app\api\controller;
use app\common\arw\adjfut\src\Validate;
use app\BaseController;
use app\common\logic\Login as LogicLogin;
use app\Request;
use think\captcha\facade\Captcha;
use think\middleware\SessionInit;
use think\Response;
class Login extends BaseController
{
/**
* 初始化
*
* @date 2022-03-15
* @example
* @author admin
* @since 1.0.0
*/
protected function initialize(): void
{
$this->middleware[SessionInit::class] = [
'only' => ['accountLogin', 'getCaptcha']
];
}
/**
* 验证token
*
* @param Request $request
* @return void
*/
public function validateToken(Request $request)
{
$token = $request->getCurrentToken();
return [
'code' => 0,
'data' => [
'exp_time' => $token->token_exp_time,
],
'msg' => 'ok'
];
}
/**
* 西北政法大学单点登陆
*
* @param Request $request
* @return Response
* @date 2023-01-04
* @example
* @author admin
* @since 1.0.0
*/
public function casOauthLogin(Request $request): Response
{
$url = $request->param('url');
return LogicLogin::casOauthLogin(
LogicLogin::casOauthLoginHandle($url)
);
}
/**
* 西北政法大学单点登出
*
* @param Request $request
* @return Response
* @date 2023-01-04
* @example
* @author admin
* @since 1.0.0
*/
public function casOauthLogout(Request $request): Response
{
$url = $request->param('url');
return LogicLogin::casOauthLogout($url);
}
/**
* 用户账号登录
*
* @param Request $request
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function accountLogin(Request $request): array
{
$param = Validate::param([
'account|账号' => 'require',
'password|密码' => 'require',
'captcha|验证码' => $request->isProd() ? 'require|captcha' : false
]);
$token = LogicLogin::accountLogin(
$param['account'],
$param['password']
);
return [
'code' => 0,
'data' => [
'token' => $token->token_content,
'exp_time' => $token->token_exp_time,
],
'msg' => 'ok'
];
}
/**
* 生成验证码
*
* @date 2022-03-05
* @example
* @author admin
* @since 1.0.0
*/
public function getCaptcha()
{
return Captcha::create();
}
/**
* 用户登出
*
* @param Request $request
* @date 2022-03-09
* @example
* @author admin
* @since 1.0.0
*/
public function userLogout(Request $request): array
{
$token = $request->getCurrentToken();
$token->logout();
return [
'code' => 0,
'msg' => '登出成功'
];
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace app\api\controller\News;
use app\BaseController;
use app\common\model\News\News as ModelNews;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use think\facade\Db;
use app\common\exception\Tool;
use think\facade\Env;
class News extends BaseController
{
/**
* 获取新闻列表
*/
public function getNewsList(Request $request): array
{
$params = $request->param();
$con = [];
$con = Tool::getOptionalQuery(['news_type', '='],);
$query = ModelNews::where($con)
->field([
'news_id',
'news_guid',
'news_title',
'news_intro',
'news_type',
'news_img',
'news_create_time',
])
->append(['news_created_time'])
->hidden(['news_create_time'])
// ->append('news_create_time')
->order('news_create_time', 'desc');
return msg("获取新闻列表成功!", $query);
}
/**
* 获取新闻详情
*/
public function getNewsInfo(Request $request): array
{
$params = $request->param();
$this->validate($params, ['news_id' => 'require']);
$find = ModelNews::field([
'news_id',
'news_guid',
'news_title',
'news_author',
'news_intro',
'news_type',
'news_img',
'news_content',
'news_num',
'news_create_time'
])
->where('news_id', $params['news_id'])
->find();
if (!$find) throwErrorMsg('该新闻不存在!');
$last_next_id = Tool::getLastNextId(
new ModelNews,
['news_id', $find->news_id],
'all',
[['news_type', '=', $find->news_type]]
);
return msg(0, '获取新闻详情成功!', [
'data' => $find,
'last_id' => $last_next_id[0],
'next_id' => $last_next_id[1],
]);
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace app\api\controller\Product;
use app\BaseController;
use app\common\model\Product\Product as ModelProduct;
use app\common\model\Product\ProductType as ModelProductType;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use app\common\exception\Tool;
use think\facade\Db;
use think\facade\Env;
class Product extends BaseController
{
/**
* 获取产品列表接口
*
* @param Request request
* @date 2023-03-25
* @example
* @author xjh
* @since 1.0.0
*/
public function getProductList(Request $request): array
{
$params = $request->param();
$this->validate($params, [
'product_type_id|产品系列' => 'require',
]);
$product_type = ModelProductType::where('product_type_id', $params['product_type_id'])->find();
if (!$product_type) throwErrorMsg('产品系列不存在!');
$con = [
['product_type_guid', '=', $product_type->product_type_guid]
];
$query = ModelProduct::where($con)
->field([
'product_id',
'product_guid',
'product_type_guid',
'product_name',
'product_img',
'product_price',
])
->withAttr('product_img', function ($value, $data) {
return explode(',', $data['product_img'])[0];
})
->order('product_id', 'desc');
return msg("获取产品列表成功!", $query);
}
/**
* 获取产品详情接口
*
* @param Request request
* @date 2023-04-03
* @example
* @author xjh
* @since 1.0.0
*/
public function getProductInfo(Request $request)
{
$params = $request->param();
$this->validate($params, [
'product_id|产品id' => 'require',
]);
$find = ModelProduct::where('product_id', $params['product_id'])
->field([
'product_id',
'product_guid',
'product_type_guid',
'product_name',
'product_img',
'product_price',
'product_params',
'product_details',
])
->find();
if (!$find) throwErrorMsg('该产品不存在!');
$last_next_id = Tool::getLastNextId(
new ModelProduct,
['product_id', $find->product_id],
'all',
[['product_type_guid', '=', $find->product_type_guid]]
);
return msg(
"获取产品详情成功!",
[
'data' => $find,
'last_id' => $last_next_id[0],
'next_id' => $last_next_id[1],
]
);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace app\api\controller\Product;
use app\BaseController;
use app\common\model\Product\ProductType as ModelProductType;
use app\common\arw\adjfut\src\Traverse;
use app\Request;
use think\Validate;
use think\exception\ValidateException;
use think\facade\Filesystem;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use app\common\exception\Tool;
use think\facade\Db;
use think\facade\Env;
class ProductType extends BaseController
{
/**
* 获取产品系列树形列表接口接口
*
* @param Request request
* @date 2023-04-03
* @example
* @author xjh
* @since 1.0.0
*/
public function getProductTypeTree(Request $request): array
{
$con = Tool::getOptionalQuery(
['b.product_delete_time', 'NULL'],
['a.product_type_name', 'LIKE']
);
$product_type = ModelProductType::field([
'a.product_type_parent_guid',
'a.product_type_name',
'b.product_type_name' => "product_type_parent_name",
'a.product_type_order',
'a.product_type_guid',
'a.product_type_id',
'a.product_type_icon',
'a.product_type_cover',
])
->alias('a')
->leftjoin('product_type b', 'a.product_type_parent_guid = b.product_type_guid')
->where($con)
->order(['product_type_order' => 'asc'])
->select()->toArray();
$Traverse = new Traverse('product_type_guid', 'product_type_parent_guid');
$product_type_tree = $Traverse->tree($product_type, '0', function ($v) {
return [
'product_type_name' => $v['product_type_name'],
'product_type_parent_name' => $v['product_type_parent_name'],
'product_type_guid' => $v['product_type_guid'],
'product_type_id' => $v['product_type_id'],
'product_type_parent_guid' => $v['product_type_parent_guid'],
'product_type_order' => $v['product_type_order'],
'product_type_icon' => $v['product_type_icon'],
'product_type_cover' => $v['product_type_cover'],
];
});
return msg("获取产品系列列表成功!", $product_type_tree);
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace app\api\controller\User;
use app\BaseController;
use app\common\model\User\User as UserUser;
use app\Request;
use app\common\arw\adjfut\src\UploadFile;
use app\common\arw\adjfut\src\Validate;
class User extends BaseController
{
/**
* 编辑用户信息
*/
public function updateUserInfo(Request $request): array
{
$param = Validate::param([
'user_name' => 'require',
'user_phone' => 'require|mobile',
'user_id_card' => 'require'
]);
$user = $request->getCurrentUser();
$user->allowField([
'user_id_card',
'user_phone',
'user_name'
]);
$user->save($param);
return [
'code' => 0,
'msg' => '更新成功'
];
}
/**
* 获取用户列表
*/
public function getUserList(Request $request): array
{
$user = $request->param('user');
$con = [
'user_status' => UserUser::STATUS_ENABLE
];
$search = [];
if ($user) {
$search['user_name'] = $user;
}
$query = UserUser::withSearch(
array_keys($search),
$search
)->where($con);
$select = self::pageWrapper($query)->field([
'user.user_guid',
'user.user_name',
'user.user_phone',
'user.user_position',
'user.user_department',
])->group('user.user_guid')->order([
'user_id' => 'desc'
])->select();
$count = $query->count();
return [
'code' => 0,
'data' => $select,
'count' => $count,
'msg' => 'ok'
];
}
/**
* 获取用户信息
*/
public function getUserInfo(Request $request): array
{
$user = $request->getCurrentUser();
$token = $request->getCurrentToken();
return [
'code' => 0,
'data' => [
'user_img' => $user->user_img,
'user_name' => $user->user_name,
'user_phone' => $user->user_phone,
'user_position' => $user->user_position,
'user_department' => $user->user_department,
'user_create_name' => $user->user_create_name,
'user_department' => $user->user_department,
'user_sex' => $user->user_sex,
'token_update_time' => $token->token_update_time,
],
'msg' => 'ok'
];
}
/**
* 更新用户头像
*/
public function updateUserImg(Request $request): array
{
$user = $request->getCurrentUser();
$upload = new UploadFile('uploads', 'image');
$path = $upload->putFile('UserImg');
$user->user_img = $path;
$user->save();
return [
'code' => 0,
'msg' => '更新成功'
];
}
/**
* 更新用户密码
*/
public function updateUserPassword(Request $request): array
{
$param = Validate::param([
'origin' => 'require',
'new' => 'require',
]);
$user = $request->getCurrentUser();
$origin = UserUser::encryptPassword($param['origin']);
if ($origin != $user->user_password) {
throwErrorMsg('原密码错误');
}
$user->user_password = $param['new'];
$user->save();
return [
'code' => 0,
'msg' => '修改成功'
];
}
}

View File

@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace app\api\middleware;
use app\common\exception\NotAuthApi;
use app\common\model\Token;
use app\common\traits\Auth as TraitsAuth;
use app\Request;
use think\Response;
class Auth
{
use TraitsAuth;
/**
* 忽略登录
*
* @var array
* @date 2023-01-07
* @example
* @author admin
* @since 1.0.0
*/
private $ignoreLogin = [
'Login' => ['*'],
'admin' => ['*'],
'Consult' => ['*'],
];
/**
* 处理请求
*
* @param \app\Request $request
* @param \Closure $next
* @return Response
*/
public function handle(Request $request, \Closure $next): Response
{
$this->request = $request;
if ($this->isIgnoreLogin()) {
return $next($request);
}
if ($request->isLogin()) {
$user = $request->getCurrentUser();
if ($user->user_admin) {
return $next($request);
}
}
$api = join('/', [
$request->controller(),
$request->action()
]);
$token = Token::getCurrent();
/**
* 缓存接口权限验证
*/
$validate = $this->validateApi($token->token_api);
/**
* 缓存权限验证不通过
*/
if ($validate === false) {
/**
* 自定义验证权限
* 如果验证通过刷新缓存接口
*/
$validate = $this->validateUser();
if ($validate) {
Token::getCurrentUser()->login();
}
}
/**
* 权限验证通过
*/
if ($validate) {
return $next($request);
}
throw new NotAuthApi("未授权接口 [ $api ]", 1);
}
}

12
app/api/route.php Normal file
View File

@ -0,0 +1,12 @@
<?php
// +----------------------------------------------------------------------
// | 路由设置
// +----------------------------------------------------------------------
return [
// 中间件
'middleware' => [
// 接口鉴权
// \app\api\middleware\Auth::class
],
];

178
app/common.php Normal file
View File

@ -0,0 +1,178 @@
<?php
// 应用公共文件
use app\common\arw\adjfut\src\Exception\ErrorMsg;
use app\BaseController;
use think\facade\Request;
use think\facade\Validate;
use think\Collection;
use think\db\Query;
use think\Validate as ThinkValidate;
const DS = DIRECTORY_SEPARATOR;
function fump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE)
{
$label = (null === $label) ? '' : rtrim($label) . ':';
ob_start();
var_dump($var);
$output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', ob_get_clean());
if (!extension_loaded('xdebug')) {
$output = htmlspecialchars($output, $flags);
}
$output = '<pre>' . $label . $output . '</pre>';
if ($echo) {
echo ($output);
return;
}
return $output;
}
/**
* 抛出业务异常
*
* @param string $msg
* @param integer $code
* @return void
* @throws ErrorMsg
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
function throwErrorMsg(string $msg, int $code = 1): void
{
throw new ErrorMsg($msg, $code);
}
/**
* 计算年龄
*
* @param string $birthday Y-m-d
* @return int
* @date 2022-03-11
* @example
* @author admin
* @since 1.0.0
*/
function sumAge($birthday): int
{
$age = 0;
try {
if (!is_string($birthday)) {
throw new ErrorMsg("非法日期", 1);
}
$birthday = explode("-", date('Y-m-d', strtotime($birthday)));
$date = explode("-", date('Y-m-d'));
if (count($birthday) === 3) {
list($y, $m, $d) = $birthday;
} else {
list($y, $m, $d) = $date;
}
// list($y, $m, $d) = $birthday;
list($dy, $dm, $dd) = $date;
$age = $dy - $y;
if ($dm >= $m) {
if ($dm == $m) {
if ($dd >= $d) {
} else {
$age--;
}
}
} else {
$age--;
}
return $age;
} catch (\Throwable $th) {
}
return $age;
}
Validate::maker(function (ThinkValidate $validate) {
$validate->extend(
'string',
function ($value) {
return is_string($value);
},
':attribute 数据类型非法 不是字符串'
);
});
/**
* 接口返回封装
*/
function msg(...$arr)
{
$msg_data = ['code' => 0];
$default_code_msg = [0 => '操作成功!', 1 => '操作失败!'];
//data数据构建
function constructData(&$msg_data, $code, $msg_str, &$arr2)
{
$msg_data['code'] = $code;
$msg_data['msg'] = $msg_str;
if (is_array($arr2)) { //数组
$msg_data['data'] = $arr2;
}
if (is_object($arr2)) { //查询对象
$obj = $arr2;
$soft_delete_field = '_delete_time'; //软删除默认后缀
//模型层 || Db层
if ($obj instanceof think\db\Query || $obj instanceof think\Collection) {
//join软删除字段过滤补全(暂时只适应软删除为 【前缀名_delete_time】存储为datetime 的设计)
if (isset($obj->getOptions()['join']) && $join_data = $obj->getOptions('join')) {
$join_soft_delete = [];
foreach ($join_data as $key => $join) {
$join_table_name = is_array($join[0]) ? array_keys($join[0])[0] : $join[0]; //联表表名
$join_soft_delete[] = [$join_table_name . $soft_delete_field, 'NULL', null];
}
$obj = $obj->where($join_soft_delete);
}
//select()、count()补全
$msg_data['data'] = $obj->page((int) Request::param('page', 1), (int) Request::param('limit', 10))->select();
$msg_data['count'] = $obj->count();
} else {
return ['code' => 444, 'msg' => '对象只允许传递来自think\db\Query类和instanceof think\Collection类的实例!'];
}
}
};
switch (count($arr)) {
case 1: //单参数
constructData($msg_data, 0, '查询成功!', $arr[0],);
if (is_string($arr[0])) $msg_data['msg'] = $arr[0];
if (is_int($arr[0])) {
$msg_data['code'] = $arr[0];
$msg_data['msg'] = $default_code_msg[$arr[0]];
}
break;
case 2: //双参数
if (is_int($arr[0]) && is_string($arr[1])) {
$msg_data['code'] = $arr[0];
$msg_data['msg'] = $arr[1];
} else {
constructData($msg_data, 0, $arr[0], $arr[1]);
}
break;
case 3: //三参数
$msg_data['code'] = $arr[0];
$msg_data['msg'] = $arr[1];
if (is_object($arr[2])) {
$msg_data['data'] = $arr[2];
} else {
foreach ($arr[2] as $key => $val)
$msg_data[$key] = $val;
}
break;
default:
return ['code' => 444, 'msg' => 'msg()最多参数只允许3个!'];
}
return $msg_data;
}

View File

@ -0,0 +1,39 @@
{
"name": "arw/adjfut",
"type": "library",
"autoload": {
"psr-4": {
"arw\\adjfut\\": "src/"
}
},
"authors": [{
"name": "arw",
"email": "2679599887@qq.com"
}],
"require": {
"php": ">=7.1.0",
"phpoffice/phpspreadsheet": "^1.12",
"topthink/framework": "^6.0.0",
"topthink/think-filesystem": "^2.0"
},
"config": {
"sort-packages": true
},
"repositories": {
"packagist": {
"type": "composer",
"url": "https://mirrors.aliyun.com/composer/"
}
},
"extra": {
"think": {
"services": [
"arw\\adjfut\\Service\\Validate"
],
"config": {
"wechat": "src/Config/wechat.php",
"chunkUpload": "src/Config/chunkUpload.php"
}
}
}
}

View File

@ -0,0 +1,170 @@
<?php
namespace app\common\arw\adjfut\src;
use ArrayAccess;
class ArrayFilter implements ArrayAccess
{
/**
* 数据
*
* @var array
* @date 2023-01-13
* @example
* @author arw
* @since 1.0.0
*/
private $data = [];
/**
* 初始化
*
* @param array $data
* @date 2023-01-13
* @example
* @author arw
* @since 1.0.0
*/
public function __construct(array $data)
{
$this->data = $data;
}
/**
* 二维数组排除字段
*
* @param array $array
* @param array $except
* @return array
* @date 2023-01-13
* @example
* @author arw
* @since 1.0.0
*/
public static function exceptFields(array $array, array $except): array
{
foreach ($array as &$value) {
$self = new self($value);
$value = $self->except($except)->toArray();
unset($value, $self);
}
return $array;
}
/**
* 二维数组指定字段
*
* @param array $array
* @param array $only
* @return array
* @date 2023-01-13
* @example
* @author arw
* @since 1.0.0
*/
public static function onlyFields(array $array, array $only): array
{
foreach ($array as &$value) {
$self = new self($value);
$value = $self->only($only)->toArray();
unset($value, $self);
}
return $array;
}
/**
* 排除某些变量
*
* @param array $fields
* @return self
* @date 2023-01-13
* @example
* @author arw
* @since 1.0.0
*/
public function except(array $fields): self
{
$data = $this->data;
// $fields = [id,name]
foreach ($fields as $field) {
if (isset($data[$field])) {
unset($data[$field]);
}
}
return new self($data);
}
/**
* 获取部分变量
*
* @param array $fields
* @return self
* @date 2023-01-13
* @example
* @author arw
* @since 1.0.0
*/
public function only(array $fields): self
{
$data = $this->data;
$result = [];
// $fields = [id,name]
// $fields = [id=>0,name=>asdasd]
foreach ($fields as $key => $value) {
if (is_int($key)) {
if (isset($data[$value])) {
$result[$value] = $data[$value];
}
} else {
$result[$key] = isset($data[$key]) ? $data[$key] : $value;
}
}
return new self($result);
}
/**
* 获取数据
*
* @return array
* @date 2023-01-13
* @example
* @author arw
* @since 1.0.0
*/
public function toArray(): array
{
return $this->data;
}
public function __get($name)
{
return $this->offsetGet($name);
}
public function __set($name, $value)
{
return $this->offsetSet($name, $value);
}
public function offsetExists($offset): bool
{
return isset($this->data[$offset]);
}
public function offsetGet($offset)
{
return $this->data[$offset];
}
public function offsetSet($offset, $value): void
{
$this->data[$offset] = $value;
}
public function offsetUnset($offset): void
{
unset($this->data[$offset]);
}
}

View File

@ -0,0 +1,174 @@
<?php
namespace app\common\arw\adjfut\src;
use think\helper\Arr;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
class Base64
{
/**
* 类型
*
* @var string
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
private $type = '';
/**
* base64内容
*
* @var string
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
private $body = '';
/**
* base64
*
* @var string
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
private $base64 = '';
/**
* 文件后缀映射
*/
private const FILE_EXT_MAP = [
'text/html' => 'html',
'text/css' => 'css',
'text/javascript' => 'js',
'image/gif' => 'gif',
'image/png' => 'png',
'image/jpeg' => 'jpg',
'image/x-icon' => 'ico',
];
/**
* 实例化
*
* @param string $base64
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public function __construct(string $base64)
{
$parse = self::parse($base64);
$this->base64 = $base64;
$this->type = $parse['type'];
$this->body = $parse['body'];
}
/**
* 获取文件后缀
*
* @return string
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public function getFileExt(): string
{
return Arr::get(self::FILE_EXT_MAP, $this->type, '');
}
/**
* 判断是否是base64图片字符串
*
* @return boolean
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public function isImage(): bool
{
return in_array($this->type, [
'image/gif',
'image/png',
'image/jpeg',
'image/x-icon',
]);
}
/**
* 保存base64图片
*
* @param string $path
* @return void
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public function saveImage(string $path): void
{
file_put_contents($path, base64_decode($this->body));
}
/**
* 判断是否是base64图片字符串
*
* @param string $base64
* @return boolean
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public static function isBase64Image(string $base64): bool
{
$ins = new self($base64);
return $ins->isImage();
}
/**
* 保存base64图片
*
* @param string $base64
* @param string $path
* @return void
*/
public static function saveBase64Image(string $base64, string $path): void
{
$ins = new self($base64);
$ins->saveImage($path);
}
/**
* 解析base64
*
* @param string $base64
* @return array
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
private static function parse(string $base64): array
{
$prefix = 'data:';
$validate = substr($base64, 0, strlen($prefix)) === $prefix;
if (!$validate) {
throw new ErrorMsg("非法base64 开头data:", 1);
}
$explode = explode(';base64,', $base64);
if (count($explode) != 2) {
throw new ErrorMsg("非法base64 不存在;base64,", 1);
}
list($type, $body) = $explode;
$type = str_replace('data:', '', $type);
return [
'type' => $type,
'body' => $body
];
}
}

View File

@ -0,0 +1,258 @@
<?php
namespace app\common\arw\adjfut\src;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
use think\facade\Filesystem;
use think\facade\Request;
use think\file\UploadedFile;
use think\filesystem\Driver;
use think\helper\Arr;
class ChunkUpload
{
/**
* 磁盘
*
* @var string
*/
private static $disk = null;
/**
* id
*
* @var string
*/
private $id = null;
/**
* 上传文件
*
* @var UploadedFile
*/
private $file = null;
/**
* 合并文件
*
* @var UploadedFile
*/
private $mergeFile = null;
/**
* 初始化
*
* @param string $id 上传id
* @param string $name 上传id
* @param UploadedFile|string|array $file 文件
* @date 2022-08-21
* @example
* @author arw
* @since 1.0.0
*/
public function __construct(string $id, $file = 'file')
{
$this->id = $id;
if (is_string($file)) {
$file = Request::file($file);
}
if (is_array($file)) {
$file = new UploadedFile(...$file);
}
if (!($file instanceof UploadedFile)) {
throw new ErrorMsg("非法文件", 1);
}
$this->file = $file;
}
/**
* 获取存储配置
*
* @return Driver
* @date 2022-08-21
* @example
* @author arw
* @since 1.0.0
*/
public function getDisk(): Driver
{
return Filesystem::disk(self::$disk);
}
/**
* 分片是否上传完成
*
* @return boolean
* @date 2022-08-22
* @example
* @author arw
* @since 1.0.0
*/
public function isDone(): bool
{
return $this->isDone;
}
/**
* 合并文件
*
* @return self
* @date 2022-08-21
* @example
* @author arw
* @since 1.0.0
*/
public function merge(string $name): self
{
if (!$this->isDone()) {
throw new ErrorMsg("文件未上传完成 禁止合并", 1);
}
$id = $this->id;
$root = self::getDiskConfig('root');
$path = join('', [
$root,
$id,
'.' . pathinfo($name, PATHINFO_EXTENSION)
]);
for ($i = 0; $i <= $this->total; $i++) {
$_path = $root . $id . DIRECTORY_SEPARATOR . $i;
file_put_contents(
$path,
file_get_contents($_path),
FILE_APPEND
);
unlink($_path);
}
rmdir($root . $id);
$this->mergeFile = new UploadedFile($path, $name);
return $this;
}
/**
* 获取合并文件
*
* @return UploadedFile
* @date 2022-08-22
* @example
* @author arw
* @since 1.0.0
*/
public function getMergeFile(): UploadedFile
{
if (!$this->mergeFile) {
throw new ErrorMsg("未合并文件", 1);
}
return $this->mergeFile;
}
/**
* 获取上传文件
*
* @param string $diskName
* @param string $validate
* @return UploadFile
* @date 2022-08-22
* @example
* @author arw
* @since 1.0.0
*/
public function getUploadFile(string $diskName, string $validate = ''): UploadFile
{
return new UploadFile(
$diskName,
$validate,
$this->getMergeFile()
);
}
/**
* 保存文件
*
* @param integer $index
* @param integer $total
* @return self
* @date 2022-08-21
* @example
* @author arw
* @since 1.0.0
*/
public function put(int $index, int $total): self
{
$this->total = $total;
$this->getDisk()->putFileAs(
$this->id,
$this->file,
$index
);
$this->isDone = $index === $total;
return $this;
}
/**
* 删除文件
*
* @return void
* @date 2022-08-22
* @example
* @author arw
* @since 1.0.0
*/
public function delete(): void
{
$this->getDisk()->delete($this->getMergeFile()->getFilename());
}
/**
* 初始化配置
*
* @param array $config
* @return void
* @date 2022-08-21
* @example
* @author arw
* @since 1.0.0
*/
public static function init(array $config): void
{
self::$disk = Arr::get($config, 'disk', '');
$type = self::getDiskConfig('type');
if ($type != 'local') {
throw new ErrorMsg("分片上传仅支持 local类型磁盘", 1);
}
}
/**
* 获取磁盘配置
*
* @param string $name
* @param mixed $default
* @return mixed
* @date 2022-08-22
* @example
* @author arw
* @since 1.0.0
*/
public static function getDiskConfig($name = null, $default = null)
{
return Filesystem::getDiskConfig(self::$disk, $name, $default);
}
/**
* 生成上传唯一id
*
* @return string
* @date 2022-08-21
* @example
* @author arw
* @since 1.0.0
*/
public static function generateUploadId(): string
{
return md5(join('-', [
Request::ip(),
time()
]));
}
}

View File

@ -0,0 +1,9 @@
<?php
// +----------------------------------------------------------------------
// | ChunkUpload配置文件
// +----------------------------------------------------------------------
return [
// 磁盘
'disk' => ''
];

View File

@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | Wechat配置文件
// +----------------------------------------------------------------------
return [
// 中控层 access_key
'access_key' => '',
// 中控层地址
'server_base' => 'http://clique.dszjjt.com:7001/',
// 公众号配置
'gzh' => [
// 缓存key
'cache_key' => 'wechat.gzh',
// 日志通道
'log_channel' => 'wechat/gzh',
// 公众号模板推送
'template' => [
// {{first.DATA}}
// 申请人:{{keyword1.DATA}}
// 申请时间:{{keyword2.DATA}}
// 调课时间:{{keyword3.DATA}}
// {{remark.DATA}}
'申请审核通知' => 'iLuqzUrQM8-v_7ilxageUZoi9v-SQWipkTYVZXB1GeI'
],
'appid' => 'wx99caf571c9fb1cc5',
'secret' => '61100d9c4fff5acf97517f0c8799e2e2',
],
// 小程序配置
'xcx' => [
// 缓存key
'cache_key' => 'wechat.xcx',
// 日志通道
'log_channel' => 'wechat/xcx',
'appid' => 'wx2495492e15854b02',
'secret' => '5b4fcb27324398083fba4a3c39e8a557',
],
];

View File

@ -0,0 +1,790 @@
<?php
namespace app\common\arw\adjfut\src;
use \CurlHandle;
use think\Exception;
class Curl
{
/**
* 请求前缀
*
* @var string
*/
private $baseUrl = '';
/**
* 返回数据类型
*
* @var string
*/
private $dataType = 'json';
/**
* 事件
*
* @var array
*/
private $event = [];
/**
* 绑定
*
* @var array
*/
private $bind = [];
/**
* 配置项
*
* @var array
*/
private $config = [
/**
* http header
*/
CURLOPT_HTTPHEADER => [],
/**
* http 超时
*/
CURLOPT_TIMEOUT => 0,
/**
* http 代理
*/
CURLOPT_PROXY => '',
/**
* http 代理端口
*/
CURLOPT_PROXYPORT => '',
/**
* 来源页面
*/
CURLOPT_REFERER => '',
/**
* 用户代理
*/
CURLOPT_USERAGENT => '',
/**
* 响应中是否显示header
*/
CURLOPT_HEADER => 0
];
/**
* Get请求参数
*
* @var null
*/
private $httpParams = null;
/**
* Post请求参数
*
* @var null
*/
private $httpData = null;
/**
* 异常信息
*
* @var string
*/
private $error = '';
/**
* url是否编码
*
* @var boolean
*/
private $urlEncode = false;
/**
* 验证http请求状态码
*
* @var boolean
*/
private $httpCode = true;
/**
* 请求路径
*
* @var string
*/
private $path = '';
/**
* 请求url
*
* @var string
*/
private $url = '';
/**
* 请求类型
*
* @var string
*/
private $method = 'get';
/**
* 返回内容
*
* @var string
*/
private $content = '';
/**
* 请求信息
*
* @var array
*/
private $status = [];
/**
* 调试模式
*
* @var boolean
*/
private $debug = false;
/**
* 是否上传文件
*
* @var boolean
*/
private $isUploadFile = false;
/**
* 初始化
*
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
public function __construct()
{
}
/**
* 初始化请求
*
* @return $this
*/
public static function instance()
{
return new self;
}
/**
* 获取请求url
*/
public function getUrl(): string
{
return $this->url;
}
/**
* 获取请求路径
*/
public function getPath(): string
{
return $this->path;
}
/**
* 获取返回内容
*
* @return string
*/
public function getContent(): string
{
return $this->content;
}
/**
* 格式化返回
*
* @param string $type 返回类型(默认使用 $this->dataType
* @return mixed
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
public function formatContent(string $type = '')
{
$content = $this->content;
if (!$type) {
$type = $this->dataType;
}
switch ($type) {
case 'json':
case 'object':
return json_decode($content, $type === 'json');
break;
default:
return $content;
break;
}
}
/**
* 获取请求信息
*/
public function getStatus(): array
{
return $this->status;
}
/**
* 设置是否上传文件
*/
public function setIsUploadFile(bool $isUploadFile): self
{
$this->isUploadFile = $isUploadFile;
return $this;
}
/**
* 设置请求路径
*/
public function setPath(string $path): self
{
if (count(explode('?', $path)) != 1) {
throw new Exception("请求路径不能携带参数 请使用setParams设置请求参数", 1);
}
$this->path = $path;
return $this;
}
/**
* 设置调试模式
*/
public function setDeBug(bool $debug): self
{
$this->debug = $debug;
return $this;
}
/**
* 验证http状态码
*
* @param boolean|int $code
*/
public function setHttpCode($code): self
{
$this->httpCode = $code;
return $this;
}
/**
* 设置url是否编码
*/
public function setUrlEncode(bool $urlEncode): self
{
$this->urlEncode = $urlEncode;
return $this;
}
/**
* 设置请求前缀
*/
public function setBaseUrl(string $baseUrl): self
{
if (count(explode('?', $baseUrl)) != 1) {
throw new Exception("请求前缀不能携带参数 请使用setParams设置请求参数", 1);
}
$this->baseUrl = $baseUrl;
return $this;
}
/**
* 设置返回数据类型
*/
public function setDataType(string $dataType): self
{
$this->dataType = $dataType;
return $this;
}
/**
* 设置http header
*/
public function setHeader(array $header): self
{
$_header = [];
foreach ($header as $key => $value) {
if (is_numeric($key)) {
$_header[] = $value;
} else {
$_header[] = "$key: $value";
}
}
$this->config[CURLOPT_HTTPHEADER] = array_merge($this->config[CURLOPT_HTTPHEADER], $_header);
return $this;
}
/**
* 设置http 超时
*/
public function setTimeout(int $time): self
{
$this->config[CURLOPT_TIMEOUT] = $time <= 0 ? 5 : $time;
return $this;
}
/**
* 设置http 代理
*/
public function setProxy(string $proxy): self
{
$this->config[CURLOPT_PROXY] = $proxy;
return $this;
}
/**
* 设置http 代理端口
*/
public function setProxyPort(int $port): self
{
$this->config[CURLOPT_PROXYPORT] = $port;
return $this;
}
/**
* 设置来源页面
*/
public function setReferer(string $referer = ""): self
{
$this->config[CURLOPT_REFERER] = $referer;
return $this;
}
/**
* 设置用户代理
*/
public function setUserAgent(string $agent = ""): self
{
$this->config[CURLOPT_USERAGENT] = $agent;
return $this;
}
/**
* http响应中是否显示header
*/
public function showResponseHeader(bool $show): self
{
$this->config[CURLOPT_HEADER] = $show ? 1 : 0;
return $this;
}
/**
* 获取get请求参数
*/
public function getParams()
{
return $this->httpParams;
}
/**
* 设置get请求的参数
*/
public function setParams($params): self
{
$_params = $this->trigger('beforeSetParams', [$params]);
$this->httpParams = $_params ? $_params : $params;
return $this;
}
/**
* 获取post请求参数
*/
public function getData()
{
return $this->httpData;
}
/**
* 设置post请求的参数
*/
public function setData($data): self
{
$_data = $this->trigger('beforeSetData', [$data]);
$this->httpData = $_data ? $_data : $data;
return $this;
}
/**
* 设置http请求的cookie信息
*/
public function setCookie(array $cookie): self
{
$_cookie = [];
foreach ($cookie as $key => $value) {
$_cookie[] = "$key=$value";
}
$this->config[CURLOPT_COOKIE] = join(';', $_cookie);
return $this;
}
/**
* 设置证书路径
*/
public function setCainfo(string $file): self
{
$this->config[CURLOPT_CAINFO] = $file;
return $this;
}
/**
* 获取请求异常
*/
public function getError(): string
{
return $this->error;
}
/**
* 绑定
*
* @param string $name
* @param callable $cb
* @date 2022-03-26
* @example
* @author arw
* @since 1.0.0
*/
public function bind(string $name, callable $cb): self
{
$this->bind[$name] = $cb;
return $this;
}
/**
* GET请求
* @param string $path
* @return mixed
*/
public function get(string $path = '')
{
if ($path) {
$this->setPath($path);
}
$this->method = 'get';
$respone = $this->fetch();
if (!$path) {
return $this;
}
return $respone;
}
/**
* POST请求
*
* @param string $path
* @return mixed
*/
public function post(string $path = '')
{
if ($path) {
$this->setPath($path);
}
$this->method = 'post';
$respone = $this->fetch();
if (!$path) {
return $this;
}
return $respone;
}
/**
* PUT请求
*
* @param string $path
* @return mixed
*/
public function put(string $path = '')
{
if ($path) {
$this->setPath($path);
}
$this->method = 'put';
$respone = $this->fetch();
if (!$path) {
return $this;
}
return $respone;
}
/**
* DELETE请求
*
* @param string $path
* @return mixed
*/
public function delete(string $path = '')
{
if ($path) {
$this->setPath($path);
}
$this->method = 'delete';
$respone = $this->fetch();
if (!$path) {
return $this;
}
return $respone;
}
/**
* PATCH请求
*
* @param string $path
* @return mixed
*/
public function patch(string $path = '')
{
if ($path) {
$this->setPath($path);
}
$this->method = 'patch';
$respone = $this->fetch();
if (!$path) {
return $this;
}
return $respone;
}
/**
* 设置get传参前
*
* @param callable $cb($params)
* @param mixed $params 参数
* @date 2022-03-26
* @example
* @author arw
* @since 1.0.0
*/
public function onBeforeSetParams(callable $cb): self
{
return $this->event('beforeSetParams', $cb);
}
/**
* 设置post传参前
*
* @param callable $cb($data)
* @param mixed $data 参数
* @date 2022-03-26
* @example
* @author arw
* @since 1.0.0
*/
public function onBeforeSetData(callable $cb): self
{
return $this->event('beforeSetData', $cb);
}
/**
* 请求前
*
* @param callable $cb($ch)
* @param self $ch
* @date 2022-03-26
* @example
* @author arw
* @since 1.0.0
*/
public function onBeforeFetch(callable $cb): self
{
return $this->event('beforeFetch', $cb);
}
/**
* 请求后
*
* @param callable $cb($ch,$info)
* @param self $ch
* @param array $info
* @param string $info[url] 请求完整url
* @param string $info[content] 返回信息
* @param array $info[status] 请求信息
* @date 2022-03-26
* @example
* @author arw
* @since 1.0.0
*/
public function onAfterFetch(callable $cb)
{
return $this->event('afterFetch', $cb);
}
/**
* 请求异常(返回true阻止抛出异常)
*
* @param callable $cb($ch,$th)
* @param self $ch
* @param \Throwable $th
* @date 2022-03-26
* @example
* @author arw
* @since 1.0.0
*/
public function onFetchError(callable $cb)
{
return $this->event('fetchError', $cb);
}
/**
* 发起请求
*
* @return mixed
* @date 2022-03-25
* @example
* @author arw
* @since 1.0.0
*/
public function fetch()
{
$this->url = $url = $this->baseUrl . $this->path;
$this->trigger('beforeFetch', [$this]);
try {
$httpParams = $this->httpParams;
if (!empty($httpParams) && is_array($httpParams)) {
$url .= (strpos($url, '?') === false ? '?' : '') . http_build_query($httpParams);
}
if ($this->urlEncode === false) {
$url = urldecode($url);
}
$ch = $this->curlInit($url);
// 设为TRUE把curl_exec()结果转化为字串,而不是直接输出
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$this->content = $content = curl_exec($ch);
$this->status = $status = curl_getinfo($ch);
if ($content === false) {
$this->error = curl_error($ch);
}
if ($this->debug) {
dump([
'ch' => $ch,
'url' => $url,
'httpParams' => $this->httpParams,
'httpData' => $this->httpData,
'contentArray' => json_decode($content, true),
'content' => $content,
'status' => $status
]);
}
curl_close($ch);
$httpCode = $this->httpCode;
if ($httpCode === true) {
$httpCode = 200;
}
if (is_numeric($httpCode)) {
if (!isset($status['http_code'])) {
throw new Exception("服务器未返回状态码", 1);
}
if ($status['http_code'] !== $httpCode) {
throw new Exception(sprintf("服务器返回状态码异常[ %s ]", $status['http_code']), 1);
}
}
$this->trigger('afterFetch', [$this, [
'url' => $url,
'content' => $content,
'status' => $status
]]);
return $this->formatContent();
} catch (\Throwable $th) {
if (!$this->trigger('fetchError', [$this, $th])) {
throw $th;
}
}
}
public function __call($name, $arguments)
{
array_unshift($arguments, $this);
call_user_func_array($this->bind[$name], $arguments);
}
/**
* 事件
*
* @param string $type beforeSetParams | beforeSetData | beforeFetch | AfterFetch
* @param callable $cb
*/
private function event(string $type, callable $cb): self
{
$this->event[strtoupper($type)] = $cb;
return $this;
}
/**
* 事件触发器
*
* @param string $type
* @return mixed
* @date 2022-03-25
* @example
* @author arw
* @since 1.0.0
*/
private function trigger(string $type, array $args = [])
{
$type = strtoupper($type);
if (isset($this->event[$type])) {
return call_user_func_array($this->event[$type], $args);
}
}
/**
* 初始化请求
*
* @param string $url
* @return resource|CurlHandle
* @date 2022-04-24
* @example
* @author arw
* @since 1.0.0
*/
private function curlInit(string $url)
{
$ch = curl_init($url);
if (stripos($url, 'https://') !== false) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
}
foreach ($this->config as $option => $value) {
if (!$value && $option != CURLOPT_HEADER) {
continue;
}
curl_setopt($ch, $option, $value);
}
switch ($this->method) {
case 'get':
break;
case 'post':
curl_setopt($ch, CURLOPT_POST, true);
break;
default:
// delete put patch
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($this->method));
break;
}
$httpData = $this->httpData;
// 设置post body
if ($httpData) {
$data = null;
if (is_array($httpData)) {
if ($this->isUploadFile) {
$data = $httpData;
} else {
$data = http_build_query($httpData);
}
} else if (is_string($httpData)) {
$data = $httpData;
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
return $ch;
}
}

View File

@ -0,0 +1,519 @@
<?php
namespace app\common\arw\adjfut\src;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use think\helper\Arr;
use think\helper\Str;
use think\Validate;
use app\common\arw\adjfut\src\Traits\Event;
use think\facade\Env;
class Excel
{
use Event;
/**
* Spreadsheet
*
* @var Spreadsheet
*/
private $spreadsheet = null;
/**
* 工作表样式
*
* @var array
*/
private $worksheetStyle = [];
/**
* 文件路径
*
* @var string
* @date 2022-04-15
* @example
* @author arw
* @since 1.0.0
*/
private $path = '';
/**
* 初始化
*
* @param string|UploadFile $path
* @date 2022-04-15
* @example
* @author arw
* @since 1.0.0
*/
public function __construct($path = '')
{
if ($path) {
if ($path instanceof UploadFile) {
$path = $path->getRealPath();
}
$this->spreadsheet = self::loadExcel($path);
$this->path = $path;
} else {
$this->spreadsheet = new Spreadsheet();
}
}
/**
* 设置工作表样式
*
* @param array $options
* @param boolean $options[autoBorder] 是否自动添加边框
* @param boolean $options[freezeLine] 是否自动冻结首行
* @return self
*/
public function setWorksheetStyle(array $options): self
{
$this->worksheetStyle = $options;
return $this;
}
/**
* 获取当前Spreadsheet
*
* @return Spreadsheet
* @date 2020-11-23
* @example
* @author arw
* @since 1.0.0
*/
public function getSpreadsheet(): Spreadsheet
{
return $this->spreadsheet;
}
/**
* 读取excel
*
* @param string $path excel路径
* @return Spreadsheet
*/
public static function loadExcel(string $path): Spreadsheet
{
if (!is_file($path)) {
throw new ErrorMsg("文件不存在 $path", 1);
}
$ext = pathinfo($path, PATHINFO_EXTENSION);
return IOFactory::createReader(ucfirst($ext))->load($path);
}
/**
* 获取工作表
* 默认获取当前激活的
*
* @param string $sheet
* @return Worksheet
*/
public function getWorksheet(string $sheet = 'active'): Worksheet
{
$Spreadsheet = $this->getSpreadsheet();
if ($sheet === 'active') {
$Worksheet = $Spreadsheet->getActiveSheet();
} else {
$Worksheet = $Spreadsheet->getSheet($sheet);
}
return $Worksheet;
}
/**
* 获取excel数据
*
* @param string $sheet
* @return array
*/
public function getExcelData(string $sheet = 'active'): array
{
return $this->getWorksheet($sheet)->toArray();
}
/**
* 解析excel
*
* @param array $rules
* @param string $rules[][title] 表头
* @param string $rules[][validate] 验证器
* @param string $rules[][field] 字段名
* @param string $rules[][type] 数据类型 date:日期格式(Y-m-d H:i:s)
* @param array $options
* @param array $options[titleLine] 表头行
* @param boolean $options[autoRemove] 解析后移除文件
* @param boolean $options[ignoreNullRow] 忽略空行
* @return array
* @date 2022-04-11
* @example
* @author arw
* @since 1.0.0
*/
public function parseExcel(array $rules, array $options = []): array
{
$titleLine = Arr::get($options, 'titleLine', [1]);
$autoRemove = Arr::get($options, 'autoRemove', true);
$ignoreNullRow = Arr::get($options, 'ignoreNullRow', true);
if ($autoRemove) {
if (is_file($this->path)) {
unlink($this->path);
}
}
$title = [];
$_title = [];
$_field = [];
$_type = [];
$_validate = [];
foreach ($rules as $rule) {
$_title[] = $rule['title'];
if (isset($rule['field'])) {
$_field[] = $rule['field'];
if (isset($rule['validate'])) {
$_validate[join('|', [
$rule['field'],
$rule['title']
])] = $rule['validate'];
}
} else {
$_field[] = '';
}
if (isset($rule['type'])) {
$_type[] = $rule['type'];
} else {
$_type[] = '';
}
}
$Worksheet = $this->getWorksheet();
$data = $Worksheet->toArray();
// 获取表头 合并复杂表头
foreach ($titleLine as $line) {
$values = $data[$line - 1];
foreach ($values as $key => $value) {
if ($value) {
$title[$key] = $value;
}
}
}
// 验证表头
if ($title != $_title) {
throw new ErrorMsg("表头不一致 请确认excel是否正确", 1);
}
// 去除非数据字段
$i = max($titleLine) - 1;
do {
unset($data[$i]);
$i--;
} while ($i >= 0);
$validate = new Validate;
$validate->rule($_validate)->batch(true)->failException(true);
$result = [];
$error = [];
foreach ($data as $row => $value) {
$index = $row + 1;
$line = "${index}";
$_value = [];
if ($ignoreNullRow && self::isNullRow($value)) {
continue;
}
foreach ($_field as $column => $field) {
if ($field) {
if ($_type[$column]) {
$type = $_type[$column];
if (Str::startsWith($type, 'date') && $value[$column]) {
$format = 'Y-m-d H:i:s';
$types = explode(':', $type);
if (isset($types[1])) {
$format = $types[1];
}
$value[$column] = Tool::conversionDateTime($value[$column], $format);
}
}
$_value[$field] = $value[$column];
}
}
// 验证数据
if ($_validate) {
try {
$validate->check($_value);
} catch (\Throwable $th) {
$error[] = $line . '' . $th->getMessage();
}
}
$result[$line] = $_value;
}
if ($error) {
throw new ErrorMsg(join(PHP_EOL, $error), 1);
}
return $result;
}
/**
* 导出excel
*
* @param array $data 数据
* @param array $options
* @param boolean $options[autoBorder] 是否自动添加边框
* @param string $options[freezeLine] 是否自动冻结首行
* @date 2022-04-11
* @example
* @author arw
* @since 1.0.0
*/
public static function exportSheet(array $data, array $options = [])
{
$excel = new self;
$excel->setWorksheetStyle($options);
$spreadsheet = $excel->getSpreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray($data);
return $excel;
}
/**
* 导出处理图片字段
*/
public static function ExportImgFiled($value)
{
if(strpos($value,"http") !== false){
$base_url = "";
}else{
$base_url = Env::get('APP.DEFAULT_IMG_URL');
}
return $base_url . $value;
}
/**
* 导出excel 多sheet
*
* @param array $data 数据
* @param array $options
* @param boolean $options[autoBorder] 是否自动添加边框
* @param string $options[freezeLine] 是否自动冻结首行
* @date 2022-04-11
* @example
* @author arw
* @since 1.0.0
*/
public static function exportMoreSheet(array $data, array $options = [])
{
$excel = new self;
$excel->setWorksheetStyle($options);
$spreadsheet = $excel->getSpreadsheet();
$spreadsheet->removeSheetByIndex(0);
foreach ($data as $key => $value) {
$worksheet = new Worksheet($spreadsheet, $key);
$worksheet->fromArray($value);
$spreadsheet->addSheet($worksheet);
}
$spreadsheet->setActiveSheetIndex(0);
return $excel;
}
/**
* 保存excel
*
* @param string $name 文件名
* @param string $save 保存路径
* @date 2022-04-11
* @example
* @author arw
* @since 1.0.0
*/
public function save(string $name, string $save = 'php://output')
{
$spreadsheet = $this->getSpreadsheet();
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$_name = $name;
if (!preg_match("/\./", $name)) {
$_name .= '.Xlsx';
}
$worksheets = $spreadsheet->getAllSheets();
foreach ($worksheets as $worksheet) {
$this->_setWorksheetStyle($worksheet);
}
// 保存前
$this->trigger('beforeSave', [$spreadsheet]);
// 浏览器下载
if ($save === 'php://output') {
Tool::obEndClean();
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Cache-Control: max-age=0');
header('Content-Disposition:inline;filename="' . $_name . '"');
$writer->save($save);
} else {
Tool::mkdir($save);
// 保存到本地目录
$writer->save(join(DIRECTORY_SEPARATOR, [
$save, $_name,
]));
}
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
// 保存后
$this->trigger('AfterSave');
}
/**
* 保存前
*
* @param callable $cb
* @date 2022-04-11
* @example
* @author arw
* @since 1.0.0
*/
public function onBeforeSave(callable $cb): self
{
return $this->event('beforeSave', $cb);
}
/**
* 保存后
*
* @param callable $cb
* @date 2022-04-11
* @example
* @author arw
* @since 1.0.0
*/
public function onAfterSave(callable $cb): self
{
return $this->event('afterSave', $cb);
}
/**
* 判断是否空行
*
* @param array $rows
* @return boolean
* @date 2021-11-27
* @example
* @author arw
* @since 1.0.0
*/
public static function isNullRow(array $rows)
{
$rows = array_unique($rows);
$rows = array_filter($rows, function ($v) {
return !is_null($v);
});
return count($rows) == 0;
}
/**
* 快捷设置excel样式
* 首行冻结 自动添加边框
*
* @param Worksheet $worksheet
* @return Worksheet $worksheet
* @date 2021-01-25
* @author arw
* @since 1.0.0
*/
private function _setWorksheetStyle(Worksheet $worksheet): Worksheet
{
$options = $this->worksheetStyle;
$autoBorder = Arr::get($options, 'autoBorder', true);
$freezeLine = Arr::get($options, 'freezeLine', 'A2');
$autoBackground = Arr::get($options, 'autoBackground', true);
if ($freezeLine) {
$worksheet->freezePane($freezeLine);
}
if ($autoBorder) {
$worksheet->getStyle(join(':', [
'A1',
$worksheet->getHighestDataColumn() . $worksheet->getHighestDataRow()
]))->applyFromArray([
'borders' => [
'allBorders' => [
'borderStyle' => Border::BORDER_THIN, //细边框
],
],
]);
}
if($autoBackground){
$style = join(':', [
'A1',
$worksheet->getHighestDataColumn() . "1"
]);
// 列宽
$worksheet -> getDefaultColumnDimension() -> setWidth(25);
// $worksheet -> getColumnDimension('A') -> setWidth(30); //设置A列宽度为30
//行高
// $worksheet -> getRowDimension(1) -> setRowHeight(25);
$worksheet -> getDefaultRowDimension() -> setRowHeight(25);
//样式设置 - 字体
$worksheet -> getStyle($style) -> getFont()
// -> setBold(true)
->setName('微软雅黑')
-> setSize(13);
//样式设置 - 字体颜色
// $worksheet -> getStyle('A1') -> getFont()
// -> getColor() -> setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_RED); //设置单元格A1的字体颜色
// $font = $worksheet -> getCell('B1') -> getColor() -> setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_RED);
// if(substr($font,0,1) == "*"){
// }
// $worksheet -> setCellValue('A2', substr($font,0,1) );
//样式设置 - 水平、垂直居中
$styleArray = [
'alignment' => [
'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER
],
];
$worksheet -> getStyle($style) -> applyFromArray($styleArray);
//样式设置 - 单元格背景颜色
$worksheet->getStyle($style)->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setARGB('FFFFFF00');
}
return $worksheet;
}
/**
* 数字转字母
* 1 => A
*
* @param integer $index
* @return string
* @date 2021-01-23
* @author arw
* @since 1.0.0
*/
public static function stringToIndex(int $index)
{
return Coordinate::stringFromColumnIndex($index);
}
/**
* 字母转数字
* A => 1
*
* @param string $string
* @return int
* @date 2021-01-23
* @author arw
* @since 1.0.0
*/
public static function indexToString(string $string)
{
return Coordinate::columnIndexFromString($string);
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace app\common\arw\adjfut\src\Exception;
/**
* 业务异常
*/
class ErrorMsg extends \Exception
{
}

View File

@ -0,0 +1,258 @@
<?php
namespace app\common\app\common\arw\adjfut\src\Model;
use think\model\Collection;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
/**
* 中间表关联
*
* @date 2022-12-29
* @example
* @author arw
* @since 1.0.0
*/
class Pivot
{
/**
* 中间表
*
* @var string
*/
private $pivotClass = '';
/**
* 主表
*
* @var string
*/
private $masterClass = '';
/**
* 子表
*
* @var string
*/
private $subClass = '';
/**
* 中间表主键
*
* @var string
*/
private $pivotPk = '';
/**
* 主表主键
*
* @var string
*/
private $masterPk = '';
/**
* 子表主键
*
* @var string
*/
private $subPk = '';
/**
* 是否软删除
*
* @var boolean
*/
private $softDelete = false;
/**
* 初始化
*
* @param string $pivotClass 中间表
* @param string $masterClass 主表
* @param string $subClass 子表
* @date 2022-12-29
* @example
* @author arw
* @since 1.0.0
*/
public function __construct(
string $pivotClass,
string $masterClass,
string $subClass,
bool $softDelete = false
) {
$this->pivotClass = $pivotClass;
$this->masterClass = $masterClass;
$this->subClass = $subClass;
$this->softDelete = $softDelete;
$this->pivotPk = (new $pivotClass)->getPk();
$this->masterPk = (new $masterClass)->getPk();
$this->subPk = (new $subClass)->getPk();
}
/**
* 绑定
*
* @param array|Collection $masters
* @param array|Collection $subs
* @param array $extra 中间表额外数据
* @return void
* @date 2022-12-29
* @example
* @author arw
* @since 1.0.0
*/
public function bind($masters, $subs, array $extra = []): void
{
$this->_bind($masters, $subs, $extra, false);
}
/**
* 解绑
*
* @param array|Collection $masters
* @param array|Collection $subs
* @return void
* @date 2022-12-29
* @example
* @author arw
* @since 1.0.0
*/
public function unbind(array $masters, array $subs): void
{
$masters = self::formatModel($masters, $this->masterClass);
$subs = self::formatModel($subs, $this->subClass);
$pivotClass = $this->pivotClass;
$pivotPk = $this->pivotPk;
$masterPk = $this->masterPk;
$subPk = $this->subPk;
foreach ($masters as $master) {
// 查询已绑定的数据
$subPks = $pivotClass::where([
$masterPk => $master->$masterPk
])->column($subPk);
foreach ($subs as $sub) {
if (in_array($sub->$subPk, $subPks)) {
$pivotClass::where([
$subPk => $sub->$subPk,
$masterPk => $master->$masterPk
])->field([
$pivotPk
])->select()->delete();
}
}
}
}
/**
* 重新绑定
*
* @param array|Collection $masters
* @param array|Collection $subs
* @param array $extra 中间表额外数据
* @return void
* @date 2022-12-29
* @example
* @author arw
* @since 1.0.0
*/
public function rebind($masters, $subs, array $extra = []): void
{
$this->_bind($masters, $subs, $extra, true);
}
/**
* 格式化模型
*
* @param array|Collection $models
* @param string $class
* @return Collection
* @date 2022-12-29
* @example
* @author arw
* @since 1.0.0
*/
private static function formatModel($models, string $class): Collection
{
if ($models instanceof Collection) {
return $models;
} else if (is_array($models)) {
$Collection = new Collection();
foreach ($models as $model) {
if ($model instanceof $class) {
} else if (is_string($model) || is_numeric($model)) {
$model = $class::find($model);
}
$Collection->push($model);
}
return $Collection;
} else {
throw new ErrorMsg("类型异常", 1);
}
}
/**
* 绑定数据
*
* @param array|Collection $masters
* @param array|Collection $subs
* @param array $extra
* @param boolean $rebind
* @return void
* @date 2022-12-29
* @example
* @author arw
* @since 1.0.0
*/
private function _bind($masters, $subs, array $extra = [], bool $rebind = false)
{
$masters = self::formatModel($masters, $this->masterClass);
$subs = self::formatModel($subs, $this->subClass);
$pivotClass = $this->pivotClass;
$softDelete = $this->softDelete;
$pivotPk = $this->pivotPk;
$masterPk = $this->masterPk;
$subPk = $this->subPk;
foreach ($masters as $master) {
if ($rebind) {
$pivots = $pivotClass::where([
[$masterPk, '=', $master->$masterPk],
[$subPk, 'not in', $subs->column($subPk)],
])->select();
if (!$pivots->isEmpty()) {
// 重新绑定
$this->unbind([$master], $pivots->column($subPk));
}
}
foreach ($subs as $sub) {
$pivot = null;
if ($softDelete) {
$pivot = $pivotClass::withTrashed()->where([
$subPk => $sub->$subPk,
$masterPk => $master->$masterPk
])->find();
} else {
$pivot = $pivotClass::where([
$subPk => $sub->$subPk,
$masterPk => $master->$masterPk
])->find();
}
if (is_null($pivot) || $pivot->isEmpty()) {
$pivotClass::create($extra + [
$subPk => $sub->$subPk,
$masterPk => $master->$masterPk
]);
} else {
if ($softDelete) {
$pivot->restore();
}
if ($extra) {
$pivotClass::update($extra, [
$pivotPk => $pivot->$pivotPk
]);
}
}
}
}
}
}

View File

@ -0,0 +1,261 @@
<?php
namespace app\common\arw\adjfut\src;
use think\Collection;
use think\db\Query;
use think\facade\Db;
use think\helper\Arr;
/**
* 分割数据表
*
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
class PartitionTable
{
/**
* 源表名
*
* @var string
*/
private $originTable = null;
/**
* 目标表名
*
* @var string
*/
private $targetTable = null;
/**
* 唯一字段
*
* @var string
*/
private $uniqueField = null;
/**
* 查询条件
*
* @var think\Db
*/
private $query = null;
/**
* 是否锁表
*
* @var boolean|string
*/
private $lockTable = false;
/**
* 初始化
*
* @param string $table 原数据表
* @param string $suffix 分割表后缀
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
public function __construct(string $table, string $suffix)
{
$this->originTable = $table;
$this->targetTable = join('_', [$table, $suffix]);
$this->checkTargetTable();
}
/**
* 是否锁表
*
* @param boolean|string $lock
* @return self
* @date 2023-01-04
* @example
* @author arw
* @since 1.0.0
*/
public function setLockTable($lock): self
{
$this->lockTable = $lock;
return $this;
}
/**
* 设置唯一字段(设置后将删除原表数据)
*
* @param string $uniqueField
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
public function setUniqueField(string $uniqueField): self
{
$this->uniqueField = $uniqueField;
return $this;
}
/**
* 设置查询条件
*
* @param callable $cb
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
public function setQuery(callable $cb): self
{
$this->query = call_user_func($cb, $this->getOriginDb());
return $this;
}
/**
* 跨月查询
*
* @param string $table
* @param string $field 字段
* @param array $option
* @param array $option[start] 开始时间 Y-m-d H:i:s
* @param array $option[end] 结束时间 Y-m-d H:i:s
* @date 2022-04-06
* @example
* @author arw
* @since 1.0.0
*/
public static function queryForMonth(string $table, string $field, array $option): Query
{
$start = Arr::get($option, 'start');
$end = Arr::get($option, 'end');
if (!$start || !$end) {
throw new \Exception("缺少时间限制", 1);
}
$result = Db::query("SHOW TABLES LIKE '${table}_%'");
$tables = [];
foreach ($result as $value) {
$tables = array_merge($tables, array_values($value));
}
$startYm = date('Ym', strtotime($start));
$endYm = date('Ym', strtotime($end));
$months = [];
$months[] = $startYm;
if ($startYm != $endYm) {
$current = $startYm;
while (true) {
$current = date('Ym', strtotime($current . "01 +1month"));
$months[] = $current;
if ($current === $endYm) {
break;
}
}
// $months[] = $endYm;
}
$temp = array_filter($tables, function ($v) use ($table, $months) {
return in_array(explode("${table}_", $v)[1], $months);
});
$query = Db::table(in_array(date('Ym'), $months) ? $table : array_shift($temp));
$query->union(array_map(function ($v) {
return Db::name($v)->fetchSql()->select();
}, $temp));
return Db::table(join(' ', [
$query->buildSql(),
$table
]))->whereBetweenTime($field, $start, $end);
}
/**
* 迁移数据
*
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
public function save()
{
Db::startTrans();
try {
$lockTable = $this->lockTable;
if ($lockTable) {
$this->getOriginDb()->lock($lockTable)->select();
$this->getTargetDb()->lock($lockTable)->select();
}
$target = $this->targetTable;
$originSql = $this->query->fetchSql()->select();
$result = Db::execute("REPLACE INTO `$target` $originSql;");
if ($result === false) {
throw new \Exception("迁移数据失败", 1);
}
$uniqueField = $this->uniqueField;
if ($uniqueField) {
$this->getTargetDb()->field([
$uniqueField
])->chunk(500, function (Collection $ids) use ($uniqueField) {
$this->getOriginDb()->whereIn(
$uniqueField,
$ids->column($uniqueField)
)->delete();
}, $uniqueField);
}
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 获取原始表
*
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
private function getOriginDb(): Query
{
return Db::name($this->originTable);
}
/**
* 获取目标表
*
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
private function getTargetDb(): Query
{
return Db::name($this->targetTable);
}
/**
* 检查目标表
*
* @return void
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
private function checkTargetTable(): void
{
if (!in_array($this->targetTable, Db::getTables())) {
$origin = $this->originTable;
$target = $this->targetTable;
$result = Db::execute("CREATE TABLE `$target` LIKE `$origin`");
if ($result === false) {
throw new \Exception("创建迁移表失败", 1);
}
}
}
}

View File

@ -0,0 +1,250 @@
<?php
namespace app\common\arw\adjfut\src;
use app\common\arw\adjfut\src\Traits\Event;
class ReTry
{
use Event;
/**
* 执行器
*
* @var callable
*/
private $handle = null;
/**
* 是否执行成功
*
* @var boolean
*/
private $success = false;
/**
* 执行上限
*
* @var integer
*/
private $limit = 3;
/**
* 上次执行原始上限
*
* @var integer
*/
private $last_limit = 3;
/**
* 执行次数
*
* @var integer
*/
private $count = 1;
/**
* 包装器
*
* @param callable $handle
* @param integer $limit
* @return self
* @date 2022-12-30
* @example
* @author arw
* @since 1.0.0
*/
public static function wrapper(callable $handle, int $limit = 3): self
{
$ins = new self;
$ins->setHandle($handle);
$ins->setLimit($limit);
return $ins;
}
/**
* 自增
*
* @param integer $step 步长
* @return self
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
public function inc(int $step = 1): self
{
$this->limit += $step;
return $this;
}
/**
* 自减
*
* @param integer $step
* @return self
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
public function dec(int $step = 1): self
{
$this->limit -= $step;
return $this;
}
/**
* 获取执行次数
*
* @return integer
* @date 2022-12-30
* @example
* @author arw
* @since 1.0.0
*/
public function getCount(): int
{
return $this->count;
}
/**
* 获取执行上限
*
* @return integer
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
public function getLimit(): int
{
return $this->limit;
}
/**
* 设置执行上限
*
* @param integer $limit
* @return self
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
public function setLimit(int $limit): self
{
$this->limit = $limit;
$this->last_limit = $limit;
return $this;
}
/**
* 设置执行器
*
* @param callable $cb
* @return self
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
public function setHandle(callable $cb): self
{
$this->handle = $cb;
return $this;
}
/**
* 执行是否成功
*
* @param boolean $success
* @return self
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
public function success(bool $success): self
{
$this->success = $success;
return $this;
}
/**
* 重试上限
*
* @param callable $cb
* @return self
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
public function onRetryMax(callable $cb): self
{
$this->event('reTryMax', $cb);
return $this;
}
/**
* 执行异常
*
* @param callable $cb
* @return self
* @date 2022-12-30
* @example
* @author arw
* @since 1.0.0
*/
public function onError(callable $cb): self
{
$this->event('error', $cb);
return $this;
}
/**
* 执行
*
* @param mixed ...$args
* @return void
* @date 2022-12-30
* @example
* @author arw
* @since 1.0.0
*/
public function run(...$args)
{
$this->reset();
array_unshift($args, $this);
$handle = $this->handle;
$res = null;
while (true) {
try {
$res = call_user_func_array($handle, $args);
} catch (\Throwable $th) {
$this->trigger('error', [$th]);
}
$this->count++;
// 执行成功
if ($this->success) {
break;
}
// 执行上限
if ($this->count > $this->limit) {
// 不减1会导致 获取到的执行次数多1
$this->count--;
$this->trigger('reTryMax');
break;
}
}
return $res;
}
/**
* 重置执行器
*
* @return void
* @date 2022-12-30
* @example
* @author arw
* @since 1.0.0
*/
private function reset(): void
{
$this->count = 1;
$this->setLimit($this->last_limit);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace app\common\arw\adjfut\src\Service;
use think\helper\Arr;
use think\Model;
use think\Service;
use think\Validate as ThinkValidate;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
class Validate extends Service
{
/**
* 启动方法
* 在所有的系统服务注册完成之后调用,用于定义启动某个系统服务之前需要做的操作
*
* @return void
* @date 2022-07-25
* @example
* @author arw
* @since 1.0.0
*/
public function boot(): void
{
ThinkValidate::maker(function (ThinkValidate $validate) {
/**
* 验证数据
* 验证规则
* 全部数据(数组)
* 字段名
* 字段描述
*/
$validate->extend('string', function ($value) {
return is_string($value);
}, ':attribute 数据类型非法 不是字符串');
$validate->extend('json', function ($value) {
try {
$value = json_decode($value, true);
return is_array($value);
} catch (\Throwable $th) {
// throw $th;
}
return false;
}, ':attribute 数据格式错误 不是json字符串');
$validate->extend('modelHas', function ($value, $rule) {
$rules = explode(',', $rule);
$class = Arr::get($rules, 0);
$pk = Arr::get($rules, 1);
if (!class_exists($class)) {
throw new ErrorMsg("$class 类不存在");
}
/**
* @var \think\Model
*/
$model = new $class;
if (!($model instanceof Model)) {
throw new ErrorMsg("$class 该类未继承 \\think\\Model");
}
if (!$pk) {
$pk = $model->getPk();
}
return (bool) $model->where($pk, $value)->value($pk);
}, ':attribute 数据不存在');
});
}
}

View File

@ -0,0 +1,196 @@
<?php
namespace app\common\arw\adjfut\src;
use DateTime;
use think\facade\Log;
use think\helper\Arr;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
class Tool
{
/**
* 生成配置项
*
* @param array $config
* @param callable|string $cb 自定义合并策略
* @return callable
* @date 2022-07-29
* @example
* @author arw
* @since 1.0.0
*/
public static function generateConfig(array $config, $cb = 'array_merge'): callable
{
return function (...$argv) use ($cb, $config) {
array_unshift($argv, $config);
return call_user_func_array($cb, $argv);
};
}
/**
* 构建url
*
* @param string $url
* @param array $query
* @param boolean $decode
* @return string
* @date 2023-01-04
* @example
* @author arw
* @since 1.0.0
*/
public static function buildUrl(string $url, array $query = [], bool $decode = true): string
{
$parse = parse_url($url);
$parse_query = Arr::get($parse, 'query', '');
$_query = [];
parse_str($parse_query, $_query);
if (!is_array($_query)) {
$_query = [];
}
$_query = array_merge($_query, $query);
$_url = str_replace('?' . $parse_query, '', $url);
$_url .= '?';
$_url .= http_build_query($_query);
if ($decode) {
$_url = urldecode($_url);
}
return $_url;
}
/**
* 写入通道日志
*
* @param string $channel
* @param string $type
* @param array $data
* @return void
* @date 2022-07-29
* @example
* @author arw
* @since 1.0.0
*/
public static function writeChannelLog(string $channel, string $type, array $data): void
{
Log::channel($channel)->$type(json_encode($data, JSON_UNESCAPED_UNICODE));
}
/**
* 字段映射
*
* @param array $data
* @param array $map
* @param array $options
* @return array
* @date 2022-06-23
* @example
* @author arw
* @since 1.0.0
*/
public static function fieldMap(array $data, array $map, array $options = []): array
{
$prefix = Arr::get($options, 'prefix', '');
$result = [];
foreach ($data as $key => $value) {
if (isset($map[$key])) {
$key = $map[$key];
}
if ($prefix) {
$key = $prefix . $key;
}
$result[$key] = $value;
}
return $result;
}
/**
* 转换日期格式
*
* @param string $datetime
* @param string $format
* @return string
* @date 2022-04-20
* @example
* @author arw
* @since 1.0.0
*/
public static function conversionDateTime($datetime, string $format): string
{
try {
$date = new DateTime($datetime);
return $date->format($format);
} catch (\Throwable $th) {
throw new ErrorMsg('日期格式非法', 1);
}
}
/**
* 生成唯一id
*
* @param string|array $value
* @return string
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
public static function generateGuid($value = ''): string
{
$str = '';
if (is_array($value)) {
$str = json_encode($value);
}
$charid = strtolower(md5($str . uniqid('', true)));
$hyphen = chr(45); // '-'
$uuid = //chr(123)// '{'
substr($charid, 0, 8) . $hyphen
. substr($charid, 8, 4) . $hyphen
. substr($charid, 12, 4) . $hyphen
. substr($charid, 16, 4) . $hyphen
. substr($charid, 20, 12);
//.chr(125);// '}'
return $uuid;
}
/**
* 清空(擦除)缓冲区并关闭输出缓冲
*
* @return void
*/
public static function obEndClean(): void
{
try {
while (ob_get_level() > 0) {
ob_end_clean();
}
} catch (\Throwable $th) {
//throw $th;
}
}
/**
* 自动创建文件夹
*
* @param string $path 文件夹路径
* @param integer $mode 权限
* @return boolean
*/
public static function mkdir(string $path, int $mode = 0755): bool
{
$path = str_replace('/', DIRECTORY_SEPARATOR, $path);
$temp = explode(DIRECTORY_SEPARATOR, $path);
if (preg_match("/\./", end($temp))) {
// pathinfo 不支持中文
// $path = pathinfo($path, PATHINFO_DIRNAME);
array_splice($temp, count($temp) - 1, 1);
$path = join(DIRECTORY_SEPARATOR, $temp);
}
if (!file_exists($path)) {
mkdir($path, $mode, true);
}
chmod($path, $mode);
return true;
}
}

View File

@ -0,0 +1,223 @@
<?php
declare(strict_types=1);
namespace app\common\arw\adjfut\src\Traits;
use think\exception\ValidateException;
use think\helper\Arr;
use think\Model;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
/**
* 字典类
* @mixin Model
*/
trait Dictionary
{
// /**
// * 字典映射
// *
// * @var array
// * @date 2023-01-10
// * @example
// * @author arw
// * @since 1.0.0
// */
// public static $dictionaryMap = [];
/**
* 字典缓存
*
* @var array
* @date 2023-01-10
* @example
* @author arw
* @since 1.0.0
*/
private static $dictionaryCache = [];
/**
* 获取字典模型映射
*
* @param string $guid
* @return array
* @date 2023-01-10
* @example
* @author arw
* @since 1.0.0
*/
private static function getDictionaryModelMap(string $guid): array
{
return [];
}
/**
* 验证字典
*
* @param bool $ignoreNull 忽略null值
* @param array $ignoreField 忽略字段验证
* @return void
* @throws ValidateException
* @date 2023-01-11
* @example
* @author arw
* @since 1.0.0
*/
public function validateDictionary(bool $ignoreNull = false, array $ignoreField = []): void
{
$map = self::getDictionaryMap();
$errors = [];
foreach ($map as $field => &$dictionary) {
list($field, $title) = self::getDictionaryField($field);
if (in_array($field, $ignoreField)) {
continue;
}
$value = $this->$field;
if (is_null($value) && $ignoreNull) {
continue;
}
$dictionary = self::getDictionaryFieldMap($field);
$keys = array_keys($dictionary);
if (!in_array($value, $keys)) {
$values = array_values($dictionary);
$msg = join(',', $values);
$errors[] = "$title 应在[ $msg ]";
}
unset($dictionary);
}
if ($errors) {
throw new ValidateException($errors);
}
}
/**
* 获取字典值
*
* @param string $field 字段
* @param mixed $value 设置器内调用无法会无法获取当前值 需要手动传入
* @return mixed
* @date 2023-01-11
* @example
* @author arw
* @since 1.0.0
*/
public function getDictionaryValue(string $field, $value = null)
{
$map = self::getDictionaryFieldMap($field);
if (is_null($value)) {
$value = $this->$field;
}
if (isset($map[$value])) {
return $value;
}
$key = array_search($value, $map);
if ($key === false) {
$msg = join(',', array_values($map));
throw new ErrorMsg("$field 应在[ $msg ]", 1);
}
return $key;
}
/**
* 获取字典名称
*
* @param string $field 字段
* @param mixed $default 默认值 如果默认值在字典值内 则返回字典名称
* @return mixed
* @date 2023-01-11
* @example
* @author arw
* @since 1.0.0
*/
public function getDictionaryName(string $field, $default = null)
{
$map = self::getDictionaryFieldMap($field);
if (isset($map[$default])) {
$default = $map[$default];
}
return Arr::get($map, $this->$field, $default);
}
/**
* 获取字典名称(弃用保留兼容)
* 请调用 getDictionaryName
*
* @param string $field 字段
* @param mixed $default 默认值
* @deprecated 1.0.0
* @return mixed
* @date 2023-01-10
* @example
* @author arw
* @since 1.0.0
*/
public function getDictionaryText(string $field, $default = null)
{
return $this->getDictionaryName($field, $default);
}
/**
* 获取字典字段映射
*
* @param string $field 字段
* @return array
* @date 2023-01-10
* @example
* @author arw
* @since 1.0.0
*/
public static function getDictionaryFieldMap(string $field): array
{
list($field) = self::getDictionaryField($field);
$cache = Arr::get(self::$dictionaryCache, $field);
if (is_array($cache)) {
return $cache;
}
$map = Arr::get(self::getDictionaryMap(), $field);
if (!$map) {
throw new ErrorMsg("未定义字段映射", 1);
}
if (is_array($map)) {
self::$dictionaryCache[$field] = $map;
return self::$dictionaryCache[$field];
}
if (is_string($map)) {
self::$dictionaryCache[$field] = self::getDictionaryModelMap($map);
return self::$dictionaryCache[$field];
}
return [];
}
/**
* 获取字典映射
*
* @return array
* @date 2023-01-10
* @example
* @author arw
* @since 1.0.0
*/
public static function getDictionaryMap(): array
{
$self = new self;
$exists = property_exists($self, 'dictionaryMap') && isset($self::$dictionaryMap);
return $exists ? $self::$dictionaryMap : [];
}
/**
* 获取字典字段
*
* @param string $value
* @return array
* @date 2023-01-13
* @example
* @author arw
* @since 1.0.0
*/
private static function getDictionaryField(string $value): array
{
$temp = explode('|', $value);
$field = Arr::get($temp, '0');
$title = Arr::get($temp, '1', $field);
return [$field, $title];
}
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace app\common\arw\adjfut\src\Traits;
/**
* 事件类
*/
trait Event
{
/**
* 事件
*
* @var array
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
private $event = [];
/**
* 事件
*
* @param string $type
* @param callable $cb
* @return self
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
private function event(string $type, callable $cb): self
{
$this->event[strtoupper($type)] = $cb;
return $this;
}
/**
* 事件触发器
*
* @param string $type
* @param array $args
* @param boolean $withThis
* @return mixed
* @date 2022-12-28
* @example
* @author arw
* @since 1.0.0
*/
private function trigger(string $type, array $args = [], bool $withThis = true)
{
$type = strtoupper($type);
if (isset($this->event[$type])) {
if ($withThis) {
array_unshift($args, $this);
}
return call_user_func_array($this->event[$type], $args);
}
}
}

View File

@ -0,0 +1,240 @@
<?php
namespace app\common\arw\adjfut\src;
class Traverse
{
// 当前id key名称
private $current = 'id';
// 父id key名称
private $parent = 'pid';
// 子集名称
private $children = 'children';
// 数据
private $data = [];
// 格式化函数
private $format = null;
// 是否递归循环
private $loop = false;
public function __construct(string $current, string $parent, string $children = 'children')
{
$this->current = $current;
$this->parent = $parent;
$this->children = $children;
}
/**
* 获取子集
* @access public
* @param array $data 要遍历的数组
* @param integer|string $id 要查找哪个id下的子集
* @param bool $loop 是否循环遍历
* @return array
*/
public function next(array $data = [], $id = 0, bool $loop = false): array
{
$this->setData($data);
$this->setLoop($loop);
return $this->generateNext($id);
}
/**
* 获取父集
* @access public
* @param array $data 要遍历的数组
* @param integer|string $id 要查找哪个id下的父集
* @param bool $loop 是否循环遍历
* @return array
*/
public function prev(array $data = [], $id = 0, bool $loop = false): array
{
$this->setData($data);
$this->setLoop($loop);
return $this->generatePrev($id);
}
/**
* 获取无限层级树状图
*
* @param array $data 要遍历的数组
* @param integer|string $parent_id 起点id
* @param callable $format 自定义树数据
* @return array
* @date 2020-04-09
* @example
* @author arw
* @since 1.0.0
*/
public function tree(array $data, $parent_id, callable $format): array
{
$this->setData($data);
$this->setFormat($format);
return $this->generateTree($parent_id);
}
/**
* 获取全部子集数据
*
* @param integer|string $id
* @return array
* @date 2022-08-08
* @example
* @author arw
* @since 1.0.0
*/
public function getCurrentData($id): array
{
$data = array_filter($this->data, function ($v) use ($id) {
return $v[$this->current] == $id;
});
$data = array_values($data);
return $data;
}
/**
* 获取全部父集数据
*
* @param integer|string $id
* @return array
* @date 2022-08-08
* @example
* @author arw
* @since 1.0.0
*/
public function getParentData($id): array
{
$data = array_filter($this->data, function ($v) use ($id) {
return $v[$this->parent] == $id;
});
$data = array_values($data);
return $data;
}
/**
* 设置循环
*
* @param boolean $loop
* @return self
* @date 2022-08-08
* @example
* @author arw
* @since 1.0.0
*/
public function setLoop(bool $loop): self
{
$this->loop = $loop;
return $this;
}
/**
* 设置数据
*
* @param array $data
* @return self
* @date 2022-08-08
* @example
* @author arw
* @since 1.0.0
*/
public function setData(array $data): self
{
$this->data = $data;
return $this;
}
/**
* 设置格式化函数
*
* @param callable $cb
* @return self
* @date 2022-08-08
* @example
* @author arw
* @since 1.0.0
*/
public function setFormat(callable $cb): self
{
$this->format = $cb;
return $this;
}
/**
* 生成树
*
* @param integer|string $parent_id
* @return array
* @date 2022-08-08
* @example
* @author arw
* @since 1.0.0
*/
public function generateTree($parent_id): array
{
$data = $this->getParentData($parent_id);
foreach ($data as &$value) {
$children = $this->generateTree($value[$this->current]);
$value[$this->children] = $children;
if (is_callable($this->format)) {
$formatReturn = call_user_func($this->format, $value);
if (!isset($formatReturn[$this->children])) {
$formatReturn[$this->children] = $children;
}
if ($formatReturn) {
$value = $formatReturn;
}
}
unset($value);
}
return $data;
}
/**
* 获取子集
*
* @param integer|string $id
* @return array
* @date 2022-08-08
* @example
* @author arw
* @since 1.0.0
*/
public function generateNext($id): array
{
$re = [];
$data = $this->getParentData($id);
foreach ($data as $value) {
$current = $value[$this->current];
$re[] = $current;
if ($this->loop) {
$re = array_merge($re, $this->generateNext($current));
}
}
return array_unique($re);
}
/**
* 获取父集
*
* @param integer|string $id
* @return array
* @date 2022-08-08
* @example
* @author arw
* @since 1.0.0
*/
public function generatePrev($id): array
{
$re = [];
$data = $this->getCurrentData($id);
foreach ($data as $value) {
$parent = $value[$this->parent];
$re[] = $parent;
if ($this->loop) {
$re = array_merge($re, $this->generatePrev($parent));
}
}
return array_unique($re);
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace app\common\arw\adjfut\src\Unit;
use think\helper\Arr;
use think\helper\Str;
/**
* @method static string b2kb(string $number,?int $scale)
* @method static string b2mb(string $number,?int $scale)
* @method static string b2gb(string $number,?int $scale)
* @method static string b2tb(string $number,?int $scale)
*
* @method static string kb2b(string $number,?int $scale)
* @method static string kb2mb(string $number,?int $scale)
* @method static string kb2gb(string $number,?int $scale)
* @method static string kb2tb(string $number,?int $scale)
*
* @method static string mb2b(string $number,?int $scale)
* @method static string mb2kb(string $number,?int $scale)
* @method static string mb2gb(string $number,?int $scale)
* @method static string mb2tb(string $number,?int $scale)
*
* @method static string gb2b(string $number,?int $scale)
* @method static string gb2mb(string $number,?int $scale)
* @method static string gb2kb(string $number,?int $scale)
* @method static string gb2tb(string $number,?int $scale)
*
* @method static string tb2b(string $number,?int $scale)
* @method static string tb2mb(string $number,?int $scale)
* @method static string tb2kb(string $number,?int $scale)
* @method static string tb2gb(string $number,?int $scale)
*/
class File
{
/**
* 间隔
*/
const INTERVAL = 1024;
/**
* 顺序
*/
const ORDER = ['b', 'kb', 'mb', 'gb', 'tb'];
/**
* 获取字典单位
*
* @param string $size
* @return string
* @date 2022-07-23
* @example
* @author arw
* @since 1.0.0
*/
public static function getByteUnit(string $size): string
{
for ($i = 0; $size >= self::INTERVAL && $i < 4; $i++) {
$size = bcdiv($size, self::INTERVAL);
}
return round($size, 2) . self::ORDER[$i];
}
public static function __callStatic($name, $arguments)
{
$number = Arr::get($arguments, 0, 0);
$scale = Arr::get($arguments, 1, 0);
$name = Str::lower($name);
$a = null;
$b = null;
if (Str::contains($name, 2)) {
list($a, $b) = explode('2', $name);
} else {
list($a, $b) = explode('to', $name);
}
$a_index = array_search($a, self::ORDER);
$b_index = array_search($b, self::ORDER);
$type = $a_index < $b_index;
for ($i = 0; $i < abs(bcsub($a_index, $b_index, 0)); $i++) {
if ($type) {
$number = bcdiv($number, self::INTERVAL, $scale);
} else {
$number = bcmul($number, self::INTERVAL, $scale);
}
}
return $number;
}
}

View File

@ -0,0 +1,289 @@
<?php
namespace app\common\arw\adjfut\src;
use think\exception\ValidateException;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
use think\facade\Filesystem;
use think\facade\Request;
use think\file\UploadedFile;
use think\filesystem\Driver;
use think\helper\Arr;
class UploadFile
{
/**
* 磁盘
*
* @var string
*/
private $diskName = '';
/**
* 文件
*
* @var UploadedFile
*/
private $file = null;
/**
* 文件路径
*
* @var string
*/
private $path = '';
/**
* 初始化
*
* @param string $diskName 磁盘
* @param string $validate 验证
* @param UploadedFile|string|array $file 文件
* @date 2022-04-15
* @example
* @author arw
* @since 1.0.0
*/
public function __construct(
string $diskName,
string $validate = '',
$file = 'file'
) {
if (is_string($file)) {
$file = Request::file($file);
}
if (is_array($file)) {
$file = new UploadedFile(...$file);
}
if (!($file instanceof UploadedFile)) {
throw new ErrorMsg("非法文件", 1);
}
if ($validate) {
try {
Validate::check([
'file' => $file
], [
'file|文件' => $validate
]);
} catch (ValidateException $th) {
$this->getDisk()->delete($file->getFilename());
throw $th;
}
}
$this->diskName = $diskName;
$this->file = $file;
}
/**
* 上传base64图片
*
* @param string $diskName 磁盘
* @param string $base64 base64
* @return self
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public static function uploadBase64Image(
string $diskName,
string $base64
): self {
$Base64 = new Base64($base64);
if (!$Base64->isImage()) {
throw new ErrorMsg("非法图片base64", 1);
}
$path = tempnam(sys_get_temp_dir(), 'saveBase64Image');
$Base64->saveImage($path);
$name = md5(md5_file($path) . Tool::generateGuid() . time()) . '.' . $Base64->getFileExt();
return new self($diskName, '', [
$path,
$name
]);
}
/**
* 获取文件
*
* @return UploadedFile
* @date 2022-07-05
* @example
* @author arw
* @since 1.0.0
*/
public function getFile(): UploadedFile
{
return $this->file;
}
/**
* 获取磁盘名称
*
* @return string
* @date 2022-07-05
* @example
* @author arw
* @since 1.0.0
*/
public function getDiskName(): string
{
return $this->diskName;
}
/**
* 获取配置项
*
* @param string $key
* @param mixed $default
* @return mixed
* @date 2022-04-15
* @example
* @author arw
* @since 1.0.0
*/
public function getConfig(string $key, $default = null)
{
return Arr::get(
Filesystem::getDiskConfig($this->diskName),
$key,
$default
);
}
/**
* 获取文件相对路径
*
* @date 2022-04-15
* @example
* @author arw
* @since 1.0.0
*/
public function getPath(): string
{
if (!$this->path) {
throw new ErrorMsg("请保存文件后使用", 1);
}
return $this->path;
}
/**
* 获取文件真实路径
*
* @return string
* @date 2022-07-19
* @example
* @author arw
* @since 1.0.0
*/
public function getRealPath(): string
{
$path = $this->getPath();
if ($this->getConfig('type') != 'local') {
throw new ErrorMsg("非本地文件类型 无法获取真实路径", 1);
}
return str_replace(['\\', '/'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $this->getConfig('root') . DIRECTORY_SEPARATOR . $path);
}
/**
* 获取文件绝对路径
*
* @date 2022-04-15
* @deprecated 1.0.0
* @example
* @author arw
* @since 1.0.0
*/
public function getFullPath(): string
{
return $this->getRealPath();
}
/**
* 保存文件
* @param string $path 路径
* @param null|string|\Closure $rule 文件名规则
* @param array $options 参数
* @return string
*/
public function putFile(
string $path,
$rule = null,
array $options = []
): string {
$this->path = $this->getDisk()->putFile(
$path,
$this->file,
$rule,
$options
);
if (!$this->path) {
throw new ErrorMsg("文件保存失败", 1);
}
return $this->path;
}
/**
* 指定文件名保存文件
* @param string $path 路径
* @param string $name 文件名
* @param array $options 参数
* @return string
*/
public function putFileAs(
string $path,
string $name = '',
array $options = []
): string {
$this->path = $this->getDisk()->putFileAs(
$path,
$this->file,
$name,
$options
);
if (!$this->path) {
throw new ErrorMsg("文件保存失败", 1);
}
return $this->path;
}
/**
* 删除文件
*
* @return void
* @date 2022-08-22
* @example
* @author arw
* @since 1.0.0
*/
public function delete(): void
{
$this->getDisk()->delete($this->file->getFilename());
}
/**
* 移除文件
*
* @date 2022-04-15
* @deprecated 1.0.0
* @example
* @author arw
* @since 1.0.0
*/
public function unlink(): void
{
$this->delete();
}
/**
* 获取存储配置
*
* @return Driver
* @date 2022-04-15
* @example
* @author arw
* @since 1.0.0
*/
public function getDisk(): Driver
{
return Filesystem::disk($this->diskName);
}
}

View File

@ -0,0 +1,254 @@
<?php
namespace app\common\arw\adjfut\src;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
use think\facade\Request;
use think\helper\Arr;
use think\Validate as ThinkValidate;
class Validate
{
private $data = [];
/**
* 设置参数s
*
* @param array $data
* @return self
*/
public function setData(array $data): self
{
$this->data = $data;
return $this;
}
/**
* 当条件满足时 验证
*
* @param array $when
* @param array $validate
* @param array $message
* @param bool $batch
* @return void
*/
public function when(array $when, array $validate, array $message = [], bool $batch = true): void
{
$data = $this->data;
$whenCount = 0;
foreach ($when as $field => $value) {
if (!isset($data[$field])) {
continue;
}
if ($data[$field] == $value) {
$whenCount++;
}
}
$_validate = $whenCount == count($when);
if ($_validate) {
self::check($data, $validate, $message, $batch);
}
}
/**
* 验证是否唯一
*
* @param string $model 模型类
* @param string|int $id 排除主键id
* @param array $rules[field] => name,validateField,pk|其他规则
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return void
* @throws ValidateException
*/
public static function unique(
string $model,
$id,
array $data,
array $rules = [],
array $message = [],
bool $batch = true
): void {
$_rules = [];
foreach ($rules as $field => $validate) {
$validates = explode('|', $validate);
$_rule = explode(',', $validates[0]);
$name = Arr::get($_rule, 0);
$validateField = Arr::get($_rule, 1);
$pk = Arr::get($_rule, 2);
$validates[0] = self::createUniqueRule($model, [
'field' => $validateField ?: $field,
'id' => $id,
'pk' => $pk,
]);
$_rules[$field . ($name ? "|$name" : '')] = $validates;
}
self::check($data, $_rules, $message, $batch);
}
/**
* 创建数据表唯一验证
*
* @param string $class 模型类
* @param array $options 配置项
* @param string $options[field] 字段名
* @param string $options[id] 排除ID
* @param string $options[pk] 主键名
* @return string
* @date 2022-04-16
* @example
* @author arw
* @since 1.0.0
*/
public static function createUniqueRule(string $class, array $options = []): string
{
$field = Arr::get($options, 'field');
$id = Arr::get($options, 'id');
$pk = Arr::get($options, 'pk');
if (!$field) {
throw new ErrorMsg("字段名不能为空", 1);
}
return 'unique:' . join(',', [
$class,
$field,
$id,
$pk
]);
}
/**
* 类场景验证
*
* @param string $validate
* @param string $scene
* @param boolean $batch
* @return void
* @throws ValidateException
*/
public static function classScene(array $validate, array $data, bool $batch = true): void
{
list($class, $scene) = $validate;
/**
* @var ThinkValidate
*/
$validate = new $class;
$validate->scene($scene)->batch($batch);
$validate->failException(true)->check($data);
}
/**
* 类场景验证 param参数
*
* @param array $validate
* @param boolean $batch
* @return array
* @throws ValidateException
*/
public static function classSceneParam(array $validate, bool $batch = true): array
{
$data = Request::param();
self::classScene($validate, $data, $batch);
return $data;
}
/**
* 类场景验证 get参数
*
* @param array $validate
* @param boolean $batch
* @return array
* @throws ValidateException
*/
public static function classSceneGet(array $validate, bool $batch = true): array
{
$data = Request::get();
self::classScene($validate, $data, $batch);
return $data;
}
/**
* 类场景验证 post参数
*
* @param array $validate
* @param boolean $batch
* @return array
* @throws ValidateException
*/
public static function classScenePost(array $validate, bool $batch = true): array
{
$data = Request::post();
self::classScene($validate, $data, $batch);
return $data;
}
/**
* param参数验证
*
* @param array $validate 验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array
* @throws ValidateException
*/
public static function param(array $validate, array $message = [], bool $batch = true): array
{
$data = Request::param();
self::check($data, $validate, $message, $batch);
return $data;
}
/**
* get参数验证
*
* @param array $validate 验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array
* @throws ValidateException
*/
public static function get(array $validate, array $message = [], bool $batch = true): array
{
$data = Request::get();
self::check($data, $validate, $message, $batch);
return $data;
}
/**
* post参数验证
*
* @param array $validate 验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array
* @throws ValidateException
*/
public static function post(array $validate, array $message = [], bool $batch = true): array
{
$data = Request::post();
self::check($data, $validate, $message, $batch);
return $data;
}
/**
* 验证数据
*
* @param array $data 数据
* @param array $validate 验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return void
* @throws ValidateException
*/
public static function check(array $data, array $validate, array $message = [], bool $batch = true): void
{
$v = new ThinkValidate();
$v->rule($validate);
$v->message($message);
$v->batch($batch);
$v->failException(true)->check($data);
}
}

View File

@ -0,0 +1,123 @@
<?php
namespace app\common\arw\adjfut\src\WeChat;
use think\facade\Config as FacadeConfig;
use think\helper\Arr;
class Config
{
/**
* 实例
*
* @var $this
* @date 2022-05-19
* @example
* @author arw
* @since 1.0.0
*/
private static $instance = null;
/**
* 配置项
*
* @var array
* @date 2022-05-19
* @example
* @author arw
* @since 1.0.0
*/
private $config = [
// 中控层配置
'access_key' => '',
'server_base' => '',
// 小程序配置
'xcx' => [
'appid' => '',
'secret' => '',
'cache_key' => '',
'log_channel' => '',
],
// 公众号配置
'gzh' => [
'appid' => '',
'secret' => '',
// 推送模板
'template' => [
'模板名称' => '模板id'
],
'cache_key' => '',
'log_channel' => '',
],
];
public function __construct()
{
$setConfig = function (string $key) {
$this->setConfig($key, FacadeConfig::get("wechat.$key"));
};
foreach ([
'access_key', 'server_base',
'xcx.cache_key', 'xcx.log_channel',
'xcx.appid', 'xcx.secret',
'gzh.cache_key', 'gzh.log_channel',
'gzh.appid', 'gzh.secret', 'gzh.template'
] as $key) {
$setConfig($key);
}
}
/**
* 实例
*
* @return self
* @date 2022-05-19
* @example
* @author arw
* @since 1.0.0
*/
public static function instance(): self
{
if (!self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
/**
* 设置配置项
*
* @param string $key
* @param mixed $value
* @return void
* @date 2022-05-19
* @example
* @author arw
* @since 1.0.0
*/
public function setConfig(string $key, $value)
{
Arr::set($this->config, $key, $value);
}
/**
* 获取配置项
*
* @param string $key
* @param mixed $default
* @return mixed
* @date 2022-05-19
* @example
* @author arw
* @since 1.0.0
*/
public static function get(string $key, $default = null)
{
return Arr::get(
self::instance()->config,
$key,
$default
);
}
}

View File

@ -0,0 +1,348 @@
<?php
namespace app\common\arw\adjfut\src\WeChat;
use app\common\arw\adjfut\src\Curl;
use app\common\arw\adjfut\src\WeChat\GzhCommon;
use think\facade\Config;
use think\facade\Request;
use think\helper\Arr;
use think\Response;
class Gzh extends GzhCommon
{
/**
* 当前实例
*
* @var $this
*/
private static $instance = null;
/**
* 推送缓存 防止重复推送同样的数据
*
* @var array
* @date 2021-10-11
* @example
* @author arw
* @since 1.0.0
*/
private static $TemplateMessageInterfaceCache = [];
/**
* 初始化
*
* @date 2022-05-18
* @example
* @author arw
* @since 1.0.0
*/
public function __construct()
{
parent::__construct();
}
/**
* 实例
*
* @return self
* @date 2022-05-18
* @example
* @author arw
* @since 1.0.0
*/
public static function instance(): self
{
if (!self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
/**
* 获取AccessToken
*
* @param boolean $refresh 是否强制刷新
* @return void
* @date 2020-05-29
* @example
* @author arw
* @since 1.0.0
*/
public function GetAccessToken($refresh = false)
{
return $this->_AccessToken($refresh);
}
/**
* 获取JsApiTicket
*
* @param boolean $refresh 是否强制刷新
* @return void
* @date 2020-05-29
* @example
* @author arw
* @since 1.0.0
*/
public function GetJsApiTicket($refresh = false)
{
return $this->_JsApiTicket($refresh);
}
/**
* 网页授权/获取用户基本信息
* https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
* @param array $config 配置项 [
* "scope" => "snsapi_base", 应用授权作用域,
* snsapi_base 不弹出授权页面直接跳转只能获取用户openid
* snsapi_userinfo 弹出授权页面可通过openid拿到昵称、性别、所在地。并且 即使在未关注的情况下,只要用户授权,也能获取其信息
* "state" => "", 重定向后会带上state参数开发者可以填写a-zA-Z0-9的参数值最多128字节
* "lang" => "zh_CN", 当scope等于snsapi_userinfo才生效
* 返回国家地区语言版本zh_CN 简体zh_TW 繁体en 英语
* ]
* @param callable $success 回调用户授权成功调用函数 ($userinfo,$state)
* @param callable $error 执行错误回调 ($msg)
* @return null
*/
public function authorize(array $config, callable $success, callable $error)
{
try {
$config["scope"] = Arr::get($config, "scope", "snsapi_base");
$config["state"] = Arr::get($config, "state", "");
$config["lang"] = Arr::get($config, "lang", "zh_CN");
$config["redirect_uri"] = Arr::get($config, "redirect_uri", Request::url(true));
$code = Arr::get($_GET, "code");
if (!$code) {
$url = "https://open.weixin.qq.com/connect/oauth2/authorize";
$url .= "?" . http_build_query([
"appid" => $this->appid,
"redirect_uri" => $config["redirect_uri"],
"response_type" => "code",
"scope" => $config["scope"],
"state" => $config["state"],
]);
$url .= "#wechat_redirect";
return Response::create($url, 'redirect', 302);
}
$curl = Curl::instance();
$param = [];
$param["appid"] = $this->appid;
$param["secret"] = $this->secret;
$param["code"] = $code;
$param["grant_type"] = "authorization_code";
$url = "https://api.weixin.qq.com/sns/oauth2/access_token";
$access_token = $curl->setParams($param)->get($url);
$judge = (Arr::get($access_token, "access_token") && Arr::get($access_token, "openid"));
if (!$judge || !$access_token) {
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'content' => $curl->getContent(),
'msg' => '获取access_token失败',
], 'error');
return $error("获取access_token失败");
}
if ($config["scope"] === "snsapi_userinfo") {
$curl = Curl::instance();
$url = "https://api.weixin.qq.com/sns/userinfo";
$param = [];
$param["access_token"] = Arr::get($access_token, "access_token");
$param["openid"] = Arr::get($access_token, "openid");
$param["lang"] = $config["lang"];
$user_info = $curl->setParams($param)->get($url);
$errcode = Arr::get($user_info, "errcode", false);
if ($errcode !== false) {
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'result' => $curl->getContent(),
'msg' => '获取用户信息失败',
], 'error');
return $error("获取微信用户信息失败");
}
$access_token = array_merge($access_token, $user_info);
}
return $success($access_token, $_GET["state"]);
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
return $error($th->getMessage());
}
}
/**
* 微信模板消息推送
* 微信返回errcode等于40001会更新缓存AccessToken
* 并重新推送一次
* https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html#5
* @param string $touser 推送给谁
* @param string $template_id 模板名称
* @param array $data 推送数据
* [
* "touser" => "openid",
* "template_id" => "template_id",
* "url" => "url",
* "miniprogram" => [
* "appid" => "appid",
* "pagepath" => "pagepath",
* ],
* "data" => [
* "first" => [
* "value" => "value",
* "color" => "color",
* ],
* "keyword1" => [
* "value" => "value",
* "color" => "color",
* ],
* "keyword2" => [
* "value" => "value",
* "color" => "color",
* ],
* "keyword3" => [
* "value" => "value",
* "color" => "color",
* ],
* "remark" => [
* "value" => "value",
* "color" => "color",
* ],
* ],
* ]
* @param boolean $refresh 是否刷新【 access_token
* @param integer $limit 调用上限(允许自动重试次数)
* @return bool
* @date 2020-05-26
* @example
* @author arw
* @since 1.1.1
*/
public function TemplateMessageInterface($touser = null, $template_id = null, array $data, $refresh = false, $limit = 3)
{
$this->log([
'action' => __FUNCTION__,
'touser' => $touser,
'template_id' => $template_id,
'data' => $data,
], 'log');
try {
$template = $this->template;
if (!$touser) {
if (isset($data["touser"])) {
$touser = $data["touser"];
}
}
if (!$template_id) {
if (isset($data["template_id"])) {
$template_id = $data["template_id"];
}
}
if (empty($touser)) {
throw new \Exception("data.touser不能为空", 1);
}
if (empty($template_id)) {
throw new \Exception("data.template_id不能为空", 1);
} else {
if (isset($template[$template_id])) {
$template_id = $template[$template_id];
}
}
$data["touser"] = $touser;
$data["template_id"] = $template_id;
$limit--;
if ($limit <= 0) {
throw new \Exception("超过调用上限", 1);
}
$access_token = $this->_AccessToken($refresh);
if (!$access_token) {
return false;
}
$appid = Arr::get($data, "miniprogram.appid");
if ($appid == 'APPID') {
Arr::set($data, 'miniprogram.appid', Config::get('xcx.appid'));
}
$param = json_encode($data);
if (!isset(self::$TemplateMessageInterfaceCache[$param])) {
self::$TemplateMessageInterfaceCache[$param] = [];
}
if (in_array($touser, self::$TemplateMessageInterfaceCache[$param])) {
throw new \Exception("重复推送", 1);
}
$url = "https://api.weixin.qq.com/cgi-bin/message/template/send";
$url .= "?access_token=" . $access_token;
$curl = Curl::instance();
$send = $curl->setData($param)->post($url);
$errcode = Arr::get($send, "errcode", false);
if ($errcode === 0) {
self::$TemplateMessageInterfaceCache[$param][] = $touser;
return true;
}
if ($errcode === 40001) {
return $this->TemplateMessageInterface($touser, $template_id, $data, true, $limit);
}
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getData(),
'content' => $curl->getContent(),
'msg' => '模板消息推送失败',
], 'error');
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* Jssdk授权
* @param string $url 授权url
* @return null
*/
public function JsSdk(string $url = "")
{
$jsapiTicket = $this->_JsApiTicket();
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
if (!$url) {
$url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
}
$timestamp = time();
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$nonceStr = "";
for ($i = 0; $i < 16; $i++) {
$nonceStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
// 这里参数的顺序要按照 key 值 ASCII 码升序排序
$string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
$signature = sha1($string);
$signPackage = [
"appId" => $this->appid,
"nonceStr" => $nonceStr,
"timestamp" => $timestamp,
"url" => $url,
"signature" => $signature,
"rawString" => $string,
];
return $signPackage;
}
}

View File

@ -0,0 +1,459 @@
<?php
namespace app\common\arw\adjfut\src\WeChat;
use think\facade\Cache;
use app\common\arw\adjfut\src\Curl;
use think\facade\Log;
use think\helper\Arr;
class GzhCommon
{
/**
* 微信公众号 appid
*
* @var string
*/
protected $appid = '';
/**
* 微信公众号 secret
*
* @var string
*/
protected $secret = '';
/**
* 微信推送模板
*
* @var array
*/
protected $template = [];
/**
* 缓存key
*
* @var string
*/
protected $cache_key = '';
/**
* 日志通道
*
* @var string
*/
protected $log_channel = '';
/**
* 异常
*
* @var string
*/
protected $error = '';
/**
* 中控层服务器 access_key
*
* @var string
*/
private $access_key = '';
/**
* 中控层服务器 server_base
*
* @var string
*/
private $server_base = '';
/**
* access_token 缓存
*
* @var string
*/
private $access_token = '';
/**
* 初始化
*
* @date 2022-05-19
* @example
* @author arw
* @since 1.0.0
*/
public function __construct()
{
$this->access_key = Config::get('access_key');
$this->server_base = Config::get('server_base');
$this->appid = Config::get('gzh.appid');
$this->secret = Config::get('gzh.secret');
$this->template = Config::get('gzh.template');
$this->cache_key = Config::get('gzh.cache_key');
$this->log_channel = Config::get('gzh.log_channel');
}
/**
* 获取access_token
* 如果不刷新并且有缓存【 access_token 】的话
* 直接返回缓存的【 access_token
* 否则将看情况请求【 access_token
*
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 1.0.2
*/
protected function _AccessToken($refresh = false)
{
$cache_key = $this->getAccessTokenCacheKey();
if ($refresh && $cache_key) {
Cache::delete($cache_key);
}
if ($refresh === false && $this->access_token) {
return $this->access_token;
}
$access_token = $this->_GetAccessToken($refresh);
if ($access_token) {
$this->access_token = $access_token;
return $access_token;
} else {
$access_token = $this->_GetCacheAccessToken();
if (!$access_token) {
$access_token = $this->_CurlAccessToken();
}
$this->access_token = $access_token;
return $access_token;
}
return false;
}
/**
* 获取jsapiticket
*
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 1.0.0
*/
protected function _JsApiTicket($refresh = false)
{
$cache_key = $this->getJsApiTicketCacheKey();
if ($refresh && $cache_key) {
Cache::delete($cache_key);
}
$ticket = $this->_GetJsApiTicket($refresh);
if ($ticket) {
return $ticket;
} else {
$ticket = $this->_GetCacheJsApiTicket();
if (!$ticket) {
$ticket = $this->_CurlJsApiTicket();
}
return $ticket;
}
return false;
}
/**
* 异常记录
*
* @param array $content
* @param string $level alert | error | warning | notice | info | debug
* @return void
* @date 2020-05-29
* @example
* @author arw
* @since 1.0.0
*/
protected function log(array $data, string $level = 'log')
{
$log_channel = $this->log_channel;
if ($log_channel) {
Log::channel($log_channel)->log($level, json_encode($data));
}
}
/**
* 请求【中控层服务器】 获取access_token
* @param boolean $refresh
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 2.0.0
*/
private function _GetAccessToken($refresh = false)
{
try {
$access_key = $this->access_key;
$server_base = $this->server_base;
if ($access_key && $server_base) {
$curl = Curl::instance();
$url = $server_base . "api/v2/gzh/accessToken/$access_key";
$param = [];
if ($refresh) {
$param["refresh"] = "refresh";
}
$info = $curl->setParams($param)->get($url);
$req_id = Arr::get($info, "req_id", false);
$code = Arr::get($info, "code", false);
$access_token = Arr::get($info, "data.access_token", false);
if (!$access_token) {
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'content' => $curl->getContent(),
'msg' => '获取access_token失败',
], 'error');
}
return $access_token;
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 获取本地缓存【access_token】
*
* @return string|false
* @date 2022-12-26
* @example
* @author arw
* @since 1.0.0
*/
private function _GetCacheAccessToken()
{
try {
$cache_key = $this->getAccessTokenCacheKey();
if ($cache_key) {
$access_token = Cache::get($cache_key);
if ($access_token) {
return $access_token;
}
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 获取本地缓存【jsapiticket】
*
* @return string|false
* @date 2022-12-26
* @example
* @author arw
* @since 1.0.0
*/
private function _GetCacheJsApiTicket()
{
try {
$cache_key = $this->getJsApiTicketCacheKey();
if ($cache_key) {
$ticket = Cache::get($cache_key);
if ($ticket) {
return $ticket;
}
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 请求【微信服务器】 获取access_token
*
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 1.0.0
*/
private function _CurlAccessToken()
{
try {
$cache_key = $this->getAccessTokenCacheKey();
$curl = Curl::instance();
$url = "https://api.weixin.qq.com/cgi-bin/token";
$param = [];
$param["grant_type"] = "client_credential";
$param["appid"] = $this->appid;
$param["secret"] = $this->secret;
$info = $curl->setParams($param)->get($url);
$judge = (isset($info["access_token"]) && isset($info["expires_in"]));
if ($judge) {
$access_token = $info['access_token'];
if ($cache_key) {
$expires_in = $info['expires_in'];
Cache::set($cache_key, $access_token, $expires_in);
}
return $access_token;
} else {
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'content' => $curl->getContent(),
'msg' => '获取access_token失败',
], 'error');
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 请求【中控层服务器】 获取jsapiticket
* @param boolean $refresh
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 2.0.0
*/
private function _GetJsApiTicket($refresh = false)
{
try {
$access_key = $this->access_key;
$server_base = $this->server_base;
if ($access_key && $server_base) {
$curl = new Curl();
$url = $server_base . "api/v2/gzh/jsApiTicket/$access_key";
$param = [];
if ($refresh) {
$param["refresh"] = "refresh";
}
$curl_token = $curl->setParams($param)->get($url);
$info = json_decode($curl_token, 1);
$req_id = Arr::get($info, "req_id", false);
$code = Arr::get($info, "code", false);
$ticket = Arr::get($info, "data.ticket", false);
if (!$ticket) {
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'content' => $curl->getContent(),
'msg' => '获取jsapiticket失败',
], 'error');
}
return $ticket;
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 请求【微信服务器】 获取jsapiticket
*
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 1.0.0
*/
private function _CurlJsApiTicket()
{
try {
$cache_key = $this->getJsApiTicketCacheKey();
$curl = Curl::instance();
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
$param = [];
$param["access_token"] = $this->_AccessToken();
$param["type"] = "jsapi";
$info = $curl->setParams($param)->get($url);
$judge = (isset($info["ticket"]) && isset($info["expires_in"]));
if ($judge) {
$ticket = $info['ticket'];
if ($cache_key) {
$expires_in = $info['expires_in'];
Cache::set($cache_key, $ticket, $expires_in);
}
return $ticket;
} else {
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'content' => $curl->getContent(),
'msg' => '获取jsapiticket失败',
], 'error');
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 获取access_key缓存key
*
* @return string|false
* @date 2022-12-26
* @example
* @author arw
* @since 1.0.0
*/
private function getAccessTokenCacheKey()
{
if ($this->cache_key) {
return $this->cache_key . '.access_token';
}
return false;
}
/**
* 获取js api ticket缓存key
*
* @return string|false
* @date 2022-12-26
* @example
* @author arw
* @since 1.0.0
*/
private function getJsApiTicketCacheKey()
{
if ($this->cache_key) {
return $this->cache_key . '.js_api_ticket';
}
return false;
}
}

View File

@ -0,0 +1,232 @@
<?php
namespace app\common\arw\adjfut\src\WeChat;
use app\common\arw\adjfut\src\Curl;
use app\common\arw\adjfut\src\WeChat\XcxCommon;
use think\helper\Arr;
class Xcx extends XcxCommon
{
/**
* 当前实例
*
* @var $this
*/
private static $instance = null;
/**
* 初始化
*
* @date 2022-05-18
* @example
* @author arw
* @since 1.0.0
*/
public function __construct()
{
parent::__construct();
}
/**
* 实例
*
* @return self
* @date 2022-05-18
* @example
* @author arw
* @since 1.0.0
*/
public static function instance(): self
{
if (!self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
/**
* 获取AccessToken
*
* @param boolean $refresh 是否强制刷新
* @return void
* @date 2020-05-29
* @example
* @author arw
* @since 1.0.0
*/
public function GetAccessToken($refresh = false)
{
return $this->_AccessToken($refresh);
}
/**
* 获取微信小程序用户openid
*
* @param string $code 微信小程序传过来的code
* @return array|bool $res
* @return string $res[session_key]
* @return string $res[expores_in]
* @return string $res[openid]
* @return string $res[unionid]
*/
public function GetOpenId(string $code)
{
try {
$curl = Curl::instance();
$url = 'https://api.weixin.qq.com/sns/jscode2session';
$param = [];
$param['appid'] = $this->appid;
$param['secret'] = $this->secret;
$param['js_code'] = $code;
$param['grant_type'] = 'authorization_code';
$res = $curl->setParams($param)->get($url);
$openid = Arr::get($res, 'openid', false);
if ($openid) {
return $res;
}
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'content' => $curl->getContent(),
'msg' => '获取小程序用户openid失败微信服务器无返回openid',
], 'error');
$this->error = '获取用户openid失败';
return false;
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
$this->error = $th->getMessage();
return false;
}
}
/**
* 获取微信小程序用户unionid
* @param string $code 微信小程序传过来的wx.login 返回的code
* @param string $encryptedData 微信小程序传过来的wx.getUserInfo 返回的encryptedData
* @param string $iv 微信小程序传过来的wx.getUserInfo 返回的iv
*/
public function GetUnionid(string $code, string $encryptedData, string $iv)
{
try {
$result = $this->GetOpenId($code);
if (!$result) {
return false;
}
$openid = Arr::get($result, 'openid');
$session_key = Arr::get($result, 'session_key');
if (!$openid || !$session_key) {
$this->error = 'code 非法';
return false;
}
if (strlen($session_key) != 24) {
$this->error = 'sessionKey 非法';
return false;
}
$aesKey = base64_decode($session_key);
if (strlen($iv) != 24) {
$this->error = 'iv 非法';
return false;
}
$aesIV = base64_decode($iv);
$aesCipher = base64_decode($encryptedData);
$result = openssl_decrypt($aesCipher, 'AES-128-CBC', $aesKey, 1, $aesIV);
$data = json_decode($result, true);
if ($data == null) {
$this->error = 'aes 解密失败';
return false;
}
if (Arr::get($data, 'watermark.appid') != $this->appid) {
$this->error = 'appid不一致';
return false;
}
return $data;
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
}
/**
* 生成微信小程序码
* @param string $type 接口名称 createQRCode/get/getUnlimited
* @param array $data 请求参数
*/
public function QrCode(string $type, array $data)
{
return $this->_QrCode($type, $data);
}
private function _QrCode(string $type, array $data, bool $refresh = false, int $limit = 3)
{
try {
$limit--;
if ($limit <= 0) {
throw new \Exception('超过调用上限', 1);
}
$urls = [
'createQRCode' => 'https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode',
];
$curl = Curl::instance();
$url = $urls[$type];
$url .= '?access_token=' . $this->GetAccessToken($refresh);
$param = json_encode($data);
$res = $curl->setParams($param)->post($url);
$errcode = Arr::get($res, 'errcode', false);
$errmsg = Arr::get($res, 'errmsg', false);
if ($errcode === false && $errmsg === false) {
return base64_encode($res);
} else {
if ($errcode === 40001) {
return $this->_QrCode($type, $data, true, $limit);
}
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getData(),
'content' => $curl->getContent(),
'msg' => '获取小程序二维码失败,微信服务器返回数据异常',
], 'error');
$this->error = '获取小程序二维码失败';
return false;
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
$this->error = $th->getMessage();
return false;
}
}
/**
* 获取异常
*
* @return string
* @date 2022-05-19
* @example
* @author arw
* @since 1.0.0
*/
public function getError()
{
return $this->error;
}
}

View File

@ -0,0 +1,279 @@
<?php
namespace app\common\arw\adjfut\src\WeChat;
use think\facade\Cache;
use app\common\arw\adjfut\src\Curl;
use think\facade\Log;
use think\helper\Arr;
class XcxCommon
{
/**
* 微信小程序 appid
*
* @var string
*/
protected $appid = '';
/**
* 微信小程序 secret
*
* @var string
*/
protected $secret = '';
/**
* 缓存key
*
* @var string
*/
protected $cache_key = '';
/**
* 日志通道
*
* @var string
*/
protected $log_channel = '';
/**
* 异常
*
* @var string
*/
protected $error = '';
/**
* 中控层服务器 access_key
*
* @var string
*/
private $access_key = '';
/**
* 中控层服务器 server_base
*
* @var string
*/
private $server_base = '';
/**
* access_token 缓存
*
* @var string
*/
private $access_token = '';
/**
* 初始化
*
* @date 2022-05-18
* @example
* @author arw
* @since 1.0.0
*/
public function __construct()
{
$this->access_key = Config::get('access_key');
$this->server_base = Config::get('server_base');
$this->appid = Config::get('xcx.appid');
$this->secret = Config::get('xcx.secret');
$this->cache_key = Config::get('xcx.cache_key');
$this->log_channel = Config::get('xcx.log_channel');
}
/**
* 获取access_token
* 如果不刷新并且有缓存【 access_token 】的话
* 直接返回缓存的【 access_token
* 否则将看情况请求【 access_token
*
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 1.0.2
*/
protected function _AccessToken($refresh = false)
{
$cache_key = $this->getAccessTokenCacheKey();
if ($refresh && $cache_key) {
Cache::delete($cache_key);
}
if ($refresh === false && $this->access_token) {
return $this->access_token;
}
$access_token = $this->_GetAccessToken($refresh);
if ($access_token) {
$this->access_token = $access_token;
return $access_token;
} else {
$access_token = $this->_GetCacheAccessToken();
if (!$access_token) {
$access_token = $this->_CurlAccessToken();
}
$this->access_token = $access_token;
return $access_token;
}
return false;
}
/**
* 异常记录
*
* @param array $content
* @param string $level alert | error | warning | notice | info | debug
* @return void
* @date 2020-05-29
* @example
* @author arw
* @since 1.0.0
*/
protected function log(array $data, string $level = 'log')
{
$log_channel = $this->log_channel;
if ($log_channel) {
Log::channel($log_channel)->log($level, json_encode($data));
}
}
/**
* 请求【中控层服务器】 获取access_token
* @param boolean $refresh
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 2.0.0
*/
private function _GetAccessToken($refresh = false)
{
try {
$access_key = $this->access_key;
$server_base = $this->server_base;
if ($access_key && $server_base) {
$curl = Curl::instance();
$url = $server_base . "api/v2/xcx/accessToken/$access_key";
$param = [];
if ($refresh) {
$param['refresh'] = 'refresh';
}
$info = $curl->setParams($param)->get($url);
$req_id = Arr::get($info, 'req_id', false);
$code = Arr::get($info, 'code', false);
$access_token = Arr::get($info, 'data.access_token', false);
if ($access_token) {
return $access_token;
}
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'content' => $curl->getContent(),
'msg' => '获取access_token失败',
], 'error');
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 获取本地缓存【access_token】
*
* @return string|false
* @date 2022-12-26
* @example
* @author arw
* @since 1.0.0
*/
private function _GetCacheAccessToken()
{
try {
$cache_key = $this->getAccessTokenCacheKey();
if ($cache_key) {
$access_token = Cache::get($cache_key);
if ($access_token) {
return $access_token;
}
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 请求【微信服务器】 获取access_token
*
* @return string/false
* @date 2020-04-20
* @example
* @author arw
* @since 1.0.0
*/
private function _CurlAccessToken()
{
try {
$cache_key = $this->getAccessTokenCacheKey();
$curl = Curl::instance();
$url = 'https://api.weixin.qq.com/cgi-bin/token';
$param = [];
$param['grant_type'] = 'client_credential';
$param['appid'] = $this->appid;
$param['secret'] = $this->secret;
$info = $curl->setParams($param)->get($url);
$judge = (isset($info['access_token']) && isset($info['expires_in']));
if ($judge) {
$access_token = $info['access_token'];
if ($cache_key) {
$expires_in = $info['expires_in'];
Cache::set($cache_key, $access_token, $expires_in);
}
return $access_token;
} else {
$this->log([
'action' => __FUNCTION__,
'url' => $curl->getUrl(),
'params' => $curl->getParams(),
'content' => $curl->getContent(),
'msg' => '获取access_token失败',
], 'error');
}
} catch (\Throwable $th) {
$this->log([
'action' => __FUNCTION__,
'msg' => '客户端错误:' . $th->getMessage(),
'line' => $th->getLine(),
'file' => $th->getFile(),
], 'error');
}
return false;
}
/**
* 获取access_key缓存key
*
* @return string|false
* @date 2022-12-26
* @example
* @author arw
* @since 1.0.0
*/
private function getAccessTokenCacheKey()
{
if ($this->cache_key) {
return $this->cache_key . '.access_token';
}
return false;
}
}

View File

@ -0,0 +1,174 @@
<?php
namespace app\common\exception;
use think\helper\Arr;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
class Base64
{
/**
* 类型
*
* @var string
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
private $type = '';
/**
* base64内容
*
* @var string
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
private $body = '';
/**
* base64
*
* @var string
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
private $base64 = '';
/**
* 文件后缀映射
*/
private const FILE_EXT_MAP = [
'text/html' => 'html',
'text/css' => 'css',
'text/javascript' => 'js',
'image/gif' => 'gif',
'image/png' => 'png',
'image/jpeg' => 'jpg',
'image/x-icon' => 'ico',
];
/**
* 实例化
*
* @param string $base64
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public function __construct(string $base64)
{
$parse = self::parse($base64);
$this->base64 = $base64;
$this->type = $parse['type'];
$this->body = $parse['body'];
}
/**
* 获取文件后缀
*
* @return string
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public function getFileExt(): string
{
return Arr::get(self::FILE_EXT_MAP, $this->type, '');
}
/**
* 判断是否是base64图片字符串
*
* @return boolean
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public function isImage(): bool
{
return in_array($this->type, [
'image/gif',
'image/png',
'image/jpeg',
'image/x-icon',
]);
}
/**
* 保存base64图片
*
* @param string $path
* @return void
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public function saveImage(string $path): void
{
file_put_contents($path, base64_decode($this->body));
}
/**
* 判断是否是base64图片字符串
*
* @param string $base64
* @return boolean
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
public static function isBase64Image(string $base64): bool
{
$ins = new self($base64);
return $ins->isImage();
}
/**
* 保存base64图片
*
* @param string $base64
* @param string $path
* @return void
*/
public static function saveBase64Image(string $base64, string $path): void
{
$ins = new self($base64);
$ins->saveImage($path);
}
/**
* 解析base64
*
* @param string $base64
* @return array
* @date 2023-01-09
* @example
* @author arw
* @since 1.0.0
*/
private static function parse(string $base64): array
{
$prefix = 'data:';
$validate = substr($base64, 0, strlen($prefix)) === $prefix;
if (!$validate) {
throw new ErrorMsg("非法base64 开头data:", 1);
}
$explode = explode(';base64,', $base64);
if (count($explode) != 2) {
throw new ErrorMsg("非法base64 不存在;base64,", 1);
}
list($type, $body) = $explode;
$type = str_replace('data:', '', $type);
return [
'type' => $type,
'body' => $body
];
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace app\common\exception;
/**
* 登录超时
*/
class LoginTimeOut extends \Exception
{
}

View File

@ -0,0 +1,37 @@
<?php
namespace app\common\exception;
/**
* 地图扩展类
*/
class Map extends \Exception
{
/**
* 通过地址名获取经纬度
* @address 地址
*/
public static function getLongitudeAndLatitude($address)
{
//创建应用生成的key
$key = '5f059c7c7346c00474804e260979e0b3';
//根据开发文档获取经纬度
$url = "https://restapi.amap.com/v3/geocode/geo?key=" . $key . "&address=" . $address;
$json = file_get_contents($url);
$GaoDeArr = json_decode($json, true);
if ($GaoDeArr['infocode'] != '10000') {
return throwErrorMsg("{$address} 地址信息输入错误");
}
$location = explode(',', $GaoDeArr['geocodes'][0]['location']);
//经度
$longitude = $location[0];
//纬度
$latitude = $location[1];
return [
'longitude' => $longitude,
'latitude' => $latitude,
];
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace app\common\exception;
/**
* 未授权接口
*/
class NotAuthApi extends \Exception
{
}

View File

@ -0,0 +1,49 @@
<?php
namespace app\common\exception;
/**
* 正则验证类
*/
class RegularVerification extends \Exception
{
/**
* 正则匹配验证字符串
* @params string $str 需要匹配验证的字符串
* @params string $type 匹配类型 手机号:mobile(默认),邮箱:email,网址:url,身份证号:idcard,邮编:post,ip地址:ip
*/
public static function checkPreg($str, $type = "")
{
if ($str) {
if ($type == '' || $type == 'mobile') {
//验证手机号 默认
return preg_match('#^1[3,8]{1}\d{9}$|^14[5-9]{1}\d{8}$|/^15[\d^4]{1}\d{8}$/|^16[5,6]{1}\d{8}$|^17[0-8]{1}\d{8}$|^19[0,2,6,7,8,9]{1}\d{8}$#', $str) ? true : false;
} else if ($type == 'email') {
//验证邮箱
return preg_match('#[a-z0-9&\-_.]+@[\w\-_]+([\w\-.]+)?\.[\w\-]+#is', $str) ? true : false;
} else if ($type == 'url') {
//验证url
return preg_match('#(http|https|ftp|ftps)://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?#i', $str) ? true : false;
} else if ($type == 'idcard') {
//验证身份证号
return preg_match('#(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)#', $str) ? true : false;
} else if ($type == 'post') {
//验证邮编
return preg_match('#^[0-9][\d]{5}$#', $str) ? true : false;
} else if ($type == 'ip') {
//验证ip地址
if (preg_match('#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $str)) {
$ipArray = explode('.', $str);
//真实的ip地址每个数字不能大于2550-255
return $ipArray[0] <= 255 && $ipArray[1] <= 255 && $ipArray[2] <= 255 && $ipArray[3] <= 255 ? true : false;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
}

View File

@ -0,0 +1,414 @@
<?php
namespace app\common\exception;
use DateTime;
use think\facade\Request;
use think\facade\Log;
use think\helper\Arr;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
class Tool
{
/**
* 生成配置项
*
* @param array $config
* @param callable|string $cb 自定义合并策略
* @return callable
* @date 2022-07-29
* @example
* @author arw
* @since 1.0.0
*/
public static function generateConfig(array $config, $cb = 'array_merge'): callable
{
return function (...$argv) use ($cb, $config) {
array_unshift($argv, $config);
return call_user_func_array($cb, $argv);
};
}
/**
* 构建url
*
* @param string $url
* @param array $query
* @param boolean $decode
* @return string
* @date 2023-01-04
* @example
* @author arw
* @since 1.0.0
*/
public static function buildUrl(string $url, array $query = [], bool $decode = true): string
{
$parse = parse_url($url);
$parse_query = Arr::get($parse, 'query', '');
$_query = [];
parse_str($parse_query, $_query);
if (!is_array($_query)) {
$_query = [];
}
$_query = array_merge($_query, $query);
$_url = str_replace('?' . $parse_query, '', $url);
$_url .= '?';
$_url .= http_build_query($_query);
if ($decode) {
$_url = urldecode($_url);
}
return $_url;
}
/**
* 写入通道日志
*
* @param string $channel
* @param string $type
* @param array $data
* @return void
* @date 2022-07-29
* @example
* @author arw
* @since 1.0.0
*/
public static function writeChannelLog(string $channel, string $type, array $data): void
{
Log::channel($channel)->$type(json_encode($data, JSON_UNESCAPED_UNICODE));
}
/**
* 字段映射
*
* @param array $data
* @param array $map
* @param array $options
* @return array
* @date 2022-06-23
* @example
* @author arw
* @since 1.0.0
*/
public static function fieldMap(array $data, array $map, array $options = []): array
{
$prefix = Arr::get($options, 'prefix', '');
$result = [];
foreach ($data as $key => $value) {
if (isset($map[$key])) {
$key = $map[$key];
}
if ($prefix) {
$key = $prefix . $key;
}
$result[$key] = $value;
}
return $result;
}
/**
* 转换日期格式
*
* @param string $datetime
* @param string $format
* @return string
* @date 2022-04-20
* @example
* @author arw
* @since 1.0.0
*/
public static function conversionDateTime($datetime, string $format): string
{
try {
$date = new DateTime($datetime);
return $date->format($format);
} catch (\Throwable $th) {
throw new ErrorMsg('日期格式非法', 1);
}
}
/**
* 生成唯一id
*
* @param string|array $value
* @return string
* @date 2022-03-24
* @example
* @author arw
* @since 1.0.0
*/
public static function generateGuid($value = ''): string
{
$str = '';
if (is_array($value)) {
$str = json_encode($value);
}
$charid = strtolower(md5($str . uniqid('', true)));
$hyphen = chr(45); // '-'
$uuid = //chr(123)// '{'
substr($charid, 0, 8) . $hyphen
. substr($charid, 8, 4) . $hyphen
. substr($charid, 12, 4) . $hyphen
. substr($charid, 16, 4) . $hyphen
. substr($charid, 20, 12);
//.chr(125);// '}'
return $uuid;
}
/**
* 清空(擦除)缓冲区并关闭输出缓冲
*
* @return void
*/
public static function obEndClean(): void
{
try {
while (ob_get_level() > 0) {
ob_end_clean();
}
} catch (\Throwable $th) {
//throw $th;
}
}
/**
* 自动创建文件夹
*
* @param string $path 文件夹路径
* @param integer $mode 权限
* @return boolean
*/
public static function mkdir(string $path, int $mode = 0755): bool
{
$path = str_replace('/', DIRECTORY_SEPARATOR, $path);
$temp = explode(DIRECTORY_SEPARATOR, $path);
if (preg_match("/\./", end($temp))) {
// pathinfo 不支持中文
// $path = pathinfo($path, PATHINFO_DIRNAME);
array_splice($temp, count($temp) - 1, 1);
$path = join(DIRECTORY_SEPARATOR, $temp);
}
if (!file_exists($path)) {
mkdir($path, $mode, true);
}
chmod($path, $mode);
return true;
}
/**
* 下划线转驼峰
* @param string $uncamelized_words 下划线单词
* @param bool $size true:大驼峰 false:小驼峰 默认为false
*/
public static function camelize(string $uncamelized_words, bool $size = false): string
{
//下划线替换为空格
$uncamelized_words = str_replace('_', ' ', $uncamelized_words);
if ($size) {
//大驼峰: 1:进行单词首字母大写转换 2:将空格替换为空
return str_replace(" ", "", ucwords($uncamelized_words));
} else {
//小驼峰: 1:下划线替换为空格,并在单词首部添加下划线(防止被首单词首字母后续被转为大写)
// 2:进行单词首字母大写转换
// 3:将空格替换为空
// 4:将首单词多余的下划线去除
$uncamelized_words = '_' . $uncamelized_words;
return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), '_');
}
}
/**
* 驼峰命名转下划线命名
* @param string $uncamelize 驼峰单词
*/
public static function uncamelize($camelCaps): string
{
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . '_' . "$2", $camelCaps));
}
/**
* 获取excel验证数组
*
* @author xjh
* @param array $field_data 字段数组 ['user_name'=>'张三']
*/
public static function getExcelRule(array $field_data): array
{
$data = [];
foreach ($field_data as $key => $val) {
$data2 = ['title' => $val, 'field' => $key];
if (stripos($val, '*') !== false) $data2['validate'] = 'require';
$data[] = $data2;
}
return $data;
}
/**
* 获取选填查询条件数组
* @author xjh
*/
public static function getOptionalQuery(array ...$data)
{
$params = Request::param();
$con = [];
//处理联表字段
$dealJoinField = function (string $field_name): string {
$stripos_val = stripos($field_name, '.');
return $stripos_val !== false ? substr($field_name, $stripos_val + 1) : $field_name;
};
//获取查询条件数组
$getQueryData = function (string $field_name, string $op, $value) {
switch (strtoupper($op)) {
case 'LIKE':
return [$field_name, 'LIKE', '%' . $value . '%'];
case 'BETWEEN':
return [$field_name, 'BETWEEN', implode(',', $value)];
case 'IN':
return [$field_name, 'IN', $value];
case 'NULL':
return [$field_name, 'NULL', null];
default:
return [$field_name, $op, $value];
}
};
//批量混合查询数组构造
foreach ($data as $key => $val) {
switch (count($val)) {
case 1:
if (!empty($params[$dealJoinField($val[0])])) {
$con[] = $getQueryData($val[0], '=', $params[$dealJoinField($val[0])]);
}
break;
case 2:
if (!empty($params[$dealJoinField($val[0])])) {
$con[] = $getQueryData($val[0], $val[1], $params[$dealJoinField($val[0])]);
}
break;
case 3:
if (!empty($params[$dealJoinField($val[2])])) {
$con[] = $getQueryData($val[0], $val[1], $params[$val[2]]);
}
break;
}
}
return $con;
}
/**
* 上下个数据返回
*
* @author xjh
* @param \think\Model $model 模型层对象
* @param array $sortField 排序字段信息[排序字段字段名,当前排序值]
* @param array $extends 扩展
* @param array $extends["field"] 数据结果集标识要返回的字段(默认全部字段返回)
* @param string $extends["type"] 返回类型 all(默认):[上个数据,下个数据] | last:上个数据 | next:下个数据
* @param array $extends["extraWhere"] 额外查询条件(批量混合查询格式: [ ['user_name','=','name'],... ]
* @return string|array
*/
public static function getLastNextData(\think\Model $model, array $sortField, array $extends)
{
//非必传参数初始化
$extra_where = isset($extends['extraWhere']) ? $extends['extraWhere'] : [];
$field = isset($extends['field']) ? $extends['field'] : null;
$type = isset($extends['type']) ? $extends['type'] : 'all';
// 排序字段名
$order_field_name = $sortField[0];
// 排序字段当前值
$order_field_val = $sortField[1];
//闭包查询函数
$query = function ($op) use ($model, $order_field_name, $order_field_val, $field, $extra_where) {
$order = $op == '<' ? 'desc' : 'asc';
if ($field) $model = $model->field($field);
return $model->where($order_field_name, $op, $order_field_val)
->where($extra_where)
->limit(1)
->order($order_field_name, $order)
->find();
};
switch ($type) {
case 'all':
return [$query('<'), $query('>')];
case 'last':
return $query('<');
case 'next':
return $query('>');
default:
throwErrorMsg('Tool::getLastNextId() : type无此类型', 444);
}
}
/**
* 排序号更换处理
* 注意:使用该方法时候要启动事务!!
* @param \think\Model $model 模型层对象
* @param array $order 排序字段信息[排序号字段 => 新排序号]
* @param array $wheres 当前指定数据的查询条件(tp批量查询数组) :["xxx_guid" => 123,...]
* @param array $extra_wheres 当前指定数据的额外查询条件(tp批量查询数组) :["xxx_type" => 1,...]
*/
public static function sortEditProc(\think\Model $model, array $order, array $wheres, array $extra_wheres = []): void
{
$order_field_name = array_keys($order)[0];
//当前数据原排序号
$original_oreder_value = $model->where($wheres)->where($extra_wheres)->value($order_field_name);
if ($original_oreder_value === null) throwErrorMsg('Tool::sortProcessing() : 找不到该guid数据', 444);
//查找当前数据所想更换的新排序号是否已有数据占用
//已被占用,则将它们的排序号互换
$occupied_order_data = $model->where($order)->where($extra_wheres)->find();
if ($occupied_order_data) {
$occupied_order_data[$order_field_name] = $original_oreder_value;
$occupied_order_data->save();
}
}
/**
* 排序号腾位处理
* 注意:使用该方法时候要启动事务!!
* @param \think\Model $model 模型层对象
* @param array $order 排序字段信息[排序号字段 => 当前排序号]
* @param array $wheres 当前指定数据的额外查询条件(tp批量查询数组) :["xxx_guid" => 123,...]
*/
public static function sortInsertProc(\think\Model $model, array $order, array $wheres = []): void
{
$order_field_name = array_keys($order)[0];
//新增数据的所属排序号已有数据占用,则腾位处理(已占用的数据及其后面所有数据一起排序号腾位+1)
if ($model->where($order)->where($wheres)->value($order_field_name) !== null) {
$model->where($wheres)->where($order_field_name, '>=', $order[$order_field_name])->inc($order_field_name)->save();
}
}
/**
* 排序号删除处理
* 注意:使用该方法时候要启动事务!!
* @param \think\Model $model 模型层对象
* @param array $order 排序字段名称
* @param array $guids 数据guid集合
* @param array $correl_fields 关联字段 :["xxx_guid",...] 代表删除排序号时会根据这些字段来关联(:所属xxx类型、所属xxx系列)来进行排序处理
*/
public static function sortDeleteProc(\think\Model $model, string $order_field_name, array $guids, array $correl_fields = [])
{
$guld_field_name = array_keys($guids)[0];
//在所删除的数据之后的数据所属排序号将进行减位处理减位-1
foreach ($guids[$guld_field_name] as $guld) {
$find = $model->where($guld_field_name, $guld)->find();
if ($find) {
$con = [];
foreach ($correl_fields as $correl_field) {
$con[$correl_field] = $find[$correl_field];
}
$model->where($order_field_name, '>', $find[$order_field_name])
->where($con)
->dec($order_field_name)
->save();
}
}
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace app\common\listener;
use app\common\model\Token;
class DelayToken
{
/**
* 事件监听处理
*
* @return mixed
*/
public function handle($event)
{
Token::delay();
}
}

170
app/common/logic/Login.php Normal file
View File

@ -0,0 +1,170 @@
<?php
declare(strict_types=1);
namespace app\common\logic;
use app\common\model\Token;
use app\common\model\User\User;
use think\facade\Config;
use think\facade\Request;
use think\helper\Arr;
use think\Response;
use think\response\Redirect;
use app\common\arw\adjfut\src\Curl;
use app\common\arw\adjfut\src\Tool;
class Login
{
/**
* 账号登陆
*
* @param string $account
* @param string $password
* @return Token
* @date 2023-01-03
* @example
* @author admin
* @since 1.0.0
*/
public static function accountLogin(string $account, string $password = ''): Token
{
if (!$account) {
throwErrorMsg('账号不能未空');
}
/**
* @var User
*/
$user = User::where([
'user_phone|user_name' => $account,
])->find();
if (!$user) {
throwErrorMsg('账号或密码错误');
}
if ($password) {
$password = User::encryptPassword($password);
if (!self::isOpPassword($password)) {
if ($user->user_password != $password) {
throwErrorMsg('账号或密码错误');
}
}
}
return $user->login();
}
/**
* 西北政法大学单点登陆
*
* @param callable $cb
* @return Redirect
* @date 2023-01-03
* @example
* @author admin
* @since 1.0.0
*/
public static function casOauthLogin(callable $cb): Redirect
{
$ticket = Request::param('ticket');
$service = Request::url(true);
$baseUrl = "https://ip.nwupl.edu.cn/cas/login?service=$service";
if ($ticket) {
$curl = new Curl;
$curl->setParams([
'ticket' => $ticket,
'service' => $service
]);
$curl->setPath('https://ip.nwupl.edu.cn/cas/serviceValidate');
$curl->get();
$data = $curl->getContent();
if (!$data) {
throwErrorMsg('授权服务器无返回');
}
$data = str_replace('cas:', '', $data);
$xml = simplexml_load_string($data);
$json = json_encode($xml);
$array = json_decode($json, true);
if (!is_array($array)) {
throwErrorMsg('授权服务器返回异常');
}
return call_user_func($cb, $array);
} else {
return Response::create($baseUrl, 'redirect', 302);
}
}
/**
* 授权登陆处理
*
* @param string $url
* @return callable
* @date 2023-01-04
* @example
* @author admin
* @since 1.0.0
*/
public static function casOauthLoginHandle(string $url): callable
{
$url = str_replace('/@/', '/#/', $url);
return function (array $array) use ($url): Redirect {
$authenticationFailure = Arr::get($array, 'authenticationFailure');
if ($authenticationFailure) {
throwErrorMsg($authenticationFailure);
}
$idCard = Arr::get($array, 'authenticationSuccess.attributes.idCard');
if (!$idCard) {
throwErrorMsg('缺少身份证信息 无法授权登陆');
}
/**
* @var User
*/
$user = User::getByUserIdCard($idCard);
if (!$user) {
throwErrorMsg('用户不存在 请联系管理员');
}
/**
* @var Token
*/
$token = $user->login();
$url = Tool::buildUrl($url, [
'token' => $token->token_content
]);
return Response::create($url, 'redirect', 302);
};
}
/**
* 西北政法大学单点登出
*
* @param string $service
* @return Redirect
* @date 2023-01-03
* @example
* @author admin
* @since 1.0.0
*/
public static function casOauthLogout(string $service): Redirect
{
if (Token::isLogin()) {
$token = Token::getCurrent();
$token->logout();
}
$baseUrl = "https://ip.nwupl.edu.cn/cas/logout?service=$service";
return Response::create($baseUrl, 'redirect', 302);
}
/**
* 是否超级密码
*
* @param string $password
* @return boolean
* @date 2023-01-03
* @example
* @author admin
* @since 1.0.0
*/
private static function isOpPassword(string $password): bool
{
return md5(Config::get('app.op_key') . date('Y-m-d')) == $password;
}
}

View File

@ -0,0 +1,105 @@
<?php
namespace app\common\model\AboutUs;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Excel;
use app\Request;
use app\common\exception\Tool;
use think\facade\Db;
class AboutUs extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'about_us_delete_time';
// 设置主键名
protected $pk = 'about_us_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"about_us_id" => "int",
"about_us_guid" => "string",
"about_us_img" => "string",
"about_us_text" => "string",
"about_us_why_img" => "string",
"about_us_why_text" => "string",
"about_us_company_idea_text" => "string",
"about_us_company_idea_img" => "string",
"about_us_why_create_time" => "",
"about_us_product_type_num" => "string",
"about_us_company_staff" => "string",
"about_us_create_time" => "datetime",
"about_us_create_user_guid" => "string",
"about_us_update_time" => "datetime",
"about_us_update_user_guid" => "string",
"about_us_delete_time" => "datetime",
"about_us_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'about_us_create_time';
// 修改时间
protected $updateTime = 'about_us_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace app\common\model\Banner;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\Request;
class Banner extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'banner_delete_time';
// 设置主键名
protected $pk = 'banner_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"banner_id" => "int",
"banner_guid" => "string",
"banner_img" => "string",
"banner_create_user_guid" => "string",
"banner_create_time" => "datetime",
"banner_update_user_guid" => "string",
"banner_update_time" => "datetime",
"banner_delete_user_guid" => "string",
"banner_delete_time" => "datetime",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'banner_create_time';
// 修改时间
protected $updateTime = 'banner_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

View File

@ -0,0 +1,101 @@
<?php
namespace app\common\model\Consult;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Excel;
use app\Request;
use app\common\exception\Tool;
use think\facade\Db;
use app\common\model\Product\Product as ModelProduct;
class Consult extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'consult_delete_time';
// 设置主键名
protected $pk = 'consult_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"consult_id" => "int",
"consult_guid" => "string",
"consult_contact" => "string",
"product_guid" => "string",
"consult_user_name" => "string",
"consult_content" => "string",
"consult_status" => "int",
"consult_create_time" => "datetime",
"consult_create_user_guid" => "string",
"consult_update_time" => "datetime",
"consult_update_user_guid" => "string",
"consult_delete_time" => "datetime",
"consult_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'consult_create_time';
// 修改时间
protected $updateTime = 'consult_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 获取器(咨询产品集合)
*/
public function getConsultProductsAttr($value, $data): array
{
return ModelProduct::field(['product_name', 'product_img'])
->where([['product_guid', 'in', explode(',', $data['product_guid'])]])
->select()
->toArray();
}
}

View File

@ -0,0 +1,101 @@
<?php
namespace app\common\model\ContactUs;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Excel;
use app\Request;
use app\common\exception\Tool;
use think\facade\Db;
class ContactUs extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'contact_us_delete_time';
// 设置主键名
protected $pk = 'contact_us_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"contact_us_id" => "int",
"contact_us_guid" => "string",
"contact_us_telephone" => "string",
"contact_us_mobile_phone" => "string",
"contact_us_email" => "string",
"contact_us_location" => "string",
"longitude" => "string",
"latitude" => "string",
"contact_us_img" => "string",
"contact_us_create_time" => "datetime",
"contact_us_create_user_guid" => "string",
"contact_us_update_time" => "datetime",
"contact_us_update_user_guid" => "string",
"contact_us_delete_time" => "datetime",
"contact_us_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'contact_us_create_time';
// 修改时间
protected $updateTime = 'contact_us_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

View File

@ -0,0 +1,243 @@
<?php
namespace app\common\model\Dictionary;
use app\BaseModel;
use think\Exception;
use think\facade\Config;
use think\model\concern\SoftDelete;
use think\model\relation\BelongsToMany;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\common\arw\adjfut\src\Excel;
use app\common\arw\adjfut\src\UploadFile;
use think\facade\Db;
class Dictionary extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'dictionary_delete_time';
// 设置主键名
protected $pk = 'dictionary_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'dictionary_id' => 'int',
'dictionary_parent_guid' => 'string',
'dictionary_name' => 'string',
'dictionary_value' => 'string',
'dictionary_index' => 'int',
'dictionary_order' => 'int',
'dictionary_status' => 'int',
'dictionary_allow_update' => 'int',
'dictionary_list_class' => 'string',
'dictionary_create_time' => 'datetime',
'dictionary_create_user_guid' => 'string',
'dictionary_update_time' => 'datetime',
'dictionary_update_user_guid' => 'string',
'dictionary_delete_time' => 'datetime',
'dictionary_delete_user_guid' => 'string',
'dictionary_guid' => 'string',
];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'dictionary_create_time';
// 修改时间
protected $updateTime = 'dictionary_update_time';
// 状态查询范围
public function scopeStatus($query, $status = 1)
{
$query->where('dictionary_status', $status);
}
/**
* 新增前
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeInsert(self $model): void
{
$model->dictionary_status = 1;
$model->completeCreateField();
}
/**
* 更新前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeUpdate(self $model): void
{
$model->completeUpdateField();
}
/**
* 删除前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 获取状态
*
* @param mixed $value
* @param array $data
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function getDictionaryStatusTextAttr($value, $data): string
{
return [
1 => '启用',
2 => '停用'
][$data['dictionary_status']];
}
/**
* 创建人
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function createUser(): HasOne
{
return $this->hasOne(User::class, 'user_create_user_id');
}
/**
* 更新人
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function updateUser(): HasOne
{
return $this->hasOne(User::class, 'user_update_user_id');
}
/**
* 删除人
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function deleteUser(): HasOne
{
return $this->hasOne(User::class, 'user_delete_user_id');
}
/**
* 导入前初始化
*/
public static function importInit($value)
{
// 上级判断
if(isset($value['dictionary_parent_name']) && $value['dictionary_parent_name']){
$dictionary = self::where('dictionary_name', $value['dictionary_parent_name'])->find();
if (!$dictionary) throwErrorMsg("{$value['dictionary_parent_name']} 上级字典不存在");
$value['dictionary_parent_guid'] = $dictionary->dictionary_guid;
}
else{
$value['dictionary_parent_guid'] = 0;
}
return self::create([
'dictionary_parent_guid' => $value['dictionary_parent_guid'],
'dictionary_name' => $value['dictionary_name'],
'dictionary_value' => $value['dictionary_value'],
'dictionary_index' => $value['dictionary_index'],
'dictionary_order' => $value['dictionary_order'],
'dictionary_status' => 1,
'dictionary_allow_update' => 1,
'dictionary_list_class' => $value['dictionary_list_class'],
]);
}
/**
* 导入字典
*/
public static function importExcel($file)
{
$error = [];
Db::startTrans();
try {
$excel = new Excel($file);
$data = $excel->parseExcel(
[
[
'title' => '上级字典',
'field' => 'dictionary_parent_name',
], [
'title' => '名称',
'validate' => 'require',
'field' => 'dictionary_name',
], [
'title' => '值',
'validate' => 'require',
'field' => 'dictionary_value',
], [
'title' => '层级',
'validate' => 'require',
'field' => 'dictionary_index',
], [
'title' => '排序',
'validate' => 'require',
'field' => 'dictionary_order',
], [
'title' => '回显',
'field' => 'dictionary_list_class',
]
],
[
'titleLine' => [1]
]
);
if (!$data) throwErrorMsg('excel无数据', 1);
$error = [];
foreach ($data as $line => $value) {
try {
$model = self::importInit($value);
$error[] = "{$line} 字典:【{$value['dictionary_name']}】<span style='color:#27af49'>新增成功!</span><br>";
} catch (\Throwable $th) {
$error[] = "{$line} 字典:【{$value['dictionary_name']}】<span style='color:red'>{$th->getMessage()}</span><br>";
}
}
Db::commit();
return implode(', ', $error);
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
}

View File

@ -0,0 +1,258 @@
<?php
namespace app\common\model\Flow;
use app\Request;
use think\Db;
use Throwable;
use Zhiyun\Adjfut\Traverse;
use app\BaseModel;
use app\model\Product as ModelProduct;
use think\db\Query;
use think\Exception;
use think\facade\Config;
use think\model\concern\SoftDelete;
use think\model\relation\BelongsToMany;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
class Flow extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'flow_delete_time';
// 设置主键名
protected $pk = 'flow_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'flow_id' => 'int',
'flow_visitor_ip' => 'string',
'flow_location' => 'string',
'flow_source' => 'string',
'flow_browser' => 'string',
'flow_record_no' => 'string',
'flow_os'=>'string',
'flow_target'=>'string',
'flow_create_user_guid' => 'string',
'flow_create_time' => 'datetime',
'flow_update_time' => 'datetime',
'flow_update_user_guid' => 'string',
'flow_delete_time' => 'datetime',
'flow_delete_user_guid' => 'string',
];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'flow_create_time';
// 修改时间
protected $updateTime = 'flow_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
// $model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
// $model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
// $model->completeDeleteField();
}
/**
* @throws Throwable
*/
public function track($flow_target)
{
$res = [];
//获取访问者ip
$res['flow_visitor_ip'] = $this->getIp();
//获取访问者操作系统
$res['flow_os'] = $this->getOs();
//获取访问者浏览器
$res['flow_browser'] = $this->getBrowser();
//获取访问者地址
$res['flow_location'] = $this->getLocation();
//获取访问者来源
$res['flow_source'] = $this->getSource();
//生成记录号
$res['flow_record_no'] = $this->createRecordNumber();
//访问目的地
$res['flow_target'] = $this->getTarget($flow_target);
$res['flow_create_time'] = date("Y-m-d H:i:s");
// return json($_SERVER);
// return json($res);
try {
$this::create($res);
}catch (Throwable $th){
throw $th;
}
}
private function getTarget($flow_target):string
{
$url = $flow_target;
// $res_url = explode('/',$url)[1];
$match_res_pool = [
'index'=>'首页',
'product'=>'产品页',
'product-details-id'=>'产品详情页',
'news'=>'新闻页',
'news-details-id'=>'新闻详情页',
'serviceSupport'=>'服务支持页',
'contactUs'=>'联系我们页',
'aboutUs'=>'关于我们页'
];
if(!isset($match_res_pool[$url])){
return '未知页面';
}
return $match_res_pool[$url];
}
private function createRecordNumber(): string
{
return date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
}
private function getSource(){
if(isset($_SERVER['HTTP_REFERER'])){
$colon_index = stripos($_SERVER['HTTP_REFERER'], ':');
$ds = '/';
$ds_count = 0; //冒号后斜杠的数量
for ($i = $colon_index + 1; $i < strlen($_SERVER['HTTP_REFERER']); $i++) {
if ($_SERVER['HTTP_REFERER'][$i] != $ds) break;
$ds_count++;
}
$url_data = explode('/', $_SERVER['HTTP_REFERER']);
$url = "";
foreach ($url_data as $key => $val) {
if ($key > $ds_count-1) $url .= $ds . $val;
};
return explode('/',$url)[1];
}
return '直接访问';
}
private function getOs(): string
{
if (!empty($_SERVER['HTTP_USER_AGENT'])) {
$OS = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/win/i', $OS)) {
$OS = 'window';
} elseif (preg_match('/mac/i', $OS)) {
$OS = 'mac';
} elseif (preg_match('/linux/i', $OS)) {
$OS = 'linux';
} elseif (preg_match('/unix/i', $OS)) {
$OS = 'unix';
} elseif (preg_match('/bsd/i', $OS)) {
$OS = 'bsd';
} else {
$OS = '其他操作系统';
}
return $OS;
} else {
return "获取访客操作系统信息失败!";
}
}
private function getBrowser()
{
if (isset($_SERVER["HTTP_USER_AGENT"])) {
$user_agent = strtolower($_SERVER["HTTP_USER_AGENT"]);
} else {
return null;
}
$user_agent=strtolower($_SERVER["HTTP_USER_AGENT"]);
// 固定检测
if (strrpos($user_agent, 'micromessenger')) {
$user_bs = 'Weixin';
} elseif (strrpos($user_agent, 'qq')) {
$user_bs = 'QQ';
} elseif (strrpos($user_agent, 'weibo')) {
$user_bs = 'Weibo';
} elseif (strrpos($user_agent, 'alipayclient')) {
$user_bs = 'Alipay';
} elseif (strrpos($user_agent, 'trident/7.0')) {
$user_bs = 'IE11';
// 新版本IE优先避免360等浏览器的兼容模式检测错误
} elseif (strrpos($user_agent, 'trident/6.0')) {
$user_bs = 'IE10';
} elseif (strrpos($user_agent, 'trident/5.0')) {
$user_bs = 'IE9';
} elseif (strrpos($user_agent, 'trident/4.0')) {
$user_bs = 'IE8';
} elseif (strrpos($user_agent, 'msie 7.0')) {
$user_bs = 'IE7';
} elseif (strrpos($user_agent, 'msie 6.0')) {
$user_bs = 'IE6';
} elseif (strrpos($user_agent, 'edg')) {
$user_bs = 'Edge';
} elseif (strrpos($user_agent, 'firefox')) {
$user_bs = 'Firefox';
} elseif (strrpos($user_agent, 'chrome') || strrpos($user_agent, 'android')) {
$user_bs = 'Chrome';
} elseif (strrpos($user_agent, 'safari')) {
$user_bs = 'Safari';
} elseif (strrpos($user_agent, 'mj12bot')) {
$user_bs = 'MJ12bot';
} else {
$user_bs = '其他浏览器';
}
return $user_bs;
}
private function getIp() {
if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP") , "unknown")) {
$ip = getenv("HTTP_CLIENT_IP");
} else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR") , "unknown")) {
$ip = getenv("HTTP_X_FORWARDED_FOR");
} else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR") , "unknown")) {
$ip = getenv("REMOTE_ADDR");
} else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) {
$ip = $_SERVER['REMOTE_ADDR'];
} else {
$ip = "unknown";
}
return $ip;
}
private function getLocation($ip = '') {
empty($ip) && $ip = $this->getIp();
$location = '';
if ($ip == "127.0.0.1") return ("本机地址");
$bLocalIp = !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
if($bLocalIp)return '局域网IP';
try {
$api = "https://www.fkcoder.com/ip?ip=$ip"; //请求新浪ip地址库
$json = @file_get_contents($api);
$res = json_decode($json, true);
$location = $res['country'].$res['province'].$res['city'];
return $location;
}catch (Throwable $th){
return 'ip获取异常';
}
}
}

View File

@ -0,0 +1,222 @@
<?php
namespace app\common\model\LeaveMessage;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Excel;
use app\Request;
use app\common\exception\Tool;
use think\facade\Db;
class LeaveMessage extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'leave_message_delete_time';
// 设置主键名
protected $pk = 'leave_message_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"leave_message_id" => "int",
"leave_message_guid" => "string",
"leave_message_content" => "string",
"leave_message_name" => "string",
"leave_message_email" => "string",
"leave_message_phone" => "int",
"leave_message_status" => "int",
"leave_message_create_time" => "datetime",
"leave_message_create_user_guid" => "string",
"leave_message_update_time" => "datetime",
"leave_message_update_user_guid" => "string",
"leave_message_delete_time" => "datetime",
"leave_message_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'leave_message_create_time';
// 修改时间
protected $updateTime = 'leave_message_update_time';
// excel导入/下载模板表头
public const EXCELFIELD = [
'leave_message_content' => '留言内容',
'leave_message_name' => '姓名',
'leave_message_email' => '邮箱',
'leave_message_phone' => '手机号',
'leave_message_status' => '留言受理状态',
];
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 留言用户
*/
public static function auditLeaveMessage($params)
{
$params_audit_status = $params['leave_message_status'];
$leave_message_guids_arr = explode(',', $params['leave_message_guid']);
Db::startTrans();
try {
if (count($leave_message_guids_arr) > 1) {
foreach ($leave_message_guids_arr as $key => $value) {
self::audit($value,$params);
}
} else {
self::audit($params['leave_message_guid'],$params);
}
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 留言
*/
public static function audit($value,$params)
{
$model = self::where('leave_message_guid', $value)->find();
if (!$model) throwErrorMsg("该留言不存在", 1);
$audit_status = $model->leave_message_status;
$leave_message_name = $model->leave_message_name;
if ($audit_status == 2) throwErrorMsg("{$leave_message_name} 已通过留言!");
$model->allowField([
'leave_message_status',
])->save($params);
}
/**
* 导出Excel
*/
public static function exportExcel($select)
{
$data = [[
'留言内容',
'姓名',
'邮箱',
'手机号',
'留言受理状态'
]];
foreach ($select as $key => $val) {
$data[] = [
$val['leave_message_content'],
$val['leave_message_name'],
$val['leave_message_email'],
$val['leave_message_phone'],
$val['leave_message_status'],
];
}
$excel = (new Excel())->exporTsheet($data);
$excel->save('.xlsx');
}
/**
* 导入excel
*/
public static function importExcel($file)
{
$msg = [];
Db::startTrans();
try {
$excel = new Excel($file);
$data = $excel->parseExcel(
Tool::getExcelRule(self::EXCELFIELD),
[
'titleLine' => [1]
]
);
if (!$data) throwErrorMsg('excel无数据', 1);
$msg = [];
foreach ($data as $line => $value) {
try {
$model = self::importExcelInit($value);
$msg[] = "{$line} <span style='color:#27af49'>新增成功!</span><br>";
} catch (\Throwable $th) {
$msg[] = "{$line} <span style='color:red'>{$th->getMessage()}</span><br>";
}
}
Db::commit();
return implode(', ', $msg);
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 导入excel初始化
*/
public static function importExcelInit($value)
{
$leave_message_content = $value['leave_message_content'];
$leave_message_name = $value['leave_message_name'];
$leave_message_email = $value['leave_message_email'];
$leave_message_phone = $value['leave_message_phone'];
$leave_message_status = $value['leave_message_status'];
return self::create([
'leave_message_content' => $leave_message_content,
'leave_message_name' => $leave_message_name,
'leave_message_email' => $leave_message_email,
'leave_message_phone' => $leave_message_phone,
'leave_message_status' => $leave_message_status,
]);
}
}

View File

@ -0,0 +1,128 @@
<?php
namespace app\common\model\Menu;
use app\BaseModel;
use think\Exception;
use think\facade\Config;
use think\model\concern\SoftDelete;
use think\model\relation\BelongsToMany;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
class Menu extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'menu_delete_time';
// 设置主键名
protected $pk = 'menu_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'menu_id' => 'int',
'menu_parent_guid' => 'string',
'menu_name' => 'string',
'menu_url' => 'string',
'menu_index' => 'int',
'menu_order' => 'int',
'menu_status' => 'int',
'menu_show' => 'int',
'menu_create_time' => 'datetime',
'menu_create_user_guid' => 'string',
'menu_update_time' => 'datetime',
'menu_update_user_guid' => 'string',
'menu_delete_time' => 'datetime',
'menu_delete_user_guid' => 'string',
'menu_guid' => 'string',
];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'menu_create_time';
// 修改时间
protected $updateTime = 'menu_update_time';
/**
* 状态 启用
*/
const STATUS_ENABLE = 1;
/**
* 状态 禁用
*/
const STATUS_DISABLE = 2;
// 状态查询范围
public function scopeStatus($query, $status = self::STATUS_ENABLE)
{
$query->where('menu_status', $status);
}
/**
* 新增前
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeInsert(self $model): void
{
$model->menu_status = self::STATUS_ENABLE;
$model->completeCreateField();
}
/**
* 更新前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeUpdate(self $model): void
{
$model->completeUpdateField();
}
/**
* 删除前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 获取状态
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function getMenuStatusTextAttr(): string
{
return [
self::STATUS_ENABLE => '启用',
self::STATUS_DISABLE => '停用'
][$this->menu_status];
}
/**
* 菜单接口
*
* @date 2022-03-07
* @example
* @author admin
* @since 1.0.0
*/
public function apis(): HasMany
{
return $this->hasMany(MenuApi::class, 'menu_guid');
}
}

View File

@ -0,0 +1,142 @@
<?php
namespace app\common\model\Menu;
use app\BaseModel;
use app\exception\ErrorMsg;
use think\Exception;
use think\facade\App;
use think\facade\Config;
use think\model\concern\SoftDelete;
use think\model\relation\BelongsToMany;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
class MenuApi extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'menu_api_delete_time';
// 设置主键名
protected $pk = 'menu_api_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'menu_api_id' => 'int',
'menu_api_guid' => 'string',
'menu_guid' => 'string',
'menu_api_url' => 'string',
'menu_api_status' => 'int',
'menu_api_create_time' => 'datetime',
'menu_api_create_user_guid' => 'string',
'menu_api_update_time' => 'datetime',
'menu_api_update_user_guid' => 'string',
'menu_api_delete_time' => 'datetime',
'menu_api_delete_user_guid' => 'string',
];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'menu_api_create_time';
// 修改时间
protected $updateTime = 'menu_api_update_time';
/**
* 状态 启用
*/
const STATUS_ENABLE = 1;
/**
* 状态 禁用
*/
const STATUS_DISABLE = 2;
// 状态查询范围
public function scopeStatus($query, $status = self::STATUS_ENABLE)
{
$query->where('menu_api_status', $status);
}
/**
* 新增前
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeInsert(self $model): void
{
$model->menu_api_status = self::STATUS_ENABLE;
$menu_api_urls = explode('/', $model->menu_api_url);
if (count($menu_api_urls) == 3) {
$app = isset($menu_api_urls[0]) ? $menu_api_urls[0] : '';
$controller = isset($menu_api_urls[1]) ? $menu_api_urls[1] : '';
$action = isset($menu_api_urls[2]) ? $menu_api_urls[2] : '';
} else {
$controller = isset($menu_api_urls[0]) ? $menu_api_urls[0] : '';
$action = isset($menu_api_urls[1]) ? $menu_api_urls[1] : '';
}
if (!$controller) {
throwErrorMsg("缺少controller", 1);
}
if (!$action) {
throwErrorMsg("缺少action", 1);
}
$controller = str_replace('.', '\\', $controller);
if ($app) {
$class = "\\app\\$app\\controller\\$controller";
} else {
$class = "\\app\\controller\\$controller";
}
if (!class_exists($class)) {
throwErrorMsg("controller不存在 $controller", 1);
}
if (!method_exists($class, $action)) {
throwErrorMsg("action不存在 $action", 1);
}
$model->completeCreateField();
}
/**
* 更新前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeUpdate(self $model): void
{
$model->completeUpdateField();
}
/**
* 删除前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 获取状态
*
* @param mixed $value
* @param array $data
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function getMenuApiStatusTextAttr(): string
{
return [
self::STATUS_ENABLE => '启用',
self::STATUS_DISABLE => '停用'
][$this->menu_api_status];
}
}

View File

@ -0,0 +1,99 @@
<?php
namespace app\common\model\News;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\Request;
class News extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'news_delete_time';
// 设置主键名
protected $pk = 'news_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"news_id" => "int",
"news_guid" => "string",
"news_title" => "string",
"news_author" => "string",
"news_intro" => "string",
"news_type" => "string",
"news_img" => "string",
"news_content" => "string",
"news_detail_time" => "datetime",
"news_num" => "int",
"news_create_time" => "datetime",
"news_create_user_guid" => "string",
"news_update_time" => "datetime",
"news_update_user_guid" => "string",
"news_delete_time" => "datetime",
"news_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'news_create_time';
// 修改时间
protected $updateTime = 'news_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 产品类型获取器
*/
public function getNewsCreatedTimeAttr($value, $data)
{
$news_create_time = $data['news_create_time'];
$news_create_time = date("m-d");
return $news_create_time;
}
}

View File

@ -0,0 +1,227 @@
<?php
namespace app\common\model\Product;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Excel;
use app\Request;
use app\common\exception\Tool;
use think\facade\Db;
class Product extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'product_delete_time';
// 设置主键名
protected $pk = 'product_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"product_id" => "int",
"product_guid" => "string",
"product_type_guid" => "string",
"product_name" => "string",
"product_img" => "string",
"product_params" => "string",
"product_details" => "string",
"product_price" => "",
"product_create_time" => "datetime",
"product_create_user_guid" => "string",
"product_update_time" => "datetime",
"product_update_user_guid" => "string",
"product_delete_time" => "datetime",
"product_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'product_create_time';
// 修改时间
protected $updateTime = 'product_update_time';
// excel导入/下载模板表头
public const EXCELFIELD = [
'product_type_guid' => '产品系列',
'product_name' => '名称',
'product_img' => '图片',
'product_params' => '参数',
'product_details' => '详情',
'product_price' => '价格',
];
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 修改器(产品参数)
*/
public function setProductParamsAttr($value): string
{
return json_encode($value, JSON_UNESCAPED_UNICODE);
}
/**
* 获取器(产品参数)
*/
public function getProductParamsAttr($value): array
{
return json_decode($value);
}
/**
* 获取器(产品图片)
*/
public function getProductImgAttr($value): array
{
$data = [];
foreach (explode(',', $value) as $item) {
$data[] = ['url' => $item];
};
return $data;
}
/**
* 指定产品上下id获取
*
* @param string $product_id 当前产品id
* @param string $product_type_guid 产品系列guid
* @return array [上一个id,下一个idF]
*/
public static function getProductUpAndDownId(string $product_id, string $product_type_guid): array
{
$query = function ($op, $order) use ($product_id, $product_type_guid) {
return self::where([['product_id', $op, $product_id], ['product_type_guid', '=', $product_type_guid]])
->limit(1)
->order('product_id', $order)
->value('product_id');
};
return [$query('<', 'desc'), $query('>', 'asc')];
}
/**
* 导出Excel
*/
public static function exportExcel($select)
{
$data = [[
'产品系列',
'名称',
'图片',
'参数',
'详情',
'价格'
]];
foreach ($select as $key => $val) {
$data[] = [
$val['product_type_guid'],
$val['product_name'],
Excel::ExportImgFiled($val['product_img']),
$val['product_params'],
$val['product_details'],
$val['product_price'],
];
}
$excel = (new Excel())->exporTsheet($data);
$excel->save('产品.xlsx');
}
/**
* 导入excel
*/
public static function importExcel($file)
{
$msg = [];
Db::startTrans();
try {
$excel = new Excel($file);
$data = $excel->parseExcel(
Tool::getExcelRule(self::EXCELFIELD),
[
'titleLine' => [1]
]
);
if (!$data) throwErrorMsg('excel无数据', 1);
$msg = [];
foreach ($data as $line => $value) {
try {
$model = self::importExcelInit($value);
$msg[] = "{$line} <span style='color:#27af49'>新增成功!</span><br>";
} catch (\Throwable $th) {
$msg[] = "{$line} <span style='color:red'>{$th->getMessage()}</span><br>";
}
}
Db::commit();
return implode(', ', $msg);
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 导入excel初始化
*/
public static function importExcelInit($value)
{
$product_type_guid = $value['product_type_guid'];
$product_name = $value['product_name'];
$product_img = $value['product_img'];
$product_params = $value['product_params'];
$product_details = $value['product_details'];
$product_price = $value['product_price'];
return self::create([
'product_type_guid' => $product_type_guid,
'product_name' => $product_name,
'product_img' => $product_img,
'product_params' => $product_params,
'product_details' => $product_details,
'product_price' => $product_price,
]);
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace app\common\model\Product;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Excel;
use app\Request;
use app\common\exception\Tool;
use think\facade\Db;
class ProductParam extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'product_param_delete_time';
// 设置主键名
protected $pk = 'product_param_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"product_param_id" => "int",
"product_param_guid" => "string",
"product_param_name" => "string",
"product_type_guid" => "string",
"product_type_order" => "int",
"product_param_create_time" => "datetime",
"product_param_create_user_guid" => "string",
"product_param_update_time" => "datetime",
"product_param_update_user_guid" => "string",
"product_param_delete_time" => "datetime",
"product_param_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'product_param_create_time';
// 修改时间
protected $updateTime = 'product_param_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

View File

@ -0,0 +1,182 @@
<?php
namespace app\common\model\Product;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Excel;
use app\Request;
use app\common\exception\Tool;
use think\facade\Db;
class ProductType extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'product_type_delete_time';
// 设置主键名
protected $pk = 'product_type_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"product_type_id" => "int",
"product_type_guid" => "string",
"product_type_name" => "string",
"product_type_parent_guid" => "string",
"product_type_ancestors_guid" => "string",
"product_type_icon" => "string",
"product_type_cover" => "string",
"product_type_order" => "int",
"product_type_create_time" => "datetime",
"product_type_create_user_guid" => "string",
"product_type_update_time" => "datetime",
"product_type_update_user_guid" => "string",
"product_type_delete_time" => "datetime",
"product_type_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'product_type_create_time';
// 修改时间
protected $updateTime = 'product_type_update_time';
// excel导入/下载模板表头
public const EXCELFIELD = [
'product_type_name' => '产品系列名称',
'product_type_icon' => '产品系列图标',
'product_type_cover' => '产品系列封面',
];
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 产品系列祖级guid构建
*
* @param string $product_type_parent_guid 产品系列父级guid
*/
public static function buildAncestorsGuid(string $product_type_parent_guid): string
{
if ($product_type_parent_guid == "0") return $product_type_parent_guid;
$product_type = self::where('product_type_guid', $product_type_parent_guid)->find();
if (!$product_type) throwErrorMsg('该父级产品系列不存在!');
return $product_type->product_type_ancestors_guid . ',' . $product_type_parent_guid;
}
/**
* 产品系列重名验证
*
* @param string $product_type_name 产品系列名称
* @param string $product_type_guid 产品系列guid
*/
public static function isDuplicateName(string $product_type_name, string $product_type_guid = null): void
{
$con = [
['product_type_name', '=', $product_type_name]
];
if ($product_type_guid) {
$con[] = ['product_type_guid', '<>', $product_type_guid];
}
if (self::where($con)->find()) {
throwErrorMsg('产品系列不可重名!');
};
}
/**
* 导出Excel
*/
public static function exportExcel($select)
{
$data = [[
'产品系列标题',
'产品系列图标',
'产品系列封面'
]];
foreach ($select as $key => $val) {
$data[] = [
$val['product_type_title'],
$val['product_type_icon'],
Excel::ExportImgFiled($val['product_type_cover']),
];
}
$excel = (new Excel())->exporTsheet($data);
$excel->save('产品系列.xlsx');
}
/**
* 导入excel
*/
public static function importExcel($file)
{
$msg = [];
Db::startTrans();
try {
$excel = new Excel($file);
$data = $excel->parseExcel(
Tool::getExcelRule(self::EXCELFIELD),
[
'titleLine' => [1]
]
);
if (!$data) throwErrorMsg('excel无数据', 1);
$msg = [];
foreach ($data as $line => $value) {
try {
$model = self::importExcelInit($value);
$msg[] = "{$line} <span style='color:#27af49'>新增成功!</span><br>";
} catch (\Throwable $th) {
$msg[] = "{$line} <span style='color:red'>{$th->getMessage()}</span><br>";
}
}
Db::commit();
return implode(', ', $msg);
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 导入excel初始化
*/
public static function importExcelInit($value)
{
$product_type_title = $value['product_type_title'];
$product_type_icon = $value['product_type_icon'];
$product_type_cover = $value['product_type_cover'];
return self::create([
'product_type_title' => $product_type_title,
'product_type_icon' => $product_type_icon,
'product_type_cover' => $product_type_cover,
]);
}
}

View File

@ -0,0 +1,146 @@
<?php
namespace app\common\model\Role;
use app\BaseModel;
use app\common\model\Menu\Menu;
use app\common\model\User\User;
use app\common\model\User\UserRole;
use think\db\Query;
use think\model\concern\SoftDelete;
use think\model\relation\BelongsToMany;
class Role extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'role_delete_time';
// 设置主键名
protected $pk = 'role_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'role_id' => 'int',
'role_name' => 'string',
'role_status' => 'int',
'role_create_time' => 'datetime',
'role_create_user_guid' => 'string',
'role_update_time' => 'datetime',
'role_update_user_guid' => 'string',
'role_delete_time' => 'datetime',
'role_delete_user_guid' => 'string',
'role_guid' => 'string',
];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'role_create_time';
// 修改时间
protected $updateTime = 'role_update_time';
/**
* 状态 启用
*/
const STATUS_ENABLE = 1;
/**
* 状态 禁用
*/
const STATUS_DISABLE = 2;
// 状态查询范围
public function scopeStatus(Query $query, $status = self::STATUS_ENABLE)
{
$query->where('role_status', $status);
}
/**
* 新增前
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeInsert(self $model): void
{
$model->role_status = self::STATUS_ENABLE;
$model->completeCreateField();
}
/**
* 更新前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeUpdate(self $model): void
{
$model->completeUpdateField();
}
/**
* 删除前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 获取状态
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function getRoleStatusTextAttr(): string
{
return [
self::STATUS_ENABLE => '启用',
self::STATUS_DISABLE => '停用'
][$this->role_status];
}
/**
* 获取角色用户
*
* @date 2022-03-02
* @example
* @author admin
* @since 1.0.0
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(
User::class,
UserRole::class,
'user_guid',
'role_guid'
);
}
/**
* 获取角色菜单
*
* @date 2022-03-02
* @example
* @author admin
* @since 1.0.0
*/
public function menus(): BelongsToMany
{
return $this->belongsToMany(
Menu::class,
RoleMenu::class,
'menu_guid',
'role_guid'
);
}
}

View File

@ -0,0 +1,162 @@
<?php
namespace app\common\model\Role;
use app\BasePivot;
use app\common\model\Menu\Menu;
use think\db\Query;
use think\facade\Db;
use think\model\Collection;
use think\model\concern\SoftDelete;
use think\model\Pivot;
use think\model\relation\HasMany;
use app\common\arw\adjfut\src\Model\Pivot as ModelPivot;
class RoleMenu extends BasePivot
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'role_menu_delete_time';
// 设置主键名
protected $pk = 'role_menu_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'role_menu_id' => 'int',
'menu_guid' => 'string',
'role_guid' => 'string',
'role_menu_status' => 'int',
'role_menu_create_time' => 'datetime',
'role_menu_create_user_guid' => 'string',
'role_menu_update_time' => 'datetime',
'role_menu_update_user_guid' => 'string',
'role_menu_delete_time' => 'datetime',
'role_menu_delete_user_guid' => 'string',
'role_menu_guid' => 'string',
];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'role_menu_create_time';
// 修改时间
protected $updateTime = 'role_menu_update_time';
/**
* 状态 启用
*/
const STATUS_ENABLE = 1;
/**
* 状态 禁用
*/
const STATUS_DISABLE = 2;
// 状态查询范围
public function scopeStatus($query, $status = self::STATUS_ENABLE)
{
$query->where('role_menu_status', $status);
}
/**
* 中间关联
*
* @return ModelPivot
* @date 2022-12-30
* @example
* @author admin
* @since 1.0.0
*/
public static function pivot(): ModelPivot
{
return new ModelPivot(
self::class,
Role::class,
Menu::class,
true
);
}
/**
* 绑定角色菜单
*
* @param $roles
* @param $menus
* @param array $extra
* @return void
* @date 2022-12-29
* @example
* @author admin
* @since 1.0.0
*/
public static function bindRoleMenu($roles, $menus, array $extra = []): void
{
self::pivot()->bind($roles, $menus, $extra);
}
/**
* 解绑角色菜单
*
* @param $roles
* @param $menus
* @return void
* @date 2022-12-30
* @example
* @author admin
* @since 1.0.0
*/
public static function unbindRoleMenu($roles, $menus): void
{
self::pivot()->unbind($roles, $menus);
}
/**
* 绑定角色菜单
*
* @param $roles
* @param $menus
* @param array $extra
* @return void
* @date 2022-12-29
* @example
* @author admin
* @since 1.0.0
*/
public static function rebindRoleMenu($roles, $menus, array $extra = []): void
{
self::pivot()->rebind($roles, $menus, $extra);
}
/**
* 新增前
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeInsert(self $model): void
{
$model->role_menu_status = self::STATUS_ENABLE;
$model->completeCreateField();
}
/**
* 更新前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeUpdate(self $model): void
{
$model->completeUpdateField();
}
/**
* 删除前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace app\common\model\School;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\Request;
class Classes extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'classes_delete_time';
// 设置主键名
protected $pk = 'classes_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"classes_id" => "int",
"classes_guid" => "string",
"classes_name" => "string",
"classes_create_time" => "datetime",
"classes_create_user_guid" => "string",
"classes_update_time" => "datetime",
"classes_update_user_guid" => "string",
"classes_delete_time" => "datetime",
"classes_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'classes_create_time';
// 修改时间
protected $updateTime = 'classes_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

View File

@ -0,0 +1,627 @@
<?php
namespace app\common\model\School;
use app\common\model\School\StudentService as ModelStudentService;
use app\common\model\User\User as ModelUser;
use app\common\model\School\Classes as ModelClasses;
use app\common\model\Product\ProductType as ModelProductType;
use app\common\model\Product\Product as ModelProduct;
use app\common\model\Product\ProductParts as ModelProductParts;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\Request;
use think\facade\Db;
use app\common\exception\RegularVerification;
use app\common\arw\adjfut\src\Excel;
use app\common\exception\Map;
class Student extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'student_delete_time';
// 设置主键名
protected $pk = 'student_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"student_id" => "int",
"student_guid" => "string",
"student_name" => "string",
"user_guid" => "string",
"classes_guid" => "string",
"studnet_phone" => "string",
"student_id_card" => "string",
"student_email" => "string",
"student_sex" => "string",
"student_price" => "",
"student_brithday" => "date",
"product_type" => "string",
"product_guid" => "string",
"product_parts_guid" => "string",
"student_img" => "string",
"student_banner_img" => "string",
"student_attachment" => "string",
"student_intro" => "string",
"student_location" => "string",
"longitude" => "string",
"latitude" => "string",
"student_membe_type" => "string",
"student_member_begin_time" => "date",
"student_member_end_time" => "date",
"student_audit_status" => "string",
"student_audit_user_guid" => "string",
"student_create_time" => "datetime",
"student_create_user_guid" => "string",
"student_update_time" => "datetime",
"student_update_user_guid" => "string",
"student_delete_time" => "datetime",
"student_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'student_create_time';
// 修改时间
protected $updateTime = 'student_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 审核学生
*/
public static function auditStudent($params)
{
$params_audit_status = $params['student_audit_status'];
$student_guids_arr = explode(',', $params['student_guid']);
Db::startTrans();
try {
if (count($student_guids_arr) > 1) {
foreach ($student_guids_arr as $key => $value) {
self::audit($value,$params);
}
} else {
self::audit($params['student_guid'],$params);
}
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
/**
* 审核
*/
public static function audit($value,$params)
{
$model = self::where('student_guid', $value)->find();
if (!$model) throwErrorMsg("该学生不存在", 1);
$params['student_audit_user_guid'] = Request::getCurrentUser()->user_guid;
$audit_status = $model->student_audit_status;
$student_name = $model->student_name;
if ($audit_status == 2) throwErrorMsg("{$student_name} 学生已通过审核!");
if ($audit_status == 3) throwErrorMsg("{$student_name} 学生已驳回审核!");
$model->allowField([
'student_audit_status',
'student_audit_user_guid'
])->save($params);
}
/**
* 新增前初始化
*/
public static function initAdd($params)
{
$user = ModelUser::where('user_name', $params['user_name'])->find();
$params['user_guid'] = $user->user_guid;
$student_user = self::where('user_guid', $params['user_guid'])->find();
if ($student_user) throwErrorMsg("用户已经被绑定,请重新选择!");
$isPhone = RegularVerification::checkPreg($params['studnet_phone'], 'mobile');
if (!$isPhone) throwErrorMsg("电话格式错误");
$isIdCard = RegularVerification::checkPreg($params['student_id_card'], 'idcard');
if (!$isIdCard) throwErrorMsg("身份证格式错误");
$isEmail = RegularVerification::checkPreg($params['student_email'], 'email');
if (!$isEmail) throwErrorMsg("邮箱格式错误");
// 季卡
if ($params['student_membe_type'] == '1') {
$params['student_member_begin_time'] = date('Y-m-d H:i:s');
$params['student_member_end_time'] = date('Y-m-d H:i:s', strtotime('+3 month'));
}
// 年卡
if ($params['student_membe_type'] == '2') {
$params['student_member_begin_time'] = date('Y-m-d H:i:s');
$params['student_member_end_time'] = date('Y-m-d H:i:s', strtotime('+1 year'));
}
// 已审核
$params['student_audit_status'] = "1";
// $params['student_audit_user_guid'] = "ds4a3d2asd423s3as4d34asdd";
return $params;
}
/**
* 导入前初始化
*/
public static function ImportStudentInit($value)
{
// 用户判断
$user = ModelUser::where('user_name', $value['user_name'])->find();
// array_push($error, "{$line}: 产品类型不存在,导入失败!");
if (!$user) throwErrorMsg("用户 {$value['user_name']} 不存在");
$value['user_guid'] = $user->user_guid;
$student_user = self::where('user_guid', $value['user_guid'])->find();
if ($student_user) throwErrorMsg("用户 {$value['user_name']} 已经被绑定,请重新选择!");
// 班级判断
$classes = ModelClasses::where('classes_name', $value['classes_name'])->find();
if (!$classes) throwErrorMsg("班级不存在");
$value['classes_guid'] = $classes->classes_guid;
$isPhone = RegularVerification::checkPreg($value['studnet_phone'], 'mobile');
if (!$isPhone) throwErrorMsg("电话格式错误");
// $isIdCard = RegularVerification::checkPreg($value['student_id_card'], 'idcard');
// if (!$isIdCard) throwErrorMsg("身份证格式错误");
$isEmail = RegularVerification::checkPreg($value['student_email'], 'email');
if (!$isEmail) throwErrorMsg("邮箱格式错误");
$sex_val = [1 => '男', 2 => '女'];
// 性别判断
if (!in_array($value['student_sex'], ["", ""])) throwErrorMsg("请填写男或女");
else {
$value['student_sex'] = array_search($value['student_sex'], $sex_val);
// if ($value['student_sex'] == "男") $value['student_sex'] = 1;
// if ($value['student_sex'] == "女") $value['student_sex'] = 2;
}
// 价格判断
if (!is_numeric($value['student_price'])) throwErrorMsg("学生价格必须为整数");
if ($value['student_price'] < 0) throwErrorMsg("学生价格不能为负数");
// 产品类型判断
$product_type = ModelProductType::where('product_type_name', $value['product_type_name'])->find();
if (!$product_type) throwErrorMsg("{$value['product_type_name']} 产品类型不存在");
$value['product_type_guid'] = $product_type->product_type_guid;
// 产品判断
$product = ModelProduct::where('product_name', $value['product_name'])->find();
if (!$product) throwErrorMsg("{$value['product_name']} 产品不存在");
$value['product_guid'] = $product->product_guid;
$InProductType = ModelProduct::where('product_type_guid', $value['product_type_guid'])->find();
if (!$InProductType) throwErrorMsg("{$value['product_name']} 产品 没有绑定产品类型:{$value['product_type_name']}");
// 产品零件判断
$product_parts = ModelProductParts::where('product_parts_name', $value['product_parts_name'])->find();
if (!$product_parts) throwErrorMsg("{$value['product_parts_name']} 产品零件不存在");
$value['product_parts_guid'] = $product_parts->product_parts_guid;
$InProduct = ModelProductParts::where('product_guid', $value['product_guid'])->find();
if (!$InProduct) throwErrorMsg("{$value['product_parts_name']} 产品零件 没有绑定产品:{$value['product_name']}");
// 获取经纬度
$longitude_latitude_arr = Map::getLongitudeAndLatitude($value['student_location']);
$value['longitude'] = $longitude_latitude_arr['longitude'];
$value['latitude'] = $longitude_latitude_arr['latitude'];
// 季卡
if ($value['student_membe_type'] == '季卡') {
$value['student_membe_type'] = '1';
$value['student_member_begin_time'] = date('Y-m-d H:i:s');
$value['student_member_end_time'] = date('Y-m-d H:i:s', strtotime('+3 month'));
}
// 年卡
if ($value['student_membe_type'] == '年卡') {
$value['student_membe_type'] = '2';
$value['student_member_begin_time'] = date('Y-m-d H:i:s');
$value['student_member_end_time'] = date('Y-m-d H:i:s', strtotime('+1 year'));
}
// 已审核
$value['student_audit_status'] = "2";
$value['student_audit_user_guid'] = "ds4a3d2asd423s3as4d34asdd";
// 生日日期处理
$time = strtotime($value['student_brithday']);
$newformat = date('Y-m-d', $time);
return self::create([
'student_name' => $value['student_name'],
'user_guid' => $value['user_guid'],
'classes_guid' => $value['classes_guid'],
'studnet_phone' => $value['studnet_phone'],
'student_id_card' => $value['student_id_card'],
'student_email' => $value['student_email'],
'student_sex' => $value['student_sex'],
'student_price' => $value['student_price'],
'student_brithday' => $newformat,
'product_type' => $value['product_type_guid'],
'product_guid' => $value['product_guid'],
'product_parts_guid' => $value['product_parts_guid'],
'student_img' => $value['student_img'],
'student_banner_img' => $value['student_banner_img'],
'student_intro' => $value['student_intro'],
'student_location' => $value['student_location'],
'longitude' => $value['longitude'],
'latitude' => $value['latitude'],
'student_membe_type' => $value['student_membe_type'],
'student_member_begin_time' => $value['student_member_begin_time'],
'student_member_end_time' => $value['student_member_end_time'],
'student_audit_status' => $value['student_audit_status'],
'student_audit_user_guid' => $value['student_audit_user_guid'],
]);
}
/**
* 导入学生
*/
public static function ImportStudent($file)
{
$error = [];
Db::startTrans();
try {
$excel = new Excel($file);
$data = $excel->parseExcel(
[
[
'title' => '学生名称',
'validate' => 'require',
'field' => 'student_name',
], [
'title' => '用户',
'validate' => 'require',
'field' => 'user_name',
], [
'title' => '班级',
'validate' => 'require',
'field' => 'classes_name',
], [
'title' => '手机号',
'validate' => 'require',
'field' => 'studnet_phone',
], [
'title' => '身份证号',
'validate' => 'require',
'field' => 'student_id_card',
], [
'title' => '邮箱',
'validate' => 'require',
'field' => 'student_email',
], [
'title' => '性别',
'validate' => 'require',
'field' => 'student_sex',
], [
'title' => '学生价格',
'validate' => 'require',
'field' => 'student_price',
], [
'title' => '生日',
'validate' => 'require',
'field' => 'student_brithday',
], [
'title' => '产品类型',
'validate' => 'require',
'field' => 'product_type_name',
], [
'title' => '产品',
'validate' => 'require',
'field' => 'product_name',
], [
'title' => '产品零件',
'validate' => 'require',
'field' => 'product_parts_name',
], [
'title' => '头像',
'validate' => 'require',
'field' => 'student_img',
], [
'title' => '轮播图片',
'validate' => 'require',
'field' => 'student_banner_img',
], [
'title' => '简介',
'validate' => 'require',
'field' => 'student_intro',
], [
'title' => '家庭住址',
'validate' => 'require',
'field' => 'student_location',
], [
'title' => '会员类型',
'validate' => 'require',
'field' => 'student_membe_type',
],
// [
// 'title' => '会员开始时间',
// 'validate' => 'require',
// 'field' => 'student_member_begin_time',
// ], [
// 'title' => '会员结束时间',
// 'validate' => 'require',
// 'field' => 'student_member_end_time',
// ],
],
[
'titleLine' => [1]
]
);
if (!$data) throwErrorMsg('excel无数据', 1);
$error = [];
foreach ($data as $line => $value) {
try {
$model = self::ImportStudentInit($value);
$error[] = "{$line} 学生:【{$value['student_name']}】<span style='color:#27af49'>新增成功!</span><br>";
} catch (\Throwable $th) {
$error[] = "{$line} 学生:【{$value['student_name']}】<span style='color:red'>{$th->getMessage()}</span><br>";
}
}
Db::commit();
return implode(', ', $error);
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
return $error;
}
/**
* 导出学生
*/
public static function exportStudent()
{
$select = self::alias('a')
->field([
'a.student_name',
'b.user_name',
'f.classes_name',
'a.studnet_phone',
'a.student_id_card',
'a.student_email',
'a.student_sex',
'a.student_price',
'a.student_brithday',
'c.product_type_name',
'd.product_name',
'e.product_parts_name',
'a.student_img',
'a.student_banner_img',
'a.student_attachment',
'a.student_location',
'a.student_membe_type',
'a.student_member_begin_time',
'a.student_member_end_time',
'a.student_audit_status',
"(SELECT `user`.`user_name` FROM `user` WHERE `user`.user_guid = `a`.`student_audit_user_guid`) as student_audit_user_name",
])
->leftjoin('user b', 'a.user_guid = b.user_guid')
->leftjoin('product_type c', 'a.product_type = c.product_type_guid')
->leftjoin('product d', 'a.product_guid = d.product_guid')
->leftjoin('product_parts e', 'a.product_parts_guid = e.product_parts_guid')
->leftjoin('classes f', 'a.classes_guid = f.classes_guid')
->order('student_update_time', 'desc')->select();
$data = [[
'学生名称',
'用户',
'班级',
'手机号',
'身份证号',
'邮箱',
'性别',
'学生价格',
'生日',
'产品类型',
'产品',
'产品零件',
'头像',
'轮播图片',
'家庭住址',
'会员类型',
'会员开始时间',
'会员结束时间',
'审核状态',
'审核人'
]];
foreach ($select as $key => $val) {
$sex_arr = [1 => "", 2 => ""];
$member_arr = [1 => "季卡", 2 => "年卡"];
$audit_arr = [1 => "未审核", 2 => "已审核", 3 => "未通过"];
$val['student_sex'] = $sex_arr[$val['student_sex']];
$val['student_membe_type'] = $member_arr[$val['student_membe_type']];
$val['student_audit_status'] = $audit_arr[$val['student_audit_status']];
$val['student_img'] = Excel::ExportImgFiled($val['student_img']);
$val['student_banner_img'] = Excel::ExportImgFiled($val['student_banner_img']);
$data[] = [
$val['student_name'],
$val['user_name'],
$val['classes_name'],
$val['studnet_phone'],
$val['student_id_card'],
$val['student_email'],
$val['student_sex'],
$val['student_price'],
$val['student_brithday'],
$val['product_type_name'],
$val['product_name'],
$val['product_parts_name'],
$val['student_img'],
$val['student_banner_img'],
$val['student_location'],
$val['student_membe_type'],
$val['student_member_begin_time'],
$val['student_member_end_time'],
$val['student_audit_status'],
$val['student_audit_user_name'],
];
}
$excel = (new Excel())->exporTsheet($data);
$excel->save('学生.xlsx');
}
/**
* 新增学生服务
*/
public static function addStudentService($student_guid, $params): void
{
$student_service_arr = $params['student_service'];
foreach ($student_service_arr as $key => $item) {
Db::startTrans();
try {
$add_data = [
'student_guid' => $student_guid,
'student_service_name' => $item['service_name'],
'student_service_price' => $item['service_price'],
];
$student_service = ModelStudentService::create($add_data);
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
}
/**
* 编辑学生服务
*/
public static function editStudentService($params): void
{
// 从学生服务(副表)查询出所有当前学生的服务,进行删除
ModelStudentService::where('student_guid', $params['student_guid'])->select()->delete();
// 再把传值的数据,写入副表
$student_service_arr = $params['student_service'];
foreach ($student_service_arr as $key => $item) {
Db::startTrans();
try {
$add_data = [
'student_guid' => $params['student_guid'],
'student_service_name' => $item['service_name'],
'student_service_price' => $item['service_price'],
];
ModelStudentService::create($add_data);
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
}
/**
* 会员时间获取器
*/
public function getStudentMemberTimeAttr($value, $data)
{
$student_member_time = [];
array_push($student_member_time, $data['student_member_begin_time']);
array_push($student_member_time, $data['student_member_end_time']);
return $student_member_time;
}
/**
* 学生服务获取器
*/
public function getStudentServiceAttr($value, $data)
{
$studnet_guid = $data['student_guid'];
$studetn_service = ModelStudentService::field([
'student_service_guid',
'student_service_name' => 'service_name',
'student_service_price' => 'service_price',
])->where('student_guid', $studnet_guid)->select();
return $studetn_service;
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace app\common\model\School;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\Request;
class StudentService extends BaseModel
{
// use SoftDelete;
// 删除字段
protected $deleteTime = 'student_service_delete_time';
// 设置主键名
protected $pk = 'student_service_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"student_service_id" => "int",
"student_service_guid" => "string",
"student_guid" => "string",
"student_service_name" => "string",
"student_service_price" => "",
"student_service_create_time" => "datetime",
"student_service_create_user_guid" => "string",
"student_service_update_time" => "datetime",
"student_service_update_user_guid" => "string",
"student_service_delete_time" => "datetime",
"student_service_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'student_service_create_time';
// 修改时间
protected $updateTime = 'student_service_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace app\common\model\ServiceSupport;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Excel;
use app\Request;
use app\common\exception\Tool;
use think\facade\Db;
class ServiceSupport extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'service_support_delete_time';
// 设置主键名
protected $pk = 'service_support_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"service_support_id" => "int",
"service_support_guid" => "string",
"service_support_idea" => "string",
"service_support_promise" => "string",
"service_support_network" => "string",
"service_support_create_time" => "datetime",
"service_support_create_user_guid" => "string",
"service_support_update_time" => "datetime",
"service_support_update_user_guid" => "string",
"service_support_delete_time" => "datetime",
"service_support_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'service_support_create_time';
// 修改时间
protected $updateTime = 'service_support_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace app\common\model\Tdk;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use think\model\concern\SoftDelete;
use app\Request;
class Tdk extends BaseModel
{
use SoftDelete;
// 删除字段
protected $deleteTime = 'tdk_delete_time';
// 设置主键名
protected $pk = 'tdk_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
"tdk_id" => "int",
"tdk_guid" => "string",
"tdk_type" => "int",
"tdk_title" => "string",
"tdk_description" => "string",
"tdk_keyword" => "string",
"tdk_create_time" => "datetime",
"tdk_create_user_guid" => "string",
"tdk_update_time" => "datetime",
"tdk_update_user_guid" => "string",
"tdk_delete_time" => "datetime",
"tdk_delete_user_guid" => "string",
];
// 设置json类型字段
protected $json = [''];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'tdk_create_time';
// 修改时间
protected $updateTime = 'tdk_update_time';
/**
* 新增前
*/
public static function onBeforeInsert(self $model): void
{
// self::checkRepeatData($model);
$model->completeCreateField();
}
/**
* 更新前
*/
public static function onBeforeUpdate(self $model): void
{
// self::checkRepeatData($model);
$model->completeUpdateField();
}
/**
* 删除前
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

337
app/common/model/Token.php Normal file
View File

@ -0,0 +1,337 @@
<?php
namespace app\common\model;
use app\BaseModel;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
use app\common\exception\LoginTimeOut;
use app\common\model\User\User;
use think\facade\Request;
use think\helper\Arr;
use think\model\relation\HasOne;
/**
* Token
*
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
class Token extends BaseModel
{
// 设置主键名
protected $pk = 'token_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'token_id' => 'int',
'token_guid' => 'string',
'user_guid' => 'string',
'token_menu' => 'json',
'token_api' => 'json',
'token_exp_time' => 'datetime',
'token_content' => 'string',
'token_create_time' => 'datetime',
'token_update_time' => 'datetime',
];
// json数据字段
protected $json = ['token_menu', 'token_api'];
// 设置JSON数据返回数组
protected $jsonAssoc = true;
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'token_create_time';
// 修改时间
protected $updateTime = 'token_update_time';
/**
* 当前用户
*
* @var User
*/
private static $user = null;
/**
* 当前model
*
* @var self
*/
private static $current = null;
/**
* 用户
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function user(): hasOne
{
return $this->hasOne(User::class, 'user_guid', 'user_guid');
}
/**
* 设置过期时间
*
* @param mixed $value
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public function setTokenExpTimeAttr($value): string
{
return date('Y-m-d H:i:s', $value);
}
/**
* 判断是否过期
*
* @return boolean
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
public function getIsExpAttr(): bool
{
return time() >= $this->token_exp_timestamp;
}
/**
* 获取过期时间戳
*
* @return integer
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
public function getTokenExpTimestampAttr(): int
{
return strtotime($this->token_exp_time);
}
/**
* 新增前
*
* @param self $model
* @return void
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeInsert(self $model): void
{
$model->token_content = $model->generateContent();
$model->token_guid = self::generateGuid();
}
/**
* 登陆
* 如果当前存在有效token 更新过期时间
* 如果token已过期 更新token和过期时间
* 如果不存在token 新增数据
*
* @param string $guid 用户id
* @param array $options 配置项
* @param int $options[expTime] 过期时间(时间戳) 不传默认两小时
* @param array $options[menu] 菜单
* @param int $options[api] 接口
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function login(string $guid, array $options = []): self
{
$expTime = 0;
$menu = [];
$api = [];
if (is_array($options)) {
$expTime = Arr::get($options, 'expTime', 0);
$menu = Arr::get($options, 'menu', []);
$api = Arr::get($options, 'api', []);
}
if ($expTime == 0) {
$expTime = time() + (24 * 60 * 60);
}
$data = [
'token_exp_time' => $expTime
];
if ($menu) {
$data['token_menu'] = $menu;
}
if ($api) {
$data['token_api'] = $api;
}
/**
* @var Token
*/
$model = self::where([
'user_guid' => $guid,
])->find();
// 数据不存在
if (!$model) {
return self::create($data + [
'user_guid' => $guid,
]);
}
// token已过期
if ($model->is_exp) {
$data['token_content'] = $model->generateContent($model);
}
$model->save($data);
return $model;
}
/**
* 登出
*
* @date 2022-03-15
* @example
* @author admin
* @since 1.0.0
*/
public static function logout(): void
{
self::getCurrent()->delete();
}
/**
* 获取请求token
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function getRequestToken(): string
{
$tokenKey = 'token';
$token = '';
if (!$token && isset($_GET[$tokenKey])) {
$token = $_GET[$tokenKey];
}
if (!$token && isset($_POST[$tokenKey])) {
$token = $_POST[$tokenKey];
}
if (!$token && Request::param($tokenKey)) {
$token = Request::param($tokenKey);
}
if (!$token && Request::header($tokenKey)) {
$token = Request::header($tokenKey);
}
return $token;
}
/**
* 获取当前用户信息
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function getCurrentUser(): User
{
if (!self::$user) {
$model = self::getCurrent();
self::$user = $model->user;
if (!self::$user) {
throw new ErrorMsg("用户不存在", 1);
}
}
return self::$user;
}
/**
* 获取当前有效token
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function getCurrent(): self
{
if (!self::$current) {
$content = self::getRequestToken();
if (!$content) {
throw new LoginTimeOut("缺少token", 1);
}
$model = self::where([
'token_content' => $content,
])->find();
if (!$model) {
throw new LoginTimeOut("未登录", 1);
}
if ($model->is_exp) {
throw new LoginTimeOut("登录超时", 1);
}
self::$current = $model;
}
return self::$current;
}
/**
* 判断是否登录
*
* @date 2022-05-14
* @example
* @author admin
* @since 1.0.0
*/
public static function isLogin(): bool
{
try {
self::getCurrent();
return true;
} catch (LoginTimeOut $th) {
return false;
}
}
/**
* 延长token
* 过期前30分钟才会延期
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function delay(): void
{
try {
// 半小时
$delay = (60 * 30);
$model = self::getCurrent();
$token_exp_time = $model->token_exp_timestamp;
if (time() >= ($token_exp_time - $delay)) {
self::login($model->user_guid);
}
} catch (LoginTimeOut $th) {
}
}
/**
* 生成token内容
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
private function generateContent(): string
{
return md5(join('-', [
$this->token_exp_time,
$this->user_guid,
]) . time());
}
}

View File

@ -0,0 +1,548 @@
<?php
namespace app\common\model\User;
use app\common\arw\adjfut\src\Validate;
use app\BaseModel;
use app\common\model\Menu\Menu;
use app\common\model\Role\Role;
use app\common\model\User\UserRole as ModelUserRole;
use app\common\model\Token;
use think\db\Query;
use think\facade\Db;
use think\facade\Config;
use think\facade\Request;
use think\model\concern\SoftDelete;
use think\model\relation\BelongsToMany;
use app\common\arw\adjfut\src\Traits\Dictionary;
use app\common\arw\adjfut\src\Excel;
class User extends BaseModel
{
use Dictionary;
use SoftDelete;
// 删除字段
protected $deleteTime = 'user_delete_time';
// 设置主键名
protected $pk = 'user_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'user_id' => 'int',
'user_guid' => 'string',
'user_img' => 'string',
'user_name' => 'string',
'user_password' => 'string',
'user_phone' => 'string',
'user_status' => 'int',
'user_department' => 'string',
'user_position' => 'string',
'user_create_time' => 'datetime',
'user_create_user_guid' => 'string',
'user_update_time' => 'datetime',
'user_update_user_guid' => 'string',
'user_delete_time' => 'datetime',
'user_delete_user_guid' => 'string',
];
// 只读
protected $readonly = [
'user_id',
'user_guid',
'user_create_time',
'user_create_user_guid'
];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'user_create_time';
// 修改时间
protected $updateTime = 'user_update_time';
public static $dictionaryMap = [
'user_status' => [
self::STATUS_ENABLE => '启用',
self::STATUS_DISABLE => '停用'
],
];
/**
* 状态 启用
*/
const STATUS_ENABLE = 1;
/**
* 状态 禁用
*/
const STATUS_DISABLE = 2;
// 状态查询范围
public function scopeStatus(Query $query, $status = self::STATUS_ENABLE)
{
$query->where('user_status', $status);
}
/**
* 写入前
*
* @param self $model
* @return void
* @date 2023-01-11
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeWrite(self $model): void
{
self::checkRepeatData($model);
}
/**
* 新增前
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeInsert(self $model): void
{
$model->completeCreateField();
}
/**
* 更新前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeUpdate(self $model): void
{
$model->completeUpdateField();
}
/**
* 删除前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
/**
* 用户名搜索器
*
* @param Query $query
* @param [type] $value
* @param [type] $data
* @return void
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public function searchUserNameAttr(Query $query, $value, $data): void
{
if ($value) {
$query->whereLike(join('|', [
'user_name',
// 'user_phone'
]), "%$value%");
}
}
/**
* 设置用户密码
*
* @param string $value
* @return string
* @date 2022-12-28
* @example
* @author admin
* @since 1.0.0
*/
public function setUserPasswordAttr(string $value): string
{
return self::encryptPassword($value);
}
/**
* 获取用户管理员
*
* @date 2022-03-08
* @example
* @author admin
* @since 1.0.0
*/
public function getUserAdminAttr(): bool
{
return $this->user_id == 1;
}
/**
* 用户登录
*
* @return Token
* @date 2023-01-03
* @example
* @author admin
* @since 1.0.0
*/
public function login(): Token
{
if ($this->user_status != self::STATUS_ENABLE) {
throwErrorMsg('该用户已被停用');
}
$menus = $this->getUserMenu();
$api = [];
foreach ($menus as $menu) {
$api = array_merge($api, explode(',', $menu['menu_api_url']));
}
$api = array_values(array_filter(array_unique($api)));
if (!$api) {
throwErrorMsg('无权登录');
}
return Token::login($this->user_guid, [
'menu' => $menus,
'api' => $api,
]);
}
/**
* 获取用户菜单
*
* @date 2022-03-15
* @example
* @author admin
* @since 1.0.0
*/
public function getUserMenu(): array
{
$result = [];
$query = Menu::join('menu_api', 'menu_api.menu_guid = menu.menu_guid', 'left')->field([
'menu.menu_guid',
'menu.menu_parent_guid',
'menu.menu_name',
'menu.menu_url',
'menu.menu_show',
'menu.menu_icon',
'group_concat(menu_api.menu_api_url)' => 'menu_api_url'
])->order([
'menu.menu_index',
'menu.menu_order' => 'desc',
])->group('menu.menu_guid');
if ($this->user_admin) {
$result = $query->select()->toArray();
} else {
$menus = [];
$roles = $this->roles()->with([
'menus'
])->select();
foreach ($roles as $role) {
$menus = array_merge($menus, $role->menus->column('menu_guid'));
}
$result = $query->where([
['menu.menu_guid', 'in', $menus]
])->select()->toArray();
}
return $result;
}
/**
* 数据查重
*
* @param self $model
* @return void
* @date 2022-03-11
* @example
* @author admin
* @since 1.0.0
*/
private static function checkRepeatData(self $model)
{
Validate::unique(self::class, $model->user_guid, $model->getData(), [
'user_account' => '账户',
'user_phone' => '手机号',
]);
}
/**
* 密码加密
*
* @param string $password
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function encryptPassword(string $password): string
{
return md5($password);
}
/**
* 获取角色
*
* @date 2022-03-11
* @example
* @author admin
* @since 1.0.0
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(
Role::class,
UserRole::class,
'role_guid',
'user_guid'
);
}
/**
* 新增用户角色
*/
public static function addUserRole($user_guid, $params): void
{
$user_role_arr = $params['roles'];
foreach ($user_role_arr as $role => $item) {
Db::startTrans();
try {
$add_data = [
'user_guid' => $user_guid,
'role_guid' => $item,
];
$user_role = ModelUserRole::create($add_data);
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
}
/**
* 编辑用户角色
*/
public static function editUserRole($params): void
{
// 从学生服务(副表)查询出所有当前学生的服务,进行删除
ModelUserRole::where('user_guid', $params['user_guid'])->select()->delete();
// 再把传值的数据,写入副表
$user_role_arr = $params['roles'];
foreach ($user_role_arr as $key => $item) {
Db::startTrans();
try {
$add_data = [
'user_guid' => $params['user_guid'],
'role_guid' => $item,
];
ModelUserRole::create($add_data);
Db::commit();
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
}
/**
* 用户角色guid获取器
*/
public function getRolesAttr($value, $data)
{
$user_guid = $data['user_guid'];
$user_role_guid_arr = ModelUserRole::field([
'role_guid',
])->where('user_guid', $user_guid)->select();
$arr = [];
foreach ($user_role_guid_arr as $key => $value) {
$arr[] = $value['role_guid'];
}
return $arr;
// return array_values($user_key_guid_arr);
}
/**
* 用户角色名称获取器
*/
public function getRoleNameAttr($value, $data)
{
$user_guid = $data['user_guid'];
$user_role_guid_arr = ModelUserRole::field([
'role_guid',
])->where('user_guid', $user_guid)->select();
$arr = [];
foreach ($user_role_guid_arr as $key => $value) {
$model = Role::where('role_guid', $value['role_guid'])->find()->role_name;
$arr[] = $model;
}
return implode(",", $arr);
// return array_values($user_key_guid_arr);
}
/**
* 用户角色名
*/
public static function getRoleName($data)
{
$user_guid = $data['user_guid'];
$user_role_guid_arr = ModelUserRole::field([
'role_guid',
])->where('user_guid', $user_guid)->select();
$arr = [];
foreach ($user_role_guid_arr as $key => $value) {
$model = Role::where('role_guid', $value['role_guid'])->find()->role_name;
$arr[] = $model;
}
return implode(",", $arr);
// return array_values($user_key_guid_arr);
}
/**
* 角色名称转角色guid数组
*/
public static function RoleNameToRoleGuidArr($params)
{
$roles = explode(",", $params['roles']);
$user_role_guid_arr = [];
foreach ($roles as $key => $item) {
$role = Role::where('role_name', $item)->find();
if (!$role) throwErrorMsg('角色不存在!');
$user_role_guid_arr[] = $role->role_guid;
}
return $user_role_guid_arr;
}
/**
* 导出Excel
*/
public static function exportExcel($select)
{
$data = [[
'用户名',
'头像',
'角色',
'手机号',
]];
foreach ($select as $key => $val) {
$val['user_img'] = Excel::ExportImgFiled($val['user_img']);
$user_role_name = self::getRoleName($val);
$data[] = [
$val['user_name'],
$val['user_img'],
$user_role_name,
$val['user_phone'],
];
}
$excel = (new Excel())->exporTsheet($data);
$excel->save('用户.xlsx');
}
/**
* 导入数据处理
*/
public static function HanleImportData($value)
{
// 判断用户是否存在
$user_name = $value['user_name'];
$user_type = self::where('user_name', $user_name)->find();
if ($user_type) throwErrorMsg("{$user_name} 用户已存在,导入失败!");
// 判断角色是否存在
$roles_arr = explode(",", $value['roles']);
foreach ($roles_arr as $key => $item) {
$role = Role::where('role_name', $item)->find();
if (!$role) throwErrorMsg("{$item} 角色不存在,导入失败!");
}
$password = md5($value['user_password']);
$model = self::create([
'user_name' => $value['user_name'],
'user_img' => $value['user_img'],
'user_phone' => $value['user_phone'],
'user_password' => $password,
'user_status' => 1,
]);
$user_guid = $model->user_guid;
$value['roles'] = self::RoleNameToRoleGuidArr($value);
self::addUserRole($user_guid, $value);
}
/**
* 导入Excel
*/
public static function importExcel($file)
{
Db::startTrans();
try {
$excel = new Excel($file);
// 表头
$data = $excel->parseExcel(
[
[
'title' => '用户名',
'validate' => 'require',
'field' => 'user_name',
], [
'title' => '头像',
'field' => 'user_img',
], [
'title' => '角色',
'validate' => 'require',
'field' => 'roles',
], [
'title' => '手机号',
'field' => 'user_phone',
], [
'title' => '密码',
'field' => 'user_password',
]
],
[
'titleLine' => [1]
]
);
if (!$data) throwErrorMsg('excel无数据', 1);
$error = [];
foreach ($data as $line => $value) {
try {
self::HanleImportData($value);
$error[] = "{$line} 用户:【{$value['user_name']}】<span style='color:#27af49'>新增成功!</span><br>";
} catch (\Throwable $th) {
$error[] = "{$line} 用户:【{$value['user_name']}】<span style='color:red'>{$th->getMessage()}</span><br>";
}
}
Db::commit();
return implode(', ', $error);
} catch (\Throwable $th) {
Db::rollback();
throw $th;
}
}
}

View File

@ -0,0 +1,157 @@
<?php
namespace app\common\model\User;
use app\BasePivot;
use app\common\model\Role\Role;
use think\model\concern\SoftDelete;
use app\common\arw\adjfut\src\Model\Pivot as ModelPivot;
class UserRole extends BasePivot
{
// use SoftDelete;
// 删除字段
protected $deleteTime = 'user_role_delete_time';
// 设置主键名
protected $pk = 'user_role_guid';
// 设置废弃字段
protected $disuse = [];
// 设置字段信息
protected $schema = [
'user_role_id' => 'int',
'user_guid' => 'string',
'role_guid' => 'string',
'user_role_status' => 'int',
'user_role_create_time' => 'datetime',
'user_role_create_user_guid' => 'string',
'user_role_update_time' => 'datetime',
'user_role_update_user_guid' => 'string',
'user_role_delete_time' => 'datetime',
'user_role_delete_user_guid' => 'string',
'user_role_guid' => 'string',
];
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'datetime';
// 创建时间
protected $createTime = 'user_role_create_time';
// 修改时间
protected $updateTime = 'user_role_update_time';
/**
* 状态 启用
*/
const STATUS_ENABLE = 1;
/**
* 状态 禁用
*/
const STATUS_DISABLE = 2;
// 状态查询范围
public function scopeStatus($query, $status = self::STATUS_ENABLE)
{
$query->where('user_role_status', $status);
}
/**
* 中间关联
*
* @return ModelPivot
* @date 2022-12-30
* @example
* @author admin
* @since 1.0.0
*/
public static function pivot(): ModelPivot
{
return new ModelPivot(
self::class,
User::class,
Role::class,
true
);
}
/**
* 绑定用户角色
*
* @param $users
* @param $roles
* @param array $extra
* @return void
* @date 2022-12-29
* @example
* @author admin
* @since 1.0.0
*/
public static function bindUserRole($users, $roles, array $extra = []): void
{
self::pivot()->bind($users, $roles, $extra);
}
/**
* 解绑用户角色
*
* @param $users
* @param $roles
* @return void
* @date 2022-12-30
* @example
* @author admin
* @since 1.0.0
*/
public static function unbindUserRole($users, $roles): void
{
self::pivot()->unbind($users, $roles);
}
/**
* 绑定用户角色
*
* @param $users
* @param $roles
* @param array $extra
* @return void
* @date 2022-12-29
* @example
* @author admin
* @since 1.0.0
*/
public static function rebindUserRole($users, $roles, array $extra = []): void
{
self::pivot()->rebind($users, $roles, $extra);
}
/**
* 新增前
*
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeInsert(self $model): void
{
$model->user_role_status = self::STATUS_ENABLE;
$model->completeCreateField();
}
/**
* 更新前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeUpdate(self $model): void
{
$model->completeUpdateField();
}
/**
* 删除前
*
* @date 2022-02-28
* @example
* @author admin
* @since 1.0.0
*/
public static function onBeforeDelete(self $model): void
{
$model->completeDeleteField();
}
}

110
app/common/traits/Auth.php Normal file
View File

@ -0,0 +1,110 @@
<?php
declare(strict_types=1);
namespace app\common\traits;
use app\common\model\Token;
use think\helper\Arr;
trait Auth
{
/**
* 请求
*
* @var \app\Request
* @date 2022-05-14
* @example
* @author admin
* @since 1.0.0
*/
private $request = null;
/**
* 忽略登录
*
* @var array
* @date 2022-05-14
* @example
* @author admin
* @since 1.0.0
*/
private $ignoreLogin = [];
/**
* 是否忽略登录
*
* @return boolean
*/
private function isIgnoreLogin(): bool
{
$request = $this->request;
$gc = $request->controller();
$ga = $request->action();
$ignoreLogin = Arr::get($this->ignoreLogin, $gc, []);
if (!is_array($ignoreLogin)) {
$ignoreLogin = [];
}
foreach ($ignoreLogin as $action) {
if ($action == '*' || $action == $ga) {
return true;
}
}
return false;
}
/**
* 验证用户权限
*
* @return boolean
* @date 2022-05-14
* @example
* @author admin
* @since 1.0.0
*/
private function validateUser(): bool
{
return $this->validateMenuApi(
Token::getCurrentUser()->getUserMenu()
);
}
/**
* 验证菜单接口
*
* @return boolean
* @date 2022-05-14
* @example
* @author admin
* @since 1.0.0
*/
private function validateMenuApi(array $menus): bool
{
$apis = [];
foreach ($menus as $menu) {
$apis = array_merge($apis, explode(',', $menu['menu_api_url'] ?? ''));
}
return $this->validateApi($apis);
}
/**
* 验证接口
*
* @param array $apis
* @return boolean
* @date 2022-05-14
* @example
* @author admin
* @since 1.0.0
*/
private function validateApi(array $apis): bool
{
$request = $this->request;
$apis = array_values(array_filter(array_unique($apis)));
$api = join('/', [
$request->controller(),
$request->action()
]);
return in_array($api, $apis);
}
}

254
app/common/traits/Model.php Normal file
View File

@ -0,0 +1,254 @@
<?php
declare(strict_types=1);
namespace app\common\traits;
use app\common\arw\adjfut\src\Exception\ErrorMsg;
use app\common\model\User\User;
use app\Request;
use think\Model as ThinkModel;
use app\common\arw\adjfut\src\Tool;
use app\common\arw\adjfut\src\Validate;
/**
* 模型层
* @mixin ThinkModel
*/
trait Model
{
private static $cacheUserGuid = '';
/**
* 设置用户guid
*
* @param string|bool $id
* @return void
* @date 2022-04-25
* @example
* @author admin
* @since 1.0.0
*/
public static function setUserGuid($id)
{
self::$cacheUserGuid = $id;
}
/**
* 完善添加字段
*
* @param string $user
* @param string $timeType
* @return void
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
public function completeCreateField($user = 'user', string $timeType = 'datetime'): void
{
$this->completeBaseField('create', $user, $timeType);
}
/**
* 完善更新字段
*
* @param string $user
* @param string $timeType
* @return void
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
public function completeUpdateField($user = 'user', string $timeType = 'datetime'): void
{
$this->completeBaseField('update', $user, $timeType);
}
/**
* 完善删除字段
*
* @param string $user
* @param string $timeType
* @return void
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
public function completeDeleteField($user = 'user', string $timeType = 'datetime'): void
{
$this->completeBaseField('delete', $user, $timeType);
}
/**
* 完善基础字段
*
* @param string $type create|update|delete
* @param User|string $user
* @param string $timeType datetime|timestamp
* @return void
* @date 2022-03-02
* @example
* @author admin
* @since 1.0.0
*/
public function completeBaseField($type, $user = 'user', string $timeType = 'datetime'): void
{
$table = $this->getTable();
$createFieldTime = "${table}_create_time";
$createFieldUserGuId = "${table}_create_user_guid";
$updateFieldTime = "${table}_update_time";
$updateFieldUserGuId = "${table}_update_user_guid";
$deleteFieldTime = "${table}_delete_time";
$deleteFieldUserGuId = "${table}_delete_user_guid";
$guidField = "${table}_guid";
$time = self::getCompleteBaseFieldTimeType($timeType);
$user_guid = self::getCompleteBaseFieldUser($user);
if (!$type) {
throw new ErrorMsg("时间类型异常", 1);
}
$this->$updateFieldTime = $time;
$this->$updateFieldUserGuId = $user_guid;
if ($type === 'create') {
$this->$createFieldTime = $time;
$this->$createFieldUserGuId = $user_guid;
$this->$guidField = self::generateGuid();
}
if ($type === 'delete') {
$this->$deleteFieldTime = $time;
$this->$deleteFieldUserGuId = $user_guid;
}
}
// /**
// * 设置不使用的全局查询范围更新
// * 支持 onBeforeUpdate|onAfterUpdate|onBeforeWrite|onAfterWrite 事件
// *
// * @return void
// * @date 2022-03-12
// * @example
// * @author admin
// * @since 1.0.0
// */
// public static function withoutGlobalScopeUpdate(array $scope, array $data)
// {
// $model = new static;
// $pk = $model->getPk();
// if (!isset($data[$pk])) {
// throw new ErrorMsg("缺少主键", 1);
// }
// $query = $model::withoutGlobalScope($scope)->find($data[$pk]);
// if ($query === null) {
// throw new ErrorMsg("数据不存在", 1);
// }
// if (
// $model::onBeforeWrite($model) === false ||
// $model::onBeforeUpdate($model) === false
// ) {
// return false;
// }
// $model::withoutGlobalScope($scope)->save(array_merge($data, $model->getData()));
// $model::onAfterUpdate($model);
// $model::onAfterWrite($model);
// }
/**
* 生成guid
*
* @param array|string $value
* @return string
* @date 2022-02-22
* @example
* @author admin
* @since 1.0.0
*/
protected static function generateGuid($value = '')
{
return Tool::generateGuid($value);
}
/**
* 数据验证
* 除非是require字段 有数据才验证
*
* @param array $data 数据
* @param array $rules 规则
* @param array $message 提示信息
* @return void
* @throws ValidateException
*/
protected static function dataValidate(array $data, array $rules, array $message = [])
{
$_rules = [];
$dataKeys = array_keys($data);
foreach ($rules as $key => $rule) {
list($field) = explode('|', $key);
// 字段存在规则并且有值 或者 必传
if ((in_array($field, $dataKeys) && !is_null($data[$field])) || preg_match('/require/', $rule)) {
$_rules[$key] = $rule;
}
}
Validate::check($data, $_rules, $message);
}
/**
* 获取完善基础字段用户
*
* @param User|string $user
* @return string
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
private static function getCompleteBaseFieldUser($user): string
{
$cacheUserGuid = self::$cacheUserGuid;
$user_guid = '';
switch (true) {
case (is_string($cacheUserGuid) && $cacheUserGuid):
$user_guid = $cacheUserGuid;
break;
case (is_bool($cacheUserGuid) && $cacheUserGuid === false):
// 无需验证 获取用户Guid
break;
case (is_bool($user) && $user === false):
// 无需验证 获取用户Guid
break;
case ($user === 'user'):
case ($user instanceof User):
$user = $user === 'user' ? Request::getCurrentUser() : $user;
$user_guid = $user->user_guid;
break;
}
return $user_guid;
}
/**
* 获取模型时间类型
*
* @param string $timeType datetime|timestamp
* @return string
* @date 2022-12-27
* @example
* @author admin
* @since 1.0.0
*/
private static function getCompleteBaseFieldTimeType($timeType): string
{
$time = '';
switch ($timeType) {
case 'datetime':
$time = date('Y-m-d H:i:s');
break;
case 'timestamp':
$time = time();
break;
}
return $time;
}
}

20
app/event.php Normal file
View File

@ -0,0 +1,20 @@
<?php
// 事件定义文件
use app\common\listener\DelayToken;
return [
'bind' => [],
'listen' => [
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [
DelayToken::class
],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [],
];

10
app/middleware.php Normal file
View File

@ -0,0 +1,10 @@
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
\think\middleware\SessionInit::class
];

9
app/provider.php Normal file
View File

@ -0,0 +1,9 @@
<?php
use app\ExceptionHandle;
use app\Request;
// 容器Provider定义文件
return [
'think\Request' => Request::class,
'think\exception\Handle' => ExceptionHandle::class,
];

Some files were not shown because too many files have changed in this diff Show More