代码功能更新
This commit is contained in:
Executable
+7
@@ -0,0 +1,7 @@
|
||||
/.idea
|
||||
/.vscode
|
||||
/vendor
|
||||
/runtime
|
||||
*.log
|
||||
.env
|
||||
composer.lock
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<head><title>404 Not Found</title></head>
|
||||
<body>
|
||||
<center><h1>404 Not Found</h1></center>
|
||||
<hr><center>nginx</center>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
Laytp遵循Apache2开源协议发布,并提供免费使用。
|
||||
@@ -0,0 +1,115 @@
|
||||
## 目标
|
||||
简单部署 迅速开展业务!五分钟安装 填写参数 即可!
|
||||
|
||||
### 原理
|
||||
我做好了 后端开通接口!你们负责开展业务即可!收钱到你们自己钱包!
|
||||
## 前言
|
||||
> 基于ThinkPHP6+LayUI开发
|
||||
<div align="center">
|
||||
|
||||
</div>
|
||||
<p align="center"><strong>价值源自分享 成功在于坚持</strong></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://t.me/xiaotouadmin" target="_blank">官方平台</a>
|
||||
<a href="https://t.me/xiaotouadmin" rel="nofollow" >在线演示</a>
|
||||
<a href="https://t.me/xiaotouadmin" target="_blank">框架文档</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<font size="20" >一套基于tp6 开发已会员分销系统</font>
|
||||
</p>
|
||||
|
||||
<p>交流①群:https://t.me/xiaotouadmin</p>
|
||||
|
||||
</b><br/>
|
||||
<b>超管账号 admin 123456 </b><br/>
|
||||
|
||||
|
||||
## 开发初衷
|
||||
|
||||
许多同学问 我也想开下下级怎么办!我没办法呀! 那就多开发一条分销系统吧!你们自己管理下级! 软件后续更新! 在安装目录下 运行 git pull 即可更新
|
||||
|
||||
## 框架优势
|
||||
|
||||
* `PHP框架选用简单且优美的ThinkPHP6`
|
||||
|
||||
* `参考官方文档,只需会PHP LayUI 开箱即用`
|
||||
|
||||
* `前后端完全分离,代码清晰明了`
|
||||
|
||||
* `封装常用Html表单元素,且仅需使用Html标记语言即可渲染表单元素`
|
||||
|
||||
* `基于Token验证的用户鉴权`
|
||||
|
||||
* `前端JavaScript鉴权,后端AUTH类鉴权,减少请求`
|
||||
|
||||
* `提供插件市场,方便框架丰富功能`
|
||||
|
||||
* `永久免费提供一键生成CURD插件,简单重复性CURD代码可以可视化一键生成`
|
||||
|
||||
* `永久免费提供一键生成Api文档插件,Api文档可以使用MEditor和代码注解生成`
|
||||
|
||||
* `代码安全质量高,修复大部分低危、高危代码漏洞`
|
||||
|
||||
## 集成功能
|
||||
|
||||
- [x] `API模块` token鉴权,签名规则
|
||||
- [x] `权限管理` 后台权限管理
|
||||
- [x] `管理员管理` 后台管理员管理
|
||||
- [x] `角色管理` 后台管理员角色管理
|
||||
- [x] `菜单管理` 后台菜单管理
|
||||
- [x] `系统配置` 每个配置页面独立设置,仅需复制配置样例,修改html文件即可拥有多个配置界面
|
||||
- [x] `插件市场` 可开发定制属于自己的插件,可安装升级社区插件,目前提供的插件:
|
||||
- [x] `生成CRUD插件` 前后端代码的生成(php、html、layui、sql)支持一键生成CRUD
|
||||
- [x] `生成Api文档插件` Api文档可以使用MEditor和代码注解生成
|
||||
- [x] `UEditor编辑器插件` 与`阿里云OSS对象存储插件`和`七牛云KODO对象存储插件`深度兼容,编辑器的上传也可以上传到`阿里云`和`七牛云`
|
||||
- [x] `MEditor编辑器插件` 与`阿里云OSS对象存储插件`和`七牛云KODO对象存储插件`深度兼容,编辑器的上传也可以上传到`阿里云`和`七牛云`
|
||||
- [x] `阿里云OSS对象存储插件`
|
||||
- [x] `七牛云KODO对象存储插件`
|
||||
- [x] `阿里云短信插件`
|
||||
- [x] `Email邮件服务插件`
|
||||
- [x] `操作日志` 用户后台操作日志,Api接口请求日志,后台管理员登录日志
|
||||
- [x] `地区管理`
|
||||
- [x] `附件管理`
|
||||
|
||||
## 常用表单元素封装
|
||||
对于常用表单元素,在`Laytp`中,无需写太多JS代码,你只需要像如下这样
|
||||
```
|
||||
<div class="表单元素class标识"
|
||||
data-属性名="属性值"
|
||||
>
|
||||
</div>
|
||||
```
|
||||
就可以渲染常用表单元素,比如上传组件,多选下拉框组件,编辑器,省市区联动下拉框等
|
||||
|
||||
## 安装使用
|
||||
1、首先将本框架直接clone到你本地,或者直接下载
|
||||
```
|
||||
git clone https://gitee.com/junstar/laytp
|
||||
```
|
||||
2、先设置mysql的sql_mode=NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 然后创建一个数据库
|
||||
```
|
||||
数据库字符集 utf8mb4 -- UTF-8 Unicode
|
||||
排序规则 utf8mb4_general_ci
|
||||
```
|
||||
3、复制根目录下的.example.env文件成.env文件,修改.env文件的数据库连接部分
|
||||
```
|
||||
[DATABASE]
|
||||
TYPE = mysql
|
||||
HOSTNAME = 127.0.0.1
|
||||
DATABASE = 创建的数据库名称
|
||||
USERNAME = 数据库用户名
|
||||
PASSWORD = 数据库密码
|
||||
HOSTPORT = 3306
|
||||
CHARSET = utf8
|
||||
DEBUG = true
|
||||
PREFIX = 数据库前缀,推荐使用lt_
|
||||
```
|
||||
4、根目录执行 composer install 安装必要的Composer包,包括ThinkPHP6框架和ThinkPHP6的其他代码!
|
||||
```
|
||||
composer install
|
||||
```
|
||||
5、根目录执行ThinkPHP6的数据库迁移命令,这里会导入Laytp框架需要的数据库文件
|
||||
```
|
||||
php think migrate:run
|
||||
```
|
||||
Executable
+10
File diff suppressed because one or more lines are too long
Executable
+46
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
use think\facade\Db;
|
||||
use laytp\BaseController;
|
||||
use think\facade\Cache;
|
||||
|
||||
class Index extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
||||
return redirect("/admin/index.html");
|
||||
}
|
||||
public function getnumber()
|
||||
{
|
||||
$uplist=Cache::get("getnumber");
|
||||
if(empty($uplist)){
|
||||
$url="http://git.zf789.life/kaifa/premium/graph";
|
||||
$html= file_get_contents($url);
|
||||
preg_match_all('/<span class="message tw-inline-block gt-ellipsis tw-mr-2">\s*<span>(.*?)<\/span>\s*<\/span>/', $html, $matches);
|
||||
$uplist=array();
|
||||
if ($matches[1]) {
|
||||
$messages = $matches[1]; // Array of all matched messages
|
||||
foreach ($messages as $message) {
|
||||
$uplist[]=$message;
|
||||
// var_dump($message);
|
||||
// Process each message
|
||||
}
|
||||
}
|
||||
|
||||
Cache::set("getnumber",$uplist,1024);
|
||||
}
|
||||
|
||||
//平台总用户
|
||||
$ptzuser=Db::name("member")->count();
|
||||
//平台托管机器人
|
||||
$ptzbot=Db::name("admin_bot")->count();
|
||||
//平台机器人总余额
|
||||
$ptzbotmoney=Db::name("admin_bot")->sum('money');
|
||||
//平台总利润
|
||||
$ptlirun=Db::name("order")->sum('lirun');
|
||||
|
||||
return $this->success('返回成功', ['uplist'=>$uplist,'ptzuser'=>$ptzuser,'ptzbot'=>$ptzbot,'ptzbotmoney'=>$ptzbotmoney,'ptlirun'=>$ptlirun]);
|
||||
}
|
||||
}
|
||||
Executable
+109
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use laytp\library\CommonFun;
|
||||
use laytp\library\Tree;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 地区管理
|
||||
*/
|
||||
class Area extends Backend
|
||||
{
|
||||
|
||||
/**
|
||||
* area模型对象
|
||||
* @var \app\model\Area
|
||||
*/
|
||||
protected $model;
|
||||
public $hasSoftDel = 1;//是否拥有软删除功能
|
||||
public $orderRule = ['sort' => 'DESC', 'id' => 'ASC'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\Area();
|
||||
}
|
||||
|
||||
//查看
|
||||
public function index()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$sourceData = $this->model->where($where)->order($order)->with(['parent']);
|
||||
$isTree = $this->request->param('is_tree');
|
||||
if ($isTree) {
|
||||
$menuTreeObj = Tree::instance();
|
||||
$menuTreeObj->init($sourceData->select()->toArray());
|
||||
$data = $menuTreeObj->getRootTrees();
|
||||
} else {
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $sourceData->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $sourceData->select()->toArray();
|
||||
}
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
//删除
|
||||
public function del()
|
||||
{
|
||||
$ids = $this->request->post('ids');
|
||||
if (!$ids) {
|
||||
return $this->error('参数ids不能为空');
|
||||
}
|
||||
|
||||
$sourceData = $this->model->select()->toArray();
|
||||
$treeLib = Tree::instance();
|
||||
$treeLib->init($sourceData);
|
||||
$childIds = $treeLib->getChildIds($ids);
|
||||
|
||||
if ($this->model->destroy($childIds)) {
|
||||
return $this->success('数据删除成功');
|
||||
} else {
|
||||
return $this->error('数据删除失败');
|
||||
}
|
||||
}
|
||||
|
||||
//回收站
|
||||
public function recycle()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $this->model->onlyTrashed()
|
||||
->with(['parent'])
|
||||
->order($order)->where($where)->paginate($limit)->toArray();
|
||||
return $this->success('回收站数据获取成功', $data);
|
||||
}
|
||||
|
||||
//设置排序
|
||||
public function setSort()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['sort'] = $fieldVal;
|
||||
try {
|
||||
if ($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+10
File diff suppressed because one or more lines are too long
Executable
+235
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\service\admin\UserServiceFacade;
|
||||
use app\service\ConfServiceFacade;
|
||||
use laytp\library\UploadDomain;
|
||||
use plugin\ali_oss\service\Oss;
|
||||
use plugin\qiniu_kodo\service\Kodo;
|
||||
use laytp\controller\Backend;
|
||||
use think\facade\Env;
|
||||
use think\facade\Filesystem;
|
||||
use think\File;
|
||||
|
||||
class Common extends Backend
|
||||
{
|
||||
protected $noNeedAuth = ['*'];
|
||||
protected $noNeedLogin = ['getLoginNeedCaptchaConf'];
|
||||
|
||||
/**
|
||||
* 获取登录后台是否需要验证码的配置
|
||||
* 这个接口是后台登录界面使用的,给这个接口独立的访问权限,无需登录,无需鉴权
|
||||
*/
|
||||
public function getLoginNeedCaptchaConf()
|
||||
{
|
||||
return $this->success('获取成功', ConfServiceFacade::get('system.basic.loginNeedCaptcha', 0));
|
||||
}
|
||||
|
||||
//上传接口
|
||||
public function upload()
|
||||
{
|
||||
try {
|
||||
$defaultType = ConfServiceFacade::get('system.upload.defaultType', 'local');
|
||||
$uploadType = $this->request->param('upload_type', 'default');
|
||||
if ($uploadType == 'default') $uploadType = $defaultType;
|
||||
if (!in_array($uploadType, ['local', 'ali-oss', 'qiniu-kodo'])) {
|
||||
return $this->error($uploadType . '上传方式未定义');
|
||||
}
|
||||
$file = $this->request->file('laytpUploadFile'); // 获取上传的文件
|
||||
if (!$file) {
|
||||
return $this->error('上传失败,请选择需要上传的文件');
|
||||
}
|
||||
$fileExt = strtolower($file->getOriginalExtension());
|
||||
$uploadDomain = new UploadDomain();
|
||||
if (!$uploadDomain->check($file->getOriginalName(), $file->getSize(), $fileExt, $file->getMime())) {
|
||||
return $this->error($uploadDomain->getError());
|
||||
}
|
||||
$saveName = date("Ymd") . "/" . md5(uniqid(mt_rand())) . ".{$fileExt}";
|
||||
/**
|
||||
* 不能以斜杆开头
|
||||
* - 因为OSS存储时,不允许以/开头
|
||||
*/
|
||||
$uploadDir = $this->request->param('dir');
|
||||
$object = $uploadDir ? $uploadDir . '/' . $saveName : $saveName;//设置了上传目录的上传文件名
|
||||
$filePath = $object; //保存到lt_files中的path
|
||||
|
||||
//如果上传的是图片,验证图片的宽和高
|
||||
$accept = $this->request->param('accept');
|
||||
if ($accept == "image") {
|
||||
$width = $this->request->param('width');
|
||||
$height = $this->request->param('height');
|
||||
if ($width || $height) {
|
||||
$imageInfo = getimagesize($file->getFileInfo());
|
||||
if (($width && $imageInfo[0] > $width) || ($height && $imageInfo[1] > $height)) {
|
||||
return $this->error('上传失败,图片尺寸要求宽:' . $width . 'px,高:' . $height . 'px,实际上传文件[ ' . $file->getOriginalName() . ' ]的尺寸为宽' . $imageInfo[0] . 'px,高:' . $imageInfo[1] . 'px');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$inputValue = "";
|
||||
//上传至七牛云
|
||||
if ($uploadType == 'qiniu-kodo') {
|
||||
if (ConfServiceFacade::get('plugin.qiniu_kodo.switch') != 1) {
|
||||
return $this->error('未开启七牛云KODO存储,请到七牛云KODO配置中开启,如果未安装七牛云KODO存储插件,请先到插件市场进行安装');
|
||||
}
|
||||
$kodoConf = [
|
||||
'accessKey' => ConfServiceFacade::get('plugin.qiniu_kodo.accessKey'),
|
||||
'secretKey' => ConfServiceFacade::get('plugin.qiniu_kodo.secretKey'),
|
||||
'bucket' => ConfServiceFacade::get('plugin.qiniu_kodo.bucket'),
|
||||
'domain' => ConfServiceFacade::get('plugin.qiniu_kodo.domain'),
|
||||
];
|
||||
$kodo = Kodo::instance();
|
||||
$kodoRes = $kodo->upload($file->getPathname(), $object, $kodoConf);
|
||||
if ($kodoRes) {
|
||||
$inputValue = $kodoRes;
|
||||
} else {
|
||||
return $this->error($kodo->getError());
|
||||
}
|
||||
}
|
||||
|
||||
//上传至阿里云
|
||||
if ($uploadType == 'ali-oss') {
|
||||
if (ConfServiceFacade::get('plugin.ali_oss.switch') != 1) {
|
||||
return $this->error('未开启阿里云OSS存储,请到阿里云OSS配置中开启');
|
||||
}
|
||||
$ossConf = [
|
||||
'accessKeyID' => ConfServiceFacade::get('plugin.ali_oss.accessKeyID'),
|
||||
'accessKeySecret' => ConfServiceFacade::get('plugin.ali_oss.accessKeySecret'),
|
||||
'bucket' => ConfServiceFacade::get('plugin.ali_oss.bucket'),
|
||||
'endpoint' => ConfServiceFacade::get('plugin.ali_oss.endpoint'),
|
||||
'domain' => ConfServiceFacade::get('plugin.ali_oss.domain'),
|
||||
];
|
||||
$oss = Oss::instance();
|
||||
$ossUploadRes = $oss->upload($file->getPathname(), $object, $ossConf);
|
||||
if ($ossUploadRes) {
|
||||
$inputValue = $ossUploadRes;
|
||||
} else {
|
||||
return $this->error($oss->getError());
|
||||
}
|
||||
}
|
||||
|
||||
//本地上传
|
||||
if ($uploadType == 'local') {
|
||||
$uploadDir = ltrim('/', $uploadDir);
|
||||
$saveName = Filesystem::putFileAs('/' . $uploadDir, $file, '/' . $object);
|
||||
$filePath = $saveName;
|
||||
$staticDomain = Env::get('domain.static');
|
||||
if ($staticDomain) {
|
||||
$inputValue = $staticDomain . '/storage/' . $saveName;
|
||||
} else {
|
||||
$inputValue = request()->domain() . '/static/storage/' . $saveName;
|
||||
}
|
||||
}
|
||||
|
||||
//将inputValue存入lt_files表中
|
||||
$filesModel = new \app\model\Files();
|
||||
$fileId = $filesModel->insertGetId([
|
||||
'category_id' => 0,
|
||||
'name' => $file->getOriginalName(),
|
||||
'file_type' => $this->request->param('accept'),
|
||||
'path' => $filePath,
|
||||
'upload_type' => $uploadType,
|
||||
'size' => $file->getSize(),
|
||||
'ext' => $file->getExtension(),
|
||||
'create_admin_user_id' => UserServiceFacade::getUser()->id,
|
||||
'update_admin_user_id' => UserServiceFacade::getUser()->id,
|
||||
'create_time' => date('Y-m-d H:i:s'),
|
||||
'update_time' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
return $this->success('上传成功', [
|
||||
'id' => $fileId,
|
||||
'path' => $inputValue,
|
||||
'name' => $file->getOriginalName(),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取阿里云sts的临时凭证,目前仅用于客户端直接上传到oss前获取到临时凭证进行上传
|
||||
public function aliSts()
|
||||
{
|
||||
if (ConfServiceFacade::get('plugin.ali_oss_sts.switch') != 1) {
|
||||
return $this->error('阿里云OSS存储的STS方式,请到阿里云STS配置中开启');
|
||||
}
|
||||
$uploadDomain = new UploadDomain();
|
||||
$fileName = $this->request->param('name');
|
||||
$fileSize = $this->request->param('size');
|
||||
$fileExt = $this->request->param('ext');
|
||||
if (!$uploadDomain->check($fileName, $fileSize, $fileExt, '')) {
|
||||
return $this->error($uploadDomain->getError());
|
||||
}
|
||||
$stsConf = [
|
||||
'accessKeyID' => ConfServiceFacade::get('plugin.ali_oss_sts.accessKeyID'),
|
||||
'accessKeySecret' => ConfServiceFacade::get('plugin.ali_oss_sts.accessKeySecret'),
|
||||
'ARN' => ConfServiceFacade::get('plugin.ali_oss_sts.ARN'),
|
||||
'endpoint' => ConfServiceFacade::get('plugin.ali_oss_sts.endpoint'),
|
||||
'domain' => ConfServiceFacade::get('plugin.ali_oss_sts.domain'),
|
||||
'bucket' => ConfServiceFacade::get('plugin.ali_oss_sts.bucket'),
|
||||
];
|
||||
$oss = Oss::instance();
|
||||
$sts = $oss->sts($stsConf);
|
||||
$file = new File('', false);
|
||||
|
||||
if ($sts) {
|
||||
return $this->success('sts获取成功', [
|
||||
'sts' => $sts,
|
||||
'path' => str_replace('\\', '/', $file->hashName()) . $fileExt,
|
||||
'index' => $this->request->param('index'),
|
||||
]);
|
||||
} else {
|
||||
return $this->error('sts获取失败,' . $oss->getError());
|
||||
}
|
||||
}
|
||||
|
||||
// 获取kodo上传凭证token
|
||||
public function kodoToken()
|
||||
{
|
||||
if (ConfServiceFacade::get('plugin.qiniu_kodo.switch') != 1) {
|
||||
return $this->error('未开启七牛云KODO存储,请到七牛云KODO配置中开启');
|
||||
}
|
||||
$uploadDomain = new UploadDomain();
|
||||
$fileName = $this->request->param('name');
|
||||
$fileSize = $this->request->param('size');
|
||||
$fileExt = $this->request->param('ext');
|
||||
if (!$uploadDomain->check($fileName, $fileSize, $fileExt, '')) {
|
||||
return $this->error($uploadDomain->getError());
|
||||
}
|
||||
$kodoConf = [
|
||||
'accessKey' => ConfServiceFacade::get('plugin.qiniu_kodo.accessKey'),
|
||||
'secretKey' => ConfServiceFacade::get('plugin.qiniu_kodo.secretKey'),
|
||||
'domain' => ConfServiceFacade::get('plugin.qiniu_kodo.domain'),
|
||||
'bucket' => ConfServiceFacade::get('plugin.qiniu_kodo.bucket'),
|
||||
];
|
||||
$kodo = Kodo::instance();
|
||||
$token = $kodo->token($kodoConf);
|
||||
$file = new File('', false);
|
||||
|
||||
if ($token) {
|
||||
return $this->success('KodoToken获取成功', [
|
||||
'token' => $token,
|
||||
'domain' => ConfServiceFacade::get('plugin.qiniu_kodo.domain'),
|
||||
'bucket' => ConfServiceFacade::get('plugin.qiniu_kodo.bucket'),
|
||||
'path' => str_replace('\\', '/', $file->hashName()) . $fileExt,
|
||||
'index' => $this->request->param('index'),
|
||||
]);
|
||||
} else {
|
||||
return $this->error('KodoToken获取失败,' . $kodo->getError());
|
||||
}
|
||||
}
|
||||
|
||||
//解锁屏幕
|
||||
function unLockScreen()
|
||||
{
|
||||
$password = $this->request->post('password');
|
||||
$userId = UserServiceFacade::getUser()->id;
|
||||
$passwordHash = User::where('id', '=', $userId)->value('password');
|
||||
if (!password_verify(md5($password), $passwordHash)) {
|
||||
return $this->error('解锁失败,密码错误');
|
||||
} else {
|
||||
return $this->success('解锁成功');
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\service\ConfServiceFacade;
|
||||
use laytp\controller\Backend;
|
||||
use laytp\library\CommonFun;
|
||||
use laytp\library\UploadDomain;
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 系统配置控制器
|
||||
* Class Conf
|
||||
* @package app\admin\controller
|
||||
*/
|
||||
class Conf extends Backend
|
||||
{
|
||||
protected $model;
|
||||
protected $noNeedAuth = ['getGroupConf', 'saveGroupConf'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\Conf();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个分组下所有的配置项
|
||||
*/
|
||||
public function getGroupConf()
|
||||
{
|
||||
$group = $this->request->param('group');
|
||||
$return = ConfServiceFacade::groupGet($group, true);
|
||||
return $this->success('获取成功', $return);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存配置
|
||||
*/
|
||||
public function saveGroupConf()
|
||||
{
|
||||
$post = $this->request->post();
|
||||
if (isset($post['laytpUploadFile'])) {
|
||||
unset($post['laytpUploadFile']);
|
||||
}
|
||||
$group = $post['group'];
|
||||
unset($post['group']);
|
||||
$formType = $post['form_type'];
|
||||
unset($post['form_type']);
|
||||
$allConf = [];
|
||||
foreach ($post as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$temp = [];
|
||||
foreach ($value['key'] as $arrK => $arrV) {
|
||||
if ($arrV) {
|
||||
$temp[$arrV] = $value['value'][$arrK];
|
||||
}
|
||||
}
|
||||
$value = $temp;
|
||||
}
|
||||
$conf['group'] = $group;
|
||||
$conf['key'] = $key;
|
||||
$conf['value'] = $value;
|
||||
$conf['form_type'] = $formType[$key];
|
||||
$allConf[] = $conf;
|
||||
}
|
||||
ConfServiceFacade::groupSet($allConf);
|
||||
return $this->success('保存成功', $allConf);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某个分组下某个key的配置信息
|
||||
* 这个不在配置页面进行调用,后续要做生成工具的时候统一管理所有的key
|
||||
*/
|
||||
public function del()
|
||||
{
|
||||
$group = $this->request->param('group');
|
||||
$key = $this->request->param('key');
|
||||
ConfServiceFacade::del($group, $key);
|
||||
return $this->success('删除成功');
|
||||
}
|
||||
}
|
||||
Executable
+135
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use app\service\admin\UserServiceFacade;
|
||||
use laytp\library\CommonFun;
|
||||
use laytp\library\UploadDomain;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 附件管理
|
||||
*/
|
||||
class Files extends Backend
|
||||
{
|
||||
/**
|
||||
* files模型对象
|
||||
* @var \app\model\Files
|
||||
*/
|
||||
protected $model;
|
||||
public $hasSoftDel = 1;//是否拥有软删除功能
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
$this->model = new \app\model\Files();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$data = $this->model->where($where)->order($order)->with(['category', 'createAdminUser'=>['avatarFile']]);
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $data->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $data->select()->toArray();
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
//添加
|
||||
public function add()
|
||||
{
|
||||
return $this->error('当前版本暂时不支持在附件管理中添加附件');
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$post['create_admin_user_id'] = UserServiceFacade::getUser()->id;
|
||||
$post['update_admin_user_id'] = UserServiceFacade::getUser()->id;
|
||||
$post['path'] = UploadDomain::singleDelUploadDomain($post['path']);
|
||||
if ($this->model->create($post)) {
|
||||
return $this->success('添加成功', $post);
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
//不经过服务器方式上传成功后,回调的ajax请求地址,将上传成功的文件信息存入表中
|
||||
public function unViaSave()
|
||||
{
|
||||
$post = $this->request->post();
|
||||
$post['create_admin_user_id'] = UserServiceFacade::getUser()->id;
|
||||
$post['update_admin_user_id'] = UserServiceFacade::getUser()->id;
|
||||
$post['create_time'] = date('Y-m-d H:i:s');
|
||||
$post['update_time'] = date('Y-m-d H:i:s');
|
||||
$post['id'] = $this->model->insertGetId($post);
|
||||
if ($post['id']) {
|
||||
return $this->success('添加成功', $post);
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
//编辑
|
||||
public function edit()
|
||||
{
|
||||
return $this->error('当前版本暂时不支持在附件管理中编辑附件');
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$post['update_admin_user_id'] = UserServiceFacade::getUser()->id;
|
||||
$post['path'] = UploadDomain::singleDelUploadDomain($post['path']);
|
||||
foreach ($post as $k => $v) {
|
||||
$info->$k = $v;
|
||||
}
|
||||
try {
|
||||
$updateRes = $info->save();
|
||||
if ($updateRes) {
|
||||
return $this->success('编辑成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未做修改');
|
||||
} else if ($updateRes === null) {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
//删除
|
||||
public function del()
|
||||
{
|
||||
$ids = array_filter($this->request->post('ids'));
|
||||
if (!$ids) {
|
||||
return $this->error('参数ids不能为空');
|
||||
}
|
||||
try {
|
||||
if ($this->model->destroy($ids)) {
|
||||
return $this->success('数据删除成功');
|
||||
} else {
|
||||
return $this->error('数据删除失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
//回收站
|
||||
public function recycle()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $this->model->onlyTrashed()
|
||||
->with(['category', 'createAdminUser', 'updateAdminUser'])
|
||||
->order($order)->where($where)->paginate($limit)->toArray();
|
||||
return $this->success('回收站数据获取成功', $data);
|
||||
}
|
||||
}
|
||||
Executable
+138
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use think\facade\Config;
|
||||
use laytp\library\CommonFun;
|
||||
use app\validate\admin\member\Add;
|
||||
use app\validate\admin\member\Edit;
|
||||
use laytp\library\Str;
|
||||
use laytp\library\UploadDomain;
|
||||
|
||||
/**
|
||||
* 会员管理
|
||||
*/
|
||||
class Member extends Backend
|
||||
{
|
||||
|
||||
/**
|
||||
* member模型对象
|
||||
* @var \app\model\Member
|
||||
*/
|
||||
protected $model;
|
||||
protected $hasSoftDel=1;//是否拥有软删除功能
|
||||
|
||||
protected $noNeedLogin = []; // 无需登录即可请求的方法
|
||||
protected $noNeedAuth = ['index', 'info']; // 无需鉴权即可请求的方法
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\Member();
|
||||
}
|
||||
|
||||
|
||||
//查看和搜索列表
|
||||
public function index(){
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$data = $this->model->where($where)->order($order)->with(['avatar_pic_file']);
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $data->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $data->select()->toArray();
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
|
||||
//添加
|
||||
public function add()
|
||||
{
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$validate = new Add();
|
||||
if(!$validate->check($post)){
|
||||
return $this->error($validate->getError());
|
||||
}
|
||||
if(isset($post['password']) && $post['password']) $post['password'] = Str::createPassword($post['password']);
|
||||
try {
|
||||
if ($this->model->create($post)) {
|
||||
return $this->success('添加成功', $post);
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//查看详情
|
||||
public function info()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->with(['avatar_pic_file'])->find($id);
|
||||
return $this->success('获取成功', $info);
|
||||
}
|
||||
|
||||
|
||||
//编辑
|
||||
public function edit(){
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$validate = new Edit();
|
||||
if(!$validate->check($post)){
|
||||
return $this->error($validate->getError());
|
||||
}
|
||||
if(!$post['password']){
|
||||
unset($post['password']);
|
||||
}else{
|
||||
$post['password'] = Str::createPassword($post['password']);
|
||||
}
|
||||
foreach ($post as $k => $v) {
|
||||
$info->$k = $v;
|
||||
}
|
||||
try {
|
||||
$updateRes = $info->save();
|
||||
if ($updateRes) {
|
||||
return $this->success('编辑成功');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//设置账号状态
|
||||
public function setStatus()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['status'] = $fieldVal;
|
||||
try {
|
||||
if($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+267
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\service\admin\UserServiceFacade;
|
||||
use laytp\controller\Backend;
|
||||
use laytp\library\CommonFun;
|
||||
use laytp\library\Tree;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 菜单控制器
|
||||
*/
|
||||
class Menu extends Backend
|
||||
{
|
||||
public $noNeedAuth = ['getMenuTree', 'getTree'];
|
||||
public $model;
|
||||
public $orderRule = ['sort' => 'desc', 'id' => 'asc'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\admin\Menu();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$sourceData = $this->model->where($where)->order($order);
|
||||
$isTree = $this->request->param('is_tree');
|
||||
if ($isTree) {
|
||||
$menuTreeObj = Tree::instance();
|
||||
$menuTreeObj->init($sourceData->select()->toArray());
|
||||
$data = $menuTreeObj->getRootTrees();
|
||||
} else {
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $sourceData->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $sourceData->select()->toArray();
|
||||
}
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
//获取当前登录者的权限列表,返回树形数据,角色管理赋予权限时用到
|
||||
public function getTree()
|
||||
{
|
||||
$user = UserServiceFacade::getUser();
|
||||
if ($user->is_super_manager === 1) {
|
||||
$sourceData = $this->model->order($this->orderRule)->select()->toArray();
|
||||
} else {
|
||||
$roleIds = \app\model\admin\role\User::where('admin_user_id', '=', $user->id)
|
||||
->column('admin_role_id');
|
||||
$menuIds = \app\model\admin\menu\Role::where('admin_role_id', 'in', $roleIds)
|
||||
->column('admin_menu_id');
|
||||
$where[] = ['id', 'in', $menuIds];
|
||||
$sourceData = $this->model->order($this->orderRule)->where($where)->select()->toArray();
|
||||
}
|
||||
$menuTreeObj = Tree::instance();
|
||||
$menuTreeObj->init($sourceData);
|
||||
//由列表数据转化成树形结构数据
|
||||
$data = $menuTreeObj->getRootTrees();
|
||||
return $this->success('获取成功', $data);
|
||||
}
|
||||
|
||||
//获取当前登录者的菜单列表,返回树形数据,仅返回is_menu=1的列表,后台菜单列表展示使用
|
||||
public function getMenuTree()
|
||||
{
|
||||
$user = UserServiceFacade::getUser();
|
||||
$where[] = ['is_show', '=', 1];
|
||||
$where[] = ['is_menu', '=', 1];
|
||||
if ($user->is_super_manager === 1) {
|
||||
$sourceData = $this->model->order($this->orderRule)->where($where)->select()->toArray();
|
||||
} else {
|
||||
$roleIds = \app\model\admin\role\User::where('admin_user_id', '=', $user->id)
|
||||
->column('admin_role_id');
|
||||
$menuIds = \app\model\admin\menu\Role::where('admin_role_id', 'in', $roleIds)
|
||||
->column('admin_menu_id');
|
||||
$where[] = ['id', 'in', $menuIds];
|
||||
$sourceData = $this->model->order($this->orderRule)->where($where)->select()->toArray();
|
||||
}
|
||||
$menuTreeObj = Tree::instance();
|
||||
$menuTreeObj->init($sourceData);
|
||||
//由列表数据转化成树形结构数据
|
||||
$data = $menuTreeObj->getRootTrees();
|
||||
return $this->success('获取成功', $data);
|
||||
}
|
||||
|
||||
//添加
|
||||
public function add()
|
||||
{
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
if ($post['rule'] && substr($post['rule'], 0, 1) != '/') {
|
||||
$post['rule'] = '/' . $post['rule'];
|
||||
}
|
||||
if ($this->model->create($post)) {
|
||||
return $this->success('添加成功', $post);
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
//编辑
|
||||
public function edit()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
if ($post['rule'] && substr($post['rule'], 0, 1) != '/') {
|
||||
$post['rule'] = '/' . $post['rule'];
|
||||
}
|
||||
if ($id == $post['pid']) {
|
||||
return $this->error('不能将上级改成自己');
|
||||
}
|
||||
foreach ($post as $k => $v) {
|
||||
$info->$k = $v;
|
||||
}
|
||||
$update_res = $info->save();
|
||||
if ($update_res) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($update_res === 0) {
|
||||
return $this->success('未做修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
//删除
|
||||
public function del()
|
||||
{
|
||||
$ids = $this->request->post('ids');
|
||||
if (!$ids) {
|
||||
return $this->error('参数ids不能为空');
|
||||
}
|
||||
|
||||
$sourceData = $this->model->select()->toArray();
|
||||
$treeLib = Tree::instance();
|
||||
$treeLib->init($sourceData);
|
||||
$childIds = $treeLib->getChildIds($ids);
|
||||
|
||||
if ($this->model->destroy($childIds)) {
|
||||
return $this->success('数据删除成功', $childIds);
|
||||
} else {
|
||||
return $this->error('数据删除失败');
|
||||
}
|
||||
}
|
||||
|
||||
//设置排序
|
||||
public function setSort()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['sort'] = $fieldVal;
|
||||
try {
|
||||
if ($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
//设置是否为菜单
|
||||
public function setIsMenu()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['is_menu'] = $fieldVal;
|
||||
try {
|
||||
if ($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
//设置是否显示
|
||||
public function setIsShow()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['is_show'] = $fieldVal;
|
||||
try {
|
||||
if ($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
// 复制菜单
|
||||
public function copy()
|
||||
{
|
||||
$pid = (int)$this->request->post('pid');
|
||||
$ids = $this->request->post('ids');
|
||||
if (!$ids) {
|
||||
return $this->error('参数ids不能为空');
|
||||
}
|
||||
|
||||
$data = \app\model\admin\Menu::where('id', 'in', $ids)
|
||||
->withoutField('id')->select()
|
||||
->each(function ($item) use ($pid) {
|
||||
$item->pid = $pid;
|
||||
})->toArray();
|
||||
|
||||
$insert = $this->model->insertAll($data);
|
||||
if ($insert) {
|
||||
return $this->success('复制成功');
|
||||
} else {
|
||||
return $this->error('复制失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 移动菜单
|
||||
public function move()
|
||||
{
|
||||
$pid = (int)$this->request->post('pid');
|
||||
$ids = $this->request->post('ids');
|
||||
if (!$ids) {
|
||||
return $this->error('参数ids不能为空');
|
||||
}
|
||||
|
||||
$save = \app\model\admin\Menu::where('id', 'in', $ids)
|
||||
->save(['pid' => $pid]);
|
||||
|
||||
if ($save) {
|
||||
return $this->success('移动成功');
|
||||
} else {
|
||||
return $this->error('移动失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+158
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use think\facade\Config;
|
||||
use laytp\library\CommonFun;
|
||||
use app\validate\admin\bot\Add;
|
||||
use app\validate\admin\bot\Edit;
|
||||
use laytp\library\Str;
|
||||
use laytp\library\UploadDomain;
|
||||
use app\service\Telegram as Telegrambot;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 会员管理
|
||||
*/
|
||||
class Order extends Backend
|
||||
{
|
||||
|
||||
/**
|
||||
* member模型对象
|
||||
* @var \app\model\Bot
|
||||
*/
|
||||
protected $model;
|
||||
protected $hasSoftDel=1;//是否拥有软删除功能
|
||||
|
||||
protected $noNeedLogin = []; // 无需登录即可请求的方法
|
||||
protected $noNeedAuth = ['index', 'info']; // 无需鉴权即可请求的方法
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\Order();
|
||||
}
|
||||
|
||||
|
||||
//查看和搜索列表
|
||||
public function index(){
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
//var_dump($where,$order);
|
||||
$data = $this->model->where($where)->order($order)->with(['avatar_pic_file']);
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $data->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $data->select()->toArray();
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
|
||||
//添加
|
||||
public function add()
|
||||
{
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$validate = new Add();
|
||||
if(!$validate->check($post)){
|
||||
return $this->error($validate->getError());
|
||||
}
|
||||
try {
|
||||
if ($this->model->create($post)) {
|
||||
return $this->success('添加成功', $post);
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//查看详情
|
||||
public function info()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
return $this->success('获取成功', $info);
|
||||
}
|
||||
|
||||
//webhook
|
||||
public function webhook(){
|
||||
$botkey = $this->request->param('botkey');
|
||||
$id = $this->request->param('id');
|
||||
$botid = explode(":", $botkey)[0];
|
||||
$webhookdm = Request::domain() . '/api.Telegram/callback?botid='.$botid;
|
||||
$Telegrambot=new Telegrambot($botkey);
|
||||
$Telegrambot->setWebhook($webhookdm);
|
||||
$me=$Telegrambot->getme();
|
||||
$first_name=isset($me["result"]['first_name'])?$me["result"]['first_name']:"";
|
||||
$username=isset($me["result"]['username'])?$me["result"]['username']:"";
|
||||
|
||||
|
||||
$updateRes = $this->model->where('id', '=', $id)->update(['botid'=>$botid,'botuser'=>$username,'first_name'=>$first_name]);
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
}
|
||||
//编辑
|
||||
public function edit(){
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
//var_dump($info);
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$validate = new Edit();
|
||||
if(!$validate->check($post)){
|
||||
return $this->error($validate->getError());
|
||||
}
|
||||
|
||||
foreach ($post as $k => $v) {
|
||||
$info->$k = $v;
|
||||
}
|
||||
try {
|
||||
$updateRes = $info->save();
|
||||
if ($updateRes) {
|
||||
return $this->success('编辑成功');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//设置账号状态
|
||||
public function setStatus()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['status'] = $fieldVal;
|
||||
try {
|
||||
if($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+151
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\service\admin\PluginsServiceFacade;
|
||||
use laytp\controller\Backend;
|
||||
use laytp\library\Http;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 插件管理
|
||||
*/
|
||||
class Plugins extends Backend
|
||||
{
|
||||
/**
|
||||
* files模型对象
|
||||
* @var \app\model\Files
|
||||
*/
|
||||
protected $model;
|
||||
public $hasSoftDel = 1;//是否拥有软删除功能
|
||||
|
||||
// 获取laytp官网定义的插件分类列表
|
||||
public function category()
|
||||
{
|
||||
$url = Config::get('plugin.apiUrl') . '/plugins/category';
|
||||
$data = json_decode(Http::get($url), true)['data'];
|
||||
return $this->success('获取成功', $data);
|
||||
}
|
||||
|
||||
// 查看
|
||||
public function index()
|
||||
{
|
||||
$params['page'] = $this->request->param('page', 1);
|
||||
$params['limit'] = $this->request->param('limit', 10);
|
||||
$params['category_id'] = $this->request->param('category_id', 0);
|
||||
$url = Config::get('plugin.apiUrl') . '/plugins/index';
|
||||
$data = json_decode(Http::get($url, $params), true)['data'];
|
||||
$installed = Config::get('plugin.installed');
|
||||
foreach ($data['data'] as $k => $datum) {
|
||||
if ($installed && in_array($datum['alias'], $installed)) {
|
||||
$data['data'][$k]['installed'] = 1;
|
||||
$pluginInfo = PluginsServiceFacade::getPluginInfo($datum['alias']);
|
||||
if (isset($pluginInfo['version'])) {
|
||||
$version = $pluginInfo['version'];
|
||||
} else {
|
||||
$version = '1.0.0';
|
||||
}
|
||||
$data['data'][$k]['version'] = $version;
|
||||
} else {
|
||||
$data['data'][$k]['installed'] = 2;
|
||||
}
|
||||
}
|
||||
return $this->success('获取成功', $data);
|
||||
}
|
||||
|
||||
// 离线安装 - 所有的离线安装都是覆盖安装
|
||||
public function offLineInstall()
|
||||
{
|
||||
if (PluginsServiceFacade::offLineInstall()) {
|
||||
sleep(1);
|
||||
$file = request()->file('laytpUploadFile'); // 获取上传的文件
|
||||
$pluginConf = Config::get('plugin');
|
||||
$fileName = $file->getOriginalName();
|
||||
$pathinfo = pathinfo($fileName);
|
||||
$plugin = $pathinfo['filename'];
|
||||
$pluginConf['installed'][] = $plugin;
|
||||
$pluginConf['installed'] = array_unique($pluginConf['installed']);
|
||||
sort($pluginConf['installed']);
|
||||
|
||||
$info = PluginsServiceFacade::getPluginInfo($plugin);
|
||||
if(isset($info['is_editor']) && $info['is_editor']){
|
||||
$pluginConf['installedEditor'][] = $plugin;
|
||||
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
|
||||
sort($pluginConf['installedEditor']);
|
||||
}
|
||||
|
||||
return $this->success('安装成功', [
|
||||
'pluginConf' => $pluginConf
|
||||
]);
|
||||
} else {
|
||||
return $this->error(PluginsServiceFacade::getError());
|
||||
}
|
||||
}
|
||||
|
||||
// 卸载
|
||||
public function uninstall()
|
||||
{
|
||||
$plugin = $this->request->param('plugin');
|
||||
$info = PluginsServiceFacade::getPluginInfo($plugin);
|
||||
|
||||
if (PluginsServiceFacade::unInstall($plugin)) {
|
||||
$pluginConf = Config::get('plugin');
|
||||
foreach($pluginConf['installed'] as $k=>$installed){
|
||||
if($installed === $plugin) unset($pluginConf['installed'][$k]);
|
||||
}
|
||||
$pluginConf['installed'] = array_unique($pluginConf['installed']);
|
||||
sort($pluginConf['installed']);
|
||||
|
||||
if(isset($info['is_editor']) && $info['is_editor']){
|
||||
foreach($pluginConf['installedEditor'] as $k=>$installedEditor){
|
||||
if($installedEditor === $plugin) unset($pluginConf['installedEditor'][$k]);
|
||||
}
|
||||
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
|
||||
sort($pluginConf['installedEditor']);
|
||||
// 如果根目录下有相应的html文件,将文件内容进行替换
|
||||
$htmlFile = root_path() . 'public/admin/' . $plugin . '.html';
|
||||
if(is_file($htmlFile)){
|
||||
file_put_contents($htmlFile, '<p style="color:blue">请先到插件市场安装' . $plugin . '编辑器。</p>
|
||||
<p style="color:red">注意:安装或卸载编辑器后,需要清空浏览器缓存才能生效</p>');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success($plugin . '插件卸载成功', [
|
||||
'pluginConf' => $pluginConf,
|
||||
'info' => $info
|
||||
]);
|
||||
} else {
|
||||
return $this->error(PluginsServiceFacade::getError());
|
||||
}
|
||||
}
|
||||
|
||||
// 安装
|
||||
public function install()
|
||||
{
|
||||
$plugin = $this->request->param('plugin');
|
||||
$laytpGwToken = $this->request->param('laytpGwToken');
|
||||
|
||||
if (PluginsServiceFacade::install($plugin, $laytpGwToken)) {
|
||||
// 如果是文件存储,插件安装信息,刚安装完成马上要取出来,取出来的不会是最新的文件内容
|
||||
sleep(1);
|
||||
$pluginConf = Config::get('plugin');
|
||||
$pluginConf['installed'][] = $plugin;
|
||||
$pluginConf['installed'] = array_unique($pluginConf['installed']);
|
||||
sort($pluginConf['installed']);
|
||||
|
||||
$info = PluginsServiceFacade::getPluginInfo($plugin);
|
||||
if(isset($info['is_editor']) && $info['is_editor']){
|
||||
$pluginConf['installedEditor'][] = $plugin;
|
||||
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
|
||||
sort($pluginConf['installedEditor']);
|
||||
}
|
||||
|
||||
return $this->success($plugin . '插件安装成功', [
|
||||
'pluginConf' => $pluginConf
|
||||
]);
|
||||
} else {
|
||||
$error = PluginsServiceFacade::getError();
|
||||
return $this->error($error['msg'], $error['code']);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+177
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use laytp\library\CommonFun;
|
||||
use think\facade\Config;
|
||||
use think\facade\Db;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 角色控制器
|
||||
*/
|
||||
class Role extends Backend
|
||||
{
|
||||
protected $noNeedAuth = ['getMenuIds'];
|
||||
|
||||
public $model;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\admin\Role();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* all_data参数的值为true时,表示查询表中所有数据集,否则进行分页查询
|
||||
* @return mixed
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$data = $this->model->where($where)->order($order);
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $data->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $data->select()->toArray();
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加,同时添加lt_plugin_core_role和lt_plugin_core_role_menu两个表的数据
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
Db::startTrans();
|
||||
try {
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$roleInfo = $this->model->getByName($post['name']);
|
||||
if ($roleInfo) throw new \Exception('角色名已存在');
|
||||
|
||||
$menuIds = explode(',', $post['menu_ids']);
|
||||
unset($post['menu_ids']);
|
||||
$saveMenu = $this->model->save($post);
|
||||
if (!$saveMenu) throw new \Exception('保存角色基本信息失败');
|
||||
|
||||
$saveAllData = [];
|
||||
foreach ($menuIds as $menu_id) {
|
||||
$saveAllData[] = [
|
||||
'admin_role_id' => $this->model->id,
|
||||
'admin_menu_id' => $menu_id,
|
||||
];
|
||||
}
|
||||
$menu = new \app\model\admin\menu\Role();
|
||||
$saveAllMenu = $menu->saveAll($saveAllData);
|
||||
if (!$saveAllMenu) throw new \Exception('保存角色权限失败');
|
||||
|
||||
Db::commit();
|
||||
return $this->success('操作成功');
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑,同时编辑lt_plugin_core_role和lt_plugin_core_role_menu两个表的数据
|
||||
* @return bool|\think\response\Json
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
|
||||
$postData = Request::only(['id', 'name', 'menu_ids']);
|
||||
$post = CommonFun::filterPostData($postData);
|
||||
|
||||
$roleInfo = $this->model->getByName($post['name']);
|
||||
if ($roleInfo && ($roleInfo['id'] != $id)) {
|
||||
return $this->error('角色名已存在');
|
||||
}
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
$menuIds = explode(',', $post['menu_ids']);
|
||||
unset($post['menu_ids']);
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($post);
|
||||
if (!is_numeric($updateRes)) throw new \Exception('保存角色基本信息失败');
|
||||
|
||||
$delRes = \app\model\admin\menu\Role::where('admin_role_id', '=', $id)->delete();
|
||||
if (!is_numeric($delRes)) throw new \Exception('删除角色权限失败');
|
||||
|
||||
$saveAllData = [];
|
||||
foreach ($menuIds as $menu_id) {
|
||||
$saveAllData[] = [
|
||||
'admin_role_id' => $id,
|
||||
'admin_menu_id' => $menu_id,
|
||||
];
|
||||
}
|
||||
$menu = new \app\model\admin\menu\Role();
|
||||
$menu->saveAll($saveAllData);
|
||||
|
||||
Db::commit();
|
||||
return $this->success('操作成功');
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 真实删除
|
||||
* lt_admin_role、lt_admin_menu_role、lt_admin_role_user三表数据都要真实删除
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function trueDel()
|
||||
{
|
||||
$ids = $this->request->param('ids');
|
||||
Db::startTrans();
|
||||
try {
|
||||
$roles = $this->model->onlyTrashed()->where('id', 'in', $ids)->select();
|
||||
foreach ($roles as $key => $item) {
|
||||
$delRes = $item->force()->delete();
|
||||
if (!$delRes) throw new \Exception('角色删除失败');
|
||||
}
|
||||
$delRes = \app\model\admin\menu\Role::where('admin_role_id', 'in', $ids)->delete();
|
||||
if (!is_numeric($delRes)) throw new \Exception('角色权限删除失败');
|
||||
|
||||
$delRes = \app\model\admin\role\User::where('admin_role_id', 'in', $ids)->delete();
|
||||
if (!is_numeric($delRes)) throw new \Exception('角色用户删除失败');
|
||||
|
||||
Db::commit();
|
||||
return $this->success('操作成功');
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取编辑页面权限设置应该选中的菜单id
|
||||
* 只能获取最低级别的菜单id,有子菜单的菜单id不能返回
|
||||
* 原因:比如tree.setChecked('auth_node',1);会选中整棵树,因为layui的树组件,模拟点击了树的首节点
|
||||
* @return false|string|\think\response\Json
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getMenuIds()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$menuIds = \app\model\admin\menu\Role::where('admin_role_id', '=', $id)->column('admin_menu_id');
|
||||
$auth = [];
|
||||
foreach ($menuIds as $menuId) {
|
||||
$hasChild = \app\model\admin\Menu::where('pid', '=', $menuId)->find() ? true : false;
|
||||
if (!$hasChild) {
|
||||
$auth[] = $menuId;
|
||||
}
|
||||
}
|
||||
return $this->success('获取成功', $auth);
|
||||
}
|
||||
}
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use think\facade\Config;
|
||||
use laytp\library\CommonFun;
|
||||
use app\validate\admin\bot\Add;
|
||||
use app\validate\admin\bot\Edit;
|
||||
use laytp\library\Str;
|
||||
use think\facade\App;
|
||||
use laytp\library\UploadDomain;
|
||||
use app\service\Telegram as Telegrambot;
|
||||
use think\facade\Request;
|
||||
use GitWrapper\GitWrapper;
|
||||
|
||||
/**
|
||||
* 会员管理
|
||||
*/
|
||||
class Updata extends Backend
|
||||
{
|
||||
|
||||
/**
|
||||
* member模型对象
|
||||
* @var \app\model\Bot
|
||||
*/
|
||||
protected $model;
|
||||
protected $hasSoftDel=1;//是否拥有软删除功能
|
||||
|
||||
protected $noNeedLogin = []; // 无需登录即可请求的方法
|
||||
protected $noNeedAuth = ['index', 'info']; // 无需鉴权即可请求的方法
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//查看和搜索列表
|
||||
//查看和搜索列表
|
||||
public function index(){
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
//var_dump($where,$order);
|
||||
$data = $this->model->where($where)->order($order)->with(['avatar_pic_file']);
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $data->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $data->select()->toArray();
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
|
||||
//添加
|
||||
public function updata()
|
||||
{
|
||||
|
||||
$repoPath = App::getRootPath();
|
||||
$output = shell_exec("cd {$repoPath} && git pull 2>&1");
|
||||
|
||||
// 输出结果
|
||||
echo "Git Pull Output:\n";
|
||||
echo $output;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Executable
+306
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\model\admin\login\Log;
|
||||
use app\service\admin\AuthServiceFacade;
|
||||
use app\service\admin\UserServiceFacade;
|
||||
use app\validate\admin\user\Add;
|
||||
use app\validate\admin\user\Edit;
|
||||
use app\validate\admin\user\Login;
|
||||
use app\validate\admin\user\singleEdit;
|
||||
use laytp\controller\Backend;
|
||||
use laytp\library\CommonFun;
|
||||
use laytp\library\Random;
|
||||
use laytp\library\Str;
|
||||
use laytp\library\Token;
|
||||
use think\facade\Config;
|
||||
use think\facade\Db;
|
||||
use think\facade\Cache;
|
||||
|
||||
/**
|
||||
* 后台管理员控制器
|
||||
*/
|
||||
class User extends Backend
|
||||
{
|
||||
protected $model;
|
||||
//当前模型对象
|
||||
protected $noNeedLogin = ['login', 'logout'];
|
||||
protected $noNeedAuth = ['loginInfo', 'singleEdit'];
|
||||
|
||||
protected function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\admin\User();
|
||||
}
|
||||
|
||||
public function login()
|
||||
{
|
||||
//获取表单提交数据
|
||||
$param = $this->request->post();
|
||||
//防止密码爆破
|
||||
$fail = Cache::get('laytp-admin-login-num-' . $param['username'], 1);
|
||||
if ($fail >= 5) return $this->error('失败次数过多,请三分钟后再试');
|
||||
//验证表单提交
|
||||
$validate = new Login();
|
||||
if (!$validate->check($param)) {
|
||||
$param['password'] = '******';
|
||||
//登录失败也不记录用户密码
|
||||
Log::create([
|
||||
'login_status' => 2,
|
||||
'admin_id' => 0,
|
||||
'request_body' => json_encode($param),
|
||||
'request_header' => json_encode($this->request->header()),
|
||||
'ip' => $this->request->ip(),
|
||||
'create_time' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
Cache::set('laytp-admin-login-num-' . $param['username'], $fail + 1, 180);
|
||||
return $this->error($validate->getError());
|
||||
}
|
||||
//设置登录信息
|
||||
$loginUserInfo = \app\model\admin\User::where('username', '=', $param['username'])
|
||||
->with(['avatar_file'])->field(UserServiceFacade::getAllowFields())->findOrEmpty();
|
||||
$loginUserInfo->login_time = date('Y-m-d H:i:s');
|
||||
$loginUserInfo->login_ip = $this->request->ip();
|
||||
$loginUserInfo->save();
|
||||
$userId = $loginUserInfo['id'];
|
||||
$token = Random::uuid();
|
||||
$loginUserInfo['token'] = $token;
|
||||
Token::set($token, $userId, 24 * 60 * 60 * 3);
|
||||
|
||||
$param['password'] = '******';
|
||||
//登录成功不记录用户密码
|
||||
Log::create([
|
||||
'login_status' => 1,
|
||||
'admin_id' => $userId,
|
||||
'request_body' => json_encode($param),
|
||||
'request_header' => json_encode($this->request->header()),
|
||||
'ip' => $this->request->ip(),
|
||||
'create_time' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
$authList = AuthServiceFacade::getAuthList($userId);
|
||||
return $this->success('登录成功', [
|
||||
'user' => $loginUserInfo,
|
||||
'authList' => $authList,
|
||||
'pluginConf' => Config::get('plugin'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function loginInfo()
|
||||
{
|
||||
$loginUserInfo = UserServiceFacade::getUserInfo();
|
||||
$authList = AuthServiceFacade::getAuthList($loginUserInfo['id']);
|
||||
|
||||
return $this->success('获取成功', [
|
||||
'user' => $loginUserInfo,
|
||||
'authList' => $authList,
|
||||
'pluginConf' => Config::get('plugin'),
|
||||
'ltVersion' => LT_VERSION,
|
||||
]);
|
||||
}
|
||||
|
||||
//退出登录
|
||||
public function logout()
|
||||
{
|
||||
$token = $this->request->header('laytp-admin-token', $this->request->cookie('laytpAdminToken'));
|
||||
Token::delete($token);
|
||||
return $this->success('退出成功');
|
||||
}
|
||||
|
||||
//查看
|
||||
public function index()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$data = $this->model->where($where)->order($order)->with(['avatar_file']);
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $data->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $data->select()->toArray();
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
//添加
|
||||
public function add()
|
||||
{
|
||||
Db::startTrans();
|
||||
try {
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$validate = new Add();
|
||||
if (!$validate->check($post)) throw new \Exception($validate->getError());
|
||||
|
||||
$post['password'] = Str::createPassword($post['password']);
|
||||
$saveRes = $this->model->save($post);
|
||||
if (!$saveRes) throw new \Exception('保存基础信息失败');
|
||||
|
||||
if ($post['role_ids']) {
|
||||
$roleIds = explode(',', $post['role_ids']);
|
||||
$data = [];
|
||||
foreach ($roleIds as $k => $v) {
|
||||
$data[] = ['admin_role_id' => $v, 'admin_user_id' => $this->model->id];
|
||||
}
|
||||
$roleUser = new \app\model\admin\role\User();
|
||||
$saveAllRes = $roleUser->saveAll($data);
|
||||
if (!$saveAllRes) throw new \Exception('保存角色信息失败');
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
return $this->success('操作成功');
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
//查看详情
|
||||
public function info()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->with(['role_ids', 'avatar_file'])->findOrEmpty($id)->toArray();
|
||||
$data = \app\resource\admin\User::info($info);
|
||||
return $this->success('获取成功', $data);
|
||||
}
|
||||
|
||||
//编辑
|
||||
public function edit()
|
||||
{
|
||||
Db::startTrans();
|
||||
try {
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$user = $this->model->findOrEmpty($post['id']);
|
||||
if (!$user) throw new \Exception('id参数错误');
|
||||
|
||||
$validate = new Edit();
|
||||
if (!$validate->check($post)) throw new \Exception($validate->getError());
|
||||
if ($post['password']) {
|
||||
$post['password'] = Str::createPassword($post['password']);
|
||||
} else {
|
||||
unset($post['password']);
|
||||
unset($post['re_password']);
|
||||
}
|
||||
$updateRes = $user->update($post);
|
||||
if (!$updateRes) throw new \Exception('保存基本信息失败');
|
||||
|
||||
$userRole = new \app\model\admin\role\User();
|
||||
$deleteRes = $userRole->where('admin_user_id', '=', $post['id'])->delete();
|
||||
if (!is_numeric($deleteRes)) throw new \Exception('删除用户角色失败');
|
||||
|
||||
if ($post['role_ids']) {
|
||||
$roleIds = explode(',', $post['role_ids']);
|
||||
$data = [];
|
||||
foreach ($roleIds as $k => $v) {
|
||||
$data[] = ['admin_role_id' => $v, 'admin_user_id' => $user->id];
|
||||
}
|
||||
|
||||
$saveAllRes = $userRole->saveAll($data);
|
||||
if (!$saveAllRes) throw new \Exception('保存用户角色失败');
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
return $this->success('操作成功');
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
//修改个人资料
|
||||
public function singleEdit()
|
||||
{
|
||||
$post = CommonFun::filterPostData($this->request->post());
|
||||
$validate = new singleEdit();
|
||||
if (!$validate->check($post)) {
|
||||
return $this->error($validate->getError());
|
||||
}
|
||||
if (!$post['password']) {
|
||||
unset($post['password']);
|
||||
} else {
|
||||
$post['password'] = Str::createPassword($post['password']);
|
||||
}
|
||||
$user = $this->model->with(['avatar_file'])->find($post['id']);
|
||||
if (!$user) {
|
||||
return $this->error('ID参数错误');
|
||||
}
|
||||
$res = $user->update($post);
|
||||
if ($res) {
|
||||
return $this->success('操作成功');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
//删除
|
||||
public function del()
|
||||
{
|
||||
$ids = array_filter($this->request->param('ids'));
|
||||
if (!$ids) {
|
||||
return $this->error('参数ids不能为空');
|
||||
}
|
||||
if (in_array(1, $ids)) {
|
||||
return $this->error('不允许删除初始化用户');
|
||||
}
|
||||
try {
|
||||
if ($this->model->destroy($ids)) {
|
||||
return $this->success('数据删除成功');
|
||||
} else {
|
||||
return $this->error('数据删除失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->exceptionError($e);
|
||||
}
|
||||
}
|
||||
|
||||
//设置状态
|
||||
public function setStatus()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['status'] = $fieldVal;
|
||||
try {
|
||||
if ($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
//设置是否为超管
|
||||
public function setIsSuperManager()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['is_super_manager'] = $fieldVal;
|
||||
try {
|
||||
if ($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin\action;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 后台操作日志
|
||||
*/
|
||||
class Log extends Backend
|
||||
{
|
||||
/**
|
||||
* admin_action_log模型对象
|
||||
* @var \app\model\admin\action\Log
|
||||
*/
|
||||
protected $model;
|
||||
protected $hasSoftDel = 0;//是否拥有软删除功能
|
||||
|
||||
protected $noNeedLogin = []; // 无需登录即可请求的方法
|
||||
protected $noNeedAuth = ['index', 'info']; // 无需鉴权即可请求的方法
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\admin\action\Log();
|
||||
}
|
||||
|
||||
//查看和搜索列表
|
||||
public function index()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$data = $this->model->where($where)->order($order)->with(['adminUser']);
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $data->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $data->select()->toArray();
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
//查看详情
|
||||
public function info()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
return $this->success('获取成功', $info);
|
||||
}
|
||||
|
||||
//回收站
|
||||
public function recycle()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $this->model->onlyTrashed()
|
||||
->with(['adminUser'])
|
||||
->order($order)->where($where)->paginate($limit)->toArray();
|
||||
return $this->success('回收站数据获取成功', $data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin\api;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* Api请求日志
|
||||
*/
|
||||
class Log extends Backend
|
||||
{
|
||||
|
||||
/**
|
||||
* api_log模型对象
|
||||
* @var \app\model\api\Log
|
||||
*/
|
||||
protected $model;
|
||||
protected $hasSoftDel = 0;//是否拥有软删除功能
|
||||
|
||||
protected $noNeedLogin = []; // 无需登录即可请求的方法
|
||||
protected $noNeedAuth = ['index', 'info']; // 无需鉴权即可请求的方法
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\api\Log();
|
||||
}
|
||||
|
||||
//查看详情
|
||||
public function info()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
return $this->success('获取成功', $info);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin\balance;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* Api请求日志
|
||||
*/
|
||||
class Log extends Backend
|
||||
{
|
||||
|
||||
/**
|
||||
* api_log模型对象app\model\admin\balance
|
||||
* @var \app\model\admin\balance\Log
|
||||
*/
|
||||
protected $model;
|
||||
protected $hasSoftDel = 0;//是否拥有软删除功能
|
||||
|
||||
protected $noNeedLogin = []; // 无需登录即可请求的方法
|
||||
protected $noNeedAuth = ['index', 'info']; // 无需鉴权即可请求的方法
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\admin\balance\Log();
|
||||
|
||||
}
|
||||
|
||||
//查看详情
|
||||
public function info()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
return $this->success('获取成功', $info);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin\files;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use laytp\library\Tree;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 附件分类管理
|
||||
*/
|
||||
class Category extends Backend
|
||||
{
|
||||
/**
|
||||
* files_category模型对象
|
||||
* @var \app\model\files\Category
|
||||
*/
|
||||
protected $model;
|
||||
public $hasSoftDel = 1;//是否拥有软删除功能
|
||||
public $orderRule = ['sort' => 'DESC', 'id' => 'ASC'];
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
$this->model = new \app\model\files\Category();
|
||||
}
|
||||
|
||||
//查看
|
||||
public function index()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$sourceData = $this->model->order($order)->where($where);
|
||||
$isTree = $this->request->param('is_tree');
|
||||
if ($isTree) {
|
||||
$menuTreeObj = Tree::instance();
|
||||
$menuTreeObj->init($sourceData->select()->toArray());
|
||||
$data = $menuTreeObj->getRootTrees();
|
||||
} else {
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $sourceData->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $sourceData->select()->toArray();
|
||||
}
|
||||
}
|
||||
return $this->success('获取成功', $data);
|
||||
}
|
||||
|
||||
//删除
|
||||
public function del()
|
||||
{
|
||||
$ids = $this->request->post('ids');
|
||||
if (!$ids) {
|
||||
return $this->error('参数ids不能为空');
|
||||
}
|
||||
|
||||
$sourceData = $this->model->select()->toArray();
|
||||
$treeLib = Tree::instance();
|
||||
$treeLib->init($sourceData);
|
||||
$childIds = $treeLib->getChildIds($ids);
|
||||
|
||||
if ($this->model->destroy($childIds)) {
|
||||
return $this->success('数据删除成功');
|
||||
} else {
|
||||
return $this->error('数据删除失败');
|
||||
}
|
||||
}
|
||||
|
||||
//回收站
|
||||
public function recycle()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $this->model->onlyTrashed()
|
||||
->with(['parent'])
|
||||
->order($order)->where($where)->paginate($limit)->toArray();
|
||||
return $this->success('回收站数据获取成功', $data);
|
||||
}
|
||||
|
||||
//设置排序
|
||||
public function setSort()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$fieldVal = $this->request->post('field_val');
|
||||
$isRecycle = $this->request->post('is_recycle');
|
||||
$update['sort'] = $fieldVal;
|
||||
try {
|
||||
if ($isRecycle) {
|
||||
$updateRes = $this->model->onlyTrashed()->where('id', '=', $id)->update($update);
|
||||
} else {
|
||||
$updateRes = $this->model->where('id', '=', $id)->update($update);
|
||||
}
|
||||
if ($updateRes) {
|
||||
return $this->success('操作成功');
|
||||
} else if ($updateRes === 0) {
|
||||
return $this->success('未作修改');
|
||||
} else {
|
||||
return $this->error('操作失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->error('数据库异常,操作失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin\login;
|
||||
|
||||
use laytp\controller\Backend;
|
||||
use laytp\library\CommonFun;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 后台登录日志
|
||||
*/
|
||||
class Log extends Backend
|
||||
{
|
||||
|
||||
/**
|
||||
* admin_login_log模型对象
|
||||
* @var \app\model\admin\login\Log
|
||||
*/
|
||||
protected $model;
|
||||
protected $hasSoftDel = 0;//是否拥有软删除功能
|
||||
|
||||
protected $noNeedLogin = []; // 无需登录即可请求的方法
|
||||
protected $noNeedAuth = ['index', 'info']; // 无需鉴权即可请求的方法
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->model = new \app\model\admin\login\Log();
|
||||
}
|
||||
|
||||
|
||||
//查看和搜索列表
|
||||
|
||||
/**
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$data = $this->model->where($where)->order($order)->with(['adminUser']);
|
||||
$paging = $this->request->param('paging', false);
|
||||
if ($paging) {
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $data->paginate($limit)->toArray();
|
||||
$data['data'] = $this->getSelectedData($data['data']);
|
||||
} else {
|
||||
$data = $data->select()->toArray();
|
||||
}
|
||||
return $this->success('数据获取成功', $data);
|
||||
}
|
||||
|
||||
|
||||
//查看详情
|
||||
public function info()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$info = $this->model->find($id);
|
||||
return $this->success('获取成功', $info);
|
||||
}
|
||||
|
||||
|
||||
//回收站
|
||||
public function recycle()
|
||||
{
|
||||
$where = $this->buildSearchParams();
|
||||
$order = $this->buildOrder();
|
||||
$limit = $this->request->param('limit', Config::get('paginate.limit'));
|
||||
$data = $this->model->onlyTrashed()
|
||||
->where($where)
|
||||
->with(['adminUser'])
|
||||
->order($order)->paginate($limit)->toArray();
|
||||
return $this->success('回收站数据获取成功', $data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Executable
+124
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\api;
|
||||
use think\facade\Db;
|
||||
use laytp\controller\Api;
|
||||
use dh2y\qrcode\QRcode;
|
||||
use think\facade\Cache;
|
||||
|
||||
/**
|
||||
* @ApiInternal ()
|
||||
*/
|
||||
class Demo extends Api
|
||||
{
|
||||
|
||||
public $noNeedLogin = ['test'];
|
||||
|
||||
/*@formatter:on*/
|
||||
/**
|
||||
*
|
||||
* @ApiTitle (需要登录的接口需要登录的接口需要登录的接口需要登录的接口)
|
||||
* @ApiSummary (需要登录的接口详细描述)
|
||||
* @ApiMethod (POST)
|
||||
* @ApiRoute (/api.demo/test)
|
||||
* @ApiHeaders (name="token", type="string", required="true", description="请求的Token")
|
||||
* @ApiParams (name="id", type="integer", required="true", description="会员ID")
|
||||
* @ApiParams (name="name", type="string", required="true", description="用户名")
|
||||
* @ApiReturnParams (name="code", type="integer", description="接口返回码.0=常规正确码,表示常规操作成功;1=常规错误码,客户端仅需提示msg;其他返回码与具体业务相关。框架实现了的唯一其他返回码:10401,前端需要跳转至登录界面。在一个复杂的交互过程中,你可能需要自行定义其他返回码")
|
||||
* @ApiReturnParams (name="msg", type="string", description="返回描述")
|
||||
* @ApiReturnParams (name="time", type="integer", description="请求时间,Unix时间戳,单位秒")
|
||||
* @ApiReturnParams (name="data", type="object", description="返回的数据对象")
|
||||
* @ApiReturnParams (name="data.id", type="string", description="参数id的值")
|
||||
* @ApiReturnParams (name="data.name", type="string", description="参数name的值")
|
||||
* @ApiReturn
|
||||
({
|
||||
"code": 0,
|
||||
"msg": "返回成功",
|
||||
"time": 1591168410,
|
||||
"data": {
|
||||
"id": "",
|
||||
"name": ""
|
||||
}
|
||||
})
|
||||
*/
|
||||
/*@formatter:on*/
|
||||
public function test()
|
||||
{ $req = ChangeMoney('7891454089', 'member', "-", 5, 8032909529, "消费" . "测试");
|
||||
var_dump($req);
|
||||
return $this->success('返回成功', $this->request->param());
|
||||
}
|
||||
|
||||
/*@formatter:off*/
|
||||
/**
|
||||
* @ApiTitle (无需登录的接口)
|
||||
* @ApiSummary (无需登录的接口详细描述)
|
||||
* @ApiMethod (POST)
|
||||
* @ApiRoute (/api.demo/test1)
|
||||
* @ApiReturnParams (name="code", type="integer", description="接口返回码.0=常规正确码,表示常规操作成功;1=常规错误码,客户端仅需提示msg;其他返回码与具体业务相关。框架实现了的唯一其他返回码:10401,前端需要跳转至登录界面。在一个复杂的交互过程中,你可能需要自行定义其他返回码")
|
||||
* @ApiReturnParams (name="msg", type="string", description="返回描述")
|
||||
* @ApiReturnParams (name="time", type="integer", description="请求时间,Unix时间戳,单位秒")
|
||||
* @ApiReturnParams (name="data", type="object", description="返回的数据对象")
|
||||
* @ApiReturnParams (name="data.action", type="string", description="固定返回test1")
|
||||
* @ApiReturn
|
||||
({
|
||||
"code": 0,
|
||||
"msg": "返回成功",
|
||||
"time": 1591168410,
|
||||
"data": {
|
||||
"action": "test1"
|
||||
}
|
||||
})
|
||||
*/
|
||||
/*@formatter:on*/
|
||||
public function createqrcoe()
|
||||
{
|
||||
|
||||
|
||||
|
||||
return $this->success('返回成功', ['action' => 'test1']);
|
||||
}
|
||||
/*@formatter:on*/
|
||||
public function test1()
|
||||
{
|
||||
$public_path= public_path();
|
||||
$code = new QRcode();
|
||||
var_dump($public_path.'img/mode.png');
|
||||
$code_path = $code->png('二维码携带的参数',$public_path.'uploads/qrcode/11122.png',10)->background(105,100,$public_path.'img/mode.jpg')->text("10.000",20,[250,480],'#000000')->text("TSCBYxKnLbLGPkcjZddWB4b64ymTdpcyY3",15,[140,550],'#000000')->getPath(true);
|
||||
|
||||
var_dump($code_path);
|
||||
|
||||
|
||||
|
||||
return $this->success('返回成功', ['action' => 'test1']);
|
||||
}
|
||||
|
||||
/*@formatter:off*/
|
||||
/**
|
||||
* @ApiTitle (参数传递array的接口)
|
||||
* @ApiSummary (参数传递array的接口详细描述)
|
||||
* @ApiMethod (POST)
|
||||
* @ApiRoute (/api.demo/arrayParam)
|
||||
* @ApiParams (name="id", type="string", required="true", description="ID")
|
||||
* @ApiParams (name="name", type="array", required="true", description="数组中的值")
|
||||
* @ApiParams (name="array[key]", type="array", required="true", description="数组中的值")
|
||||
* @ApiReturnParams (name="code", type="integer", description="接口返回码.0=常规正确码,表示常规操作成功;1=常规错误码,客户端仅需提示msg;其他返回码与具体业务相关。框架实现了的唯一其他返回码:10401,前端需要跳转至登录界面。在一个复杂的交互过程中,你可能需要自行定义其他返回码")
|
||||
* @ApiReturnParams (name="msg", type="string", description="返回描述")
|
||||
* @ApiReturnParams (name="time", type="integer", description="请求时间,Unix时间戳,单位秒")
|
||||
* @ApiReturnParams (name="data", type="object", description="返回的数据对象")
|
||||
* @ApiReturnParams (name="data.action", type="string", description="固定返回test1")
|
||||
* @ApiReturn
|
||||
({
|
||||
"code": 0,
|
||||
"msg": "返回成功",
|
||||
"time": 1591168410,
|
||||
"data": {
|
||||
"action": "test1"
|
||||
}
|
||||
})
|
||||
*/
|
||||
/*@formatter:on*/
|
||||
public function arrayParam()
|
||||
{
|
||||
return $this->success('返回成功', $this->request->param());
|
||||
}
|
||||
}
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\api;
|
||||
|
||||
use laytp\BaseController;
|
||||
|
||||
/**
|
||||
* @ApiInternal ()
|
||||
*/
|
||||
class Index extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return redirect('/api.html');
|
||||
}
|
||||
}
|
||||
Executable
+11
File diff suppressed because one or more lines are too long
Executable
+11
File diff suppressed because one or more lines are too long
Executable
+82
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\api;
|
||||
|
||||
use laytp\controller\Api;
|
||||
use laytp\library\Random;
|
||||
|
||||
/**
|
||||
* @ApiInternal ()
|
||||
*/
|
||||
class Token extends Api
|
||||
{
|
||||
public $no_need_login = [];
|
||||
|
||||
/*@formatter:off*/
|
||||
/**
|
||||
* @ApiTitle (检测Token是否过期)
|
||||
* @ApiSummary (检测Token是否过期)
|
||||
* @ApiMethod (POST)
|
||||
* @ApiRoute (/api.token/check)
|
||||
* @ApiHeaders (name="token", type="string", required="true", description="用户登录后得到的Token")
|
||||
* @ApiReturnParams (name="code", type="integer", description="接口返回码.0=常规正确码,表示常规操作成功;1=常规错误码,客户端仅需提示msg;其他返回码与具体业务相关。框架实现了的唯一其他返回码:10401,前端需要跳转至登录界面。在一个复杂的交互过程中,你可能需要自行定义其他返回码")
|
||||
* @ApiReturnParams (name="msg", type="string", description="返回描述")
|
||||
* @ApiReturnParams (name="time", type="integer", description="请求时间,Unix时间戳,单位秒")
|
||||
* @ApiReturnParams (name="data", type="object", description="返回的数据对象")
|
||||
* @ApiReturnParams (name="data.token", type="string", description="用户登录凭证,token")
|
||||
* @ApiReturnParams (name="data.expires_in", type="integer", description="token有效时间,单位秒")
|
||||
* @ApiReturn
|
||||
({
|
||||
"code": 0,
|
||||
"msg": "Token有效",
|
||||
"time": 1591167181,
|
||||
"data": {
|
||||
"token": "827fb87e-2064-45c8-839a-128e195a7411",
|
||||
"expires_in": 1789
|
||||
}
|
||||
})
|
||||
*/
|
||||
/*@formatter:on*/
|
||||
public function check()
|
||||
{
|
||||
$token = $this->service_user->getToken();
|
||||
$tokenInfo = \library\Token::get($token);
|
||||
$this->success('Token有效', ['token' => $tokenInfo['token'], 'expires_in' => $tokenInfo['expires_in']]);
|
||||
}
|
||||
|
||||
/*@formatter:off*/
|
||||
/**
|
||||
* @ApiTitle (刷新Token)
|
||||
* @ApiSummary (刷新Token)
|
||||
* @ApiMethod (POST)
|
||||
* @ApiRoute (/api.token/refresh)
|
||||
* @ApiHeaders (name="token", type="string", required="true", description="用户登录后得到的Token")
|
||||
* @ApiReturnParams (name="code", type="integer", description="接口返回码.0=常规正确码,表示常规操作成功;1=常规错误码,客户端仅需提示msg;其他返回码与具体业务相关。框架实现了的唯一其他返回码:10401,前端需要跳转至登录界面。在一个复杂的交互过程中,你可能需要自行定义其他返回码")
|
||||
* @ApiReturnParams (name="msg", type="string", description="返回描述")
|
||||
* @ApiReturnParams (name="time", type="integer", description="请求时间,Unix时间戳,单位秒")
|
||||
* @ApiReturnParams (name="data", type="object", description="返回的数据对象")
|
||||
* @ApiReturnParams (name="data.token", type="string", description="用户登录凭证,token")
|
||||
* @ApiReturnParams (name="data.expires_in", type="integer", description="token有效时间,单位秒")
|
||||
* @ApiReturn
|
||||
({
|
||||
"code": 0,
|
||||
"msg": "成功刷新Token",
|
||||
"time": 1591167423,
|
||||
"data": {
|
||||
"token": "e356df60-ff03-4f15-bb66-c0e3ef37f335",
|
||||
"expires_in": 1800
|
||||
}
|
||||
})
|
||||
*/
|
||||
/*@formatter:on*/
|
||||
public function refresh()
|
||||
{
|
||||
//删除源Token
|
||||
$token = $this->service_user->getToken();
|
||||
\library\Token::delete($token);
|
||||
//创建新Token
|
||||
$token = Random::uuid();
|
||||
\library\Token::set($token, $this->service_user->id, $this->service_user->token_keep_time);
|
||||
$this->success('成功刷新Token', ['token' => $token, 'expires_in' => $this->service_user->token_keep_time]);
|
||||
}
|
||||
}
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace app\exception;
|
||||
|
||||
use app\model\api\Log;
|
||||
use think\exception\Handle;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 异常处理接管
|
||||
* 解决的问题:
|
||||
* 1.记录数据库日志
|
||||
* 2.windows环境下,出现异常时,页面输出空白的问题
|
||||
* Class Http
|
||||
* @package app\exception
|
||||
*/
|
||||
class Http extends Handle
|
||||
{
|
||||
/**
|
||||
* 不需要记录信息(日志)的异常类列表
|
||||
* 定义为空,说明是所有异常全部都记录
|
||||
* @var array
|
||||
*/
|
||||
protected $ignoreReport = [];
|
||||
|
||||
/**
|
||||
* 记录异常信息(包括日志或者其它方式记录)
|
||||
*
|
||||
* @access public
|
||||
* @param Throwable $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $exception): void
|
||||
{
|
||||
// 非命令行下,记录错误日志
|
||||
if(PHP_SAPI !== 'cli') {
|
||||
$request = request();
|
||||
// 记录数据库日志
|
||||
// 这里必须要try,不然,如果报数据库错误,系统会循环调用异常接管程序,导致500
|
||||
try{
|
||||
Log::create([
|
||||
'rule' => $request->url(),
|
||||
'request_body' => json_encode(request()->post(), JSON_UNESCAPED_UNICODE),
|
||||
'request_header' => json_encode(request()->header(), JSON_UNESCAPED_UNICODE),
|
||||
'ip' => $request->ip(),
|
||||
'status_code' => 500,
|
||||
'response_body' => json_encode($this->convertExceptionToArray($exception), JSON_UNESCAPED_UNICODE),
|
||||
'create_time' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
}catch (\Exception $e){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 使用内置的方式记录异常日志
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集异常数据
|
||||
* 重写父类此方法,将Server/Request Data进行转码,解决windows环境下,出现异常时,页面输出空白的问题
|
||||
* @param Throwable $exception
|
||||
* @return array
|
||||
*/
|
||||
protected function convertExceptionToArray(Throwable $exception): array
|
||||
{
|
||||
$data = parent::convertExceptionToArray($exception);
|
||||
$data['tables']['Server/Request Data'] = $this->changeToUtf8($this->app->request->server());
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将获取的服务器信息中的中文编码转为utf-8
|
||||
* 修复在开启debug模式时出现的Malformed UTF-8 characters 错误
|
||||
* @access protected
|
||||
* @param $data array
|
||||
* @return array 转化后的数组
|
||||
*/
|
||||
protected function changeToUtf8(array $data): array
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
$data[$key] = is_array($value)?$this->changeToUtf8($value):mb_convert_encoding($value, "UTF-8", mb_detect_encoding($value));
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
{"code":0,"msg":"请求出现异常","data":{}}
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
// 全局中间件定义文件
|
||||
return [
|
||||
// 全局请求缓存
|
||||
// \think\middleware\CheckRequestCache::class,
|
||||
// 多语言加载
|
||||
// \think\middleware\LoadLangPack::class,
|
||||
// Session初始化
|
||||
\think\middleware\SessionInit::class,
|
||||
\app\middleware\AllowCrossDomain::class,
|
||||
];
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use laytp\BaseMiddleware;
|
||||
use think\Request;
|
||||
|
||||
/**
|
||||
* 允许跨域中间件
|
||||
* Class Auth
|
||||
* @package app\middleware
|
||||
*/
|
||||
class AllowCrossDomain extends BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* 执行中间件
|
||||
* @param Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$header = [
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
|
||||
'Access-Control-Allow-Headers' => '*',
|
||||
];
|
||||
|
||||
return $next($request)->header($header);
|
||||
}
|
||||
}
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* 后台操作日志中间件
|
||||
*/
|
||||
namespace app\middleware\admin;
|
||||
|
||||
use app\model\admin\action\Log;
|
||||
use laytp\BaseMiddleware;
|
||||
use app\model\admin\Menu;
|
||||
use app\service\admin\UserServiceFacade;
|
||||
use think\Request;
|
||||
|
||||
class ActionLog extends BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* 执行中间件
|
||||
* @param Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function handle(Request $request, \Closure $next)
|
||||
{
|
||||
$initUser = UserServiceFacade::init($request->header('laytp-admin-token', $request->cookie('laytpAdminToken')));
|
||||
if (!$initUser || $request->isGet()) return $next($request);
|
||||
|
||||
$requestBody = $request->post();
|
||||
//日志不记录密码
|
||||
if (isset($requestBody['password'])) {
|
||||
$requestBody['password'] = '******';
|
||||
}
|
||||
|
||||
$rule = $request->url();
|
||||
$menu = '';
|
||||
$menus = Menu::where('rule', '=', $rule)->order('pid', 'asc')->select()->toArray();
|
||||
if ($menus) {
|
||||
for ($i = 1; $i <= 4; $i++) {
|
||||
if ($menus[0]['pid']) {
|
||||
$tempMenu = Menu::where('id', '=', $menus[0]['pid'])->find();
|
||||
if ($tempMenu) {
|
||||
$tempMenu = $tempMenu->toArray();
|
||||
array_unshift($menus, $tempMenu);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$menuName = [];
|
||||
foreach ($menus as $v) {
|
||||
$menuName[] = $v['name'];
|
||||
}
|
||||
$menu = implode(' - ', $menuName);
|
||||
}
|
||||
|
||||
Log::create([
|
||||
'admin_id' => UserServiceFacade::getUser()->id,
|
||||
'rule' => $request->url(),
|
||||
'menu' => $menu,
|
||||
'request_body' => json_encode($requestBody, JSON_UNESCAPED_UNICODE),
|
||||
'request_header' => json_encode(request()->header(), JSON_UNESCAPED_UNICODE),
|
||||
'ip' => request()->ip(),
|
||||
'create_time' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace app\middleware\admin;
|
||||
|
||||
use app\service\admin\AuthServiceFacade;
|
||||
use app\service\admin\UserServiceFacade;
|
||||
use laytp\BaseMiddleware;
|
||||
use think\Request;
|
||||
|
||||
class Auth extends BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* 执行中间件
|
||||
* @param Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, \Closure $next)
|
||||
{
|
||||
if (AuthServiceFacade::needLogin()) {
|
||||
// 为了兼容windows和linux获取header中驼峰命名的参数修改
|
||||
// windows中,使用原样获取,比如laytpAdminToken
|
||||
// linux中,驼峰需要转换成短横杆获取,比如laytpAdminToken要使用laytp-admin-token来获取
|
||||
$initUser = UserServiceFacade::init($request->header('laytp-admin-token', $request->header('laytpAdminToken', $request->cookie('laytpAdminToken'))));
|
||||
if (!$initUser) return $this->error(UserServiceFacade::getError(), 10401);
|
||||
if (!UserServiceFacade::isLogin()) {
|
||||
if ($request->isAjax()) {
|
||||
return $this->error('登录信息已过期', 10401);
|
||||
} else {
|
||||
return redirect('/admin/login.html');
|
||||
}
|
||||
}
|
||||
if (AuthServiceFacade::needAuth()) {
|
||||
$user = UserServiceFacade::getUser();
|
||||
if ($user->is_super_manager !== 1) {
|
||||
$userId = $user->id;
|
||||
$plugin = defined('LT_PLUGIN') ? LT_PLUGIN : '';
|
||||
$controller = strtolower(str_replace("\\", ".", $request->controller()));
|
||||
if ($plugin) {
|
||||
$node = 'plugin/' . $plugin . '/' . $controller . '/' . $request->action();
|
||||
} else {
|
||||
$node = trim(app('http')->getName() . '/' . $controller . '/' . $request->action(),'/');
|
||||
}
|
||||
|
||||
if (!AuthServiceFacade::hasAuth($userId, $node)) {
|
||||
return $this->error('无权请求:/' . $node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace app\middleware\api;
|
||||
|
||||
use app\service\api\AuthServiceFacade;
|
||||
use app\service\api\MemberServiceFacade;
|
||||
use laytp\BaseMiddleware;
|
||||
use think\Request;
|
||||
|
||||
class Auth extends BaseMiddleware
|
||||
{
|
||||
/**
|
||||
* 执行中间件
|
||||
* @param Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, \Closure $next)
|
||||
{
|
||||
if (AuthServiceFacade::needLogin()) {
|
||||
$initUser = MemberServiceFacade::init($request->header('token'));
|
||||
if (!$initUser) return $this->error(MemberServiceFacade::getError(), 10401);
|
||||
if (!MemberServiceFacade::isLogin()) {
|
||||
return $this->error('登录信息已过期', 10401);
|
||||
}
|
||||
} else {
|
||||
//不需要登录的接口,也可能需要获取登录用户的信息
|
||||
MemberServiceFacade::init($request->header('token'));
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace app\middleware\api;
|
||||
|
||||
use app\service\api\CheckSignServiceFacade;
|
||||
use app\service\ConfServiceFacade;
|
||||
use laytp\BaseMiddleware;
|
||||
use laytp\traits\JsonReturn;
|
||||
use think\Request;
|
||||
|
||||
/**
|
||||
* 签名验证中间件
|
||||
* 签名生成方式:strtoupper(md5(md5($hearder['request-time']).md5(Config::get('laytp.api.signKey'))))
|
||||
* 签名验证方式:
|
||||
* 请求的header头中需要有两个参数:
|
||||
* - request-time = 当前请求的时间,这个单位并不要求固定,甚至传的都可以不是当前请求的时间,只要sign的值是使用这个参数的值按照规定的算法生成即可
|
||||
* - sign = md5(md5($hearder['request-time']).md5(Config::get('laytp.api.signKey')))
|
||||
* 此中间件,使用header头中request-time按照签名算法生成签名,然后与header中传递的sign参数比对,看是否一致,如果一致就通过验证,如果不一致就验证失败
|
||||
* 需要设计,有些方法无需验签。比如获取配置的接口,需要得到后台配置的Config::get('laytp.api.signKey')
|
||||
* Class CheckSign
|
||||
* @package app\middleware
|
||||
*/
|
||||
class CheckSign extends BaseMiddleware
|
||||
{
|
||||
use JsonReturn;
|
||||
|
||||
/**
|
||||
* 执行中间件
|
||||
* @param Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, \Closure $next)
|
||||
{
|
||||
if (intval(ConfServiceFacade::get('system.basic.checkSign')) === 1) {
|
||||
if (CheckSignServiceFacade::needCheckSign()) {
|
||||
if (CheckSignServiceFacade::check()) {
|
||||
return $next($request);
|
||||
} else {
|
||||
if(env('APP_DEBUG')){
|
||||
return $this->error('签名验证失败',0, [
|
||||
'签名验证的规则描述' => '1. 后台系统配置->基础配置,Api签名开关需要打开,Api签名的Key需要设置(允许为空);2. 客户端在请求Api接口时,需要在header里面传递两个参数,request-time和sign,sign的值要等于strtoupper(md5(md5(header:request-time).md5(conf:signKey)))',
|
||||
'注意点' => '如果是使用的生成Api文档在线测试接口,请点击右上角Api请求配置将签名验证开关打开',
|
||||
'生成签名的规则' => 'strtoupper(md5(md5(header:request-time).md5(conf:signKey)))',
|
||||
'系统配置的生成签名的Key' => ConfServiceFacade::get('system.basic.signKey'),
|
||||
'header部分传递的request-time值' => $request->header('request-time'),
|
||||
'header部分传递的sign值' => $request->header('sign'),
|
||||
'后端计算的sign值' => CheckSignServiceFacade::getError()
|
||||
]);
|
||||
}
|
||||
return $this->error(CheckSignServiceFacade::getError());
|
||||
}
|
||||
} else {
|
||||
return $next($request);
|
||||
}
|
||||
} else {
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* 地区管理模型
|
||||
*/
|
||||
namespace app\model;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Area extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
//模型名
|
||||
protected $name = 'area';
|
||||
|
||||
//附加属性
|
||||
protected $append = [];
|
||||
|
||||
//时间戳字段转换
|
||||
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
public function parent(){
|
||||
return $this->belongsTo('app\model\Area','pid','id');
|
||||
}
|
||||
|
||||
//新增属性的方法
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
|
||||
public function getUpdateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['update_time']) ? strtotime($data['update_time']) : 0;
|
||||
}
|
||||
|
||||
public function getDeleteTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['delete_time']) ? strtotime($data['delete_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* 会员管理模型
|
||||
*/
|
||||
namespace app\model;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Bot extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
//模型名
|
||||
protected $name = 'admin_bot';
|
||||
|
||||
//附加属性
|
||||
protected $append = ['create_time_int','update_time_int','delete_time_int'];
|
||||
|
||||
//时间戳字段转换
|
||||
protected $type = [
|
||||
'create_time_int' => 'timestamp:Y-m-d H:i:s',
|
||||
'update_time_int' => 'timestamp:Y-m-d H:i:s',
|
||||
'delete_time_int' => 'timestamp:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
public function avatarPicFile(){
|
||||
return $this->belongsTo('app\model\Files','avatar_pic','id');
|
||||
}
|
||||
|
||||
//新增属性的方法
|
||||
public function getVipTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['vip_time']) ? $data['vip_time'] : 0;
|
||||
}
|
||||
|
||||
public function getLoginTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['login_time']) ? strtotime($data['login_time']) : 0;
|
||||
}
|
||||
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
|
||||
public function getUpdateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['update_time']) ? strtotime($data['update_time']) : 0;
|
||||
}
|
||||
|
||||
public function getDeleteTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['delete_time']) ? strtotime($data['delete_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* 系统配置模型
|
||||
*/
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use laytp\BaseModel;
|
||||
|
||||
class Conf extends BaseModel
|
||||
{
|
||||
protected $name = 'conf';
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* 附件管理模型
|
||||
*/
|
||||
namespace app\model;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
use laytp\library\UploadDomain;
|
||||
|
||||
class Files extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
//模型名
|
||||
protected $name = 'files';
|
||||
|
||||
//时间戳字段转换
|
||||
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
public function category(){
|
||||
return $this->belongsTo('app\model\files\Category','category_id','id');
|
||||
}
|
||||
|
||||
public function createAdminUser(){
|
||||
return $this->belongsTo('app\model\admin\User','create_admin_user_id','id');
|
||||
}
|
||||
|
||||
public function updateAdminUser(){
|
||||
return $this->belongsTo('app\model\admin\User','update_admin_user_id','id');
|
||||
}
|
||||
|
||||
//新增属性的方法
|
||||
public function getPathAttr($value, $data)
|
||||
{
|
||||
return $value ? UploadDomain::singleAddUploadDomain($data) : '';
|
||||
}
|
||||
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
|
||||
public function getUpdateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['update_time']) ? strtotime($data['update_time']) : 0;
|
||||
}
|
||||
|
||||
public function getDeleteTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['delete_time']) ? strtotime($data['delete_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* 会员管理模型
|
||||
*/
|
||||
namespace app\model;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Member extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
//模型名
|
||||
protected $name = 'member';
|
||||
|
||||
//附加属性
|
||||
protected $append = ['vip_time_int','login_time_int','create_time_int','update_time_int','delete_time_int'];
|
||||
|
||||
//时间戳字段转换
|
||||
protected $type = [
|
||||
'vip_time' => 'timestamp:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
public function avatarPicFile(){
|
||||
return $this->belongsTo('app\model\Files','avatar_pic','id');
|
||||
}
|
||||
|
||||
//新增属性的方法
|
||||
public function getVipTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['vip_time']) ? $data['vip_time'] : 0;
|
||||
}
|
||||
|
||||
public function getLoginTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['login_time']) ? strtotime($data['login_time']) : 0;
|
||||
}
|
||||
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
|
||||
public function getUpdateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['update_time']) ? strtotime($data['update_time']) : 0;
|
||||
}
|
||||
|
||||
public function getDeleteTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['delete_time']) ? strtotime($data['delete_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* 数据库迁移模型
|
||||
*/
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use laytp\BaseModel;
|
||||
|
||||
class Migrations extends BaseModel
|
||||
{
|
||||
protected $name = 'migrations';
|
||||
}
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* 会员管理模型
|
||||
*/
|
||||
namespace app\model;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Order extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
//模型名
|
||||
protected $name = 'order';
|
||||
|
||||
//附加属性
|
||||
protected $append = ['create_time','end_time'];
|
||||
|
||||
//时间戳字段转换
|
||||
protected $type = [
|
||||
'end_time' => 'timestamp:Y-m-d H:i:s',
|
||||
'create_time' => 'timestamp:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
//表名
|
||||
//关联模型
|
||||
public function avatarPicFile(){
|
||||
return $this->belongsTo('app\model\Files','avatar_pic','id');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Log;
|
||||
|
||||
|
||||
class TronSdk
|
||||
{
|
||||
|
||||
private $domain;
|
||||
private $username;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->domain = "http://tron.konline.top:888/";
|
||||
$this->username= "kaihekaiyuan";
|
||||
$this->token= "a782a1f489d32687fd9f67f42f35e9e1";
|
||||
}
|
||||
//setwebhook
|
||||
public function setwebhook2($webhookurl, $trcadd){
|
||||
$func= $this->domain."custom/webhook";
|
||||
// $webhookurl='http://' . env('proxyDomain', 'false') . '/customer/PayApi/pay?type='.$mode;
|
||||
$data=['username'=>$this->username,'address'=>$trcadd,"url"=>$webhookurl];
|
||||
$sing= md5($this->username.$trcadd.$webhookurl.$this->token);
|
||||
$data['sign']=$sing;
|
||||
return json_decode(curl_post($func,http_build_query($data)),true);
|
||||
}
|
||||
public function setwebhook($mode, $trcadd) //模块 订阅地址
|
||||
{ $func= $this->domain."custom/webhook";
|
||||
$webhookurl='http://' . env('proxyDomain', 'false') . '/customer/PayApi/pay?type='.$mode;
|
||||
$data=['username'=>$this->username,'address'=>$trcadd,"url"=>$webhookurl];
|
||||
$sing= md5($this->username.$trcadd.$webhookurl.$this->token);
|
||||
$data['sign']=$sing;
|
||||
return json_decode(curl_post($func,http_build_query($data)),true);
|
||||
|
||||
}
|
||||
//delete_webhook
|
||||
public function delete_webhook($address){ //删除订阅
|
||||
$func= $this->domain."custom/delete_webhook";
|
||||
|
||||
$data=['username'=>$this->username,'address'=>$address];
|
||||
$sing= md5($this->username.$address.$this->token);
|
||||
$data['sign']=$sing;
|
||||
return json_decode(curl_post($func,http_build_query($data)),true);
|
||||
}
|
||||
public function up_webhook($address,$weburl){ //更新订阅
|
||||
$func= $this->domain."custom/up_webhook";
|
||||
|
||||
$data=['username'=>$this->username,'url'=>$weburl,'address'=>$address];
|
||||
$sing= md5($this->username.$address.$weburl.$this->token);
|
||||
$data['sign']=$sing;
|
||||
return json_decode(curl_post($func,http_build_query($data)),true);
|
||||
}
|
||||
|
||||
public function queryhook($address,$cache=null) //查询订阅
|
||||
{ $func= $this->domain."custom/query";
|
||||
|
||||
$data=['username'=>$this->username,'address'=>$address];
|
||||
$sing= md5($this->username.$address.$this->token);
|
||||
$data['sign']=$sing;
|
||||
if(empty($cache)){
|
||||
$cache= cache::get("custom/query".$address);
|
||||
if(!empty($cache)){
|
||||
// var_dump("99999");
|
||||
return $cache;
|
||||
}else{
|
||||
$cache=json_decode(curl_post($func,http_build_query($data)),true);
|
||||
cache::set("custom/query".$address,$cache,1600);
|
||||
return $cache;
|
||||
}
|
||||
}else{
|
||||
$cache=json_decode(curl_post($func,http_build_query($data)),true);
|
||||
cache::set("custom/query".$address,$cache,1600);
|
||||
return $cache;
|
||||
}
|
||||
|
||||
}
|
||||
//查询地址是否合规
|
||||
public function checkaddress($address){
|
||||
$url="https://apilist.tronscanapi.com/api/multiple/chain/query?address=".$address;//
|
||||
$data=json_decode(curl_get($url),true);
|
||||
$publicTag=isset($data['publicTag'])?$data['publicTag']:"";
|
||||
//var_dump($data);
|
||||
if(empty($publicTag)){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* 会员管理模型
|
||||
*/
|
||||
namespace app\model;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class User extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
//模型名
|
||||
protected $name = 'user';
|
||||
|
||||
//附加属性
|
||||
protected $append = ['create_time','update_time','delete_time','vip_time','login_time'];
|
||||
|
||||
//时间戳字段转换
|
||||
protected $type = [
|
||||
// 'create_time' => 'timestamp:Y-m-d H:i:s',
|
||||
// 'update_time' => 'timestamp:Y-m-d H:i:s',
|
||||
// 'delete_time' => 'timestamp:Y-m-d H:i:s',
|
||||
// 'vip_time' => 'timestamp:Y-m-d H:i:s',
|
||||
// 'login_time' => 'timestamp:Y-m-d H:i:s',
|
||||
|
||||
];
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
public function avatarPicFile(){
|
||||
return $this->belongsTo('app\model\Files','avatar_pic','id');
|
||||
}
|
||||
|
||||
//新增属性的方法
|
||||
public function getVipTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['vip_time']) ? $data['vip_time'] : 0;
|
||||
}
|
||||
|
||||
public function getLoginTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['login_time']) ? strtotime($data['login_time']) : 0;
|
||||
}
|
||||
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
|
||||
public function getUpdateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['update_time']) ? strtotime($data['update_time']) : 0;
|
||||
}
|
||||
|
||||
public function getDeleteTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['delete_time']) ? strtotime($data['delete_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* 后台菜单模型
|
||||
*/
|
||||
|
||||
namespace app\model\admin;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Menu extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
protected $name = 'admin_menu';
|
||||
|
||||
protected $append = [];
|
||||
}
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* 角色模型
|
||||
*/
|
||||
|
||||
namespace app\model\admin;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Role extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
protected $name = 'admin_role';
|
||||
}
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* 后台管理员表模型
|
||||
*/
|
||||
|
||||
namespace app\model\admin;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use laytp\library\UploadDomain;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class User extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
//模型名
|
||||
protected $name = 'admin_user';
|
||||
|
||||
//数组常量
|
||||
public $const = [
|
||||
'is_super_manager' => [
|
||||
'2' => '否'
|
||||
, '1' => '是',
|
||||
],
|
||||
'status' => [
|
||||
'2' => '禁用'
|
||||
, '1' => '正常',
|
||||
],
|
||||
];
|
||||
|
||||
public function avatarFile(){
|
||||
return $this->belongsTo('app\model\Files','avatar','id');
|
||||
}
|
||||
|
||||
// 定义默认头像
|
||||
public function getAvatarFileAttr($value){
|
||||
if(!$value){
|
||||
return [
|
||||
'id' => "",
|
||||
'filename' => '默认头像',
|
||||
'path' => UploadDomain::getDefaultAvatar(),
|
||||
];
|
||||
}else{
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function roleIds()
|
||||
{
|
||||
return $this->hasMany(\app\model\admin\role\User::class, 'admin_user_id');
|
||||
}
|
||||
}
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* 后台操作日志模型
|
||||
*/
|
||||
namespace app\model\admin\action;
|
||||
|
||||
use laytp\BaseModel;
|
||||
|
||||
class Log extends BaseModel
|
||||
{
|
||||
|
||||
//模型名
|
||||
protected $name = 'admin_action_log';
|
||||
|
||||
//附加属性
|
||||
protected $append = [];
|
||||
|
||||
//时间戳字段转换
|
||||
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
public function adminUser(){
|
||||
return $this->belongsTo('app\model\admin\User','admin_id','id');
|
||||
}
|
||||
|
||||
//新增属性的方法
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* Api请求日志模型
|
||||
*/
|
||||
namespace app\model\admin\balance;
|
||||
|
||||
use laytp\BaseModel;
|
||||
|
||||
class Log extends BaseModel
|
||||
{
|
||||
|
||||
//模型名
|
||||
protected $name = 'balance';
|
||||
|
||||
//附加属性
|
||||
protected $append = [];
|
||||
|
||||
//时间戳字段转换
|
||||
protected $type = [
|
||||
'time' => 'timestamp:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
|
||||
|
||||
//新增属性的方法
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* 后台登录日志模型
|
||||
*/
|
||||
namespace app\model\admin\login;
|
||||
|
||||
use laytp\BaseModel;
|
||||
|
||||
class Log extends BaseModel
|
||||
{
|
||||
|
||||
//模型名
|
||||
protected $name = 'admin_login_log';
|
||||
|
||||
//附加属性
|
||||
protected $append = [];
|
||||
|
||||
//时间戳字段转换
|
||||
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
public function adminUser(){
|
||||
return $this->belongsTo('app\model\admin\User','admin_id','id');
|
||||
}
|
||||
|
||||
//新增属性的方法
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* 菜单与角色关系模型
|
||||
*/
|
||||
|
||||
namespace app\model\admin\menu;
|
||||
|
||||
use think\model\Pivot;
|
||||
|
||||
class Role extends Pivot
|
||||
{
|
||||
protected $name = 'admin_menu_role';
|
||||
}
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* 角色与用户关系
|
||||
*/
|
||||
|
||||
namespace app\model\admin\role;
|
||||
|
||||
use think\model\Pivot;
|
||||
|
||||
class User extends Pivot
|
||||
{
|
||||
protected $name = 'admin_role_user';
|
||||
|
||||
}
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Api请求日志模型
|
||||
*/
|
||||
namespace app\model\api;
|
||||
|
||||
use laytp\BaseModel;
|
||||
|
||||
class Log extends BaseModel
|
||||
{
|
||||
|
||||
//模型名
|
||||
protected $name = 'api_log';
|
||||
|
||||
//附加属性
|
||||
protected $append = [];
|
||||
|
||||
//时间戳字段转换
|
||||
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
|
||||
|
||||
//新增属性的方法
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* 附件分类管理模型
|
||||
*/
|
||||
namespace app\model\files;
|
||||
|
||||
use laytp\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Category extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
//模型名
|
||||
protected $name = 'files_category';
|
||||
|
||||
//时间戳字段转换
|
||||
|
||||
|
||||
//表名
|
||||
|
||||
|
||||
//关联模型
|
||||
public function parent(){
|
||||
return $this->belongsTo('app\model\files\Category','pid','id');
|
||||
}
|
||||
|
||||
//新增属性的方法
|
||||
public function getCreateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['create_time']) ? strtotime($data['create_time']) : 0;
|
||||
}
|
||||
|
||||
public function getUpdateTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['update_time']) ? strtotime($data['update_time']) : 0;
|
||||
}
|
||||
|
||||
public function getDeleteTimeIntAttr($value, $data)
|
||||
{
|
||||
return isset($data['delete_time']) ? strtotime($data['delete_time']) : 0;
|
||||
}
|
||||
}
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
use app\exception\Http;
|
||||
|
||||
// 容器Provider定义文件
|
||||
return [
|
||||
'think\exception\Handle' => Http::class,
|
||||
];
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace app\resource\admin;
|
||||
|
||||
use laytp\Resource;
|
||||
|
||||
/**
|
||||
* 用户资源
|
||||
*/
|
||||
class User extends Resource
|
||||
{
|
||||
/**
|
||||
* 用户首页列表需要将关联模型取到的role_ids转换成以逗号分隔的字符串
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
static public function info($data)
|
||||
{
|
||||
$roleIdsArr = [];
|
||||
if($data){
|
||||
foreach ($data['role_ids'] as $k => $v) {
|
||||
$roleIdsArr[] = $v['admin_role_id'];
|
||||
}
|
||||
$data['role_ids'] = implode(',', $roleIdsArr);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
Executable
+215
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace app\service;
|
||||
|
||||
use laytp\library\UploadDomain;
|
||||
use laytp\traits\Error;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 系统配置服务器实现者
|
||||
* Class Auth
|
||||
* @package app\service
|
||||
*/
|
||||
class Conf
|
||||
{
|
||||
use Error;
|
||||
|
||||
// 是否使用redis,如果不想使用redis,修改此处为false即可
|
||||
protected $useRedis = true;
|
||||
|
||||
// 数据库连接句柄
|
||||
protected $db = null;
|
||||
|
||||
//判断是否配置了redis
|
||||
protected function hasRedis(){
|
||||
$redisConf = Config::get('cache');
|
||||
if(isset($redisConf['stores']['redis']['type']) && $this->useRedis){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过一个完整的key,获取配置信息
|
||||
* @param $wholeKey
|
||||
* @param $defaultValue
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
public function get($wholeKey, $defaultValue='')
|
||||
{
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
if($redis){
|
||||
$value = $redis->hget($wholeKey, 'value');
|
||||
$formType = $redis->hget($wholeKey, 'form_type');
|
||||
if($formType == 'array') return json_decode($value, JSON_UNESCAPED_UNICODE);
|
||||
return $value ? $value : $defaultValue;
|
||||
}
|
||||
}
|
||||
list($group, $key) = $this->getGroupKey($wholeKey);
|
||||
$conf = \app\model\Conf::where(['group'=>$group, 'key'=>$key])->findOrEmpty()->toArray();
|
||||
if($conf){
|
||||
$value = $conf['value'];
|
||||
$formType = $conf['form_type'];
|
||||
if($formType == 'array') return json_decode($value, JSON_UNESCAPED_UNICODE);
|
||||
if($formType == 'upload'){
|
||||
$fileInfo = UploadDomain::multiJoin($value);
|
||||
$return[$key] = $value;
|
||||
if($fileInfo){
|
||||
$return[$key.'_path'] = $fileInfo['path'];
|
||||
$return[$key.'_filename'] = $fileInfo['filename'];
|
||||
}else{
|
||||
$return[$key.'_path'] = '';
|
||||
$return[$key.'_filename'] = '';
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
return $value ? $value : $defaultValue;
|
||||
}else{
|
||||
return $defaultValue ? $defaultValue : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过一个完整的key,设置配置信息
|
||||
* @param $wholeKey
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function set($wholeKey, $value)
|
||||
{
|
||||
if(is_array($value)){
|
||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
list($group, $key) = $this->getGroupKey($wholeKey);
|
||||
$id = \app\model\Conf::where(['group'=>$group, 'key'=>$key])->value('id');
|
||||
if($id){
|
||||
\app\model\Conf::where('id', '=', $id)->save(['group' => $group, 'key' => $key]);
|
||||
}else{
|
||||
\app\model\Conf::insert(['group' => $group, 'key' => $key, 'value' => $value]);
|
||||
}
|
||||
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$redis->set($wholeKey, $value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function del($group, $key)
|
||||
{
|
||||
\app\model\Conf::where(['group' => $group, 'key' => $key])->delete();
|
||||
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$redis->del($group . $key);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过数组,设置配置信息
|
||||
* @param $array
|
||||
* @return bool
|
||||
*/
|
||||
public function groupSet($array)
|
||||
{
|
||||
foreach($array as $item){
|
||||
$item['value'] = is_array($item['value']) ? json_encode($item['value'], JSON_UNESCAPED_UNICODE) : $item['value'];
|
||||
$id = \app\model\Conf::where(['group'=>$item['group'], 'key'=>$item['key']])->value('id');
|
||||
if($id){
|
||||
\app\model\Conf::where('id', '=', $id)->save($item);
|
||||
}else{
|
||||
\app\model\Conf::create($item);
|
||||
}
|
||||
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$hashKey = $item['group'] . '.' . $item['key'];
|
||||
$redis->hset($hashKey, 'group', $item['group']);
|
||||
$redis->hset($hashKey, 'key', $item['key']);
|
||||
$redis->hset($hashKey, 'value', $item['value']);
|
||||
$redis->hset($hashKey, 'form_type', $item['form_type']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过配置分组名称,获取整个分组的信息
|
||||
* @param $group
|
||||
* @param $onlyMysql boolean 是否仅从数据库取配置
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function groupGet($group, $onlyMysql=false)
|
||||
{
|
||||
$return = [];
|
||||
$items = [];
|
||||
|
||||
if(!$onlyMysql){
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$keys = $redis->keys($group.'*');
|
||||
foreach($keys as $key){
|
||||
$items[$key] = $redis->hGetAll($key);
|
||||
}
|
||||
if(!$items){
|
||||
$items = \app\model\Conf::where(['group'=>$group])->select()->toArray();
|
||||
}
|
||||
}else{
|
||||
$items = \app\model\Conf::where(['group'=>$group])->select()->toArray();
|
||||
}
|
||||
}else{
|
||||
$items = \app\model\Conf::where(['group'=>$group])->select()->toArray();
|
||||
}
|
||||
|
||||
foreach ($items as $k => $v) {
|
||||
if ($v['form_type'] === 'array') {
|
||||
$array = json_decode($v['value'], true);
|
||||
if(!$array){
|
||||
$return[$v['key']] = [""=>""];
|
||||
}else{
|
||||
$return[$v['key']] =$array;
|
||||
}
|
||||
} elseif($v['form_type'] === 'upload') {
|
||||
$fileInfo = UploadDomain::multiJoin($v['value']);
|
||||
if($fileInfo){
|
||||
$return[$v['key']] = $fileInfo['id'];
|
||||
$return[$v['key'].'_path'] = $fileInfo['path'];
|
||||
$return[$v['key'].'_filename'] = $fileInfo['filename'];
|
||||
}else{
|
||||
$return[$v['key']] = '';
|
||||
$return[$v['key'].'_path'] = '';
|
||||
$return[$v['key'].'_filename'] = '';
|
||||
}
|
||||
} else {
|
||||
$return[$v['key']] = $v['value'];
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过完整的key,获取到分组名称和key值
|
||||
* @param $wholeKey
|
||||
* @return array|boolean
|
||||
*/
|
||||
protected function getGroupKey($wholeKey)
|
||||
{
|
||||
$arr = explode('.', $wholeKey);
|
||||
if(!$arr || count($arr) == 1){
|
||||
$this->setError('请输入一个完整的key,一个完整的key必须包含至少一个.号');
|
||||
return false;
|
||||
}
|
||||
$key = $arr[count($arr) - 1];
|
||||
$group = substr($wholeKey, 0 , strrpos($wholeKey, '.'));
|
||||
return [$group, $key];
|
||||
}
|
||||
}
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\service;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 系统配置服务门面
|
||||
* @package app\service
|
||||
* @method static mixed get($wholeKey, $defaultValue='') 通过完整的key获取配置信息
|
||||
* @method static mixed set($wholeKey, $value) 通过完整的key设置一个配置信息
|
||||
* @method static mixed del($group, $key) 删除某个分组下某个key的配置
|
||||
* @method static mixed groupGet($group, $onlyMysql=false) 通过分组名称,获取整个分组的配置信息
|
||||
* @method static mixed groupSet($array) 通过hash数组,设置整个分组的配置信息
|
||||
*/
|
||||
class ConfServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Conf::class;
|
||||
}
|
||||
}
|
||||
Executable
+586
@@ -0,0 +1,586 @@
|
||||
<?php
|
||||
|
||||
namespace app\service;
|
||||
|
||||
class Telegram
|
||||
{
|
||||
private $ret;
|
||||
private $token;
|
||||
private static $inlineResults = array();
|
||||
|
||||
public function __construct($token = NULL)
|
||||
{
|
||||
$this->token = $token;
|
||||
// parent::__construct();
|
||||
}
|
||||
/**
|
||||
* http_build_query兼容多维数组,返回结果数组仍支持http_build_query函数处理
|
||||
* @author Zjmainstay https://bugs.php.net/bug.php?id=67477
|
||||
* @param $data array curl传递参数的数组(原装)
|
||||
* @return array 可curl传递的格式化数组
|
||||
*/
|
||||
function http_build_query_develop($data)
|
||||
{
|
||||
if (!is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
$data = array_merge($data, http_build_query_develop(array("{$key}[{$k}]" => $v)));
|
||||
} else {
|
||||
$data["{$key}[{$k}]"] = $v;
|
||||
}
|
||||
}
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
private function fetch($url, $postdata = null)
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
if (!is_null($postdata)) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->http_build_query_develop($postdata));
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$re = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
return $re;
|
||||
}
|
||||
public function callMethod($method, $param = array(), $detection = true)
|
||||
{
|
||||
/** 访问网页 */
|
||||
$url = 'https://api.telegram.org/bot' . $this->token . '/' . $method;
|
||||
$ret = json_decode($this->fetch($url, $param), true);
|
||||
|
||||
/** 分析结果 */
|
||||
if ($ret['ok'] == false && $detection == true) {
|
||||
if ($ret['error_code'] != 400 && $ret['error_code'] != 403) {
|
||||
$errorModel = new ErrorModel;
|
||||
$errorModel->sendError(MASTER, '尝试调用 ' . $method . " 时出现问题,参数表如下:\n" . print_r($param, true) . "\n\n返回结果:\n" . print_r($ret, true));
|
||||
}
|
||||
}
|
||||
|
||||
/** 返回 */
|
||||
return $ret;
|
||||
}
|
||||
public function getWebhook()
|
||||
{
|
||||
$this->ret = $this->callMethod('getWebhookInfo', [], false);
|
||||
return $this->ret;
|
||||
}
|
||||
public function setWebhook($newurl)
|
||||
{
|
||||
$this->ret = $this->callMethod('setWebhook', [
|
||||
'url' => $newurl
|
||||
], false);
|
||||
return $this->ret;
|
||||
}
|
||||
public function sendMessage($chat_id, $text, $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML', $disable_web_page_preview = false, $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
foreach (str_split($text, 4096) as $text_i => $text_d) {
|
||||
$tmp = $this->callMethod('sendMessage', [
|
||||
'chat_id' => $chat_id,
|
||||
|
||||
'text' => $text_d,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_markup' => $reply_markup,
|
||||
'disable_web_page_preview' => $disable_web_page_preview,
|
||||
'disable_notification' => $disable_notification
|
||||
]);
|
||||
if ($text_i == 0) $this->ret = $tmp;
|
||||
}
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function editMessage($chat_id, $message_id, $text, $reply_markup = array(), $parse_mode = 'HTML')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageText', [
|
||||
'chat_id' => $chat_id,
|
||||
'message_id' => $message_id,
|
||||
'text' => $text,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_markup' => $reply_markup
|
||||
]);
|
||||
return isset($this->ret['result']['message_id'])?$this->ret['result']['message_id']:0;
|
||||
}
|
||||
public function deleteMessage($chat_id, $message_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('deleteMessage', get_defined_vars());
|
||||
return $this->ret;
|
||||
}
|
||||
public function kickMember($chat_id, $user_id, $until_date = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('kickChatMember', [
|
||||
'chat_id' => $chat_id,
|
||||
'user_id' => $user_id,
|
||||
'until_date' => $until_date
|
||||
]);
|
||||
return $this->ret;
|
||||
}
|
||||
|
||||
//键盘按钮 KeyboardButton $chat_id sender_chat_id
|
||||
public function KeyboardButton($chat_id, $text, $Keyboard = array(), $message_id = null, $message_thread_id = null)
|
||||
{
|
||||
return $this->sendthreadMessage($chat_id, $text, $message_id, $message_thread_id, $Keyboard);
|
||||
}
|
||||
|
||||
|
||||
public function sendthreadMessage($chat_id, $text, $reply_to_message_id = NULL, $message_thread_id = NULL, $reply_markup = array(), $parse_mode = 'HTML', $disable_web_page_preview = false, $disable_notification = false)
|
||||
{
|
||||
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
foreach (str_split($text, 4096) as $text_i => $text_d) {
|
||||
$tmp = $this->callMethod('sendMessage', [
|
||||
'chat_id' => $chat_id,
|
||||
'text' => $text_d,
|
||||
'message_thread_id' => $message_thread_id,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_markup' => $reply_markup,
|
||||
'disable_web_page_preview' => $disable_web_page_preview,
|
||||
'disable_notification' => $disable_notification
|
||||
]);
|
||||
if ($text_i == 0) $this->ret = $tmp;
|
||||
}
|
||||
|
||||
if ($this->ret['ok'] == false) {
|
||||
|
||||
if ($this->ret['description'] == "Bad Request: BUTTON_URL_INVALID") {
|
||||
//按钮设置错误导致异常
|
||||
$txt = $text . "\r\n" . "\r\n" . "由于按钮信息设置错误,异常,您可以点击按钮参考设置规则";
|
||||
$button = json_encode(array(
|
||||
'inline_keyboard' => array(
|
||||
array(array(
|
||||
'text' => '参考按钮设置',
|
||||
'callback_data' => 'xinshouxiuefrb '
|
||||
))
|
||||
|
||||
|
||||
)
|
||||
));
|
||||
$this->sendMessage($chat_id, $txt, null, $button, 'Markdown', true);
|
||||
}
|
||||
//按钮设置问题导致报错
|
||||
if (strpos($this->ret['description'], "keyboard button")) {
|
||||
//按钮设置错误导致异常
|
||||
$txt = $text . "\r\n" . "\r\n" . "由于按钮信息设置错误,异常,您可以点击按钮参考设置规则";
|
||||
$button = json_encode(array(
|
||||
'inline_keyboard' => array(
|
||||
array(array(
|
||||
'text' => '参考按钮设置',
|
||||
'callback_data' => 'xinshouxiuefrb '
|
||||
))
|
||||
|
||||
|
||||
)
|
||||
));
|
||||
$this->sendMessage($chat_id, $txt, null, $button, 'Markdown', true);
|
||||
} elseif (strpos($this->ret['description'], "Bad Request: have no rights to send a message")) {
|
||||
|
||||
$cuwucishu = Cache::get("cuwusishuo" . $chat_id);
|
||||
if ($cuwucishu > 100) {
|
||||
// $this->db->update('group', ['switch' => 0, 'botid' => $this->botid], ['group' => $chat_id]);
|
||||
|
||||
|
||||
Db::name("group")->where(['group' => $chat_id, 'botid' => $this->botid])->update(['switch' => 0]);
|
||||
|
||||
|
||||
$this->getgroupinfo($chat_id, $this->tokenbase, 1);
|
||||
} else {
|
||||
Cache::set("cuwusishuo" . $chat_id, $cuwucishu + 1, 36000);
|
||||
}
|
||||
} else {
|
||||
$txt = "本次请求出错了,错误日志如下" . "\r\n" . "检查下设置的地址是否正确或者是存在多余的空格" . "\r\n" . $this->ret['description'] . "\r\n" . "\r\n" . "实在解决不了 反馈 @kaihebug";
|
||||
if ($text == "查看群规") {
|
||||
$this->sendMessage($chat_id, $txt);
|
||||
}
|
||||
|
||||
// file_put_contents("tgsendmassttttt.txt", json_encode($this->ret).$text.$reply_markup.$chat_id.$parse_mode."\r\n", FILE_APPEND);
|
||||
|
||||
|
||||
|
||||
}
|
||||
if (isset($this->ret['parameters']['retry_after'])) {
|
||||
$retry_after = $this->ret['parameters']['retry_after'];
|
||||
Cache::set("retry_after" . $chat_id, 1, $retry_after);
|
||||
}
|
||||
}
|
||||
//下面还可以添加规则
|
||||
if (isset($this->ret['result']['message_id'])) {
|
||||
return $this->ret['result']['message_id'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
//return $this->ret['result']['message_id'];
|
||||
}
|
||||
//强制回复 forcereply
|
||||
public function forcereply($chat_id, $text, $message_id = null, $message_thread_id = null)
|
||||
{
|
||||
$buttonsc = json_encode(
|
||||
array(
|
||||
'force_reply' => true,
|
||||
'input_field_placeholder' => $text,
|
||||
'selective' => true,
|
||||
)
|
||||
);
|
||||
return $this->sendthreadMessage($chat_id, $text, $message_id, $message_thread_id, $buttonsc);
|
||||
}
|
||||
|
||||
public function sendPhoto($chat_id, $photo, $caption = '', $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML')
|
||||
{
|
||||
if (is_array($photo)) {
|
||||
return $this->sendMediaGroup($chat_id, array_map(function ($p) use ($caption, $parse_mode) {
|
||||
return [
|
||||
'type' => 'photo',
|
||||
'media' => $p,
|
||||
'caption' => $caption,
|
||||
'parse_mode' => $parse_mode
|
||||
];
|
||||
}, $photo), $reply_to_message_id);
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendPhoto', [
|
||||
'chat_id' => $chat_id,
|
||||
'photo' => $photo,
|
||||
'caption' => $caption,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'reply_markup' => $reply_markup
|
||||
]);
|
||||
return isset($this->ret['result']['message_id'])?$this->ret['result']['message_id']:0;;
|
||||
}
|
||||
public function sendDocumentphoto($chat_id, $document, $caption = '', $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML')
|
||||
{
|
||||
|
||||
$url = 'https://api.telegram.org/bot' . $this->token . '/sendPhoto';
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
|
||||
$finfo = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $document);
|
||||
$cFile = new \CURLFile($document, $finfo);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->http_build_query_develop([
|
||||
'chat_id' => $chat_id,
|
||||
'photo' => $cFile,
|
||||
'caption' => $caption,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'reply_markup' => $reply_markup
|
||||
]));
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$this->ret = json_decode($result, 1);
|
||||
$message_id=isset($this->ret['result']['message_id'])?$this->ret['result']['message_id']:"";
|
||||
if(!empty($message_id)){
|
||||
unlink($document);
|
||||
}
|
||||
//var_dump($this->ret);
|
||||
return $message_id;
|
||||
}
|
||||
public function sendMediaGroup($chat_id, $media, $reply_to_message_id = NULL)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendMediaGroup', [
|
||||
'chat_id' => $chat_id,
|
||||
'media' => json_encode($media),
|
||||
'reply_to_message_id' => $reply_to_message_id
|
||||
]);
|
||||
return array_map(function ($m) {
|
||||
return $m['message_id'];
|
||||
}, $this->ret['result']);
|
||||
}
|
||||
public function sendAudio($chat_id, $audio, $caption = '', $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML', $duration = '', $performer = NULL, $title = NULL, $thumb = '', $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendAudio', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendDocument($chat_id, $document, $caption = '', $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML', $thumb = '', $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendDocument', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendVideo($chat_id, $video, $duration = '', $width = '', $height = '', $thumb = '', $caption = NULL, $parse_mode = 'HTML', $supports_streaming = '', $disable_notification = false, $reply_to_message_id = '', $reply_markup = '')
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendVideo', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendAnimation($chat_id, $animation, $duration = NULL, $width = NULL, $height = NULL, $thumb = NULL, $caption = '', $parse_mode = 'HTML', $disable_notification = NULL, $reply_to_message_id = NULL, $reply_markup = array())
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendAnimation', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function getBusinessConnection($business_connection_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getBusinessConnection', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function sendVoice($chat_id, $voice, $caption = NULL, $parse_mode = 'HTML', $duration = '', $disable_notification = false, $reply_to_message_id = '', $reply_markup = '')
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendVoice', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function getUserProfilePhotos($user_id, $offset = '', $limit = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('getUserProfilePhotos', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function unbanChatMember($chat_id, $user_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('unbanChatMember', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function restrictChatMember($chat_id, $user_id, $permissions, $until_date = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('restrictChatMember', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function promoteChatMember($chat_id, $user_id, $can_change_info = NULL, $can_post_messages = NULL, $can_edit_messages = NULL, $can_delete_messages = NULL, $can_invite_users = NULL, $can_restrict_members = NULL, $can_pin_messages = NULL, $can_promote_members = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('promoteChatMember', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function setChatPermissions($chat_id, $permissions)
|
||||
{
|
||||
$this->ret = $this->callMethod('setChatPermissions', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function exportChatInviteLink($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('exportChatInviteLink', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function setChatPhoto($chat_id, $photo)
|
||||
{
|
||||
$this->ret = $this->callMethod('setChatPhoto', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function deleteChatPhoto($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('deleteChatPhoto', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function setChatTitle($chat_id, $title)
|
||||
{
|
||||
$this->ret = $this->callMethod('setChatTitle', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function setChatDescription($chat_id, $description = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('setChatDescription', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function pinChatMessage($chat_id, $message_id, $disable_notification = false)
|
||||
{
|
||||
$this->ret = $this->callMethod('pinChatMessage', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function unpinChatMessage($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('unpinChatMessage', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function leaveChat($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('leaveChat', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function getChat($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getChat', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function getChatMembersCount($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getChatMembersCount', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function getChatMember($chat_id, $user_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getChatMember', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function editMessageText($chat_id = '', $message_id = '', $inline_message_id = NULL, $text, $parse_mode = 'HTML', $disable_web_page_preview = '', $reply_markup = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageText', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function editMessageCaption($chat_id = '', $message_id = '', $inline_message_id = NULL, $caption = NULL, $parse_mode = 'HTML', $reply_markup = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageCaption', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function editMessageMedia($chat_id = '', $message_id = '', $inline_message_id = NULL, $media, $reply_markup = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageMedia', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function editMessageReplyMarkup($chat_id = '', $message_id = '', $inline_message_id = NULL, $reply_markup = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageReplyMarkup', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendSticker($chat_id, $sticker, $reply_to_message_id = NULL, $reply_markup = array(), $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendSticker', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendGame($chat_id, $game_name, $reply_to_message_id = NULL, $reply_markup = array())
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendGame', [
|
||||
'chat_id' => $chat_id,
|
||||
'game_short_name' => $game_name,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'reply_markup' => $reply_markup
|
||||
]);
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function setGameScore($user_id, $score, $force = false, $disable_edit_message = false, $chat_id = NULL, $message_id = NULL, $inline_id = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('setGameScore', [
|
||||
'user_id' => $user_id,
|
||||
'score' => $score,
|
||||
'force' => $force,
|
||||
'disable_edit_message' => $disable_edit_message,
|
||||
'chat_id' => $chat_id,
|
||||
'message_id' => $message_id,
|
||||
'inline_message_id' => $inline_id
|
||||
]);
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function forwardMessage($chat_id, $from_chat_id, $message_id, $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('forwardMessage', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function answerCallback($callback_id, $text = '', $show_alert = false, $url = '', $cache_time = 0)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('answerCallbackQuery', [
|
||||
'callback_query_id' => $callback_id,
|
||||
'text' => $text,
|
||||
'show_alert' => $show_alert,
|
||||
'url' => $url,
|
||||
'cache_time' => $cache_time
|
||||
]);
|
||||
return $this->ret;
|
||||
}
|
||||
public function sendInlineQuery($results)
|
||||
{
|
||||
self::$inlineResults = array_merge(self::$inlineResults, $results);
|
||||
}
|
||||
public function sendInline($inline_id, $cache_time = 600, $offset = '', $switch_pm_parameter = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('answerInlineQuery', [
|
||||
'inline_query_id' => $inline_id,
|
||||
'results' => json_encode(self::$inlineResults),
|
||||
'cache_time' => $cache_time,
|
||||
'next_offset' => $offset,
|
||||
'switch_pm_parameter' => $switch_pm_parameter
|
||||
]);
|
||||
return $this->ret;
|
||||
}
|
||||
public function sendChatAction($chat_id, $action)
|
||||
{
|
||||
$this->ret = $this->callMethod('sendChatAction', [
|
||||
'chat_id' => $chat_id,
|
||||
'action' => $action
|
||||
]);
|
||||
return $this->ret;
|
||||
}
|
||||
public function getFile($file_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getFile', [
|
||||
'file_id' => $file_id,
|
||||
]);
|
||||
if ($this->ret['ok']) {
|
||||
$fileUrl = 'https://api.telegram.org/file/bot' . $this->token . '/' . $this->ret['result']['file_path'];
|
||||
$this->ret['result']['down_url'] = $fileUrl;
|
||||
}
|
||||
return $this->ret;
|
||||
}
|
||||
public function getInlineId()
|
||||
{
|
||||
return hash('sha256', uniqid(mt_rand(), true));
|
||||
}
|
||||
public function getChatAdmin($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getChatAdministrators', [
|
||||
'chat_id' => $chat_id
|
||||
]);
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function getMe()
|
||||
{
|
||||
$this->ret = $this->callMethod('getMe', []);
|
||||
return $this->ret;
|
||||
}
|
||||
public function getStickerSet($name)
|
||||
{
|
||||
$this->ret = $this->callMethod('getStickerSet', [
|
||||
'name' => $name
|
||||
]);
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function isAdmin($chat_id, $user_id)
|
||||
{
|
||||
$ret = false;
|
||||
$adminList = $this->getChatAdmin($chat_id);
|
||||
foreach ($adminList as $adminList_d) {
|
||||
if ($adminList_d['user']['id'] == $user_id) {
|
||||
$ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
public function atById($userid, $username)
|
||||
{
|
||||
return '<a href="tg://user?id=' . $userid . '">@' . $username . '</a>';
|
||||
}
|
||||
public function getMaster()
|
||||
{
|
||||
return MASTER;
|
||||
}
|
||||
public function getBotName()
|
||||
{
|
||||
return BOTNAME;
|
||||
}
|
||||
public function getReturn()
|
||||
{
|
||||
return $this->ret;
|
||||
}
|
||||
public function error()
|
||||
{
|
||||
$this->callMethod('sendMessage');
|
||||
}
|
||||
}
|
||||
Executable
+157
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use app\model\admin\Role;
|
||||
use app\model\admin\role\Menu;
|
||||
use laytp\traits\Error;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 后台权限服务实现者
|
||||
* Class Auth
|
||||
* @package app\service\admin
|
||||
*/
|
||||
class Auth
|
||||
{
|
||||
use Error;
|
||||
protected $_noNeedLogin = [];//无需登录的方法名数组
|
||||
protected $_noNeedAuth = [];//无需鉴权的方法名数组
|
||||
|
||||
/**
|
||||
* 设置无需登录的方法名数组
|
||||
* @param array $noNeedLogin
|
||||
*/
|
||||
public function setNoNeedLogin($noNeedLogin = [])
|
||||
{
|
||||
$this->_noNeedLogin = $noNeedLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取无需登录的方法名数组
|
||||
* @return array
|
||||
*/
|
||||
public function getNoNeedLogin()
|
||||
{
|
||||
return $this->_noNeedLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前节点是否需要登录
|
||||
* @param bool $noNeedLogin
|
||||
* @return bool true:需要登录,false:不需要登录
|
||||
*/
|
||||
public function needLogin($noNeedLogin = false)
|
||||
{
|
||||
$noNeedLogin === false && $noNeedLogin = $this->getNoNeedLogin();
|
||||
$noNeedLogin = is_array($noNeedLogin) ? $noNeedLogin : explode(',', $noNeedLogin);
|
||||
//为空表示所有方法都需要登录,返回true
|
||||
if (!$noNeedLogin) {
|
||||
return true;
|
||||
}
|
||||
$noNeedLogin = array_map('strtolower', $noNeedLogin);
|
||||
$request = Request::instance();
|
||||
//判断当前请求的操作名是否存在于不需要登录的方法名数组中,如果存在,表明不需要登录,返回false
|
||||
if (in_array(strtolower($request->action()), $noNeedLogin) || in_array('*', $noNeedLogin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//默认为需要登录
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置无需鉴权的方法名数组
|
||||
* @param array $noNeedAuth
|
||||
*/
|
||||
public function setNoNeedAuth($noNeedAuth = [])
|
||||
{
|
||||
$this->_noNeedAuth = $noNeedAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取无需鉴权的方法名数组
|
||||
* @return array
|
||||
*/
|
||||
public function getNoNeedAuth()
|
||||
{
|
||||
return $this->_noNeedAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前节点是否需要鉴权
|
||||
* @param bool $noNeedAuth
|
||||
* @return bool true:需要登录,false:不需要登录
|
||||
*/
|
||||
public function needAuth($noNeedAuth = false)
|
||||
{
|
||||
$noNeedAuth === false && $noNeedAuth = $this->getNoNeedAuth();
|
||||
$noNeedAuth = is_array($noNeedAuth) ? $noNeedAuth : explode(',', $noNeedAuth);
|
||||
//为空表示所有方法都需要鉴权,返回true
|
||||
if (!$noNeedAuth) {
|
||||
return true;
|
||||
}
|
||||
$noNeedAuth = array_map('strtolower', $noNeedAuth);
|
||||
|
||||
//判断当前请求的操作名是否存在于不需要鉴权的方法名数组中,如果存在,表明不需要鉴权,返回false
|
||||
if (in_array(strtolower(Request::action()), $noNeedAuth) || in_array('*', $noNeedAuth)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//默认为需要鉴权
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某用户拥有的权限列表
|
||||
* @param $userId int 用户ID,当为空时,为获取当前登录用户权限列表
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getAuthList($userId = 0)
|
||||
{
|
||||
$where[] = ['is_show', '=', 1];
|
||||
$user = $userId ? \app\model\admin\User::findOrEmpty($userId) : UserServiceFacade::getUser();
|
||||
//当前后台管理员如果是超级管理员,则拥有所有的权限列表
|
||||
if ($user->is_super_manager === 1) {
|
||||
$result = \app\model\admin\Menu::where($where)->select()->toArray();
|
||||
} else {
|
||||
//如果不是超级管理员,先查询拥有哪些角色,通过角色查询出权限节点列表
|
||||
$adminUserId = $user->id;
|
||||
$roleIds = \app\model\admin\role\User::where('admin_user_id', '=', $adminUserId)->column('admin_role_id');
|
||||
$menuIds = \app\model\admin\menu\Role::where('admin_role_id', 'in', $roleIds)->column('admin_menu_id');
|
||||
$where[] = ['id', 'in', $menuIds];
|
||||
$result = \app\model\admin\Menu::where($where)->select()->toArray();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某用户是否有某节点的权限
|
||||
* @param integer $userId 登录用户ID
|
||||
* @param string $node 节点字符串
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function hasAuth($userId, $node)
|
||||
{
|
||||
if (!$userId || !$node) return false;
|
||||
$authList = $this->getAuthList($userId);
|
||||
$authArr = [];
|
||||
foreach ($authList as $k => $v) {
|
||||
$authArr[] = trim($v['rule'], '/');
|
||||
}
|
||||
|
||||
$authArr = array_filter(array_unique($authArr));
|
||||
sort($authArr);
|
||||
if (in_array($node, $authArr)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 后台权限服务门面
|
||||
* @package app\service\admin
|
||||
* @method static mixed setNoNeedLogin($noNeedLogin) 设置不需要登录的方法名数组
|
||||
* @method static mixed setNoNeedAuth($noNeedAuth) 设置不需要鉴权的方法名数组
|
||||
* @method static mixed needLogin() 当前节点是否需要登录
|
||||
* @method static mixed needAuth() 当前节点是否需要鉴权
|
||||
* @method static mixed getAuthList($userId) 获取某后台管理员拥有的权限列表
|
||||
* @method static mixed hasAuth($userId, $node) 某用户是否拥有某个节点的权限
|
||||
*/
|
||||
class AuthServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Auth::class;
|
||||
}
|
||||
}
|
||||
Executable
+403
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use app\model\admin\Menu;
|
||||
use laytp\library\DirFile;
|
||||
use laytp\library\Http;
|
||||
use laytp\traits\Error;
|
||||
use app\model\Migrations;
|
||||
use think\facade\Config;
|
||||
use think\facade\Filesystem;
|
||||
|
||||
/**
|
||||
* 插件市场服务实现者
|
||||
* Class Auth
|
||||
* @package app\service\admin
|
||||
*/
|
||||
class Plugins
|
||||
{
|
||||
use Error;
|
||||
|
||||
protected $ids=[];
|
||||
|
||||
// 离线安装
|
||||
public function offLineInstall()
|
||||
{
|
||||
if (!class_exists('ZipArchive')) {
|
||||
$this->setError('PHP扩展ZipArchive没有正确安装');
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = request()->file('laytpUploadFile'); // 获取上传的文件
|
||||
if (!$file) {
|
||||
$this->setError('上传失败,请选择需要上传的文件');
|
||||
return false;
|
||||
}
|
||||
|
||||
$fileExt = strtolower($file->getOriginalExtension());
|
||||
if($fileExt != 'zip'){
|
||||
$this->setError('仅允许上传zip文件');
|
||||
return false;
|
||||
}
|
||||
|
||||
$fileName = $file->getOriginalName();
|
||||
$pathinfo = pathinfo($fileName);
|
||||
$plugin = $pathinfo['filename'];
|
||||
try{
|
||||
// 将文件上传到指定目录
|
||||
Filesystem::disk('local')->putFileAs('plugins', $file, $fileName );
|
||||
$this->insideInstall($plugin);
|
||||
}catch (\Exception $e){
|
||||
$this->setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 安装
|
||||
public function install($plugin, $laytpGwToken)
|
||||
{
|
||||
if (!class_exists('ZipArchive')) {
|
||||
$this->setError('PHP扩展ZipArchive没有正确安装');
|
||||
return false;
|
||||
}
|
||||
|
||||
$download = $this->download($plugin, $laytpGwToken);
|
||||
|
||||
if(!$download){
|
||||
return false;
|
||||
}
|
||||
|
||||
$install = $this->insideInstall($plugin);
|
||||
if(!$install){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 卸载
|
||||
public function unInstall($plugin)
|
||||
{
|
||||
$pluginDir = $this->getPluginPath($plugin) . DS;
|
||||
// 删除数据库文件
|
||||
$migrationsFile = DirFile::recurDir($pluginDir . 'database' . DS . 'migrations');
|
||||
if($migrationsFile){
|
||||
foreach($migrationsFile as $file){
|
||||
$baseNameArr = explode('_', $file['baseName']);
|
||||
$baseNameArr = explode('.', $baseNameArr[1]);
|
||||
$migration = Migrations::where('migration_name', '=', ucfirst($baseNameArr[0]))->find();
|
||||
if($migration) $migration->delete();
|
||||
@unlink(root_path() . 'database' . DS . 'migrations' . DS . $file['baseName']);
|
||||
}
|
||||
}
|
||||
// 删除菜单
|
||||
$info = $this->getPluginInfo($plugin);
|
||||
$menuIds = $info['menu_ids'];
|
||||
if($menuIds){
|
||||
Menu::destroy(function($query) use ($menuIds){
|
||||
$query->where('id', 'in', explode(',', $menuIds));
|
||||
});
|
||||
}
|
||||
// 删除public目录下的文件
|
||||
$this->removePublicFile($plugin);
|
||||
// 删除插件目录
|
||||
DirFile::rmDirs($pluginDir);
|
||||
// 修改系统插件配置文件config/plugin.php
|
||||
$this->unInstallPluginConf($plugin, $info);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取上传zip文件所在目录
|
||||
public function getPluginRuntimeDir()
|
||||
{
|
||||
$dir = runtime_path() . 'storage' . DS . 'plugins';
|
||||
DirFile::createDir($dir);
|
||||
return $dir;
|
||||
}
|
||||
|
||||
// 下载zip文件到本地
|
||||
public function download($plugin, $laytpGwToken)
|
||||
{
|
||||
$ltVersion = request()->param('ltVersion');
|
||||
$pluginVersion = request()->param('pluginVersion');
|
||||
$res = Http::post(Config::get('plugin.apiUrl') . "/plugins/install", [
|
||||
'plugin'=>$plugin,
|
||||
'ltVersion'=>$ltVersion,
|
||||
'pluginVersion'=>$pluginVersion,
|
||||
], array(
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
"token: ".$laytpGwToken
|
||||
),
|
||||
));
|
||||
$resArr = json_decode($res, true);
|
||||
if($resArr['code'] > 0 ){
|
||||
$this->setError(['msg'=>$resArr['msg'],'code'=>$resArr['code']]);
|
||||
return false;
|
||||
}
|
||||
$url = $resArr['data']['url'];
|
||||
$zipSteam = Http::get($url, [], [
|
||||
CURLOPT_CONNECTTIMEOUT => 30,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'X-REQUESTED-WITH: XMLHttpRequest'
|
||||
]
|
||||
]);
|
||||
|
||||
$file = $this->getPluginRuntimeDir() . DS . $plugin . '.zip';
|
||||
if(file_exists($file)){
|
||||
@unlink($file);
|
||||
}
|
||||
if ($write = fopen($file, 'w')) {
|
||||
fwrite($write, $zipSteam);
|
||||
fclose($write);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 内部安装过程
|
||||
public function insideInstall($plugin)
|
||||
{
|
||||
try{
|
||||
// 解压zip文件
|
||||
$this->unzip($plugin);
|
||||
|
||||
// 复制database文件并执行php think migrate:run命令
|
||||
$this->migrate($plugin);
|
||||
|
||||
// 复制静态文件
|
||||
if(!function_exists('exec')){
|
||||
$this->setError('php函数exec不允许执行');
|
||||
return false;
|
||||
}
|
||||
$this->copyPublicFile($plugin);
|
||||
|
||||
// 生成菜单,同时将新增的菜单id写入info.ini配置文件中,便于卸载时同时删除菜单
|
||||
$this->createMenu($plugin);
|
||||
|
||||
// 修改系统插件配置文件config/plugin.php
|
||||
$this->installPluginConf($plugin);
|
||||
return true;
|
||||
}catch (\Exception $e){
|
||||
$this->setError(['msg'=>$e->getMessage(). $e->getLine() . $e->getFile(),'code'=>3]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压插件zip文件
|
||||
* @param $plugin
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function unzip($plugin)
|
||||
{
|
||||
$file = $this->getPluginRuntimeDir() . DS . $plugin . '.zip';
|
||||
$zip = new \ZipArchive;
|
||||
if ($zip->open($file) !== TRUE) {
|
||||
@unlink($file);
|
||||
throw new \Exception('不能打开zip文件');
|
||||
}
|
||||
if(strtolower(trim($zip->getNameIndex(0),'/')) == strtolower($plugin)){
|
||||
$dir = root_path() . 'plugin' . DS;
|
||||
}else{
|
||||
$dir = root_path() . 'plugin' . DS . $plugin . DS;
|
||||
}
|
||||
if (!$zip->extractTo($dir)) {
|
||||
$zip->close();
|
||||
@unlink($file);
|
||||
throw new \Exception('不能提取zip文件');
|
||||
}
|
||||
$zip->close();
|
||||
@unlink($file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 插件代码文件解压后,执行php run:migrate命令,安装数据库文件
|
||||
public function migrate($plugin)
|
||||
{
|
||||
$pluginDir = $this->getPluginPath($plugin) . DS;
|
||||
if(is_dir($pluginDir . 'database' . DS . 'migrations')){
|
||||
DirFile::copyDirs($pluginDir . 'database' . DS . 'migrations', root_path() . 'database' . DS . 'migrations');
|
||||
// 删除数据库migrations表,已经安装过的版本
|
||||
$list = scandir($pluginDir . 'database' . DS . 'migrations');
|
||||
$migrationNameArr = [];
|
||||
foreach ($list as $value) {
|
||||
$pathinfo = pathinfo($value);
|
||||
if ($pathinfo['extension'] == 'php') {
|
||||
$tempArr = explode('_', $pathinfo['filename']);
|
||||
$migrationNameArr[] = ucfirst($tempArr[1]);
|
||||
}
|
||||
}
|
||||
Migrations::where('migration_name', 'in', $migrationNameArr)->delete();
|
||||
sleep(1);
|
||||
exec('php ' . app()->getRootPath() . '\think migrate:run');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取插件路径
|
||||
public function getPluginPath($plugin)
|
||||
{
|
||||
return app()->getRootPath() . DS . 'plugin' . DS . $plugin;
|
||||
}
|
||||
|
||||
// 获取插件信息
|
||||
public function getPluginInfo($plugin)
|
||||
{
|
||||
$pluginPath = $this->getPluginPath($plugin);
|
||||
$infoFile = $pluginPath . DS . 'info.ini';
|
||||
$info = [];
|
||||
if (is_file($infoFile)) {
|
||||
$info = parse_ini_file($infoFile, true, INI_SCANNER_TYPED) ?: [];
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置插件配置信息
|
||||
* @param $plugin
|
||||
* @param $array
|
||||
* @return bool
|
||||
*/
|
||||
public function setPluginInfo($plugin, $array)
|
||||
{
|
||||
$pluginPath = $this->getPluginPath($plugin);
|
||||
$file = $pluginPath . DS . 'info.ini';
|
||||
if (!isset($array['name'])) {
|
||||
$this->setError("插件配置写入失败");
|
||||
return false;
|
||||
}
|
||||
$res = array();
|
||||
foreach ($array as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$res[] = "[$key]";
|
||||
foreach ($val as $sKey => $sVal)
|
||||
$res[] = "$sKey = " . (is_numeric($sVal) ? $sVal : $sVal);
|
||||
} else
|
||||
$res[] = "$key = " . (is_numeric($val) ? $val : $val);
|
||||
}
|
||||
if ($handle = fopen($file, 'w')) {
|
||||
fwrite($handle, implode("\n", $res) . "\n");
|
||||
fclose($handle);
|
||||
} else {
|
||||
$this->setError("文件没有写入权限");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 生成插件菜单
|
||||
public function createMenu($plugin)
|
||||
{
|
||||
$menuFile = root_path() . 'plugin' . DS . $plugin . DS . 'menu.php';
|
||||
if(!is_file($menuFile)){
|
||||
return true;
|
||||
}
|
||||
$menus = include_once $menuFile;
|
||||
$info = $this->getPluginInfo($plugin);
|
||||
if(isset($info['parent_menu']) && $info['parent_menu'] === 'first'){
|
||||
$firstMenuId = Menu::where(['pid' => 0, 'is_show' => 1])->order(['sort'=>'desc', 'id'=>'asc'])->value('id');
|
||||
$ids = $this->createMenuIds($menus, $firstMenuId);
|
||||
}else{
|
||||
$ids = $this->createMenuIds($menus, 0);
|
||||
}
|
||||
$info['menu_ids'] = implode(',', $ids);
|
||||
if(!$this->setPluginInfo($plugin, $info)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function createMenuIds($menus, $pid=0)
|
||||
{
|
||||
foreach($menus as $menu){
|
||||
$id = Menu::insertGetId([
|
||||
'name' => $menu['name'],
|
||||
'des' => isset($menu['des']) ? $menu['des'] : '',
|
||||
'href' => isset($menu['href']) ? $menu['href'] : '',
|
||||
'rule' => isset($menu['rule']) ? $menu['rule'] : '',
|
||||
'is_menu' => $menu['is_menu'],
|
||||
'pid' => $pid,
|
||||
'icon' => isset($menu['icon']) ? $menu['icon'] : ''
|
||||
]);
|
||||
$this->ids[] = $id;
|
||||
|
||||
if(isset($menu['children'])){
|
||||
self::createMenuIds($menu['children'],$id);
|
||||
}
|
||||
}
|
||||
return $this->ids;
|
||||
}
|
||||
|
||||
// 复制静态文件,包括html css js
|
||||
public function copyPublicFile($plugin)
|
||||
{
|
||||
$pluginDir = $this->getPluginPath($plugin) . DS;
|
||||
if(is_dir($pluginDir . 'public')){
|
||||
DirFile::copyDirs($pluginDir . 'public', root_path() . 'public');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 删除静态文件,包括html css js
|
||||
public function removePublicFile($plugin)
|
||||
{
|
||||
$pluginDir = $this->getPluginPath($plugin) . DS;
|
||||
$pluginHtmlDir = $pluginDir . 'public' . DS . 'admin' . DS . 'plugin' . DS . $plugin;
|
||||
$publicHtmlDir = root_path() . 'public' . DS . 'admin' . DS . 'plugin' . DS . $plugin;
|
||||
if(is_dir($pluginHtmlDir) && $publicHtmlDir){
|
||||
DirFile::rmDirs($publicHtmlDir);
|
||||
}
|
||||
$pluginStaticDir = $pluginDir . 'public' . DS . 'static' . DS . 'plugin' . DS . $plugin;
|
||||
$publicStaticDir = root_path() . 'public' . DS . 'static' . DS . 'plugin' . DS . $plugin;
|
||||
if(is_dir($pluginStaticDir) && $publicStaticDir){
|
||||
DirFile::rmDirs($publicStaticDir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 重新生成config/plugin.php文件
|
||||
public function installPluginConf($plugin)
|
||||
{
|
||||
$pluginConf = Config::get('plugin');
|
||||
$pluginConf['installed'][] = $plugin;
|
||||
$pluginConf['installed'] = array_unique($pluginConf['installed']);
|
||||
sort($pluginConf['installed']);
|
||||
|
||||
$info = $this->getPluginInfo($plugin);
|
||||
if(isset($info['is_editor']) && $info['is_editor']){
|
||||
$pluginConf['installedEditor'][] = $plugin;
|
||||
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
|
||||
sort($pluginConf['installedEditor']);
|
||||
}
|
||||
|
||||
$fileName = root_path() . DS . 'config' . DS . 'plugin.php';
|
||||
file_put_contents($fileName,"<?php\nreturn " . var_export($pluginConf,true) . ';');
|
||||
return true;
|
||||
}
|
||||
|
||||
// 重新生成config/plugin.php文件
|
||||
public function unInstallPluginConf($plugin, $info)
|
||||
{
|
||||
$pluginConf = Config::get('plugin');
|
||||
foreach($pluginConf['installed'] as $k=>$installed){
|
||||
if($installed === $plugin) unset($pluginConf['installed'][$k]);
|
||||
}
|
||||
$pluginConf['installed'] = array_unique($pluginConf['installed']);
|
||||
sort($pluginConf['installed']);
|
||||
|
||||
if(isset($info['is_editor']) && $info['is_editor']){
|
||||
foreach($pluginConf['installedEditor'] as $k=>$installedEditor){
|
||||
if($installedEditor === $plugin) unset($pluginConf['installedEditor'][$k]);
|
||||
}
|
||||
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
|
||||
sort($pluginConf['installedEditor']);
|
||||
}
|
||||
|
||||
$fileName = root_path() . DS . 'config' . DS . 'plugin.php';
|
||||
file_put_contents($fileName,"<?php\nreturn " . var_export($pluginConf,true) . ';');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 插件市场服务门面
|
||||
* @package app\service\admin
|
||||
* @method static mixed getError() 获取错误信息
|
||||
* @method static mixed offLineInstall() 离线安装
|
||||
* @method static mixed unInstall($plugin) 卸载
|
||||
* @method static mixed getPluginPath($plugin) 获取插件目录
|
||||
* @method static mixed getPluginInfo($plugin) 获取插件信息
|
||||
* @method static mixed install($plugin, $laytpGwToken) 安装插件
|
||||
*/
|
||||
class PluginsServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Plugins::class;
|
||||
}
|
||||
}
|
||||
Executable
+130
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use laytp\library\Token;
|
||||
use laytp\traits\Error;
|
||||
|
||||
/**
|
||||
* 后台用户服务实现者
|
||||
* @package app\service\admin
|
||||
*/
|
||||
class User
|
||||
{
|
||||
use Error;
|
||||
protected $_user = null;//实例化的用户对象
|
||||
protected $_token = null;//用户登录凭证,token
|
||||
protected $_isLogin = null;//当前用户是否登录
|
||||
protected $userModel = null;//用户数据模型
|
||||
protected $allowFields = ['id', 'username', 'nickname', 'avatar', 'is_super_manager', 'status', 'create_time'];
|
||||
protected $tokenKeepTime = 365 * 24 * 60 * 60;//Token默认有效时长,单位秒,365天
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @param $token
|
||||
* @return bool
|
||||
*/
|
||||
public function init($token)
|
||||
{
|
||||
if (!$token) {
|
||||
$this->setError('token不能为空,请重新登录');
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = Token::get($token);
|
||||
if (!$data) {
|
||||
$this->setError('token无效,请重新登录');
|
||||
return false;
|
||||
}
|
||||
|
||||
$userId = intval($data['user_id']);
|
||||
if ($userId > 0) {
|
||||
$user = \app\model\admin\User::with(['avatar_file'])->findOrEmpty($userId);
|
||||
if (!$user) {
|
||||
$this->setError('账号不存在,请重新登录');
|
||||
return false;
|
||||
}
|
||||
//用户状态 1正常 2禁用
|
||||
if ($user['status'] != 1) {
|
||||
$this->setError('账号被禁用,请联系管理员');
|
||||
return false;
|
||||
}
|
||||
$this->_user = $user;
|
||||
$this->_isLogin = true;
|
||||
$this->_token = $token;
|
||||
return true;
|
||||
} else {
|
||||
$this->setError('账号不存在,请重新登录');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @return bool
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
if (!$this->_isLogin) {
|
||||
$this->setError('你没有登录');
|
||||
return false;
|
||||
}
|
||||
//设置登录标识
|
||||
$this->_isLogin = false;
|
||||
//删除Token
|
||||
Token::delete($this->_token);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户信息
|
||||
*/
|
||||
public function getUserInfo()
|
||||
{
|
||||
$data = $this->_user->toArray();
|
||||
$allowFields = $this->getAllowFields();
|
||||
$userInfo = array_intersect_key($data, array_flip($allowFields));
|
||||
$userInfo['avatar_file'] = $data['avatar_file'];
|
||||
$userInfo = array_merge($userInfo, ['token' => $this->_token]);
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取允许输出的字段
|
||||
* @return array
|
||||
*/
|
||||
public function getAllowFields()
|
||||
{
|
||||
return $this->allowFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取User模型
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否登录
|
||||
* @return boolean
|
||||
*/
|
||||
public function isLogin()
|
||||
{
|
||||
if ($this->_isLogin) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Token
|
||||
* @return string
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->_token;
|
||||
}
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 后台用户服务门面
|
||||
* @package app\service\admin
|
||||
* @method static mixed init($token) 初始化
|
||||
* @method static mixed getError() 获取错误信息
|
||||
* @method static mixed logout() 退出登录
|
||||
* @method static mixed getUserInfo() 获取登录用户信息
|
||||
* @method static mixed getAllowFields() 获取允许展示的字段
|
||||
* @method static mixed getUser() 获取User模型
|
||||
* @method static mixed isLogin() 获取登录状态
|
||||
* @method static mixed getToken() 获取token
|
||||
*/
|
||||
class UserServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return User::class;
|
||||
}
|
||||
}
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
- 容器
|
||||
- 通俗一点理解容器,我们用PHP中唯一的数据结构数组来做比方。
|
||||
- 你可以直接把容器理解为一个数组
|
||||
- 数组中的key是一个字符串,作为容器中类实例的标识,方便使用这个标识来调用类的实例
|
||||
- 数组中的value就是一个一个类的实例
|
||||
- 容器就是存储具有key-value数据结构的,用于存储标识和类实例的一个大集合
|
||||
- tp6中,默认在容器中添加了很多的类实例,手册中的[系统内置绑定到容器中的类库包括]的表格中说明了标识和系统类库对应的关系
|
||||
|
||||
- 依赖注入
|
||||
- 在容器中存入了很多key-value形式的类实例,就可以实现依赖注入。
|
||||
- 比如在控制器的某个方法中,使用依赖注入的方式,参数设置一个类,其实这个类在框架进行初始化时,就已经放在容器中了
|
||||
- 如果容器中不存在,容器也可以使用composer的类自动加载机制,实时的将类注入进入容器
|
||||
|
||||
- 服务
|
||||
- 平时在编写程序的时候,我们会写很多服务,比如权限验证,用户信息,支付,手机短信,邮件等等
|
||||
- 在tp6之前,我们一般就是写一个一个的类,需要用到的时候就new一下,得到服务类的实例,然后调用服务类的方法
|
||||
- 现在tp6使用容器来管理所有的类,当服务类需要使用依赖注入的方式调用时,就需要把服务类注册到容器中
|
||||
- tp6就提供了一个配置文件,service.php,写上哪些类需要注册到容器中
|
||||
- 注册到容器中的类还可以设置一个标识,那就使用服务类的register方法,或者bind方法
|
||||
- 服务不推荐使用,因为php本身语言的问题,容器的初始化是每次请求都会执行的,意味着,每次请求都会实例化所有服务类并注册进容器。服务越多,初始化消耗越大
|
||||
|
||||
- 门面
|
||||
- 门面为容器中的动态类提供了一个静态调用接口,相比于传统的静态方法调用,带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。
|
||||
|
||||
laytp里面的服务,其实就是用了tp6的门面,一般由两个文件组成
|
||||
- 服务具体实现者 这个类无需继承任何基类,只需要实现服务的具体方法
|
||||
- 服务门面
|
||||
- 编写服务门面的原因要谈到如何调用服务
|
||||
- 第一种:使用new关键字,创建一个服务具体实现者的类实例,就可以调用服务的方法,这种方法比较通用,但是需要多一行new的代码,而且服务本身还要考虑是否需要实现单例
|
||||
- 第二种,使用依赖注入。在控制器层可以使用此方法,调用起来也很方便,但是中间件中,不能使用依赖注入
|
||||
- 第三种,编写服务门面类,可以直接使用静态方法调用服务实现者的具体实现方法。此方式代码编写方便,中间件中也可以使用,而且服务门面基类实现了单例
|
||||
- 唯一要注意的是,服务门面类需要写好注释,PHPStorm编辑器的代码跟踪才能跟踪到门面类里面来,然后就可以在门面的getFacadeClass方法中继续跟踪服务的具体实现者类
|
||||
- 服务的目录 /app/service
|
||||
- 命名规范,以ServiceFacade结尾的就是服务门面
|
||||
|
||||
- 服务提供者,文件名和类名一般以Service结尾
|
||||
- 举例:
|
||||
- tp6的验证码就是使用的服务提供者来提供全局调用的
|
||||
- vendor/topthink/think-captcha/src/CaptchaService.php
|
||||
- 提供者仅需实现服务注册方法,如果服务需要做一些其他操作,可以使用服务启动方法进行操作。
|
||||
- 在提供者中,服务启动方法,可以进行路由注册、验证器扩展标识,
|
||||
- 服务提供者的用处
|
||||
- 提供者实现了服务注册方法,就能进行依赖注入的方式调用服务
|
||||
- 提供者的启动方法,服务在调用之前,就会执行的一些程序
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use laytp\traits\Error;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* Api权限服务实现者
|
||||
* Class Auth
|
||||
* @package app\api\service
|
||||
*/
|
||||
class Auth
|
||||
{
|
||||
use Error;
|
||||
protected $_noNeedLogin = [];//无需登录的方法名数组
|
||||
|
||||
/**
|
||||
* 设置无需登录的方法名数组
|
||||
* @param array $noNeedLogin
|
||||
*/
|
||||
public function setNoNeedLogin($noNeedLogin = [])
|
||||
{
|
||||
$this->_noNeedLogin = $noNeedLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取无需登录的方法名数组
|
||||
* @return array
|
||||
*/
|
||||
public function getNoNeedLogin()
|
||||
{
|
||||
return $this->_noNeedLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前节点是否需要登录
|
||||
* @param bool $noNeedLogin
|
||||
* @return bool true:需要登录,false:不需要登录
|
||||
*/
|
||||
public function needLogin($noNeedLogin = false)
|
||||
{
|
||||
$noNeedLogin === false && $noNeedLogin = $this->getNoNeedLogin();
|
||||
$noNeedLogin = is_array($noNeedLogin) ? $noNeedLogin : explode(',', $noNeedLogin);
|
||||
//为空表示所有方法都需要登录,返回true
|
||||
if (!$noNeedLogin) {
|
||||
return true;
|
||||
}
|
||||
$noNeedLogin = array_map('strtolower', $noNeedLogin);
|
||||
$request = Request::instance();
|
||||
//判断当前请求的操作名是否存在于不需要登录的方法名数组中,如果存在,表明不需要登录,返回false
|
||||
if (in_array(strtolower($request->action()), $noNeedLogin) || in_array('*', $noNeedLogin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//默认为需要登录
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* Api权限服务门面
|
||||
* @package app\api\service
|
||||
* @method static mixed setNoNeedLogin($noNeedLogin) 设置不需要登录的方法名数组
|
||||
* @method static mixed getNoNeedLogin() 获取无需登录的方法名数组
|
||||
* @method static mixed needLogin() 获取当前节点是否需要登录
|
||||
*/
|
||||
class AuthServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Auth::class;
|
||||
}
|
||||
}
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use app\service\ConfServiceFacade;
|
||||
use laytp\traits\Error;
|
||||
use think\facade\Config;
|
||||
use think\facade\Env;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* Api验证签名服务实现者
|
||||
* Class CheckSign
|
||||
* @package app\api\service
|
||||
*/
|
||||
class CheckSign
|
||||
{
|
||||
use Error;
|
||||
protected $_noNeedCheckSign = [];//无需验证签名的方法名数组
|
||||
|
||||
/**
|
||||
* 设置无需验证签名的方法名数组
|
||||
* @param array $noNeedCheckSign
|
||||
*/
|
||||
public function setNoNeedCheckSign($noNeedCheckSign = [])
|
||||
{
|
||||
$this->_noNeedCheckSign = $noNeedCheckSign;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取无需验证签名的方法名数组
|
||||
* @return array
|
||||
*/
|
||||
public function getNoNeedCheckSign()
|
||||
{
|
||||
return $this->_noNeedCheckSign;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前节点是否需要验证签名
|
||||
* @param bool $noNeedCheckSign
|
||||
* @return bool true:需要验证签名,false:不需要验证签名
|
||||
*/
|
||||
public function needCheckSign($noNeedCheckSign = false)
|
||||
{
|
||||
$noNeedCheckSign === false && $noNeedCheckSign = $this->getNoNeedCheckSign();
|
||||
$noNeedCheckSign = is_array($noNeedCheckSign) ? $noNeedCheckSign : explode(',', $noNeedCheckSign);
|
||||
//为空表示所有方法都需要验证签名,返回true
|
||||
if (!$noNeedCheckSign) {
|
||||
return true;
|
||||
}
|
||||
$noNeedCheckSign = array_map('strtolower', $noNeedCheckSign);
|
||||
$request = Request::instance();
|
||||
//判断当前请求的操作名是否存在于不需要验证签名的方法名数组中,如果存在,表明不需要验证签名,返回false
|
||||
if (in_array(strtolower($request->action()), $noNeedCheckSign) || in_array('*', $noNeedCheckSign)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//默认为需要验证签名
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
$request = Request::instance();
|
||||
$requestTime = $request->header('request-time');
|
||||
$sign = $request->header('sign');
|
||||
$signKey = ConfServiceFacade::get('system.basic.signKey');
|
||||
$backendSign = strtoupper(md5(md5($requestTime).md5($signKey)));
|
||||
if($sign != $backendSign){
|
||||
$this->setError($backendSign);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* Api验证签名服务门面
|
||||
* @package app\api\service
|
||||
* @method static mixed setNoNeedCheckSign($noNeedCheckSign) 设置不需要验证签名的方法名数组
|
||||
* @method static mixed getNoNeedCheckSign() 获取无需验证签名的方法名数组
|
||||
* @method static mixed needCheckSign() 获取当前节点是否需要验证签名
|
||||
* @method static mixed check() 验证签名
|
||||
* @method static mixed getError() 获取错误信息
|
||||
*/
|
||||
class CheckSignServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return CheckSign::class;
|
||||
}
|
||||
}
|
||||
Executable
+178
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use laytp\library\Str;
|
||||
use laytp\library\Token;
|
||||
use laytp\traits\Error;
|
||||
use laytp\library\Random;
|
||||
|
||||
/**
|
||||
* Api用户服务实现者
|
||||
* @package app\api\service
|
||||
*/
|
||||
class Member
|
||||
{
|
||||
use Error;
|
||||
protected $_user = null;//实例化的用户对象
|
||||
protected $_token = null;//用户登录凭证,token
|
||||
protected $_isLogin = null;//当前用户是否登录
|
||||
protected $userModel = null;//用户数据模型
|
||||
protected $allowFields = ['id', 'email', 'nickname', 'avatar'];
|
||||
protected $tokenKeepTime = 10 * 365 * 24 * 60 * 60;//Token默认有效时长,单位秒,365天
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @param $token
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function init($token)
|
||||
{
|
||||
if (!$token) {
|
||||
$this->setError('token不能为空,请重新登录');
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = Token::get($token);
|
||||
if (!$data) {
|
||||
$this->setError('token无效,请重新登录');
|
||||
return false;
|
||||
}
|
||||
|
||||
$userId = intval($data['user_id']);
|
||||
if ($userId > 0) {
|
||||
$user = \app\model\Member::find($userId);
|
||||
if (!$user) {
|
||||
$this->setError('账号不存在,请重新登录');
|
||||
return false;
|
||||
}
|
||||
//用户状态 1正常 2锁定
|
||||
if ($user['status'] != 1) {
|
||||
$this->setError('账号被锁定,请联系管理员');
|
||||
return false;
|
||||
}
|
||||
$this->_user = $user;
|
||||
$this->_isLogin = true;
|
||||
$this->_token = $token;
|
||||
return true;
|
||||
} else {
|
||||
$this->setError('账号不存在,请重新登录');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱+密码注册登录
|
||||
* @param $params
|
||||
* @return bool
|
||||
*/
|
||||
public function emailRegLogin($params)
|
||||
{
|
||||
try {
|
||||
$user = \app\model\Member::where('email', '=', $params['email'])->find();
|
||||
if (!$user) {
|
||||
$data = [
|
||||
'email' => $params['email'],
|
||||
'password' => Str::createPassword($params['password']),
|
||||
'status' => 1,
|
||||
'login_time' => date('Y-m-d H:i:s'),
|
||||
'login_ip' => request()->ip(),
|
||||
];
|
||||
|
||||
$user = \app\model\Member::create($data);
|
||||
$this->_user = \app\model\Member::find($user->id);
|
||||
} else {
|
||||
$this->_user = $user;
|
||||
}
|
||||
|
||||
//设置Token
|
||||
$this->_token = Random::uuid();
|
||||
Token::set($this->_token, $user->id, $this->tokenKeepTime);
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$this->setError('操作异常');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
if (!$this->_isLogin) {
|
||||
$this->setError('你没有登录');
|
||||
return false;
|
||||
}
|
||||
//设置登录标识
|
||||
$this->_isLogin = false;
|
||||
//删除Token
|
||||
Token::delete($this->_token);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容调用user模型的属性
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->_user ? $this->_user->$name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户信息
|
||||
*/
|
||||
public function getUserInfo()
|
||||
{
|
||||
$data = $this->_user->toArray();
|
||||
$allowFields = $this->getAllowFields();
|
||||
$userInfo = array_intersect_key($data, array_flip($allowFields));
|
||||
$userInfo = array_merge($userInfo, ['token' => $this->_token]);
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取允许输出的字段
|
||||
* @return array
|
||||
*/
|
||||
public function getAllowFields()
|
||||
{
|
||||
return $this->allowFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取User模型
|
||||
* @return Member
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否登录
|
||||
* @return boolean
|
||||
*/
|
||||
public function isLogin()
|
||||
{
|
||||
if ($this->_isLogin) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Token
|
||||
* @return string
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->_token;
|
||||
}
|
||||
}
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* Api用户服务门面
|
||||
* @package plugin\core\service
|
||||
* @method static mixed init($token) 初始化
|
||||
* @method static mixed getError() 获取错误信息
|
||||
* @method static mixed emailRegLogin($param) 邮箱密码注册登录
|
||||
* @method static mixed logout() 退出登录
|
||||
* @method static mixed getUserInfo() 获取登录用户信息
|
||||
* @method static mixed getUser() 获取User模型
|
||||
* @method static mixed isLogin() 获取登录状态
|
||||
* @method static mixed getToken() 获取token
|
||||
* @method static mixed getAllowFields() 允许输出的字段
|
||||
*/
|
||||
class MemberServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Member::class;
|
||||
}
|
||||
}
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
这里面写插件提供的服务
|
||||
一个服务,一般由三个文件组成
|
||||
- 服务具体实现者 这个类无需继承任何基类,只需要实现服务的具体方法
|
||||
- 服务提供者,也可以理解为服务注册者,将服务实现者类注册进ThinkPHP容器中,方便进行调用
|
||||
- 服务门面,为了在某些地方,不方便直接使用服务提供者的地方,能静态的访问服务实现者的方法,比如中间件中需要使用服务,那么就可能需要使用到服务门面
|
||||
|
||||
其中,以Service.php结尾的文件为服务提供者,服务提供者的类名全称会加入/config/service.php文件中,完成服务的注册
|
||||
|
||||
不移动到/app/common下了,负载均衡就全量复制到多个服务器
|
||||
Executable
+2759
File diff suppressed because it is too large
Load Diff
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\admin\bot;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class Add extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序
|
||||
protected $rule = [
|
||||
'password' => 'confirm:re_password|min:6|max:26',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'password.confirm' => '两次密码输入不相同',
|
||||
'password.min' => '密码长度不能低于6个字符',
|
||||
'password.max' => '密码长度不能高于26个字符',
|
||||
];
|
||||
}
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\admin\bot;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class Edit extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序
|
||||
protected $rule = [
|
||||
'password' => 'confirm:re_password|min:6|max:26',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'password.confirm' => '两次密码输入不相同',
|
||||
'password.min' => '密码长度不能低于6个字符',
|
||||
'password.max' => '密码长度不能高于26个字符',
|
||||
];
|
||||
}
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\admin\member;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class Add extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序
|
||||
protected $rule = [
|
||||
'password' => 'confirm:re_password|min:6|max:26',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'password.confirm' => '两次密码输入不相同',
|
||||
'password.min' => '密码长度不能低于6个字符',
|
||||
'password.max' => '密码长度不能高于26个字符',
|
||||
];
|
||||
}
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\admin\member;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class Edit extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序
|
||||
protected $rule = [
|
||||
'password' => 'confirm:re_password|min:6|max:26',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'password.confirm' => '两次密码输入不相同',
|
||||
'password.min' => '密码长度不能低于6个字符',
|
||||
'password.max' => '密码长度不能高于26个字符',
|
||||
];
|
||||
}
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\admin\user;
|
||||
|
||||
use app\model\admin\User;
|
||||
use think\Validate;
|
||||
|
||||
class Add extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序
|
||||
protected $rule = [
|
||||
'username' => 'require|length:2,30|checkUsername:',
|
||||
'nickname' => 'require|length:2,30|checkNickname:',
|
||||
'password' => 'require|length:6,30|confirm:re_password',
|
||||
'is_super_manager' => 'require',
|
||||
'status' => 'require',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'username.require' => '用户名不能为空',
|
||||
'username.length' => '用户名长度2-30',
|
||||
'nickname.require' => '昵称不能为空',
|
||||
'nickname.length' => '昵称长度2-30',
|
||||
'password.require' => '密码不能为空',
|
||||
'password.length' => '密码长度6-30',
|
||||
'password.confirm' => '两次密码输入不相同',
|
||||
'is_super_manager.require' => '请设置用户是否为超级管理员',
|
||||
'status.require' => '请设置账号的状态',
|
||||
];
|
||||
|
||||
//验证用户名的唯一性
|
||||
protected function checkUsername($username, $rule, $data){
|
||||
$userId = User::getFieldByUsername($username, 'id');
|
||||
if($userId){
|
||||
return '用户名已存在';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//验证昵称的唯一性
|
||||
protected function checkNickname($nickname, $rule, $data){
|
||||
$userId = User::getFieldByUsername($nickname, 'id');
|
||||
if($userId){
|
||||
return '昵称已存在';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\admin\user;
|
||||
|
||||
use app\model\admin\User;
|
||||
use think\Validate;
|
||||
|
||||
class Edit extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序
|
||||
protected $rule = [
|
||||
'id' => 'require|checkId:',
|
||||
'username' => 'require|length:2,30|checkUsername:',
|
||||
'nickname' => 'require|length:2,30',
|
||||
'password' => 'length:6,30|confirm:re_password',
|
||||
'is_super_manager' => 'require',
|
||||
'status' => 'require',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'username.require' => '用户名不能为空',
|
||||
'username.length' => '用户名长度2-30',
|
||||
'nickname.require' => '昵称不能为空',
|
||||
'nickname.length' => '昵称长度2-30',
|
||||
'password.length' => '密码长度6-30',
|
||||
'password.confirm' => '两次密码输入不相同',
|
||||
'is_super_manager.require' => '请设置用户是否为超级管理员',
|
||||
'status.require' => '请设置账号的状态',
|
||||
];
|
||||
|
||||
public function checkId($id, $rule, $data)
|
||||
{
|
||||
if ($id == 1) {
|
||||
if ($data['is_super_manager'] == 2) {
|
||||
return '不允许将初始化用户编辑成非超级管理员';
|
||||
}
|
||||
if ($data['status'] == 2) {
|
||||
return '不允许禁用初始化用户';
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//验证用户名的唯一性
|
||||
protected function checkUsername($username, $rule, $data){
|
||||
$userId = User::getFieldByUsername($username,'id');
|
||||
if($userId && $userId != $data['id']){
|
||||
return '用户名已存在';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\admin\user;
|
||||
|
||||
use app\model\admin\User;
|
||||
use app\service\ConfServiceFacade;
|
||||
use laytp\library\Str;
|
||||
use think\facade\Config;
|
||||
use think\Validate;
|
||||
|
||||
class Login extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序,比如这里,会先检测code验证码的正确性
|
||||
protected $rule = [
|
||||
'verify_code' => 'checkVerifyCode:',
|
||||
'username' => 'require',
|
||||
'password' => 'require|checkPassword:',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'username.require' => '用户名不能为空',
|
||||
'password.require' => '密码不能为空',
|
||||
];
|
||||
|
||||
//自定义验证码检验方法
|
||||
protected function checkVerifyCode($verifyCode)
|
||||
{
|
||||
if(ConfServiceFacade::get("system.basic.loginNeedCaptcha") == 1){
|
||||
if (!captcha_check($verifyCode)) {
|
||||
return '验证码错误';
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//自定义密码检验方法
|
||||
protected function checkPassword($password, $rule, $data)
|
||||
{
|
||||
$username = $data['username'];
|
||||
$user = User::where('username', '=', $username)->find();
|
||||
if (!$user) {
|
||||
return '用户名或密码错误';
|
||||
}
|
||||
|
||||
$passwordHash = $user->password;
|
||||
if (!Str::checkPassword($password, $passwordHash)) {
|
||||
return '用户名或密码错误';
|
||||
}
|
||||
|
||||
$status = $user->status;
|
||||
if ($status == 2) {
|
||||
return '用户已被禁用,请联系管理员';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\admin\user;
|
||||
|
||||
use app\model\admin\User;
|
||||
use think\Validate;
|
||||
|
||||
class singleEdit extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序
|
||||
protected $rule = [
|
||||
'id' => 'require',
|
||||
'nickname' => 'require|length:2,30',
|
||||
'old_password' => 'length:6,30|checkOldPassword:',
|
||||
'password' => 'length:6,30|confirm:re_password',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'id.require' => 'ID不能为空',
|
||||
'nickname.require' => '昵称不能为空',
|
||||
'nickname.length' => '昵称长度2-30',
|
||||
'old_password.length' => '旧密码长度6-30',
|
||||
'password.length' => '新密码长度6-30',
|
||||
'password.confirm' => '两次新密码输入不相同',
|
||||
];
|
||||
|
||||
//验证旧密码是否正确
|
||||
protected function checkOldPassword($oldPassword, $rule, $data){
|
||||
$passwordHash = User::getFieldById($data['id'], 'password');
|
||||
if(!password_verify(md5($oldPassword), $passwordHash)){
|
||||
return '旧密码错误';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\api\member;
|
||||
|
||||
//邮箱密码登录验证器
|
||||
use app\model\Member;
|
||||
use laytp\library\Str;
|
||||
use think\Validate;
|
||||
|
||||
class EmailLogin extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序,比如这里,会先检测code验证码的正确性
|
||||
protected $rule = [
|
||||
'email' => 'require|email',
|
||||
'password' => 'require|length:6,26|checkPassword:',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'email.require' => '邮箱不能为空',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'password.require' => '密码不能为空',
|
||||
'password.length' => '密码长度需要6到26个字符',
|
||||
];
|
||||
|
||||
//自定义密码检验方法
|
||||
protected function checkPassword($password, $rule, $data)
|
||||
{
|
||||
$email = $data['email'];
|
||||
$user = new Member();
|
||||
$passwordHash = $user->getFieldByEmail($email, 'password');
|
||||
return (!Str::checkPassword($password, $passwordHash)) ? '账户信息错误' : true;
|
||||
}
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace app\validate\api\member;
|
||||
|
||||
//邮箱密码注册验证器
|
||||
use app\model\Member;
|
||||
use think\Validate;
|
||||
|
||||
class EmailReg extends Validate
|
||||
{
|
||||
//数组顺序就是检测的顺序,比如这里,会先检测code验证码的正确性
|
||||
protected $rule = [
|
||||
'email' => 'require|email|checkEmail:',
|
||||
'password' => 'require|length:6,26|confirm:repassword',
|
||||
'repassword' => 'require|length:6,26',
|
||||
];
|
||||
|
||||
//定义内置方法检验失败后返回的字符
|
||||
protected $message = [
|
||||
'email.require' => '邮箱不能为空',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'password.require' => '密码不能为空',
|
||||
'password.length' => '密码长度需要6到26个字符',
|
||||
'password.confirm' => '两次密码输入不相同',
|
||||
'repassword.require' => '重复密码不能为空',
|
||||
'repassword.length' => '重复密码长度需要6到26个字符',
|
||||
];
|
||||
|
||||
protected function checkEmail($email, $rule, $data){
|
||||
$exist = Member::getFieldByEmail($email,'id');
|
||||
if($exist){
|
||||
return '邮箱已存在';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
# 记录使用过的命令
|
||||
```
|
||||
#安装composer
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
mv composer.phar /usr/local/bin/composer
|
||||
#composer镜像使用阿里云的镜像
|
||||
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
|
||||
#安装tp6.x稳定版
|
||||
composer create-project topthink/think laytp2.0
|
||||
#更新tp版本
|
||||
composer update topthink/framework
|
||||
#安装tp多应用模式扩展
|
||||
composer require topthink/think-multi-app
|
||||
#安装数据库迁移工具
|
||||
composer require topthink/think-migration
|
||||
#创建laytp数据库迁移文件
|
||||
php think migrate:create Laytp
|
||||
#执行tp数据库迁移文件
|
||||
php think migrate:run
|
||||
#创建插入数据库数据文件,用于初始化数据库的数据
|
||||
php think seed:create Laytp
|
||||
#执行数据插入
|
||||
php think seed:run
|
||||
#安装tp模板引擎,一键生成Api文档需要使用到
|
||||
composer require topthink/think-view
|
||||
#验证码库
|
||||
composer require topthink/think-captcha
|
||||
#ide助手
|
||||
composer require topthink/think-ide-helper
|
||||
|
||||
##用户安装过程
|
||||
#安装composer库
|
||||
composer update
|
||||
#修改database.php或者.env文件,配置数据库连接
|
||||
#执行数据库迁移命令,创建数据表,给数据表设置默认数据
|
||||
php think migrate:run
|
||||
#配置nginx,以local.laytp2.com域名为例
|
||||
1.本地hosts增加如下一行
|
||||
127.0.0.1 local.laytp2.com
|
||||
2.修改nginx虚拟主机目录,增加local.laytp2.com.conf文件,文件内容如下:
|
||||
-nginx配置内容
|
||||
|
||||
```
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "topthink/think",
|
||||
"description": "the new thinkphp framework",
|
||||
"type": "project",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"thinkphp",
|
||||
"ORM"
|
||||
],
|
||||
"homepage": "http://thinkphp.cn/",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "liu21st",
|
||||
"email": "liu21st@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "yunwuxin",
|
||||
"email": "448901948@qq.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1.0",
|
||||
"topthink/framework": "^6.0.0",
|
||||
"topthink/think-orm": "^2.0",
|
||||
"topthink/think-captcha": "^3.0",
|
||||
"topthink/think-migration": "^3.0",
|
||||
"topthink/think-view": "^1.0",
|
||||
"alibabacloud/sdk": "^1.8",
|
||||
"aliyuncs/oss-sdk-php": "^2.4",
|
||||
"qiniu/php-sdk": "^7.4",
|
||||
"topthink/think-filesystem": "^2.0",
|
||||
"cpliakas/git-wrapper": "^3.1",
|
||||
"dh2y/think-qrcode": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/var-dumper": "^4.2",
|
||||
"topthink/think-trace":"^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"app\\": "app",
|
||||
"plugin\\": "plugin"
|
||||
},
|
||||
"psr-0": {
|
||||
"": "extend/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": "dist"
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"@php think service:discover",
|
||||
"@php think vendor:publish"
|
||||
]
|
||||
}
|
||||
}
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
laytp.php
|
||||
!.gitignore
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 应用地址
|
||||
'app_host' => env('app.host', ''),
|
||||
// 应用的命名空间
|
||||
'app_namespace' => '',
|
||||
// 是否启用路由
|
||||
'with_route' => true,
|
||||
// 默认应用
|
||||
'default_app' => 'index',
|
||||
// 默认时区
|
||||
'default_timezone' => 'Asia/Shanghai',
|
||||
|
||||
// 应用映射(自动多应用模式有效)
|
||||
'app_map' => [],
|
||||
// 域名绑定(自动多应用模式有效)
|
||||
'domain_bind' => [],
|
||||
// 禁止URL访问的应用列表(自动多应用模式有效)
|
||||
'deny_app_list' => [],
|
||||
|
||||
// 异常页面的模板文件
|
||||
'exception_tmpl' => env('APP_DEBUG') ? app()->getThinkPath() . 'tpl/think_exception.tpl' : app()->getAppPath() . 'exception/laytp.tpl',
|
||||
|
||||
// 错误显示信息,非调试模式有效
|
||||
'error_message' => '页面错误!请稍后再试~',
|
||||
// 显示错误信息
|
||||
'show_error_msg' => false,
|
||||
];
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 缓存设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 默认缓存驱动
|
||||
'default' => env('cache.driver', 'file'),
|
||||
|
||||
// 缓存连接方式配置
|
||||
'stores' => [
|
||||
'file' => [
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
'path' => '',
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
// 缓存标签前缀
|
||||
'tag_prefix' => 'tag:',
|
||||
// 序列化机制 例如 ['serialize', 'unserialize']
|
||||
'serialize' => [],
|
||||
],
|
||||
// 'redis' => [
|
||||
// 'type' => 'redis',
|
||||
// ]
|
||||
// 更多的缓存连接
|
||||
],
|
||||
];
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Captcha配置文件
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
//验证码位数
|
||||
'length' => 5,
|
||||
// 验证码字符集合
|
||||
'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY',
|
||||
// 验证码过期时间
|
||||
'expire' => 1800,
|
||||
// 是否使用中文验证码
|
||||
'useZh' => false,
|
||||
// 是否使用算术验证码
|
||||
'math' => false,
|
||||
// 是否使用背景图
|
||||
'useImgBg' => false,
|
||||
//验证码字符大小
|
||||
'fontSize' => 25,
|
||||
// 是否使用混淆曲线
|
||||
'useCurve' => true,
|
||||
//是否添加杂点
|
||||
'useNoise' => true,
|
||||
// 验证码字体 不设置则随机
|
||||
'fontttf' => '',
|
||||
//背景颜色
|
||||
'bg' => [243, 251, 254],
|
||||
// 验证码图片高度
|
||||
'imageH' => 0,
|
||||
// 验证码图片宽度
|
||||
'imageW' => 0,
|
||||
|
||||
// 添加额外的验证码设置
|
||||
'login' => [
|
||||
'length' => 4,
|
||||
'math' => true,
|
||||
],
|
||||
];
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 控制台配置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 指令定义
|
||||
'commands' => [
|
||||
],
|
||||
];
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Cookie设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => false,
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => false,
|
||||
// samesite 设置,支持 'strict' 'lax'
|
||||
'samesite' => '',
|
||||
];
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
// 默认使用的数据库连接配置
|
||||
'default' => env('database.driver', 'mysql'),
|
||||
|
||||
// 自定义时间查询规则
|
||||
'time_query_rule' => [],
|
||||
|
||||
// 自动写入时间戳字段
|
||||
// true为自动识别类型 false关闭
|
||||
// 字符串则明确指定时间字段类型 支持 int timestamp datetime date
|
||||
'auto_timestamp' => true,
|
||||
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
|
||||
// 数据库连接配置信息
|
||||
'connections' => [
|
||||
'mysql' => [
|
||||
// 数据库类型
|
||||
'type' => env('database.type', 'mysql'),
|
||||
// 服务器地址
|
||||
'hostname' => env('database.hostname', '127.0.0.1'),
|
||||
// 数据库名
|
||||
'database' => env('database.database', ''),
|
||||
// 用户名
|
||||
'username' => env('database.username', 'root'),
|
||||
// 密码
|
||||
'password' => env('database.password', ''),
|
||||
// 端口
|
||||
'hostport' => env('database.hostport', '3306'),
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => env('database.charset', 'utf8'),
|
||||
// 数据库表前缀
|
||||
'prefix' => env('database.prefix', 'lt_'),
|
||||
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 是否需要断线重连
|
||||
'break_reconnect' => false,
|
||||
// 监听SQL
|
||||
'trigger_sql' => env('app_debug', true),
|
||||
// 开启字段缓存
|
||||
'fields_cache' => false,
|
||||
],
|
||||
|
||||
// 更多的数据库配置信息
|
||||
],
|
||||
];
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
// 默认磁盘
|
||||
'default' => env('filesystem.driver', 'public'),
|
||||
// 磁盘列表
|
||||
'disks' => [
|
||||
'local' => [
|
||||
'type' => 'local',
|
||||
'root' => app()->getRuntimePath() . 'storage',
|
||||
],
|
||||
'public' => [
|
||||
// 磁盘类型
|
||||
'type' => 'local',
|
||||
// 磁盘路径
|
||||
'root' => app()->getRootPath() . 'public/static/storage',
|
||||
// 磁盘路径对应的外部URL路径
|
||||
'url' => '/static/storage',
|
||||
// 可见性
|
||||
'visibility' => 'public',
|
||||
],
|
||||
// 更多的磁盘配置信息
|
||||
],
|
||||
];
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 多语言设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 默认语言
|
||||
'default_lang' => env('lang.default_lang', 'zh-cn'),
|
||||
// 允许的语言列表
|
||||
'allow_lang_list' => [],
|
||||
// 多语言自动侦测变量名
|
||||
'detect_var' => 'lang',
|
||||
// 是否使用Cookie记录
|
||||
'use_cookie' => true,
|
||||
// 多语言cookie变量
|
||||
'cookie_var' => 'think_lang',
|
||||
// 多语言header变量
|
||||
'header_var' => 'think-lang',
|
||||
// 扩展语言包
|
||||
'extend_list' => [],
|
||||
// Accept-Language转义为对应语言包名称
|
||||
'accept_language' => [
|
||||
'zh-hans-cn' => 'zh-cn',
|
||||
],
|
||||
// 是否支持语言分组
|
||||
'allow_group' => false,
|
||||
];
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 日志设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 默认日志记录通道
|
||||
'default' => env('log.channel', 'file'),
|
||||
// 日志记录级别
|
||||
'level' => [],
|
||||
// 日志类型记录的通道 ['error'=>'email',...]
|
||||
'type_channel' => [],
|
||||
// 关闭全局日志写入
|
||||
'close' => false,
|
||||
// 全局日志处理 支持闭包
|
||||
'processor' => null,
|
||||
|
||||
// 日志通道列表
|
||||
'channels' => [
|
||||
'file' => [
|
||||
// 日志记录方式
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
'path' => app()->getRuntimePath() . '/log',
|
||||
// 单文件日志写入
|
||||
'single' => false,
|
||||
// 独立日志级别
|
||||
'apart_level' => [],
|
||||
// 最大日志文件数量
|
||||
'max_files' => 0,
|
||||
// 使用JSON格式记录
|
||||
'json' => false,
|
||||
// 日志处理
|
||||
'processor' => null,
|
||||
// 关闭通道日志写入
|
||||
'close' => false,
|
||||
// 日志输出格式化
|
||||
'format' => '[%s][%s] %s',
|
||||
// 是否实时写入
|
||||
'realtime_write' => false,
|
||||
],
|
||||
// 其它日志通道配置
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 分页设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 每页条数
|
||||
'limit' => 10
|
||||
];
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
return array (
|
||||
'apiUrl' => 'https://api.laytp.com',
|
||||
'installed' =>
|
||||
array (
|
||||
0 => 'apidoc',
|
||||
1 => 'meditor',
|
||||
),
|
||||
'installedEditor' =>
|
||||
array (
|
||||
0 => 'meditor',
|
||||
),
|
||||
);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user