Compare commits

...

No commits in common. "v3.0.4" and "master" have entirely different histories.

333 changed files with 7127 additions and 44911 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai [DATABASE] TYPE = mysql HOSTNAME = 127.0.0.1 DATABASE = apiadmin USERNAME = root PASSWORD = 123456 HOSTPORT = 3306 CHARSET = utf8 DEBUG = true [LANG] default_lang = zh-cn

6
.gitignore vendored
View File

@ -1 +1,5 @@
.idea/ /.idea
/.vscode
/vendor
*.log
composer.lock

42
.travis.yml Normal file
View File

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

50
DISCLAIMER.md Normal file
View File

@ -0,0 +1,50 @@
<div align="center"><h3>ApiAdmin 开源框架法律声明与授权条款</h3></div>
```
任何用户在使用由 ApiAdmin 技术开发团队以下简称「本团队」研发的系列框架以下简称「ApiAdmin 通用权限开发框架」)前,请您仔细阅读并透彻理解本声明。若您一旦使用 ApiAdmin 通用权限开发框架,您的使用行为即被视为对本声明全部内容的认可和接受。
```
**免责声明**
1. ApiAdmin 通用权限开发框架仅属于快速开发框架并不涉及具体业务应用场景,其尊重并保护所有用户的个人隐私权,不窃取任何用户计算机中的信息,更不具备用户数据存储等网络传输功能。
2. 任何单位或个人因下载使用 ApiAdmin 通用权限开发框架而产生的任何意外、疏忽、合约毁坏、诽谤、数据丢失、系统故障、服务中断、经济损失、商誉损害、版权或知识产权侵犯及其造成的损失 (包括但不限于直接、间接、附带或衍生的损失等),本团队不承担任何法律责任。
3. 任何单位或个人在阅读本免责声明后,应在开源许可证所允许的范围内进行合法的发布、传播和使用 ApiAdmin 通用权限开发框架等行为,若违反本免责声明条款或违反法律法规所造成的法律责任(包括但不限于民事赔偿和刑事责任),由违约者自行承担,本团队不承担任何法律责任。
4. 本团队对 ApiAdmin 通用权限开发框架拥有知识产权(包括但不限于商标权、专利权、著作权、商业秘密等),上述产品均受到相关法律法规的保护。任何单位或个人不得在未经本团队书面授权的情况下对 ApiAdmin 通用权限开发框架本身申请相关的知识产权。
5. 使用者必须在适用法律和法规允许的范围内正确使用 ApiAdmin严禁将其用于非法、欺诈、恶意或侵犯他人合法权益的目的亦不将运用于任何违反我国法律法规的平台。若发现任何未经授权或违法使用本框架的情况我们将依据相关法律追究责任并有权采取必要的措施予以制止。
6. 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动。任何基于本项目二次开发而产生的一切法律纠纷和责任,均与作者无关。
7. 用户明确并同意本声明条款列举的全部内容,对使用 ApiAdmin 通用权限开发框架可能存在的风险和相关后果将完全由用户自行承担,本团队不承担任何法律责任。
8. 如果本声明的任何部分被认为无效或不可执行,则该部分将被解释为反映本团队的初衷,其余部分仍具有完全效力。不可执行的部分声明,并不构成我们放弃执行该声明的权利。
**授权条款**
ApiAdmin 是一个基于 .NET 构建的开源通用权限开发框架,您可以在 MIT 许可证的条款下自由地使用、复制、分发、修改和贡献此项目。这意味着您可以根据自身需求和法律要求选择更适合您的许可条款:
1. **MIT 许可证**:另一种选择是遵循 MIT 许可协议,详情参见 [LICENSE-MIT](https://gitee.com/apiadmin/ApiAdmin/blob/master/LICENSE)。
**责任限制**
ApiAdmin 团队及社区成员尽力提供完善的文档和技术支持,但并不对因使用框架过程中产生的问题提供绝对的解决方案保障。所有用户提供或推荐的解决方案、代码片段、最佳实践等均“按原样”提供,使用者须自行判断并承担使用后的一切风险。
**法律义务与合规性**
使用者在利用 ApiAdmin 开发应用程序时,负有确保其应用程序符合所有适用法律、行业标准以及信息安全规范的全部责任。使用者应自行评估并确保其产品不会滥用框架功能,尤其是防止被用于潜在有害或不道德的目的。
**技术交流**
ApiAdmin 交流群提供的支持和资源旨在辅助开发过程,但不应视为全面的技术指导或保证。我们鼓励用户积极参与开源过程,同时也提醒用户充分测试其开发成果,确保其安全性和稳定性。
**变更说明**
本团队有权随时对声明条款及附件内容进行单方面的变更或更新,变更或更新后立即自动生效,无需另行单独通知您或任何第三方;若您在声明内容公告变更后继续使用的,表示您已充分阅读、理解并接受修改后的声明内容。

204
LICENSE
View File

@ -1,191 +1,21 @@
Apache License MIT License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION Copyright (c) 2021 Zhao
1. Definitions. Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
"License" shall mean the terms and conditions for use, reproduction, and The above copyright notice and this permission notice shall be included in all
distribution as defined by Sections 1 through 9 of this document. copies or substantial portions of the Software.
"Licensor" shall mean the copyright owner or entity authorized by the copyright THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
owner that is granting the License. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
"Legal Entity" shall mean the union of the acting entity and all other entities AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
that control, are controlled by, or are under common control with that entity. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
For the purposes of this definition, "control" means (i) the power, direct or OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
indirect, to cause the direction or management of such entity, whether by SOFTWARE.
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "{}" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright 2018 Zhao
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -3,12 +3,57 @@
# ApiAdmin # ApiAdmin
[![ApiAdmin](https://img.shields.io/hexpm/l/plug.svg)](http://www.apiadmin.org/) [![ApiAdmin](https://img.shields.io/hexpm/l/plug.svg)](http://www.apiadmin.org/)
[![ApiAdmin](https://img.shields.io/badge/release-v3.0.4-blue.svg)](http://www.apiadmin.org/) [![ApiAdmin](https://img.shields.io/badge/release-5.0.0-blue.svg)](http://www.apiadmin.org/)
[![ApiAdmin](https://img.shields.io/wercker/ci/wercker/docs.svg)](http://www.apiadmin.org/) [![ApiAdmin](https://img.shields.io/badge/build-passing-brightgreen.svg)](http://www.apiadmin.org/)
[![ApiAdmin](https://img.shields.io/badge/ApiAdmin-v3.0.4-brightgreen.svg)](http://www.apiadmin.org/) [![ApiAdmin](https://img.shields.io/badge/ApiAdmin-5.0.0-brightgreen.svg)](http://www.apiadmin.org/)
## 特别推荐
博主新开的开源项目[EasyTiktok](https://gitee.com/apiadmin/tiktok)如果你正在做抖音开发相信你会需要它目前项目还是dev状态如果你有啥意见或者遇到BUG及时提交我会随时关注及时更新
## 前端页面 ## 前端页面
ApiAdmin3.0是一个前后端完全分离的项目前端采用Vue构建如需要可视化配置的请移步[ApiAdmin-WEB](https://gitee.com/apiadmin/ApiAdmin-WEB) ApiAdmin5.0是一个前后端完全分离的项目前端采用Vue构建如需要可视化配置的请移步[ApiAdmin-WEB](https://gitee.com/apiadmin/ApiAdmin-WEB)
## 快速安装
> 第一步:安装代码
```
composer create-project apiadmin/apiadmin
```
```
你也可以:先获取基础代码 git clone https://gitee.com/apiadmin/ApiAdmin.git 再使用composer安装 composer install
```
> 第二步:检测环境以及配置数据库
```
php think apiadmin:install
```
> 第三步:完成数据迁移
```
php think migrate:run
* 如出现报错There are no commands defined in the "migrate" namespace.
* 请先更新下think版本composer update topthink/framework
* 再执行php think migrate:run
* 特别鸣谢:@孙晔华
```
> 第四步:构建后端路由
```
php think apiadmin:adminRouter
```
> 第五步:获取管理后台账号密码
```
cat install/lock.ini
```
## 灵 感 ## 灵 感
@ -25,15 +70,14 @@ ApiAdmin3.0是一个前后端完全分离的项目前端采用Vue构建
**系统需求** **系统需求**
- PHP >= 5.6 - PHP >= 7.2.5
- MySQL >= 5.5.3 - MySQL >= 5.5.3
- Redis - Redis
**项目构成** **项目构成**
- ThinkPHP v5.0.11 - ThinkPHP v6.0.*
- Vue 2.0 - Vue 2.*
- semanticUI
- ... - ...
**功能简介** **功能简介**
@ -44,8 +88,7 @@ ApiAdmin3.0是一个前后端完全分离的项目前端采用Vue构建
4. 灵活的参数规则设定 4. 灵活的参数规则设定
5. 支持三方Api无缝融合 5. 支持三方Api无缝融合
6. 本地二次开发友好 6. 本地二次开发友好
7. 使用Datatables完成数据JS加载 7. ...
8. ...
``` ```
ApiAdminPHP部分 ApiAdminPHP部分
@ -82,8 +125,8 @@ ApiAdmin3.0是一个前后端完全分离的项目前端采用Vue构建
## 鸣谢 ## 鸣谢
ApiAdmin走到今天也正式迈入3.0时代了同时ApiAdmin也迎来了它的一岁生日我们怀着激动的心情迎来这次发布。在新版本发布之际我们真诚的感谢从1.0到2.0陪我们一路走来的朋友们。感谢你们的支持和信任!当然也感谢#开源中国#给大陆本土开源提供这样一个优秀的平台 ApiAdmin走到今天也正式迈入4.1时代了我们怀着激动的心情迎来这次发布。在新版本发布之际我们真诚的感谢从1.0到5.0陪我们一路走来的朋友们。感谢你们的支持和信任!当然也感谢#开源中国#给大陆本土开源提供这样一个优秀的平台
## 附:升级指南 ## 附:升级指南
很抱歉的告诉大家,虽然我们尽可能的和往期版本进行了兼容,但是,由于整体架构变化很大,所以想要零成本升级有点困难。我们建议大家可以使用3.0做新接口慢慢的将2.0版本的接口移植到3.0。 很抱歉的告诉大家,虽然我们尽可能的和往期版本进行了兼容,但是,由于整体架构变化很大,所以想要零成本升级有点困难。我们建议大家可以使用5.0做新接口慢慢的将4.1版本的接口移植到5.0。

22
app/AppService.php Normal file
View File

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

94
app/BaseController.php Normal file
View File

@ -0,0 +1,94 @@
<?php
declare (strict_types = 1);
namespace app;
use think\App;
use think\exception\ValidateException;
use think\Validate;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
}

58
app/ExceptionHandle.php Normal file
View File

@ -0,0 +1,58 @@
<?php
namespace app;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 添加自定义异常处理机制
// 其他错误交给系统处理
return parent::render($request, $e)->header(config('apiadmin.CROSS_DOMAIN'));
}
}

8
app/Request.php Normal file
View File

@ -0,0 +1,8 @@
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
}

26
app/command/ApiAdmin.php Normal file
View File

@ -0,0 +1,26 @@
<?php
declare (strict_types=1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
class ApiAdmin extends Command {
protected function configure() {
// 指令配置
$this->setName('apiadmin:test')
->setDescription('ApiAdmin默认命令行脚本主要用于内部测试和研究');
}
protected function execute(Input $input, Output $output): void {
$a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
foreach ($a as $k => &$v) {
if ($v === 5) {
$v = 55;
}
}
dump($a);
}
}

View File

@ -0,0 +1,112 @@
<?php
declare (strict_types=1);
namespace app\command;
use app\util\AutoBuild;
use think\console\Command;
use think\console\Input;
use think\console\Output;
class AutoBuildFile extends Command {
protected function configure() {
// 指令配置
$this->setName('apiadmin:autoBuild')->setDescription('ApiAdmin自动构建文件');
}
/**
* 自动构建
* @param Input $input
* @param Output $output
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
protected function execute(Input $input, Output $output): void {
$config = $this->parseConfig($output);
(new AutoBuild())->run($config);
$output->info('Build files successful');
}
/**
* 获取cli配置输入
* @param $output
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function parseConfig($output): array {
$output->comment('Do you need to build a control? 1 or 0 (default 1)');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['control'] = strlen($input) ? $input : 1;
if ($dsn['control']) {
$dsn['name'] = $this->getControlName($output);
$output->comment('Please choose module (1:admin;2:api, default 1):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['module'] = strlen($input) ? $input : 1;
$output->comment('Do you need to build a menu? 1 or 0 (default 1):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['menu'] = strlen($input) ? $input : 1;
if ($dsn['menu']) {
$output->comment('Please input menu fid (default 0):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['fid'] = strlen($input) ? $input : 0;
$output->comment('Do you need to create a route? 1 or 0 (default 0):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['route'] = strlen($input) ? $input : 0;
}
}
$output->comment('Do you need to build a model? 1 or 0 (default 0):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['model'] = strlen($input) ? $input : 0;
if ($dsn['model']) {
$dsn['modelName'] = $this->getModelName($output);
$output->comment('Do you need to create a table? 1 or 0 (default 0):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['table'] = strlen($input) ? $input : 0;
}
return $dsn;
}
/**
* 递归获取控制器名称
* @param $output
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function getModelName($output): string {
$output->comment('Please input model name');
$input = trim(fgets(fopen('php://stdin', 'r')));
if ($input) {
return $input;
} else {
return $this->getModelName($output);
}
}
/**
* 递归获取控制器名称
* @param $output
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function getControlName($output): string {
$output->comment('Please input controller name');
$input = trim(fgets(fopen('php://stdin', 'r')));
if ($input) {
return $input;
} else {
return $this->getControlName($output);
}
}
}

View File

@ -0,0 +1,31 @@
<?php
declare (strict_types=1);
namespace app\command;
use app\util\RouterTool;
use think\console\Command;
use think\console\Input;
use think\console\Output;
class FreshAdminRouter extends Command {
protected function configure(): void {
// 指令配置
$this->setName('apiadmin:adminRouter')->setDescription('自动构建后端路由');
}
/**
* php think apiadmin:adminRouter
* @param Input $input
* @param Output $output
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
protected function execute(Input $input, Output $output): void {
RouterTool::buildAdminRouter();
$output->info('路由构建成功');
}
}

120
app/command/Install.php Normal file
View File

@ -0,0 +1,120 @@
<?php
declare (strict_types=1);
namespace app\command;
use app\util\Strs;
use think\console\Command;
use think\console\Input;
use think\console\Output;
class Install extends Command {
protected function configure(): void {
$this->setName('apiadmin:install')->setDescription('ApiAdmin安装脚本');
}
/**
* php think apiadmin:install --db mysql://root:123456@127.0.0.1:3306/apiadmin#utf8mb4
* @param Input $input
* @param Output $output
* @return int|void|null
* @throws \think\Exception
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
protected function execute(Input $input, Output $output) {
$tplPath = root_path() . 'install' . DIRECTORY_SEPARATOR;
$lockFile = $tplPath . 'lock.ini';
if (file_exists($lockFile)) {
$output->highlight("You have already installed it, please do not reinstall");
$output->highlight("If necessary, delete the install/lock.ini and try again");
exit;
}
if (!is_writable($tplPath)) {
$output->highlight($tplPath . 'cannot be modified');
exit;
}
$tempPath = runtime_path();
if (!is_writable($tempPath)) {
$output->highlight($tempPath . 'cannot be modified');
exit;
}
if (!extension_loaded('redis')) {
$output->highlight('Redis extension missing');
exit;
}
try {
$options = $this->parseDsnConfig($output);
$dsn = "{$options['type']}:dbname={$options['database']};host={$options['hostname']};port={$options['hostport']};charset={$options['charset']}";
new \PDO($dsn, $options['username'], $options['password']);
//处理数据库配置文件
$dbConf = str_replace([
'{$DB_TYPE}', '{$DB_HOST}', '{$DB_NAME}',
'{$DB_USER}', '{$DB_PASSWORD}', '{$DB_PORT}',
'{$DB_CHAR}'
], [
$options['type'], $options['hostname'], $options['database'],
$options['username'], $options['password'], $options['hostport'],
$options['charset']
], file_get_contents($tplPath . 'db.tpl'));
file_put_contents(root_path() . '.env', $dbConf);
$output->info('Database configuration updated successfully');
//处理ApiAdmin自定义配置
$authKey = substr(Strs::uuid(), 1, -1);
$apiConf = str_replace('{$AUTH_KEY}', $authKey, file_get_contents($tplPath . 'apiadmin.tpl'));
file_put_contents(config_path() . 'apiadmin.php', $apiConf);
$output->info('ApiAdmin configuration updated successfully');
//生成lock文件并且写入用户名密码
file_put_contents($lockFile, $authKey);
$output->info('Lock file initialization successful');
} catch (\PDOException $e) {
$output->highlight($e->getMessage());
}
}
/**
* DSN解析
* @param $output
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function parseDsnConfig($output): array {
$output->comment('please input database type(default mysql):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['type'] = $input ? $input : 'mysql';
$output->comment('please input database username(default root):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['username'] = $input ? $input : 'root';
$output->comment('please input database password(default 123456):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['password'] = $input ? $input : '123456';
$output->comment('please input database host(default 127.0.0.1):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['hostname'] = $input ? $input : '127.0.0.1';
$output->comment('please input database port(default 3306):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['hostport'] = $input ? $input : '3306';
$output->comment('please input database name(default apiadmin):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['database'] = $input ? $input : 'apiadmin';
$output->comment('please input database charset(default utf8mb4):');
$input = trim(fgets(fopen('php://stdin', 'r')));
$dsn['charset'] = $input ? $input : 'utf8mb4';
return $dsn;
}
}

2
app/common.php Normal file
View File

@ -0,0 +1,2 @@
<?php
// 应用公共文件

View File

@ -0,0 +1,218 @@
<?php
declare (strict_types=1);
/**
* 应用管理
* @since 2018-02-11
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminApp;
use app\model\AdminList;
use app\model\AdminGroup;
use app\util\ReturnCode;
use app\util\Strs;
use app\util\Tools;
use think\Response;
class App extends Base {
/**
* 获取应用列表
* @return Response
* @throws \think\db\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index(): Response {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $this->request->get('page', 1);
$keywords = $this->request->get('keywords', '');
$type = $this->request->get('type', '');
$status = $this->request->get('status', '');
$obj = new AdminApp();
if (strlen($status)) {
$obj = $obj->where('app_status', $status);
}
if ($type) {
switch ($type) {
case 1:
$obj = $obj->where('app_id', $keywords);
break;
case 2:
$obj = $obj->whereLike('app_name', "%{$keywords}%");
break;
}
}
$listObj = $obj->order('app_add_time', 'DESC')->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
return $this->buildSuccess([
'list' => $listObj['data'],
'count' => $listObj['total']
]);
}
/**
* 获取AppId,AppSecret,接口列表,应用接口权限细节
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getAppInfo(): Response {
$apiArr = (new AdminList())->select();
foreach ($apiArr as $api) {
$res['apiList'][$api['group_hash']][] = $api;
}
$groupArr = (new AdminGroup())->select();
$groupArr = Tools::buildArrFromObj($groupArr);
$res['groupInfo'] = array_column($groupArr, 'name', 'hash');
$id = $this->request->get('id', 0);
if ($id) {
$appInfo = (new AdminApp())->where('id', $id)->find()->toArray();
$res['app_detail'] = json_decode($appInfo['app_api_show'], true);
} else {
$res['app_id'] = mt_rand(1, 9) . Strs::randString(7, 1);
$res['app_secret'] = Strs::randString(32);
}
return $this->buildSuccess($res);
}
/**
* 刷新APPSecret
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function refreshAppSecret(): Response {
$data['app_secret'] = Strs::randString(32);
return $this->buildSuccess($data);
}
/**
* 新增应用
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add(): Response {
$postData = $this->request->post();
$data = [
'app_id' => $postData['app_id'],
'app_secret' => $postData['app_secret'],
'app_name' => $postData['app_name'],
'app_info' => $postData['app_info'],
'app_group' => $postData['app_group'],
'app_add_time' => time(),
'app_api' => '',
'app_api_show' => ''
];
if (isset($postData['app_api']) && $postData['app_api']) {
$appApi = [];
$data['app_api_show'] = json_encode($postData['app_api']);
foreach ($postData['app_api'] as $value) {
$appApi = array_merge($appApi, $value);
}
$data['app_api'] = implode(',', $appApi);
}
$res = AdminApp::create($data);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 应用状态编辑
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus(): Response {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminApp::update([
'id' => $id,
'app_status' => $status
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
$appInfo = (new AdminApp())->where('id', $id)->find();
cache('AccessToken:Easy:' . $appInfo['app_secret'], null);
if ($oldWiki = cache('WikiLogin:' . $id)) {
cache('WikiLogin:' . $oldWiki, null);
}
return $this->buildSuccess();
}
/**
* 编辑应用
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit(): Response {
$postData = $this->request->post();
$data = [
'app_secret' => $postData['app_secret'],
'app_name' => $postData['app_name'],
'app_info' => $postData['app_info'],
'app_group' => $postData['app_group'],
'app_api' => '',
'app_api_show' => ''
];
if (isset($postData['app_api']) && $postData['app_api']) {
$appApi = [];
$data['app_api_show'] = json_encode($postData['app_api']);
foreach ($postData['app_api'] as $value) {
$appApi = array_merge($appApi, $value);
}
$data['app_api'] = implode(',', $appApi);
}
$res = AdminApp::update($data, ['id' => $postData['id']]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
$appInfo = (new AdminApp())->where('id', $postData['id'])->find();
cache('AccessToken:Easy:' . $appInfo['app_secret'], null);
if ($oldWiki = cache('WikiLogin:' . $postData['id'])) {
cache('WikiLogin:' . $oldWiki, null);
}
return $this->buildSuccess();
}
/**
* 删除应用
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del(): Response {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$appInfo = (new AdminApp())->where('id', $id)->find();
cache('AccessToken:Easy:' . $appInfo['app_secret'], null);
AdminApp::destroy($id);
if ($oldWiki = cache('WikiLogin:' . $id)) {
cache('WikiLogin:' . $oldWiki, null);
}
return $this->buildSuccess();
}
}

View File

@ -1,66 +1,66 @@
<?php <?php
declare (strict_types=1);
/** /**
* *
* @since 2018-02-11 * @since 2018-02-11
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
namespace app\admin\controller; namespace app\controller\admin;
use app\model\AdminApp;
use app\model\AdminAppGroup; use app\model\AdminAppGroup;
use app\util\ReturnCode; use app\util\ReturnCode;
use app\util\Tools; use think\Response;
class AppGroup extends Base { class AppGroup extends Base {
/** /**
* 获取应用组列表 * 获取应用组列表
* @return \think\Response
* @throws \think\db\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/ */
public function index() { public function index(): Response {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT')); $limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1); $start = $this->request->get('page', 1);
$keywords = $this->request->get('keywords', ''); $keywords = $this->request->get('keywords', '');
$type = $this->request->get('type', ''); $type = $this->request->get('type', '');
$status = $this->request->get('status', ''); $status = $this->request->get('status', '');
$where = []; $obj = new AdminAppGroup();
if ($status === '1' || $status === '0') { if (strlen($status)) {
$where['status'] = $status; $obj = $obj->where('status', $status);
} }
if ($type) { if ($type) {
switch ($type) { switch ($type) {
case 1: case 1:
$where['hash'] = $keywords; if (strlen($keywords)) {
$obj = $obj->where('hash', $keywords);
}
break; break;
case 2: case 2:
$where['name'] = ['like', "%{$keywords}%"]; $obj = $obj->whereLike('name', "%{$keywords}%");
break; break;
} }
} }
$listObj = $obj->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
$listInfo = (new AdminAppGroup())->where($where)->limit($start, $limit)->select();
$count = (new AdminAppGroup())->where($where)->count();
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([ return $this->buildSuccess([
'list' => $listInfo, 'list' => $listObj['data'],
'count' => $count 'count' => $listObj['total']
]); ]);
} }
/** /**
* 获取全部有效的应用组 * 获取全部有效的应用组
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @return Response
* @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException * @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function getAll() { public function getAll(): Response {
$listInfo = (new AdminAppGroup())->where(['status' => 1])->select(); $listInfo = (new AdminAppGroup())->where(['status' => 1])->select();
return $this->buildSuccess([ return $this->buildSuccess([
@ -70,66 +70,71 @@ class AppGroup extends Base {
/** /**
* 应用组状态编辑 * 应用组状态编辑
* @return array * @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function changeStatus() { public function changeStatus(): Response {
$id = $this->request->get('id'); $id = $this->request->get('id');
$status = $this->request->get('status'); $status = $this->request->get('status');
$res = AdminAppGroup::update([ $res = AdminAppGroup::update([
'id' => $id,
'status' => $status 'status' => $status
], [
'id' => $id
]); ]);
if ($res === false) { if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
} else {
return $this->buildSuccess([]);
} }
return $this->buildSuccess();
} }
/** /**
* 添加应用组 * 添加应用组
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/ */
public function add() { public function add(): Response {
$postData = $this->request->post(); $postData = $this->request->post();
$res = AdminAppGroup::create($postData); $res = AdminAppGroup::create($postData);
if ($res === false) { if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
} else {
return $this->buildSuccess([]);
} }
return $this->buildSuccess();
} }
/** /**
* 应用组编辑 * 应用组编辑
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/ */
public function edit() { public function edit(): Response {
$postData = $this->request->post(); $postData = $this->request->post();
$res = AdminAppGroup::update($postData); $res = AdminAppGroup::update($postData);
if ($res === false) { if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
} else {
return $this->buildSuccess([]);
} }
return $this->buildSuccess();
} }
/** /**
* 应用组删除 * 应用组删除
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/ */
public function del() { public function del(): Response {
$hash = $this->request->get('hash'); $hash = $this->request->get('hash');
if (!$hash) { if (!$hash) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
} }
$has = (new AdminApp())->where(['app_group' => $hash])->count();
if ($has) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '当前分组存在' . $has . '个应用,禁止删除');
}
AdminAppGroup::destroy(['hash' => $hash]); AdminAppGroup::destroy(['hash' => $hash]);
return $this->buildSuccess([]); return $this->buildSuccess();
} }
} }

View File

@ -0,0 +1,277 @@
<?php
declare (strict_types=1);
/**
* 权限相关配置
* @since 2018-02-06
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminAuthGroup;
use app\model\AdminAuthGroupAccess;
use app\model\AdminAuthRule;
use app\model\AdminMenu;
use app\util\ReturnCode;
use app\util\Tools;
use think\Response;
class Auth extends Base {
/**
* 获取权限组列表
* @return Response
* @throws \think\db\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index(): Response {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $this->request->get('page', 1);
$keywords = $this->request->get('keywords', '');
$status = $this->request->get('status', '');
$obj = new AdminAuthGroup();
if (strlen($status)) {
$obj = $obj->where('status', $status);
}
if ($keywords) {
$obj = $obj->whereLike('name', "%{$keywords}%");
}
$listObj = $obj->order('id', 'DESC')->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
return $this->buildSuccess([
'list' => $listObj['data'],
'count' => $listObj['total']
]);
}
/**
* 获取全部已开放的可选组
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getGroups(): Response {
$listInfo = (new AdminAuthGroup())->where(['status' => 1])->order('id', 'DESC')->select();
$count = count($listInfo);
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count
]);
}
/**
* 获取组所在权限列表
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getRuleList(): Response {
$groupId = $this->request->get('group_id', 0);
$list = (new AdminMenu)->order('sort', 'ASC')->select();
$list = Tools::buildArrFromObj($list);
$list = Tools::listToTree($list);
$rules = [];
if ($groupId) {
$rules = (new AdminAuthRule())->where(['group_id' => $groupId])->select();
$rules = Tools::buildArrFromObj($rules);
$rules = array_column($rules, 'url');
}
$newList = $this->buildList($list, $rules);
return $this->buildSuccess([
'list' => $newList
]);
}
/**
* 新增组
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add(): Response {
$res = AdminAuthGroup::create([
'name' => $this->request->post('name', ''),
'description' => $this->request->post('description', '')
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 权限组状态编辑
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus(): Response {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminAuthGroup::update([
'id' => $id,
'status' => $status
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 编辑用户
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit(): Response {
$res = AdminAuthGroup::update([
'id' => $this->request->post('id', 0),
'name' => $this->request->post('name', ''),
'description' => $this->request->post('description', '')
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 删除组
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del(): Response {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$listInfo = (new AdminAuthGroupAccess())->where('find_in_set("' . $id . '", `group_id`)')->select();
if ($listInfo) {
foreach ($listInfo as $value) {
$oldGroupArr = explode(',', $value->group_id);
$key = array_search($id, $oldGroupArr);
unset($oldGroupArr[$key]);
$newData = implode(',', $oldGroupArr);
$value->group_id = $newData;
$value->save();
}
}
AdminAuthGroup::destroy($id);
AdminAuthRule::destroy(['group_id' => $id]);
return $this->buildSuccess();
}
/**
* 从指定组中删除指定用户
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function delMember(): Response {
$gid = $this->request->get('gid', 0);
$uid = $this->request->get('uid', 0);
if (!$gid || !$uid) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$oldInfo = (new AdminAuthGroupAccess())->where('uid', $uid)->find()->toArray();
$oldGroupArr = explode(',', $oldInfo['group_id']);
$key = array_search($gid, $oldGroupArr);
unset($oldGroupArr[$key]);
$newData = implode(',', $oldGroupArr);
$res = AdminAuthGroupAccess::update([
'group_id' => $newData
], [
'uid' => $uid
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 构建适用前端的权限数据
* @param $list
* @param $rules
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function buildList($list, $rules): array {
$newList = [];
foreach ($list as $key => $value) {
$newList[$key]['title'] = $value['title'];
$newList[$key]['key'] = $value['url'];
if (isset($value['children'])) {
$newList[$key]['expand'] = true;
$newList[$key]['children'] = $this->buildList($value['children'], $rules);
} else {
if (in_array($value['url'], $rules)) {
$newList[$key]['checked'] = true;
}
}
}
return $newList;
}
/**
* 编辑权限细节
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function editRule(): Response {
$id = $this->request->post('id', 0);
$rules = $this->request->post('rules', []);
if (is_array($rules)) {
$needAdd = [];
$has = (new AdminAuthRule())->where(['group_id' => $id])->select();
$has = Tools::buildArrFromObj($has);
$hasRule = array_column($has, 'url');
$needDel = array_flip($hasRule);
foreach ($rules as $key => $value) {
if (!empty($value)) {
if (!in_array($value, $hasRule)) {
$data['url'] = $value;
$data['group_id'] = $id;
$needAdd[] = $data;
} else {
unset($needDel[$value]);
}
}
}
if (count($needAdd)) {
(new AdminAuthRule())->saveAll($needAdd);
}
if (count($needDel)) {
$urlArr = array_keys($needDel);
(new AdminAuthRule())->whereIn('url', $urlArr)->where('group_id', $id)->delete();
}
}
return $this->buildSuccess();
}
}

View File

@ -0,0 +1,105 @@
<?php
declare (strict_types=1);
/**
* 工程基类
* @since 2017/02/28 创建
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminUser;
use app\model\AdminUserData;
use app\util\ReturnCode;
use app\BaseController;
use think\App;
use think\facade\Env;
use think\Response;
class Base extends BaseController {
private $debug = [];
protected $userInfo;
public function __construct(App $app) {
parent::__construct($app);
$this->userInfo = $this->request->API_ADMIN_USER_INFO;
}
/**
* 成功的返回
* @param array $data
* @param string $msg
* @param int $code
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function buildSuccess(array $data = [], string $msg = '操作成功', int $code = ReturnCode::SUCCESS): Response {
$return = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
if (Env::get('APP_DEBUG') && $this->debug) {
$return['debug'] = $this->debug;
}
return json($return);
}
/**
* 更新用户信息
* @param array $data
* @param bool $isDetail
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function updateUserInfo(array $data, bool $isDetail = false): void {
$apiAuth = $this->request->header('Api-Auth');
if ($isDetail) {
AdminUserData::update($data, ['uid' => $this->userInfo['id']]);
$this->userInfo['userData'] = (new AdminUserData())->where('uid', $this->userInfo['id'])->find();
} else {
AdminUser::update($data, ['id' => $this->userInfo['id']]);
$detail = $this->userInfo['userData'];
$this->userInfo = (new AdminUser())->where('id', $this->userInfo['id'])->find();
$this->userInfo['userData'] = $detail;
}
cache('Login:' . $apiAuth, json_encode($this->userInfo), config('apiadmin.ONLINE_TIME'));
}
/**
* 错误的返回
* @param int $code
* @param string $msg
* @param array $data
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function buildFailed(int $code, string $msg = '操作失败', array $data = []): Response {
$return = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
if (Env::get('APP_DEBUG') && $this->debug) {
$return['debug'] = $this->debug;
}
return json($return);
}
/**
* debug参数收集
* @param $data
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
protected function debug($data): void {
if ($data) {
$this->debug[] = $data;
}
}
}

View File

@ -0,0 +1,285 @@
<?php
declare (strict_types=1);
/**
* 接口输入输出字段维护
* @since 2018-02-21
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminFields;
use app\model\AdminList;
use app\util\DataType;
use app\util\ReturnCode;
use app\util\Tools;
use think\Response;
class Fields extends Base {
private $dataType = [
DataType::TYPE_INTEGER => 'Integer',
DataType::TYPE_STRING => 'String',
DataType::TYPE_BOOLEAN => 'Boolean',
DataType::TYPE_ENUM => 'Enum',
DataType::TYPE_FLOAT => 'Float',
DataType::TYPE_FILE => 'File',
DataType::TYPE_MOBILE => 'Mobile',
DataType::TYPE_OBJECT => 'Object',
DataType::TYPE_ARRAY => 'Array'
];
/**
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index(): Response {
return $this->buildSuccess($this->dataType);
}
/**
* 获取请求参数
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function request(): Response {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $this->request->get('page', 1);
$hash = $this->request->get('hash', '');
if (empty($hash)) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$listObj = (new AdminFields())->where('hash', $hash)->where('type', 0)
->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
$apiInfo = (new AdminList())->where('hash', $hash)->find();
return $this->buildSuccess([
'list' => $listObj['data'],
'count' => $listObj['total'],
'dataType' => $this->dataType,
'apiInfo' => $apiInfo
]);
}
/**
* 获取返回参数
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function response(): Response {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $this->request->get('page', 1);
$hash = $this->request->get('hash', '');
if (empty($hash)) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$listObj = (new AdminFields())->where('hash', $hash)->where('type', 1)
->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
$apiInfo = (new AdminList())->where('hash', $hash)->find();
return $this->buildSuccess([
'list' => $listObj['data'],
'count' => $listObj['total'],
'dataType' => $this->dataType,
'apiInfo' => $apiInfo
]);
}
/**
* 新增字段
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add(): Response {
$postData = $this->request->post();
$postData['show_name'] = $postData['field_name'];
$postData['default'] = $postData['defaults'];
unset($postData['defaults']);
$res = AdminFields::create($postData);
cache('RequestFields:NewRule:' . $postData['hash'], null);
cache('RequestFields:Rule:' . $postData['hash'], null);
cache('ResponseFieldsRule:' . $postData['hash'], null);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 字段编辑
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit(): Response {
$postData = $this->request->post();
$postData['show_name'] = $postData['field_name'];
$postData['default'] = $postData['defaults'];
unset($postData['defaults']);
$res = AdminFields::update($postData);
cache('RequestFields:NewRule:' . $postData['hash'], null);
cache('RequestFields:Rule:' . $postData['hash'], null);
cache('ResponseFieldsRule:' . $postData['hash'], null);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 字段删除
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del(): Response {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$fieldsInfo = (new AdminFields())->where('id', $id)->find();
cache('RequestFields:NewRule:' . $fieldsInfo->hash, null);
cache('RequestFields:Rule:' . $fieldsInfo->hash, null);
cache('ResponseFieldsRule:' . $fieldsInfo->hash, null);
AdminFields::destroy($id);
return $this->buildSuccess();
}
/**
* 批量上传返回字段
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function upload(): Response {
$hash = $this->request->post('hash');
$type = $this->request->post('type');
$jsonStr = $this->request->post('jsonStr');
$jsonStr = html_entity_decode($jsonStr);
$data = json_decode($jsonStr, true);
if ($data === null) {
return $this->buildFailed(ReturnCode::EXCEPTION, 'JSON数据格式有误');
}
AdminList::update(['return_str' => json_encode($data)], ['hash' => $hash]);
$this->handle($data['data'], $dataArr);
$old = (new AdminFields())->where('hash', $hash)->where('type', $type)->select();
$old = Tools::buildArrFromObj($old);
$oldArr = array_column($old, 'show_name');
$newArr = array_column($dataArr, 'show_name');
$addArr = array_diff($newArr, $oldArr);
$delArr = array_diff($oldArr, $newArr);
if ($delArr) {
$delArr = array_values($delArr);
(new AdminFields())->whereIn('show_name', $delArr)->delete();
}
if ($addArr) {
$addData = [];
foreach ($dataArr as $item) {
if (in_array($item['show_name'], $addArr)) {
$addData[] = $item;
}
}
(new AdminFields())->insertAll($addData);
}
cache('RequestFields:NewRule:' . $hash, null);
cache('RequestFields:Rule:' . $hash, null);
cache('ResponseFieldsRule:' . $hash, null);
return $this->buildSuccess();
}
/**
* @param $data
* @param $dataArr
* @param string $prefix
* @param string $index
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function handle(array $data, &$dataArr, string $prefix = 'data', string $index = 'data'): void {
if (!$this->isAssoc($data)) {
$addArr = [
'field_name' => $index,
'show_name' => $prefix,
'hash' => $this->request->post('hash'),
'is_must' => 1,
'data_type' => DataType::TYPE_ARRAY,
'type' => $this->request->post('type')
];
$dataArr[] = $addArr;
$prefix .= '[]';
if (isset($data[0]) && is_array($data[0])) {
$this->handle($data[0], $dataArr, $prefix);
}
} else {
$addArr = [
'field_name' => $index,
'show_name' => $prefix,
'hash' => $this->request->post('hash'),
'is_must' => 1,
'data_type' => DataType::TYPE_OBJECT,
'type' => $this->request->post('type')
];
$dataArr[] = $addArr;
$prefix .= '{}';
foreach ($data as $index => $datum) {
$myPre = $prefix . $index;
$addArr = array(
'field_name' => $index,
'show_name' => $myPre,
'hash' => $this->request->post('hash'),
'is_must' => 1,
'data_type' => DataType::TYPE_STRING,
'type' => $this->request->post('type')
);
if (is_numeric($datum)) {
if (preg_match('/^\d*$/', $datum)) {
$addArr['data_type'] = DataType::TYPE_INTEGER;
} else {
$addArr['data_type'] = DataType::TYPE_FLOAT;
}
$dataArr[] = $addArr;
} elseif (is_array($datum)) {
$this->handle($datum, $dataArr, $myPre, $index);
} else {
$addArr['data_type'] = DataType::TYPE_STRING;
$dataArr[] = $addArr;
}
}
}
}
/**
* 判断是否是关联数组true表示是关联数组
* @param array $arr
* @return bool
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function isAssoc(array $arr): bool {
if (array() === $arr) return false;
return array_keys($arr) !== range(0, count($arr) - 1);
}
}

View File

@ -1,16 +1,14 @@
<?php <?php
declare (strict_types=1);
namespace app\admin\controller; namespace app\controller\admin;
use app\util\ReturnCode; use app\util\ReturnCode;
use think\Response;
class Index extends Base { class Index extends Base {
public function index() {
return json(['welcome']);
}
public function upload() { public function upload(): Response {
$path = '/upload/' . date('Ymd', time()) . '/'; $path = '/upload/' . date('Ymd', time()) . '/';
$name = $_FILES['file']['name']; $name = $_FILES['file']['name'];
$tmp_name = $_FILES['file']['tmp_name']; $tmp_name = $_FILES['file']['tmp_name'];
@ -18,19 +16,19 @@ class Index extends Base {
//过滤错误 //过滤错误
if ($error) { if ($error) {
switch ($error) { switch ($error) {
case 1 : case 1:
$error_message = '您上传的文件超过了PHP.INI配置文件中UPLOAD_MAX-FILESIZE的大小'; $error_message = '您上传的文件超过了PHP.INI配置文件中UPLOAD_MAX-FILESIZE的大小';
break; break;
case 2 : case 2:
$error_message = '您上传的文件超过了PHP.INI配置文件中的post_max_size的大小'; $error_message = '您上传的文件超过了PHP.INI配置文件中的post_max_size的大小';
break; break;
case 3 : case 3:
$error_message = '文件只被部分上传'; $error_message = '文件只被部分上传';
break; break;
case 4 : case 4:
$error_message = '文件不能为空'; $error_message = '文件不能为空';
break; break;
default : default:
$error_message = '未知错误'; $error_message = '未知错误';
} }
die($error_message); die($error_message);

View File

@ -0,0 +1,158 @@
<?php
declare (strict_types=1);
/**
* 接口组维护
* @since 2018-02-11
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminApp;
use app\model\AdminGroup;
use app\model\AdminList;
use app\util\ReturnCode;
use think\Response;
class InterfaceGroup extends Base {
/**
* 获取接口组列表
* @return Response
* @throws \think\db\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index(): Response {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $this->request->get('page', 1);
$keywords = $this->request->get('keywords', '');
$type = $this->request->get('type', '');
$status = $this->request->get('status', '');
$obj = new AdminGroup();
if (strlen($status)) {
$obj = $obj->where('status', $status);
}
if ($type) {
switch ($type) {
case 1:
$obj = $obj->where('hash', $keywords);
break;
case 2:
$obj = $obj->whereLike('name', "%{$keywords}%");
break;
}
}
$listObj = $obj->order('create_time', 'desc')->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
return $this->buildSuccess([
'list' => $listObj['data'],
'count' => $listObj['total']
]);
}
/**
* 获取全部有效的接口组
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getAll(): Response {
$listInfo = (new AdminGroup())->where(['status' => 1])->select();
return $this->buildSuccess([
'list' => $listInfo
]);
}
/**
* 接口组状态编辑
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus(): Response {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminGroup::update([
'id' => $id,
'status' => $status,
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 添加接口组
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add(): Response {
$postData = $this->request->post();
$res = AdminGroup::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 接口组编辑
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit(): Response {
$postData = $this->request->post();
$res = AdminGroup::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 接口组删除
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del(): Response {
$hash = $this->request->get('hash');
if (!$hash) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
if ($hash === 'default') {
return $this->buildFailed(ReturnCode::INVALID, '系统预留关键数据,禁止删除!');
}
AdminList::update(['group_hash' => 'default'], ['group_hash' => $hash]);
$hashRule = (new AdminApp())->whereLike('app_api_show', "%$hash%")->select();
if ($hashRule) {
foreach ($hashRule as $rule) {
$appApiShowArr = json_decode($rule->app_api_show, true);
if (!empty($appApiShowArr[$hash])) {
if (isset($appApiShowArr['default'])) {
$appApiShowArr['default'] = array_merge($appApiShowArr['default'], $appApiShowArr[$hash]);
} else {
$appApiShowArr['default'] = $appApiShowArr[$hash];
}
}
unset($appApiShowArr[$hash]);
$rule->app_api_show = json_encode($appApiShowArr);
$rule->save();
}
}
AdminGroup::destroy(['hash' => $hash]);
return $this->buildSuccess();
}
}

View File

@ -0,0 +1,201 @@
<?php
declare (strict_types=1);
/**
* 接口管理
* @since 2018-02-11
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminApp;
use app\model\AdminFields;
use app\model\AdminList;
use app\util\ReturnCode;
use think\facade\Env;
use think\Response;
class InterfaceList extends Base {
/**
* 获取接口列表
* @return Response
* @throws \think\db\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index(): Response {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $this->request->get('page', 1);
$keywords = $this->request->get('keywords', '');
$type = $this->request->get('type', '');
$status = $this->request->get('status', '');
$obj = new AdminList();
if (strlen($status)) {
$obj = $obj->where('status', $status);
}
if ($type) {
switch ($type) {
case 1:
$obj = $obj->where('hash', $keywords);
break;
case 2:
$obj = $obj->whereLike('info', "%{$keywords}%");
break;
case 3:
$obj = $obj->whereLike('api_class', "%{$keywords}%");
break;
}
}
$listObj = $obj->order('id', 'DESC')->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
return $this->buildSuccess([
'list' => $listObj['data'],
'count' => $listObj['total']
]);
}
/**
* 获取接口唯一标识
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getHash(): Response {
$res['hash'] = uniqid();
return $this->buildSuccess($res);
}
/**
* 新增接口
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add(): Response {
$postData = $this->request->post();
if (!preg_match("/^[A-Za-z0-9_\/]+$/", $postData['api_class'])) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '真实类名只允许填写字母,数字和/');
}
$res = AdminList::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 接口状态编辑
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus(): Response {
$hash = $this->request->get('hash');
$status = $this->request->get('status');
$res = AdminList::update([
'status' => $status
], [
'hash' => $hash
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
cache('ApiInfo:' . $hash, null);
return $this->buildSuccess();
}
/**
* 编辑接口
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit(): Response {
$postData = $this->request->post();
if (!preg_match("/^[A-Za-z0-9_\/]+$/", $postData['api_class'])) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '真实类名只允许填写字母,数字和/');
}
$res = AdminList::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
cache('ApiInfo:' . $postData['hash'], null);
return $this->buildSuccess();
}
/**
* 删除接口
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del(): Response {
$hash = $this->request->get('hash');
if (!$hash) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$hashRule = (new AdminApp())->whereLike('app_api', "%$hash%")->select();
if ($hashRule) {
$oldInfo = (new AdminList())->where('hash', $hash)->find();
foreach ($hashRule as $rule) {
$appApiArr = explode(',', $rule->app_api);
$appApiIndex = array_search($hash, $appApiArr);
array_splice($appApiArr, $appApiIndex, 1);
$rule->app_api = implode(',', $appApiArr);
$appApiShowArrOld = json_decode($rule->app_api_show, true);
$appApiShowArr = $appApiShowArrOld[$oldInfo->group_hash];
$appApiShowIndex = array_search($hash, $appApiShowArr);
array_splice($appApiShowArr, $appApiShowIndex, 1);
$appApiShowArrOld[$oldInfo->group_hash] = $appApiShowArr;
$rule->app_api_show = json_encode($appApiShowArrOld);
$rule->save();
}
}
AdminList::destroy(['hash' => $hash]);
AdminFields::destroy(['hash' => $hash]);
cache('ApiInfo:' . $hash, null);
return $this->buildSuccess();
}
/**
* 刷新接口路由
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function refresh(): Response {
$rootPath = root_path();
$apiRoutePath = $rootPath . 'route/apiRoute.php';
$tplPath = $rootPath . 'install/apiRoute.tpl';
$methodArr = ['*', 'POST', 'GET'];
$tplOriginStr = file_get_contents($tplPath);
$listInfo = (new AdminList())->where('status', 1)->select();
$tplStr = [];
foreach ($listInfo as $value) {
if ($value['hash_type'] === 1) {
array_push($tplStr, 'Route::rule(\'' . addslashes($value->api_class) . '\',\'api.' . addslashes($value->api_class) . '\', \'' . $methodArr[$value->method] . '\')->middleware([app\middleware\ApiAuth::class, app\middleware\ApiPermission::class, app\middleware\RequestFilter::class, app\middleware\ApiLog::class]);');
} else {
array_push($tplStr, 'Route::rule(\'' . addslashes($value->hash) . '\',\'api.' . addslashes($value->api_class) . '\', \'' . $methodArr[$value->method] . '\')->middleware([app\middleware\ApiAuth::class, app\middleware\ApiPermission::class, app\middleware\RequestFilter::class, app\middleware\ApiLog::class]);');
}
}
$tplOriginStr = str_replace(['{$API_RULE}'], [implode(PHP_EOL . ' ', $tplStr)], $tplOriginStr);
file_put_contents($apiRoutePath, $tplOriginStr);
return $this->buildSuccess();
}
}

View File

@ -0,0 +1,65 @@
<?php
declare (strict_types=1);
/**
* 后台操作日志管理
* @since 2018-02-06
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminUserAction;
use app\util\ReturnCode;
use think\Response;
class Log extends Base {
/**
* 获取操作日志列表
* @return Response
* @throws \think\db\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index(): Response {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $this->request->get('page', 1);
$type = $this->request->get('type', '');
$keywords = $this->request->get('keywords', '');
$obj = new AdminUserAction();
if ($type) {
switch ($type) {
case 1:
$obj = $obj->whereLike('url', "%{$keywords}%");
break;
case 2:
$obj = $obj->whereLike('nickname', "%{$keywords}%");
break;
case 3:
$obj = $obj->where('uid', $keywords);
break;
}
}
$listObj = $obj->order('add_time', 'DESC')->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
return $this->buildSuccess([
'list' => $listObj['data'],
'count' => $listObj['total']
]);
}
/**
* 删除日志
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del(): Response {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
AdminUserAction::destroy($id);
return $this->buildSuccess();
}
}

View File

@ -0,0 +1,173 @@
<?php
declare (strict_types=1);
/**
* 登录登出
* @since 2017-11-02
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminAuthGroupAccess;
use app\model\AdminAuthRule;
use app\model\AdminMenu;
use app\model\AdminUser;
use app\model\AdminUserData;
use app\util\ReturnCode;
use app\util\RouterTool;
use app\util\Tools;
use think\Response;
class Login extends Base {
/**
* 用户登录【账号密码登录】
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index(): Response {
$username = $this->request->post('username');
$password = $this->request->post('password');
if (!$username) {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '缺少用户名!');
}
if (!$password) {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '缺少密码!');
} else {
$password = Tools::userMd5($password);
}
$userInfo = (new AdminUser())->where('username', $username)->where('password', $password)->find();
if (!empty($userInfo)) {
if ($userInfo['status']) {
//更新用户数据
$userData = $userInfo->userData;
$data = [];
if ($userData) {
$userData->login_times++;
$userData->last_login_ip = sprintf("%u", ip2long($this->request->ip()));
$userData->last_login_time = time();
$userData->save();
} else {
$data['login_times'] = 1;
$data['uid'] = $userInfo['id'];
$data['last_login_ip'] = sprintf("%u", ip2long($this->request->ip()));
$data['last_login_time'] = time();
$data['head_img'] = '';
AdminUserData::create($data);
$userInfo['userData'] = $data;
}
} else {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '用户已被封禁,请联系管理员');
}
} else {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '用户名密码不正确');
}
$userInfo['access'] = $this->getAccess($userInfo['id']);
$userInfo['menu'] = $this->getAccessMenuData($userInfo['id']);
$apiAuth = md5(uniqid() . time());
cache('Login:' . $apiAuth, json_encode($userInfo), config('apiadmin.ONLINE_TIME'));
cache('Login:' . $userInfo['id'], $apiAuth, config('apiadmin.ONLINE_TIME'));
$userInfo['apiAuth'] = $apiAuth;
return $this->buildSuccess($userInfo->toArray(), '登录成功');
}
/**
* 获取用户信息
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getUserInfo(): Response {
return $this->buildSuccess($this->userInfo);
}
/**
* 用户登出
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function logout(): Response {
$ApiAuth = $this->request->header('Api-Auth');
cache('Login:' . $ApiAuth, null);
cache('Login:' . $this->userInfo['id'], null);
return $this->buildSuccess([], '登出成功');
}
/**
* 获取当前用户的允许菜单
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getAccessMenu(): Response {
return $this->buildSuccess($this->getAccessMenuData($this->userInfo['id']));
}
/**
* 获取当前用户的允许菜单
* @param int $uid
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getAccessMenuData(int $uid): array {
$returnData = [];
$isSupper = Tools::isAdministrator($uid);
if ($isSupper) {
$access = (new AdminMenu())->where('router', '<>', '')->select();
$returnData = Tools::listToTree(Tools::buildArrFromObj($access));
} else {
$groups = (new AdminAuthGroupAccess())->where('uid', $uid)->find();
if (isset($groups) && $groups->group_id) {
$access = (new AdminAuthRule())->whereIn('group_id', $groups->group_id)->select();
$access = array_unique(array_column(Tools::buildArrFromObj($access), 'url'));
array_push($access, "");
$menus = (new AdminMenu())->whereIn('url', $access)->where('show', 1)->select();
$returnData = Tools::listToTree(Tools::buildArrFromObj($menus));
RouterTool::buildVueRouter($returnData);
}
}
return array_values($returnData);
}
/**
* 获取用户权限数据
* @param $uid
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getAccess(int $uid): array {
$isSupper = Tools::isAdministrator($uid);
if ($isSupper) {
$access = (new AdminMenu())->select();
$access = Tools::buildArrFromObj($access);
return array_values(array_filter(array_column($access, 'url')));
} else {
$groups = (new AdminAuthGroupAccess())->where('uid', $uid)->find();
if (isset($groups) && $groups->group_id) {
$access = (new AdminAuthRule())->whereIn('group_id', $groups->group_id)->select();
$access = Tools::buildArrFromObj($access);
return array_values(array_unique(array_column($access, 'url')));
} else {
return [];
}
}
}
}

View File

@ -1,108 +1,112 @@
<?php <?php
declare (strict_types=1);
/** /**
* 目录管理 * 目录管理
* @since 2018-01-16 * @since 2018-01-16
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
namespace app\admin\controller; namespace app\controller\admin;
use app\model\AdminMenu; use app\model\AdminMenu;
use app\util\ReturnCode; use app\util\ReturnCode;
use app\util\Tools; use app\util\Tools;
use think\Response;
class Menu extends Base { class Menu extends Base {
/** /**
* 获取菜单列表 * 获取菜单列表
* @return array * @return \think\Response
* @throws \think\exception\DbException * @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function index() { public function index(): Response {
$list = (new AdminMenu)->where([])->order('sort', 'ASC')->select(); $keywords = $this->request->get('keywords', '');
$list = Tools::buildArrFromObj($list); $obj = new AdminMenu();
$list = formatTree(listToTree($list)); if ($keywords) {
$obj = $obj->whereLike('title', "%{$keywords}%");
}
$obj = $obj->order('sort', 'ASC')->select();
$list = Tools::buildArrFromObj($obj);
if (!$keywords) {
$list = Tools::listToTree($list);
}
return $this->buildSuccess([ return $this->buildSuccess([
'list' => $list 'list' => $list
], '登录成功'); ]);
} }
/** /**
* 新增菜单 * 新增菜单
* @return array * @return \think\Response
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function add() { public function add(): Response {
$postData = $this->request->post(); $postData = $this->request->post();
if ($postData['url']) { if ($postData['url']) {
$postData['url'] = 'admin/' . $postData['url']; $postData['url'] = 'admin/' . $postData['url'];
} }
$res = AdminMenu::create($postData); $res = AdminMenu::create($postData);
if ($res === false) { if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
} else { } else {
return $this->buildSuccess([]); return $this->buildSuccess();
} }
} }
/** /**
* 菜单状态编辑 * 菜单状态编辑
* @return array * @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function changeStatus() { public function changeStatus(): Response {
$id = $this->request->get('id'); $id = $this->request->get('id');
$status = $this->request->get('status'); $status = $this->request->get('status');
$res = AdminMenu::update([ $res = AdminMenu::update([
'id' => $id, 'id' => $id,
'hide' => $status 'show' => $status
]); ]);
if ($res === false) { if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
} else {
return $this->buildSuccess([]);
} }
return $this->buildSuccess();
} }
/** /**
* 编辑菜单 * 编辑菜单
* @return array * @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function edit() { public function edit(): Response {
$postData = $this->request->post(); $postData = $this->request->post();
if ($postData['url']) { if ($postData['url']) {
$postData['url'] = 'admin/' . $postData['url']; $postData['url'] = 'admin/' . $postData['url'];
} }
$res = AdminMenu::update($postData); $res = AdminMenu::update($postData);
if ($res === false) { if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败'); return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
} else {
return $this->buildSuccess([]);
} }
return $this->buildSuccess();
} }
/** /**
* 删除菜单 * 删除菜单
* @return array * @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function del() { public function del(): Response {
$id = $this->request->get('id'); $id = $this->request->get('id');
if (!$id) { if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数'); return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
} }
$childNum = AdminMenu::where(['fid' => $id])->count(); (new AdminMenu())->whereIn('id', $id)->delete();
if ($childNum) {
return $this->buildFailed(ReturnCode::INVALID, '当前菜单存在子菜单,不可以被删除!');
} else {
AdminMenu::destroy($id);
return $this->buildSuccess([]); return $this->buildSuccess();
} }
}
} }

View File

@ -0,0 +1,18 @@
<?php
declare (strict_types=1);
namespace app\controller\admin;
use app\util\ReturnCode;
use think\Response;
class Miss extends Base {
public function index(): Response {
if ($this->request->isOptions()) {
return $this->buildSuccess();
} else {
return $this->buildFailed(ReturnCode::INVALID, '接口地址异常');
}
}
}

View File

@ -0,0 +1,350 @@
<?php
declare (strict_types=1);
/**
* 三方一键登录平台
* @since 2018-03-28
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminAuthGroupAccess;
use app\model\AdminUser;
use app\util\ReturnCode;
use app\util\Strs;
use app\util\Tools;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\QrCode;
use think\facade\Cache;
use think\facade\Env;
use think\Response;
class ThirdLogin extends Base {
/**
* QQ一键登录配置
* @var array
*/
private $qqConfig = [
'appId' => '',
'appSecret' => '',
'redirectUri' => 'https://admin.apiadmin.org/#/login/qq'
];
/**
* 微信认证服务号一键登录配置
* @var array
*/
private $wxConfig = [
'appId' => '',
'appSecret' => ''
];
/**
* 微信开放平台一键登录配置
* @var array
*/
private $wxOpenConfig = [
'appId' => '',
'appSecret' => '',
'redirectUri' => 'https://admin.apiadmin.org/#/login/wx'
];
/**
* 使用微信开放平台登录
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function wx(): Response {
$state = $this->request->get('state', '');
$code = $this->request->get('code', '');
//验证合法性
$cacheData = Cache::has($state);
if (!$cacheData) {
return $this->buildFailed(ReturnCode::SESSION_TIMEOUT, 'state已过期');
} else {
cache($state, null);
}
//获取AccessToken
$getAccessTokenUrl = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' .
$this->wxOpenConfig['appId'] . '&secret=' . $this->wxOpenConfig['appSecret'] . '&code=' . $code .
'&grant_type=authorization_code';
$tokenArr = file_get_contents($getAccessTokenUrl);
$accessTokenArr = json_decode($tokenArr, true);
//获取openId
$getUserIdUrl = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $accessTokenArr['access_token'] . '&openid=' . $accessTokenArr['openid'];
$userIdArr = file_get_contents($getUserIdUrl);
$userIdArr = json_decode($userIdArr, true);
return $this->doLogin($userIdArr['openid'], [
'nickname' => $userIdArr['nickname'],
'head_img' => $userIdArr['headimgurl']
]);
}
/**
* 获取授权登录的二维码
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getQr(): Response {
$state = uniqid();
$query = [
'appid' => $this->wxConfig['appId'],
'redirect_uri' => 'https://api.apiadmin.org/admin/ThirdLogin/loginByWx',
'response_type' => 'code',
'scope' => 'snsapi_userinfo',
'state' => $state
];
$authUrl = 'https://open.weixin.qq.com/connect/oauth2/authorize?' . http_build_query($query) . '#wechat_redirect';
$qrCode = new QrCode($authUrl);
$qrCode->setSize(300);
$qrCode->setWriterByName('png');
$qrCode->setMargin(10);
$qrCode->setEncoding('UTF-8');
$qrCode->setErrorCorrectionLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::HIGH));
$qrCode->setForegroundColor(['r' => 0, 'g' => 0, 'b' => 0, 'a' => 0]);
$qrCode->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255, 'a' => 0]);
$qrCode->setRoundBlockSize(true);
$qrCode->setValidateResult(false);
$qrCode->writeFile(Env::get('root_path') . 'public/qr/' . $state . '.png');
cache($state, 1, 300);
return $this->buildSuccess([
'qrUrl' => 'https://api.apiadmin.org/qr/' . $state . '.png',
'state' => $state
]);
}
/**
* 接受微信回调,处理用户登录
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function loginByWx(): Response {
$code = $this->request->get('code');
$state = $this->request->get('state');
$auth = cache($state);
if (!$auth) {
return view('wiki@index/login_res', [
'info' => '当前二维码已失效',
'code' => ReturnCode::RECORD_NOT_FOUND
]);
}
$query = [
'appid' => $this->wxConfig['appId'],
'secret' => $this->wxConfig['appSecret'],
'grant_type' => 'authorization_code',
'code' => $code
];
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?' . http_build_query($query);
$accessToken = json_decode(file_get_contents($url), true);
$getUserInfoQuery = [
'access_token' => $accessToken['access_token'],
'openid' => $accessToken['openid'],
'lang' => 'zh_CN'
];
$getUserInfoUrl = 'https://api.weixin.qq.com/sns/userinfo?' . http_build_query($getUserInfoQuery);
$userInfoArr = file_get_contents($getUserInfoUrl);
$userInfoArr = json_decode($userInfoArr, true);
if ($userInfoArr) {
cache($state, [
'nickname' => $userInfoArr['nickname'],
'head_img' => $userInfoArr['headimgurl'],
'openid' => $accessToken['openid']
], 300);
return view('wiki@index/login_res', [
'info' => '登录成功',
'code' => ReturnCode::SUCCESS
]);
} else {
return view('wiki@index/login_res', [
'info' => '操作失败',
'code' => ReturnCode::DB_SAVE_ERROR
]);
}
}
/**
* 处理微信用户登录
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function checkWxLogin(): Response {
$state = $this->request->get('state');
$userInfo = cache($state);
if (is_numeric($userInfo)) {
return $this->buildFailed(666, '等待扫码');
} else {
@unlink(Env::get('root_path') . 'public/qr/' . $state . '.png');
if (is_array($userInfo)) {
cache($state, null);
return $this->doLogin($userInfo['openid'], [
'nickname' => $userInfo['nickname'],
'head_img' => $userInfo['head_img']
]);
} else {
return $this->buildFailed(ReturnCode::INVALID, '登录状态已失效,请重新登录');
}
}
}
/**
* 获取qq登录必要参数
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getWxCode(): Response {
$state = md5(uniqid() . time());
cache($state, $state, 300);
return $this->buildSuccess([
'appId' => $this->wxOpenConfig['appId'],
'redirectUri' => urlencode($this->wxOpenConfig['redirectUri']),
'state' => $state
]);
}
/**
* 获取qq登录必要参数
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getQQCode(): Response {
$state = md5(uniqid() . time());
cache($state, $state, 300);
return $this->buildSuccess([
'appId' => $this->qqConfig['appId'],
'redirectUri' => urlencode($this->qqConfig['redirectUri']),
'state' => $state
]);
}
/**
* 使用QQ登录
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function loginByQQ(): Response {
$state = $this->request->get('state', '');
$code = $this->request->get('code', '');
//验证合法性
$cacheData = Cache::has($state);
if (!$cacheData) {
return $this->buildFailed(ReturnCode::SESSION_TIMEOUT, 'state已过期');
} else {
cache($state, null);
}
//获取AccessToken
$getAccessTokenUrl = 'https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=' .
$this->qqConfig['appId'] . '&client_secret=' . $this->qqConfig['appSecret'] . '&code=' . $code .
'&redirect_uri=' . urlencode($this->qqConfig['redirectUri']);
$tokenArr = file_get_contents($getAccessTokenUrl);
parse_str($tokenArr, $accessTokenArr);
//获取openId
$getUserIdUrl = 'https://graph.qq.com/oauth2.0/me?access_token=' . $accessTokenArr['access_token'];
$userIdArr = file_get_contents($getUserIdUrl);
$userIdArr = str_replace('callback( ', '', $userIdArr);
$userIdArr = str_replace(' );', '', $userIdArr);
$userIdArr = json_decode($userIdArr, true);
$getUserInfoUrl = 'https://graph.qq.com/user/get_user_info?access_token=' . $accessTokenArr['access_token'] . '&oauth_consumer_key=' .
$this->qqConfig['appId'] . '&openid=' . $userIdArr['openid'];
$userInfoArr = file_get_contents($getUserInfoUrl);
$userInfoArr = json_decode($userInfoArr, true);
return $this->doLogin($userIdArr['openid'], [
'nickname' => $userInfoArr['nickname'],
'head_img' => $userInfoArr['figureurl_qq_2']
]);
}
/**
* 统一处理用户登录
* @param $openid
* @param $userDetail
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function doLogin(string $openid, array $userDetail): Response {
$userInfo = (new AdminUser())->where('openid', $openid)->find();
if (empty($userInfo)) {
$userInfo = AdminUser::create([
'nickname' => $userDetail['nickname'],
'username' => 'ApiAdmin_qq_' . Strs::randString(8),
'openid' => $openid,
'create_ip' => sprintf("%u", ip2long($this->request->ip())),
'status' => 1,
'create_time' => time(),
'password' => Tools::userMd5('ApiAdmin')
]);
$userDataArr = [
'login_times' => 1,
'uid' => $userInfo->id,
'last_login_ip' => sprintf("%u", ip2long($this->request->ip())),
'last_login_time' => time(),
'head_img' => $userDetail['head_img']
];
$userInfo->userData()->save($userDataArr);
$userInfo['userData'] = $userDataArr;
AdminAuthGroupAccess::create([
'uid' => $userInfo->id,
'group_id' => 1
]);
} else {
if ($userInfo['status']) {
//更新用户数据
$userInfo->userData->login_times++;
$userInfo->userData->last_login_ip = sprintf("%u", ip2long($this->request->ip()));
$userInfo->userData->last_login_time = time();
$userInfo->userData->save();
} else {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '用户已被封禁,请联系管理员');
}
}
$userInfo['access'] = (new Login(App()))->getAccess(intval($userInfo['id']));
$userInfo['menu'] = (new Login(App()))->getAccessMenuData(intval($userInfo['id']));
$apiAuth = md5(uniqid() . time());
cache('Login:' . $apiAuth, json_encode($userInfo), config('apiadmin.ONLINE_TIME'));
cache('Login:' . $userInfo['id'], $apiAuth, config('apiadmin.ONLINE_TIME'));
$userInfo['apiAuth'] = $apiAuth;
return $this->buildSuccess($userInfo->toArray(), '登录成功');
}
}

View File

@ -0,0 +1,277 @@
<?php
declare (strict_types=1);
/**
* 用户管理
* @since 2018-02-06
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminAuthGroupAccess;
use app\model\AdminUser;
use app\model\AdminUserData;
use app\util\ReturnCode;
use app\util\Tools;
use think\facade\Db;
use think\Response;
class User extends Base {
/**
* 获取用户列表
* @return Response
* @throws \think\db\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index(): Response {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$start = $this->request->get('page', 1);
$type = $this->request->get('type', '', 'intval');
$keywords = $this->request->get('keywords', '');
$status = $this->request->get('status', '');
$obj = new AdminUser();
if (strlen($status)) {
$obj = $obj->where('status', $status);
}
if ($type) {
switch ($type) {
case 1:
$obj = $obj->whereLike('username', "%{$keywords}%");
break;
case 2:
$obj = $obj->whereLike('nickname', "%{$keywords}%");
break;
}
}
$listObj = $obj->order('create_time', 'DESC')
->paginate(['page' => $start, 'list_rows' => $limit])->each(function($item, $key) {
$item->userData;
})->toArray();
$listInfo = $listObj['data'];
$idArr = array_column($listInfo, 'id');
$userGroup = (new AdminAuthGroupAccess())->whereIn('uid', $idArr)->select();
$userGroup = Tools::buildArrFromObj($userGroup);
$userGroup = Tools::buildArrByNewKey($userGroup, 'uid');
foreach ($listInfo as $key => &$value) {
if ($value['userData']) {
$value['userData']['last_login_ip'] = long2ip($value['userData']['last_login_ip']);
$value['userData']['last_login_time'] = date('Y-m-d H:i:s', $value['userData']['last_login_time']);
$value['create_ip'] = long2ip($value['create_ip']);
}
if (isset($userGroup[$value['id']])) {
$value['group_id'] = explode(',', $userGroup[$value['id']]['group_id']);
} else {
$value['group_id'] = [];
}
}
return $this->buildSuccess([
'list' => $listInfo,
'count' => $listObj['total']
]);
}
/**
* 新增用户
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add() {
$groups = '';
$postData = $this->request->post();
$postData['create_ip'] = sprintf("%u", ip2long($this->request->ip()));
$postData['password'] = Tools::userMd5($postData['password']);
if (isset($postData['group_id']) && $postData['group_id']) {
$groups = trim(implode(',', $postData['group_id']), ',');
unset($postData['group_id']);
}
$res = AdminUser::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
AdminAuthGroupAccess::create([
'uid' => $res->id,
'group_id' => $groups
]);
return $this->buildSuccess();
}
/**
* 获取当前组的全部用户
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getUsers() {
$limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
$page = $this->request->get('page', 1);
$gid = $this->request->get('gid', 0);
if (!$gid) {
return $this->buildFailed(ReturnCode::PARAM_INVALID, '非法操作');
}
$totalNum = (new AdminAuthGroupAccess())->where('find_in_set("' . $gid . '", `group_id`)')->count();
$start = $limit * ($page - 1);
$sql = "SELECT au.* FROM admin_user as au LEFT JOIN admin_auth_group_access as aaga " .
" ON aaga.`uid` = au.`id` WHERE find_in_set('{$gid}', aaga.`group_id`) " .
" ORDER BY au.create_time DESC LIMIT {$start}, {$limit}";
$userInfo = Db::query($sql);
$uidArr = array_column($userInfo, 'id');
$userData = (new AdminUserData())->whereIn('uid', $uidArr)->select();
$userData = Tools::buildArrByNewKey($userData, 'uid');
foreach ($userInfo as $key => $value) {
if (isset($userData[$value['id']])) {
$userInfo[$key]['last_login_ip'] = long2ip($userData[$value['id']]['last_login_ip']);
$userInfo[$key]['login_times'] = $userData[$value['id']]['login_times'];
$userInfo[$key]['last_login_time'] = date('Y-m-d H:i:s', $userData[$value['id']]['last_login_time']);
}
$userInfo[$key]['create_ip'] = long2ip($userInfo[$key]['create_ip']);
}
return $this->buildSuccess([
'list' => $userInfo,
'count' => $totalNum
]);
}
/**
* 用户状态编辑
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus() {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminUser::update([
'id' => $id,
'status' => $status
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
if ($oldAdmin = cache('Login:' . $id)) {
cache('Login:' . $oldAdmin, null);
}
return $this->buildSuccess();
}
/**
* 编辑用户
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit() {
$groups = '';
$postData = $this->request->post();
if ($postData['password'] === 'ApiAdmin') {
unset($postData['password']);
} else {
$postData['password'] = Tools::userMd5($postData['password']);
}
if (isset($postData['group_id']) && $postData['group_id']) {
$groups = trim(implode(',', $postData['group_id']), ',');
unset($postData['group_id']);
}
$res = AdminUser::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
$has = (new AdminAuthGroupAccess())->where('uid', $postData['id'])->select();
if ($has) {
AdminAuthGroupAccess::update([
'group_id' => $groups
], [
'uid' => $postData['id'],
]);
} else {
AdminAuthGroupAccess::create([
'uid' => $postData['id'],
'group_id' => $groups
]);
}
if ($oldAdmin = cache('Login:' . $postData['id'])) {
cache('Login:' . $oldAdmin, null);
}
return $this->buildSuccess();
}
/**
* 修改自己的信息
* @return Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function own() {
$postData = $this->request->post();
$headImg = $postData['head_img'];
if ($postData['password'] && $postData['oldPassword']) {
$oldPass = Tools::userMd5($postData['oldPassword']);
unset($postData['oldPassword']);
if ($oldPass === $this->userInfo['password']) {
$postData['password'] = Tools::userMd5($postData['password']);
} else {
return $this->buildFailed(ReturnCode::INVALID, '原始密码不正确');
}
} else {
unset($postData['password']);
unset($postData['oldPassword']);
}
$postData['id'] = $this->userInfo['id'];
unset($postData['head_img']);
$res = AdminUser::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
$userData = (new AdminUserData())->where('uid', $postData['id'])->find();
$userData->head_img = $headImg;
$userData->save();
if ($oldWiki = cache('WikiLogin:' . $postData['id'])) {
cache('WikiLogin:' . $oldWiki, null);
}
return $this->buildSuccess();
}
/**
* 删除用户
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del() {
$id = $this->request->get('id/d');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$isAdmin = Tools::isAdministrator($id);
if ($isAdmin) {
return $this->buildFailed(ReturnCode::INVALID, '超级管理员不能被删除');
}
AdminUser::destroy($id);
AdminAuthGroupAccess::destroy(['uid' => $id]);
if ($oldAdmin = cache('Login:' . $id)) {
cache('Login:' . $oldAdmin, null);
}
return $this->buildSuccess();
}
}

View File

@ -1,56 +1,56 @@
<?php <?php
declare (strict_types=1);
/** /**
* 工程基类 * 工程基类
* @since 2017/02/28 创建 * @since 2017/02/28 创建
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
namespace app\api\controller; namespace app\controller\api;
use app\BaseController;
use app\util\ApiLog;
use app\util\ReturnCode; use app\util\ReturnCode;
use think\Controller; use think\facade\Env;
use think\Response;
class Base extends Controller { class Base extends BaseController {
private $debug = []; private $debug = [];
protected $userInfo = []; protected $userInfo = [];
public function _initialize() { public function _initialize() {
$this->userInfo = ApiLog::getUserInfo(); // $this->userInfo = ''; 这部分初始化用户信息可以参考admin模块下的Base去自行处理
} }
public function buildSuccess($data, $msg = '操作成功', $code = ReturnCode::SUCCESS) { public function buildSuccess(array $data = [], string $msg = '操作成功', int $code = ReturnCode::SUCCESS): Response {
$return = [ $return = [
'code' => $code, 'code' => $code,
'msg' => $msg, 'msg' => $msg,
'data' => $data 'data' => $data
]; ];
if ($this->debug) { if (Env::get('APP_DEBUG') && $this->debug) {
$return['debug'] = $this->debug; $return['debug'] = $this->debug;
} }
return json($return); return json($return);
} }
public function buildFailed($code, $msg, $data = []) { public function buildFailed(int $code, string $msg = '操作失败', array $data = []): Response {
$return = [ $return = [
'code' => $code, 'code' => $code,
'msg' => $msg, 'msg' => $msg,
'data' => $data 'data' => $data
]; ];
if ($this->debug) { if (Env::get('APP_DEBUG') && $this->debug) {
$return['debug'] = $this->debug; $return['debug'] = $this->debug;
} }
return json($return); return json($return);
} }
protected function debug($data) { protected function debug($data): void {
if ($data) { if ($data) {
$this->debug[] = $data; $this->debug[] = $data;
} }
} }
} }

View File

@ -5,11 +5,9 @@
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
namespace app\api\controller; namespace app\controller\api;
use app\model\AdminApp; use app\model\AdminApp;
use app\util\ApiLog;
use app\util\ReturnCode; use app\util\ReturnCode;
use app\util\Strs; use app\util\Strs;
@ -17,67 +15,60 @@ class BuildToken extends Base {
/** /**
* 构建AccessToken * 构建AccessToken
* @return \think\response\Json * @return \think\Response
* @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException * @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function getAccessToken() { public function getAccessToken() {
$param = $this->request->param(); $param = $this->request->param();
if (empty($param['app_id'])) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少app_id');
}
$appInfo = (new AdminApp())->where(['app_id' => $param['app_id'], 'app_status' => 1])->find(); $appInfo = (new AdminApp())->where(['app_id' => $param['app_id'], 'app_status' => 1])->find();
if (empty($appInfo)) { if (empty($appInfo)) {
return $this->buildFailed(ReturnCode::INVALID, '应用ID非法'); return $this->buildFailed(ReturnCode::INVALID, '应用ID非法');
} else {
$appInfo = $appInfo->toArray();
} }
$signature = $param['signature']; $signature = $param['signature'];
unset($param['signature']); unset($param['signature']);
unset($param['Access-Token']);
$sign = $this->getAuthToken($appInfo['app_secret'], $param); $sign = $this->getAuthToken($appInfo['app_secret'], $param);
$this->debug($sign); $this->debug($sign);
if ($sign !== $signature) { if ($sign !== $signature) {
return $this->buildFailed(ReturnCode::INVALID, '身份令牌验证失败'); return $this->buildFailed(ReturnCode::INVALID, '身份令牌验证失败');
} }
$expires = config('apiAdmin.ACCESS_TOKEN_TIME_OUT'); $expires = config('apiadmin.ACCESS_TOKEN_TIME_OUT');
$accessToken = cache($param['device_id']); $accessToken = cache('AccessToken:' . $param['device_id']);
if ($accessToken) { if ($accessToken) {
cache($accessToken, null); cache('AccessToken:' . $accessToken, null);
cache($param['device_id'], null); cache('AccessToken:' . $param['device_id'], null);
} }
$accessToken = $this->buildAccessToken($appInfo['app_id'], $appInfo['app_secret']); $accessToken = $this->buildAccessToken($appInfo['app_id'], $appInfo['app_secret']);
$appInfo['device_id'] = $param['device_id']; $appInfo['device_id'] = $param['device_id'];
ApiLog::setAppInfo($appInfo); cache('AccessToken:' . $accessToken, $appInfo, $expires);
cache($accessToken, $appInfo, $expires); cache('AccessToken:' . $param['device_id'], $accessToken, $expires);
cache($param['device_id'], $accessToken, $expires);
$return['access_token'] = $accessToken; $return['access_token'] = $accessToken;
$return['expires_in'] = $expires; $return['expires_in'] = $expires;
return $this->buildSuccess($return); return $this->buildSuccess($return);
} }
public function e1() {
return $this->buildSuccess(['e1']);
}
public function e2() {
return $this->buildSuccess(['e2']);
}
/** /**
* 根据AppSecret和数据生成相对应的身份认证秘钥 * 根据AppSecret和数据生成相对应的身份认证秘钥
* @param $appSecret * @param $appSecret
* @param $data * @param $data
* @return string * @return string
*/ */
private function getAuthToken( $appSecret, $data ){ private function getAuthToken($appSecret, $data) {
if(empty($data)){ if (empty($data)) {
return ''; return '';
}else{ } else {
unset($data['APP_CONF_DETAIL'], $data['API_CONF_DETAIL']);
$preArr = array_merge($data, ['app_secret' => $appSecret]); $preArr = array_merge($data, ['app_secret' => $appSecret]);
ksort($preArr); ksort($preArr);
$preStr = http_build_query($preArr); $preStr = http_build_query($preArr);
return md5($preStr); return md5($preStr);
} }
} }
@ -88,9 +79,9 @@ class BuildToken extends Base {
* @param $appSecret * @param $appSecret
* @return string * @return string
*/ */
private function buildAccessToken( $appId, $appSecret ){ private function buildAccessToken($appId, $appSecret) {
$preStr = $appSecret.$appId.time().Strs::keyGen(); $preStr = $appSecret . $appId . time() . Strs::keyGen();
return md5($preStr); return md5($preStr);
} }
} }

View File

@ -0,0 +1,26 @@
<?php
declare (strict_types=1);
namespace app\controller\api;
use think\Exception;
use think\facade\App;
use think\Response;
class Miss extends Base {
public function index(): Response {
$version = config('apiadmin.APP_VERSION');
if (!$version) {
throw new Exception('请先执行安装脚本,完成项目初始化!');
} else {
return $this->buildSuccess([
'Product' => config('apiadmin.APP_NAME'),
'ApiVersion' => $version,
'TpVersion' => App::version(),
'Company' => config('apiadmin.COMPANY_NAME'),
'ToYou' => "I'm glad to meet you终于等到你"
]);
}
}
}

188
app/controller/wiki/Api.php Normal file
View File

@ -0,0 +1,188 @@
<?php
declare (strict_types=1);
/**
* @since 2019-08-11
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\wiki;
use app\model\AdminApp;
use app\model\AdminFields;
use app\model\AdminGroup;
use app\model\AdminList;
use app\util\DataType;
use app\util\ReturnCode;
use app\util\Tools;
use think\Response;
class Api extends Base {
public function errorCode(): Response {
$codeArr = ReturnCode::getConstants();
$codeArr = array_flip($codeArr);
$result = [];
$errorInfo = [
ReturnCode::SUCCESS => '请求成功',
ReturnCode::INVALID => '非法操作',
ReturnCode::DB_SAVE_ERROR => '数据存储失败',
ReturnCode::DB_READ_ERROR => '数据读取失败',
ReturnCode::CACHE_SAVE_ERROR => '缓存存储失败',
ReturnCode::CACHE_READ_ERROR => '缓存读取失败',
ReturnCode::FILE_SAVE_ERROR => '文件读取失败',
ReturnCode::LOGIN_ERROR => '登录失败',
ReturnCode::NOT_EXISTS => '不存在',
ReturnCode::JSON_PARSE_FAIL => 'JSON数据格式错误',
ReturnCode::TYPE_ERROR => '类型错误',
ReturnCode::NUMBER_MATCH_ERROR => '数字匹配失败',
ReturnCode::EMPTY_PARAMS => '丢失必要数据',
ReturnCode::DATA_EXISTS => '数据已经存在',
ReturnCode::AUTH_ERROR => '权限认证失败',
ReturnCode::OTHER_LOGIN => '别的终端登录',
ReturnCode::VERSION_INVALID => 'API版本非法',
ReturnCode::CURL_ERROR => 'CURL操作异常',
ReturnCode::RECORD_NOT_FOUND => '记录未找到',
ReturnCode::DELETE_FAILED => '删除失败',
ReturnCode::ADD_FAILED => '添加记录失败',
ReturnCode::UPDATE_FAILED => '更新记录失败',
ReturnCode::PARAM_INVALID => '数据类型非法',
ReturnCode::ACCESS_TOKEN_TIMEOUT => '身份令牌过期',
ReturnCode::SESSION_TIMEOUT => 'SESSION过期',
ReturnCode::UNKNOWN => '未知错误',
ReturnCode::EXCEPTION => '系统异常',
];
foreach ($errorInfo as $key => $value) {
$result[] = [
'en_code' => $codeArr[$key],
'code' => $key,
'chinese' => $value,
];
}
return $this->buildSuccess([
'data' => $result,
'co' => config('apiadmin.APP_NAME') . ' ' . config('apiadmin.APP_VERSION')
]);
}
public function login(): Response {
$appId = $this->request->post('username');
$appSecret = $this->request->post('password');
$appInfo = (new AdminApp())->where('app_id', $appId)->where('app_secret', $appSecret)->find();
if (!empty($appInfo)) {
if ($appInfo->app_status) {
//保存用户信息和登录凭证
$appInfo = $appInfo->toArray();
$apiAuth = md5(uniqid() . time());
cache('WikiLogin:' . $apiAuth, $appInfo, config('apiadmin.ONLINE_TIME'));
cache('WikiLogin:' . $appInfo['id'], $apiAuth, config('apiadmin.ONLINE_TIME'));
$appInfo['apiAuth'] = $apiAuth;
return $this->buildSuccess($appInfo, '登录成功');
} else {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '当前应用已被封禁,请联系管理员');
}
} else {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, 'AppId或AppSecret错误');
}
}
public function groupList(): Response {
$groupInfo = (new AdminGroup())->select();
$apiInfo = (new AdminList())->select();
$listInfo = [];
if ($this->appInfo['app_id'] === -1) {
$_apiInfo = [];
foreach ($apiInfo as $aVal) {
$_apiInfo[$aVal['group_hash']][] = $aVal;
}
foreach ($groupInfo as $gVal) {
if (isset($_apiInfo[$gVal['hash']])) {
$gVal['api_info'] = $_apiInfo[$gVal['hash']];
}
$listInfo[] = $gVal;
}
} else {
$apiInfo = Tools::buildArrFromObj($apiInfo, 'hash');
$groupInfo = Tools::buildArrFromObj($groupInfo, 'hash');
$app_api_show = json_decode($this->appInfo['app_api_show'], true);
foreach ($app_api_show as $key => $item) {
$_listInfo = $groupInfo[$key];
foreach ($item as $apiItem) {
$_listInfo['api_info'][] = $apiInfo[$apiItem];
}
if (isset($_listInfo['api_info'])) {
$listInfo[] = $_listInfo;
}
}
}
return $this->buildSuccess([
'data' => $listInfo,
'co' => config('apiadmin.APP_NAME') . ' ' . config('apiadmin.APP_VERSION')
]);
}
public function detail(): Response {
$hash = $this->request->get('hash');
if (!$hash) {
return $this->buildFailed(ReturnCode::NOT_EXISTS, '缺少必要参数');
}
$apiList = (new AdminList())->whereIn('hash', $hash)->find();
if (!$apiList) {
return $this->buildFailed(ReturnCode::NOT_EXISTS, '接口hash非法');
}
$request = (new AdminFields())->where('hash', $hash)->where('type', 0)->select();
$response = (new AdminFields())->where('hash', $hash)->where('type', 1)->select();
$dataType = array(
DataType::TYPE_INTEGER => 'Integer',
DataType::TYPE_STRING => 'String',
DataType::TYPE_BOOLEAN => 'Boolean',
DataType::TYPE_ENUM => 'Enum',
DataType::TYPE_FLOAT => 'Float',
DataType::TYPE_FILE => 'File',
DataType::TYPE_ARRAY => 'Array',
DataType::TYPE_OBJECT => 'Object',
DataType::TYPE_MOBILE => 'Mobile'
);
$groupInfo = (new AdminGroup())->where('hash', $apiList['group_hash'])->find();
$groupInfo->hot = $groupInfo->hot + 1;
$groupInfo->save();
if ($apiList['hash_type'] === 1) {
$url = $this->request->domain() . '/api/' . $apiList['api_class'];
} else {
$url = $this->request->domain() . '/api/' . $hash;
}
return $this->buildSuccess([
'request' => $request,
'response' => $response,
'dataType' => $dataType,
'apiList' => $apiList,
'url' => $url,
'co' => config('apiadmin.APP_NAME') . ' ' . config('apiadmin.APP_VERSION')
]);
}
public function logout(): Response {
$ApiAuth = $this->request->header('ApiAuth');
cache('WikiLogin:' . $ApiAuth, null);
cache('WikiLogin:' . $this->appInfo['id'], null);
$oldAdmin = cache('Login:' . $ApiAuth);
if ($oldAdmin) {
$oldAdmin = json_decode($oldAdmin, true);
cache('Login:' . $ApiAuth, null);
cache('Login:' . $oldAdmin['id'], null);
}
return $this->buildSuccess([], '登出成功');
}
}

View File

@ -0,0 +1,43 @@
<?php
declare (strict_types=1);
/**
* 工程基类
* @since 2017/02/28 创建
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\wiki;
use app\BaseController;
use app\util\ReturnCode;
use think\Response;
class Base extends BaseController {
protected $appInfo;
public function __construct() {
parent::__construct(App());
$this->appInfo = $this->request->API_WIKI_USER_INFO;
}
public function buildSuccess($data = [], $msg = '操作成功', $code = ReturnCode::SUCCESS): Response {
$return = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
return json($return);
}
public function buildFailed($code, $msg = '操作失败', $data = []): Response {
$return = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
return json($return);
}
}

17
app/event.php Normal file
View File

@ -0,0 +1,17 @@
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [
],
];

10
app/middleware.php Normal file
View File

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

View File

@ -0,0 +1,45 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use app\util\ReturnCode;
use think\Response;
class AdminAuth {
/**
* ApiAuth鉴权
* @param \think\facade\Request $request
* @param \Closure $next
* @return mixed|\think\response\Json
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function handle($request, \Closure $next): Response {
$header = config('apiadmin.CROSS_DOMAIN');
$ApiAuth = $request->header('Api-Auth', '');
if ($ApiAuth) {
$userInfo = cache('Login:' . $ApiAuth);
if ($userInfo) {
$userInfo = json_decode($userInfo, true);
}
if (!$userInfo || !isset($userInfo['id'])) {
return json([
'code' => ReturnCode::AUTH_ERROR,
'msg' => 'ApiAuth不匹配',
'data' => []
])->header($header);
} else {
$request->API_ADMIN_USER_INFO = $userInfo;
}
return $next($request);
} else {
return json([
'code' => ReturnCode::AUTH_ERROR,
'msg' => '缺少ApiAuth',
'data' => []
])->header($header);
}
}
}

View File

@ -0,0 +1,45 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use app\model\AdminMenu;
use app\model\AdminUserAction;
use app\util\ReturnCode;
use think\Response;
class AdminLog {
/**
* @param \think\facade\Request $request
* @param \Closure $next
* @return \think\response\Json
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function handle($request, \Closure $next): Response {
$userInfo = $request->API_ADMIN_USER_INFO;
$menuInfo = (new AdminMenu())->where('url', $request->pathinfo())->find();
if ($menuInfo) {
$menuInfo = $menuInfo->toArray();
} else {
return json([
'code' => ReturnCode::INVALID,
'msg' => '当前路由非法:' . $request->pathinfo(),
'data' => []
])->header(config('apiadmin.CROSS_DOMAIN'));
}
AdminUserAction::create([
'action_name' => $menuInfo['title'],
'uid' => $userInfo['id'],
'nickname' => $userInfo['nickname'],
'add_time' => time(),
'url' => $request->pathinfo(),
'data' => json_encode($request->param())
]);
return $next($request);
}
}

View File

@ -1,42 +1,38 @@
<?php <?php
/** declare (strict_types=1);
* 处理后台接口请求权限
* @since 2017-07-25
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\behavior;
namespace app\middleware;
use app\model\AdminAuthGroup; use app\model\AdminAuthGroup;
use app\model\AdminAuthGroupAccess; use app\model\AdminAuthGroupAccess;
use app\model\AdminAuthRule; use app\model\AdminAuthRule;
use app\util\ReturnCode; use app\util\ReturnCode;
use app\util\Tools; use app\util\Tools;
use think\Request; use think\Response;
class ApiPermission { class AdminPermission {
/** /**
* 用户权限检测 * 用户权限检测
* @return \think\response\Json * @param \think\facade\Request $request
* @param \Closure $next
* @return mixed|\think\response\Json
* @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException * @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
public function run() { public function handle($request, \Closure $next): Response {
$request = Request::instance(); $userInfo = $request->API_ADMIN_USER_INFO;
$route = $request->routeInfo(); // rule里包含了rule(路由规则), ruoter(完整路由)
$header = config('apiAdmin.CROSS_DOMAIN'); if (!$this->checkAuth($userInfo['id'], $request->rule()->getRule())) {
$ApiAuth = $request->header('ApiAuth', ''); return json([
$userInfo = cache($ApiAuth); 'code' => ReturnCode::INVALID,
$userInfo = json_decode($userInfo, true); 'msg' => '非常抱歉,您没有权限这么做!',
if (!$this->checkAuth($userInfo['id'], $route['route'])) { 'data' => []
$data = ['code' => ReturnCode::INVALID, 'msg' => '非常抱歉,您没有权限怎么做!', 'data' => []]; ])->header(config('apiadmin.CROSS_DOMAIN'));
return json($data, 200, $header);
} }
return $next($request);
} }
/** /**
@ -58,7 +54,6 @@ class ApiPermission {
} else { } else {
return true; return true;
} }
} }
/** /**
@ -71,15 +66,15 @@ class ApiPermission {
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
private function getAuth($uid) { private function getAuth($uid) {
$groups = AdminAuthGroupAccess::get(['uid' => $uid]); $groups = (new AdminAuthGroupAccess())->where('uid', $uid)->find();
if (isset($groups) && $groups->groupId) { if (isset($groups) && $groups->group_id) {
$openGroup = (new AdminAuthGroup())->whereIn('id', $groups->groupId)->where(['status' => 1])->select(); $openGroup = (new AdminAuthGroup())->whereIn('id', $groups->group_id)->where(['status' => 1])->select();
if (isset($openGroup)) { if (isset($openGroup)) {
$openGroupArr = []; $openGroupArr = [];
foreach ($openGroup as $group) { foreach ($openGroup as $group) {
$openGroupArr[] = $group->id; $openGroupArr[] = $group->id;
} }
$allRules = (new AdminAuthRule())->whereIn('groupId', $openGroupArr)->select(); $allRules = (new AdminAuthRule())->whereIn('group_id', $openGroupArr)->select();
if (isset($allRules)) { if (isset($allRules)) {
$rules = []; $rules = [];
foreach ($allRules as $rule) { foreach ($allRules as $rule) {
@ -98,6 +93,4 @@ class ApiPermission {
return []; return [];
} }
} }
} }

View File

@ -0,0 +1,14 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use think\facade\Config;
use think\Response;
class AdminResponse {
public function handle($request, \Closure $next): Response {
return $next($request)->header(Config::get('apiadmin.CROSS_DOMAIN'));
}
}

145
app/middleware/ApiAuth.php Normal file
View File

@ -0,0 +1,145 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use app\model\AdminApp;
use app\model\AdminList;
use app\util\ReturnCode;
use think\facade\Cache;
use think\Request;
class ApiAuth {
/**
* 获取接口基本配置参数校验接口Hash是否合法校验APP_ID是否合法等
* @param Request $request
* @param \Closure $next
* @return mixed|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function handle($request, \Closure $next) {
$header = config('apiadmin.CROSS_DOMAIN');
$pathParam = [];
$pathParamStr = str_replace($request->rule()->getRule() . '/', '', $request->pathinfo());
$pathArr = explode('/', $pathParamStr);
$pathArrLen = count($pathArr);
for ($index = 0; $index < $pathArrLen; $index += 2) {
if ($index + 1 < $pathArrLen) {
$pathParam[$pathArr[$index]] = $pathArr[$index + 1];
}
}
$apiHash = str_replace('api/', '', $request->rule()->getRule());
if ($apiHash) {
$cached = Cache::has('ApiInfo:' . $apiHash);
if ($cached) {
$apiInfo = Cache::get('ApiInfo:' . $apiHash);
} else {
$apiInfo = (new AdminList())->where('hash', $apiHash)->where('hash_type', 2)->find();
if ($apiInfo) {
$apiInfo = $apiInfo->toArray();
Cache::delete('ApiInfo:' . $apiInfo['api_class']);
Cache::set('ApiInfo:' . $apiHash, $apiInfo);
} else {
$apiInfo = (new AdminList())->where('api_class', $apiHash)->where('hash_type', 1)->find();
if ($apiInfo) {
$apiInfo = $apiInfo->toArray();
Cache::delete('ApiInfo:' . $apiInfo['hash']);
Cache::set('ApiInfo:' . $apiHash, $apiInfo);
} else {
return json([
'code' => ReturnCode::DB_READ_ERROR,
'msg' => '获取接口配置数据失败',
'data' => []
])->header($header);
}
}
}
$accessToken = $request->header('Access-Token', '');
if (!$accessToken) {
$accessToken = $request->post('Access-Token', '');
}
if (!$accessToken) {
$accessToken = $request->get('Access-Token', '');
}
if (!$accessToken && !empty($pathParam['Access-Token'])) {
$accessToken = $pathParam['Access-Token'];
}
if (!$accessToken) {
return json([
'code' => ReturnCode::AUTH_ERROR,
'msg' => '缺少必要参数Access-Token',
'data' => []
])->header($header);
}
if ($apiInfo['access_token']) {
$appInfo = $this->doCheck($accessToken);
} else {
$appInfo = $this->doEasyCheck($accessToken);
}
if ($appInfo === false) {
return json([
'code' => ReturnCode::ACCESS_TOKEN_TIMEOUT,
'msg' => 'Access-Token已过期',
'data' => []
])->header($header);
}
$request->APP_CONF_DETAIL = $appInfo;
$request->API_CONF_DETAIL = $apiInfo;
return $next($request);
} else {
return json([
'code' => ReturnCode::AUTH_ERROR,
'msg' => '缺少接口Hash',
'data' => []
])->header($header);
}
}
/**
* 简易鉴权更具APP_SECRET获取应用信息
* @param $accessToken
* @return array|false|mixed|object|\think\App
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function doEasyCheck($accessToken) {
$appInfo = cache('AccessToken:Easy:' . $accessToken);
if (!$appInfo) {
$appInfo = (new AdminApp())->where('app_secret', $accessToken)->find();
if (!$appInfo) {
return false;
} else {
$appInfo = $appInfo->toArray();
cache('AccessToken:Easy:' . $accessToken, $appInfo);
}
}
return $appInfo;
}
/**
* 复杂鉴权需要先通过接口获取AccessToken
* @param $accessToken
* @return bool|mixed
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function doCheck($accessToken) {
$appInfo = cache('AccessToken:' . $accessToken);
if (!$appInfo) {
return false;
} else {
return $appInfo;
}
}
}

31
app/middleware/ApiLog.php Normal file
View File

@ -0,0 +1,31 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use app\util\ApiLogTool;
class ApiLog {
/**
* @param $request
* @param \Closure $next
* @return mixed
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function handle($request, \Closure $next) {
$response = $next($request);
$requestInfo = $request->param();
unset($requestInfo['API_CONF_DETAIL']);
unset($requestInfo['APP_CONF_DETAIL']);
ApiLogTool::setApiInfo((array)$request->API_CONF_DETAIL);
ApiLogTool::setAppInfo((array)$request->APP_CONF_DETAIL);
ApiLogTool::setRequest($requestInfo);
ApiLogTool::setResponse($response->getData(), isset($response->getData()['code']) ? strval($response->getData()['code']) : 'null');
ApiLogTool::setHeader((array)$request->header());
ApiLogTool::save();
return $response;
}
}

View File

@ -0,0 +1,33 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use app\util\ReturnCode;
class ApiPermission {
/**
* 校验当前App是否有请求当前接口的权限
* @param $request
* @param \Closure $next
* @return mixed|\think\response\Json
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function handle($request, \Closure $next) {
$header = config('apiadmin.CROSS_DOMAIN');
$appInfo = $request->APP_CONF_DETAIL;
$apiInfo = $request->API_CONF_DETAIL;
$allRules = explode(',', $appInfo['app_api']);
if (!in_array($apiInfo['hash'], $allRules)) {
return json([
'code' => ReturnCode::INVALID,
'msg' => '非常抱歉,您没有权限这么做!',
'data' => []
])->header($header);
}
return $next($request);
}
}

View File

@ -0,0 +1,13 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use think\facade\Config;
class ApiResponse {
public function handle($request, \Closure $next) {
return $next($request)->header(Config::get('apiadmin.CROSS_DOMAIN'));
}
}

View File

@ -0,0 +1,128 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use app\model\AdminFields;
use app\util\DataType;
use app\util\ReturnCode;
use think\facade\Cache;
use think\facade\Validate;
class RequestFilter {
/**
* 接口请求字段过滤【只验证数据的合法性,不再过滤数据】
* @param $request
* @param \Closure $next
* @return mixed|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function handle($request, \Closure $next) {
$apiInfo = $request->API_CONF_DETAIL;
$data = $request->param();
$has = Cache::has('RequestFields:NewRule:' . $apiInfo['hash']);
if ($has) {
$newRule = cache('RequestFields:NewRule:' . $apiInfo['hash']);
} else {
$rule = (new AdminFields())->where('hash', $apiInfo['hash'])->where('type', 0)->select();
$newRule = $this->buildValidateRule($rule);
cache('RequestFields:NewRule:' . $apiInfo['hash'], $newRule);
}
if ($newRule) {
$validate = Validate::rule($newRule);
if (!$validate->check($data)) {
return json(['code' => ReturnCode::PARAM_INVALID, 'msg' => $validate->getError(), 'data' => []]);
}
}
return $next($request);
}
/**
* 将数据库中的规则转换成TP_Validate使用的规则数组
* @param array $rule
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function buildValidateRule($rule = []) {
$newRule = [];
if ($rule) {
foreach ($rule as $value) {
if ($value['is_must']) {
$newRule[$value['field_name'] . '|' . $value['info']][] = 'require';
}
switch ($value['data_type']) {
case DataType::TYPE_INTEGER:
$newRule[$value['field_name'] . '|' . $value['info']][] = 'number';
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
if (isset($range['min'])) {
$newRule[$value['field_name'] . '|' . $value['info']]['egt'] = $range['min'];
}
if (isset($range['max'])) {
$newRule[$value['field_name'] . '|' . $value['info']]['elt'] = $range['max'];
}
}
break;
case DataType::TYPE_STRING:
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
if (isset($range['min'])) {
$newRule[$value['field_name'] . '|' . $value['info']]['min'] = $range['min'];
}
if (isset($range['max'])) {
$newRule[$value['field_name'] . '|' . $value['info']]['max'] = $range['max'];
}
}
break;
case DataType::TYPE_ENUM:
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
$newRule[$value['field_name'] . '|' . $value['info']]['in'] = implode(',', $range);
}
break;
case DataType::TYPE_FLOAT:
$newRule[$value['field_name'] . '|' . $value['info']][] = 'float';
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
if (isset($range['min'])) {
$newRule[$value['field_name'] . '|' . $value['info']]['egt'] = $range['min'];
}
if (isset($range['max'])) {
$newRule[$value['field_name'] . '|' . $value['info']]['elt'] = $range['max'];
}
}
break;
case DataType::TYPE_ARRAY:
$newRule[$value['field_name']][] = 'array';
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
if (isset($range['min'])) {
$newRule[$value['field_name'] . '|' . $value['info']]['min'] = $range['min'];
}
if (isset($range['max'])) {
$newRule[$value['field_name'] . '|' . $value['info']]['max'] = $range['max'];
}
}
break;
case DataType::TYPE_MOBILE:
$newRule[$value['field_name'] . '|' . $value['info']]['regex'] = '/^1[3456789]\d{9}$/';
break;
}
}
}
return $newRule;
}
}

View File

@ -0,0 +1,47 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use app\util\ReturnCode;
class WikiAuth {
/**
* ApiAuth鉴权
* @param \think\facade\Request $request
* @param \Closure $next
* @return mixed|\think\response\Json
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function handle($request, \Closure $next) {
$header = config('apiadmin.CROSS_DOMAIN');
$ApiAuth = $request->header('Api-Auth', '');
if ($ApiAuth) {
$userInfo = cache('Login:' . $ApiAuth);
if (!$userInfo) {
$userInfo = cache('WikiLogin:' . $ApiAuth);
} else {
$userInfo = json_decode($userInfo, true);
$userInfo['app_id'] = -1;
}
if (!$userInfo || !isset($userInfo['id'])) {
return json([
'code' => ReturnCode::AUTH_ERROR,
'msg' => 'ApiAuth不匹配',
'data' => []
])->header($header);
} else {
$request->API_WIKI_USER_INFO = $userInfo;
}
return $next($request);
} else {
return json([
'code' => ReturnCode::AUTH_ERROR,
'msg' => '缺少ApiAuth',
'data' => []
])->header($header);
}
}
}

View File

@ -2,7 +2,6 @@
namespace app\model; namespace app\model;
class AdminApp extends Base { class AdminApp extends Base {
} }

View File

@ -7,7 +7,6 @@
namespace app\model; namespace app\model;
class AdminAppGroup extends Base { class AdminAppGroup extends Base {
} }

View File

@ -0,0 +1,17 @@
<?php
declare (strict_types=1);
/**
*
* @since 2018-02-08
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\model;
use think\model\relation\HasMany;
class AdminAuthGroup extends Base {
public function rules(): HasMany {
return $this->hasMany('AdminAuthRule', 'group_id', 'id');
}
}

View File

@ -7,7 +7,6 @@
namespace app\model; namespace app\model;
class AdminAuthGroupAccess extends Base { class AdminAuthGroupAccess extends Base {
} }

View File

@ -7,7 +7,6 @@
namespace app\model; namespace app\model;
class AdminAuthRule extends Base { class AdminAuthRule extends Base {
} }

View File

@ -7,7 +7,7 @@
namespace app\model; namespace app\model;
class AdminGroup extends Base { class AdminGroup extends Base {
protected $autoWriteTimestamp = true;
} }

View File

@ -2,7 +2,6 @@
namespace app\model; namespace app\model;
class AdminMenu extends Base { class AdminMenu extends Base {
//
} }

19
app/model/AdminUser.php Normal file
View File

@ -0,0 +1,19 @@
<?php
declare (strict_types=1);
/**
* @since 2017-11-02
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\model;
use think\model\relation\HasOne;
class AdminUser extends Base {
protected $autoWriteTimestamp = true;
public function userData(): HasOne {
return $this->hasOne('AdminUserData', 'uid', 'id');
}
}

View File

@ -7,7 +7,6 @@
namespace app\model; namespace app\model;
class AdminUserAction extends Base { class AdminUserAction extends Base {
} }

View File

@ -6,7 +6,6 @@
namespace app\model; namespace app\model;
class AdminUserData extends Base { class AdminUserData extends Base {
} }

View File

@ -1,13 +1,12 @@
<?php <?php
/** /**
* 模型基类 *
* @since 2017/07/25 创建 * @since 2019-04-23
* @author zhaoxiang <zhaoxiang051405@gmail.com> * @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
namespace app\model; namespace app\model;
use think\Model; use think\Model;
class Base extends Model { class Base extends Model {

9
app/provider.php Normal file
View File

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

9
app/service.php Normal file
View File

@ -0,0 +1,9 @@
<?php
use app\AppService;
// 系统服务定义文件
// 服务在完成全局初始化之后执行
return [
AppService::class,
];

138
app/util/ApiLogTool.php Normal file
View File

@ -0,0 +1,138 @@
<?php
declare (strict_types=1);
/**
* @since 2017-04-14
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\util;
use think\facade\Env;
class ApiLogTool {
private static $appInfo = 'null';
private static $apiInfo = 'null';
private static $request = 'null';
private static $response = 'null';
private static $header = 'null';
private static $userInfo = 'null';
private static $separator = ' | ';
/**
* 设置应用信息
* @param array $data
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @desc appId|appName|deviceId
*/
public static function setAppInfo(array $data): void {
self::$appInfo =
($data['app_id'] ?? 'null') . self::$separator .
($data['app_name'] ?? 'null') . self::$separator .
($data['device_id'] ?? 'null');
}
/**
* 设置请求头日志数据
* @param array $data
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @desc accessToken|version
*/
public static function setHeader(array $data): void {
$accessToken = (isset($data['access-token']) && !empty($data['access-token'])) ? $data['access-token'] : 'null';
$version = (isset($data['version']) && !empty($data['version'])) ? $data['version'] : 'null';
self::$header = $accessToken . self::$separator . $version;
}
/**
* 设置Api日志数据
* @param array $data
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @desc hash|apiClass
*/
public static function setApiInfo(array $data): void {
self::$apiInfo =
($data['hash'] ?? 'null') . self::$separator .
($data['api_class'] ?? 'null');
}
/**
* 这部分的日志其实很关键但是由于不再强制检测UserToken所以这部分日志暂时不生效请大家各自适配
* @param $data
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function setUserInfo($data): void {
if (is_array($data) || is_object($data)) {
$data = json_encode($data);
self::$userInfo = $data;
}
}
/**
* 设置请求信息
* @param $data
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function setRequest($data): void {
if (is_array($data) || is_object($data)) {
$data = json_encode($data);
}
self::$request = $data;
}
/**
* 设置返回的信息
* @param $data
* @param string $code
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @desc 返回码|数据
*/
public static function setResponse($data, string $code = ''): void {
if (is_array($data) || is_object($data)) {
$data = json_encode($data);
}
self::$response = $code . self::$separator . $data;
}
/**
* 保存接口日志数据
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function save(): void {
$logPath = runtime_path() . 'ApiLog' . DIRECTORY_SEPARATOR;
$logStr = implode(self::$separator, array(
'[' . date('Y-m-d H:i:s') . ']',
self::$apiInfo,
self::$request,
self::$header,
self::$response,
self::$appInfo,
self::$userInfo
));
if (!file_exists($logPath)) {
mkdir($logPath, 0755, true);
}
@file_put_contents($logPath . date('YmdH') . '.log', $logStr . "\n", FILE_APPEND);
}
/**
* 保存日志文件
* @param string $log 被记录的内容
* @param string $type 日志文件名称
* @param string $filePath
*/
public static function writeLog(string $log, string $type = 'sql', string $filePath = ''): void {
if (!$filePath) {
$filePath = runtime_path() . $type . DIRECTORY_SEPARATOR;
} else {
$filePath = $filePath . $type . DIRECTORY_SEPARATOR;
}
$filename = $filePath . date("YmdH") . ".log";
if (!file_exists($filePath)) {
mkdir($filePath, 0755, true);
}
@$handle = fopen($filename, "a+");
@fwrite($handle, date('Y-m-d H:i:s') . "\t" . $log . "\r\n");
@fclose($handle);
}
}

203
app/util/AutoBuild.php Normal file
View File

@ -0,0 +1,203 @@
<?php
/**
*
* @since 2021-02-18
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\util;
use app\model\AdminMenu;
use think\facade\Db;
class AutoBuild {
private $config = [
'model' => 0, // 是否需要构建模型
'control' => 1, // 是否需要构建控制器
'menu' => 1, // 是否需要构建目录
'route' => 1, // 是否需要构建路由
'name' => '', // 唯一标识
'module' => 1, // 构建类型 1admin2api
'table' => 0, // 是否创建表
'modelName' => '', // 表名称
'fid' => 0 // 父级ID
];
/**
* 自动构建
* @param array $config
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function run($config = []) {
$this->config = array_merge($this->config, $config);
if ($this->config['model'] == 1) {
$this->buildModel();
if ($this->config['table'] == 1) {
$this->createTable();
}
}
if ($this->config['control'] && $this->config['name']) {
$this->buildControl();
if ($this->config['menu'] && $this->config['module'] == 1) {
$this->buildMenu();
}
if ($this->config['route'] && $this->config['module'] == 1) {
$this->buildRoute();
}
}
}
/**
* 驼峰命名转下划线命名
* @param $camelCaps
* @param string $separator
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function unCamelize($camelCaps, $separator = '_'): string {
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
}
/**
* 构建控制器
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function buildControl() {
$tplPath = root_path() . 'install' . DIRECTORY_SEPARATOR;
if ($this->config['module'] == 1) {
$module = 'admin';
} else {
$module = 'api';
}
$controlStr = str_replace(
['{$MODULE}', '{$NAME}'],
[$module, $this->config['name']],
file_get_contents($tplPath . 'control.tpl')
);
file_put_contents(
base_path() . 'controller' . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . $this->config['name'] . '.php',
$controlStr
);
}
/**
* 构建模型
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function buildModel() {
$modelStr = '<?php' . PHP_EOL;
$modelStr .= '/**' . PHP_EOL;
$modelStr .= ' * 由ApiAdmin自动构建' . PHP_EOL;
$modelStr .= ' * @author apiadmin <apiadmin.org>' . PHP_EOL;
$modelStr .= ' */' . PHP_EOL;
$modelStr .= 'namespace app\model;' . PHP_EOL;
$modelStr .= 'class ' . $this->config['modelName'] . ' extends Base {' . PHP_EOL;
$modelStr .= '}' . PHP_EOL;
file_put_contents(
base_path() . 'model' . DIRECTORY_SEPARATOR . $this->config['modelName'] . '.php',
$modelStr
);
}
/**
* 构建表
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function createTable() {
$tableName = $this->unCamelize($this->config['modelName']);
$cmd = "CREATE TABLE `{$tableName}` (`id` int NOT NULL AUTO_INCREMENT,PRIMARY KEY (`id`)) COMMENT='由ApiAdmin自动构建';";
Db::execute($cmd);
}
/**
* 构建菜单
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function buildMenu() {
$menus = [
[
'title' => '新增',
'fid' => $this->config['fid'],
'url' => "admin/{$this->config['name']}/add",
'auth' => 1,
'sort' => 0,
'show' => 1,
'icon' => '',
'level' => 3,
'component' => '',
'router' => '',
'log' => 1,
'permission' => 1,
'method' => 2
],
[
'title' => '编辑',
'fid' => $this->config['fid'],
'url' => "admin/{$this->config['name']}/edit",
'auth' => 1,
'sort' => 0,
'show' => 1,
'icon' => '',
'level' => 3,
'component' => '',
'router' => '',
'log' => 1,
'permission' => 1,
'method' => 2
],
[
'title' => '删除',
'fid' => $this->config['fid'],
'url' => "admin/{$this->config['name']}/del",
'auth' => 1,
'sort' => 0,
'show' => 1,
'icon' => '',
'level' => 3,
'component' => '',
'router' => '',
'log' => 1,
'permission' => 1,
'method' => 1
],
[
'title' => '列表',
'fid' => $this->config['fid'],
'url' => "admin/{$this->config['name']}/index",
'auth' => 1,
'sort' => 0,
'show' => 1,
'icon' => '',
'level' => 3,
'component' => '',
'router' => '',
'log' => 1,
'permission' => 1,
'method' => 1
]
];
(new AdminMenu())->insertAll($menus);
}
/**
* 构建路由
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function buildRoute() {
RouterTool::buildAdminRouter();
}
}

View File

@ -8,7 +8,6 @@
namespace app\util; namespace app\util;
class DataType { class DataType {
const TYPE_INTEGER = 1; const TYPE_INTEGER = 1;
@ -20,5 +19,4 @@ class DataType {
const TYPE_ENUM = 7; const TYPE_ENUM = 7;
const TYPE_MOBILE = 8; const TYPE_MOBILE = 8;
const TYPE_OBJECT = 9; const TYPE_OBJECT = 9;
} }

View File

@ -1,4 +1,5 @@
<?php <?php
declare (strict_types=1);
/** /**
* 错误码统一维护 * 错误码统一维护
* @since 2017/02/28 创建 * @since 2017/02/28 创建
@ -41,9 +42,9 @@ class ReturnCode {
const UNKNOWN = -998; const UNKNOWN = -998;
const EXCEPTION = -999; const EXCEPTION = -999;
static public function getConstants() { public static function getConstants(): array {
$oClass = new \ReflectionClass(__CLASS__); $oClass = new \ReflectionClass(__CLASS__);
return $oClass->getConstants(); return $oClass->getConstants();
} }
} }

107
app/util/RouterTool.php Normal file
View File

@ -0,0 +1,107 @@
<?php
declare (strict_types=1);
/**
*
* @since 2020-05-14
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\util;
use app\model\AdminMenu;
use think\App;
class RouterTool {
/**
* 构建后端路由
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function buildAdminRouter(): void {
$methodArr = ['*', 'get', 'post', 'put', 'delete'];
$routePath = (new App())->getRootPath() . 'route' . DIRECTORY_SEPARATOR . 'app.php';
$bakPath = (new App())->getRootPath() . 'route' . DIRECTORY_SEPARATOR . 'app.bak';
if (file_exists($bakPath)) {
unlink($bakPath);
}
if (file_exists($routePath)) {
rename($routePath, $bakPath);
}
$context = '<?php' . PHP_EOL;
$context .= 'use think\facade\Route;' . PHP_EOL;
$context .= "Route::group('admin', function() {" . PHP_EOL;
$menus = (new AdminMenu())->select();
if ($menus) {
foreach ($menus as $menu) {
$menu = $menu->toArray();
$menuUrl = str_replace('admin/', '', $menu['url']);
if ($menu['url']) {
$context .= " Route::rule('{$menuUrl}', 'admin.{$menuUrl}', '"
. $methodArr[$menu['method']] . "')" . self::getAdminMiddleware($menu) . PHP_EOL;
}
}
}
$context .= " Route::miss('admin.Miss/index');" . PHP_EOL . "});" . PHP_EOL;
file_put_contents($routePath, $context);
}
/**
* 构建前端路由
* TODO::待算法优化
* @param $menus
* @return mixed
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function buildVueRouter(array &$menus): void {
foreach ($menus as $key => $menu) {
if (isset($menu['children'])) {
foreach ($menu['children'] as $cKey => $child) {
if (!isset($child['children'])) {
unset($menus[$key]['children'][$cKey]);
} else {
$menus[$key]['children'][$cKey]['children'] = [];
}
}
} else {
unset($menus[$key]);
}
}
foreach ($menus as $k => $m) {
if (isset($m['children']) && !empty($m['children'])) {
$menus[$k]['children'] = array_values($m['children']);
} else {
unset($menus[$k]);
}
}
}
/**
* 构建菜单权限细节
* @param $menu
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private static function getAdminMiddleware(array $menu): string {
$middle = ['app\middleware\AdminResponse::class'];
if ($menu['log']) {
array_unshift($middle, 'app\middleware\AdminLog::class');
}
if ($menu['permission']) {
array_unshift($middle, 'app\middleware\AdminPermission::class');
}
if ($menu['auth']) {
array_unshift($middle, 'app\middleware\AdminAuth::class');
}
return '->middleware([' . implode(', ', $middle) . ']);';
}
}

185
app/util/StrRandom.php Normal file
View File

@ -0,0 +1,185 @@
<?php
declare (strict_types=1);
/**
* 构建各类有意义的随机数
* @since 2018-08-07
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\util;
class StrRandom {
/**
* 构建一个随机浮点数
* @param int $min 整数部分的最小值,默认值为-999999999
* @param int $max 整数部分的最大值默认值为999999999
* @param int $dmin 小数部分位数的最小值,默认值为 0
* @param int $dmax 小数部分位数的最大值,默认值为 8
* @return float
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function randomFloat(int $min = -999999999, int $max = 999999999, int $dmin = 0, int $dmax = 8): float {
$rand = '';
$intNum = mt_rand($min, $max);
$floatLength = mt_rand($dmin, $dmax);
if ($floatLength > 1) {
$rand = Strs::randString($floatLength - 1, 1);
}
$floatEnd = mt_rand(1, 9);
return floatval($intNum . '.' . $rand . $floatEnd);
}
/**
* 获取随机的时间
* @param string $format PHP的时间日期格式化字符
* @return false|string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function randomDate(string $format = 'Y-m-d H:i:s'): string {
$timestamp = time() - mt_rand(0, 86400 * 3650);
return date($format, $timestamp);
}
/**
* 构建随机IP地址
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function randomIp(): string {
$ipLong = [
['607649792', '608174079'], // 36.56.0.0-36.63.255.255
['1038614528', '1039007743'], // 61.232.0.0-61.237.255.255
['1783627776', '1784676351'], // 106.80.0.0-106.95.255.255
['2035023872', '2035154943'], // 121.76.0.0-121.77.255.255
['2078801920', '2079064063'], // 123.232.0.0-123.235.255.255
['-1950089216', '-1948778497'], // 139.196.0.0-139.215.255.255
['-1425539072', '-1425014785'], // 171.8.0.0-171.15.255.255
['-1236271104', '-1235419137'], // 182.80.0.0-182.92.255.255
['-770113536', '-768606209'], // 210.25.0.0-210.47.255.255
['-569376768', '-564133889'], // 222.16.0.0-222.95.255.255
];
$randKey = mt_rand(0, 9);
return $ip = long2ip(mt_rand($ipLong[$randKey][0], $ipLong[$randKey][1]));
}
/**
* 随机生成一个 URL 协议
* @return mixed
* @author zhaoxiang <zhaoxiang051405@gmail','com>
*/
public static function randomProtocol(): string {
$proArr = [
'http',
'ftp',
'gopher',
'mailto',
'mid',
'cid',
'news',
'nntp',
'prospero',
'telnet',
'rlogin',
'tn3270',
'wais'
];
shuffle($proArr);
return $proArr[0];
}
/**
* 随机生成一个顶级域名
* @author zhaoxiang <zhaoxiang051405@gmail','com>
*/
public static function randomTld(): string {
$tldArr = [
'com', 'cn', 'xin', 'net', 'top', '在线',
'xyz', 'wang', 'shop', 'site', 'club', 'cc',
'fun', 'online', 'biz', 'red', 'link', 'ltd',
'mobi', 'info', 'org', 'edu', 'com.cn', 'net.cn',
'org.cn', 'gov.cn', 'name', 'vip', 'pro', 'work',
'tv', 'co', 'kim', 'group', 'tech', 'store', 'ren',
'ink', 'pub', 'live', 'wiki', 'design', '中文网',
'我爱你', '中国', '网址', '网店', '公司', '网络', '集团', 'app'
];
shuffle($tldArr);
return $tldArr[0];
}
/**
* 获取一个随机的域名
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function randomDomain(): string {
$len = mt_rand(6, 16);
return strtolower(Strs::randString($len)) . '.' . self::randomTld();
}
/**
* 随机生成一个URL
* @param string $protocol 协议名称,可以不用指定
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function randomUrl($protocol = ''): string {
$protocol = $protocol ? $protocol : self::randomProtocol();
return $protocol . '://' . self::randomDomain();
}
/**
* 随机生成一个邮箱地址
* @param string $domain 可以指定邮箱域名
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function randomEmail($domain = ''): string {
$len = mt_rand(6, 16);
$domain = $domain ? $domain : self::randomDomain();
return Strs::randString($len) . '@' . $domain;
}
public static function randomPhone(): string {
$prefixArr = [133, 153, 173, 177, 180, 181, 189, 199, 134, 135,
136, 137, 138, 139, 150, 151, 152, 157, 158, 159, 172, 178,
182, 183, 184, 187, 188, 198, 130, 131, 132, 155, 156, 166,
175, 176, 185, 186, 145, 147, 149, 170, 171];
shuffle($prefixArr);
return $prefixArr[0] . Strs::randString(8, 1);
}
/**
* 随机创建一个身份证号码
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function randomId(): string {
$prefixArr = [
11, 12, 13, 14, 15,
21, 22, 23,
31, 32, 33, 34, 35, 36, 37,
41, 42, 43, 44, 45, 46,
50, 51, 52, 53, 54,
61, 62, 63, 64, 65,
71, 81, 82
];
shuffle($prefixArr);
$suffixArr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'X'];
shuffle($suffixArr);
return $prefixArr[0] . '0000' . self::randomDate('Ymd') . Strs::randString(3, 1) . $suffixArr[0];
}
}

View File

@ -1,4 +1,5 @@
<?php <?php
declare (strict_types=1);
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
@ -8,6 +9,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com> // | Author: liu21st <liu21st@gmail.com>
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace app\util; namespace app\util;
class Strs { class Strs {
@ -17,8 +19,8 @@ class Strs {
* @access public * @access public
* @return string * @return string
*/ */
static public function uuid() { public static function uuid(): string {
$charId = md5(uniqid(mt_rand(), true)); $charId = md5(uniqid(strval(mt_rand()), true));
$hyphen = chr(45); $hyphen = chr(45);
$uuid = chr(123) $uuid = chr(123)
. substr($charId, 0, 8) . $hyphen . substr($charId, 0, 8) . $hyphen
@ -35,7 +37,7 @@ class Strs {
* 生成Guid主键 * 生成Guid主键
* @return Boolean * @return Boolean
*/ */
static public function keyGen() { public static function keyGen(): string {
return str_replace('-', '', substr(self::uuid(), 1, -1)); return str_replace('-', '', substr(self::uuid(), 1, -1));
} }
@ -44,7 +46,7 @@ class Strs {
* @param string $string 字符串 * @param string $string 字符串
* @return Boolean * @return Boolean
*/ */
static public function isUtf8($string) { public static function isUtf8($string): bool {
$len = strlen($string); $len = strlen($string);
for ($i = 0; $i < $len; $i++) { for ($i = 0; $i < $len; $i++) {
$c = ord($string[$i]); $c = ord($string[$i]);
@ -71,15 +73,15 @@ class Strs {
/** /**
* 字符串截取,支持中文和其他编码 * 字符串截取,支持中文和其他编码
* @access public * @param string $str
* @param string $str 需要转换的字符串 * @param float $start
* @param integer $start 开始位置 * @param int $length
* @param string $length 截取长度 * @param string $charset
* @param string $charset 编码格式 * @param bool $suffix
* @param bool $suffix 截断显示字符
* @return string * @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/ */
static public function mSubStr($str, $start = 0, $length, $charset = "utf-8", $suffix = true) { public static function mSubStr(string $str, int $length, float $start = 0, string $charset = "utf-8", bool $suffix = true): string {
if (function_exists("mb_substr")) if (function_exists("mb_substr"))
$slice = mb_substr($str, $start, $length, $charset); $slice = mb_substr($str, $start, $length, $charset);
elseif (function_exists('iconv_substr')) { elseif (function_exists('iconv_substr')) {
@ -100,12 +102,12 @@ class Strs {
* 产生随机字串,可用来自动生成密码 * 产生随机字串,可用来自动生成密码
* 默认长度6位 字母和数字混合 支持中文 * 默认长度6位 字母和数字混合 支持中文
* @param integer $len 长度 * @param integer $len 长度
* @param string $type 字串类型 * @param int $type 字串类型
* 0 字母 1 数字 其它 混合 * 0 字母 1 数字 其它 混合
* @param string $addChars 额外字符 * @param string $addChars 额外字符
* @return string * @return string
*/ */
static public function randString($len = 6, $type = '', $addChars = '') { public static function randString(int $len = 6, int $type = 0, string $addChars = ''): string {
$str = ''; $str = '';
switch ($type) { switch ($type) {
case 0: case 0:
@ -137,7 +139,7 @@ class Strs {
} else { } else {
// 中文随机字 // 中文随机字
for ($i = 0; $i < $len; $i++) { for ($i = 0; $i < $len; $i++) {
$str .= self::msubstr($chars, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 1, 'utf-8', false); $str .= self::msubstr($chars, 1, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 'utf-8', false);
} }
} }
@ -150,14 +152,14 @@ class Strs {
* @param integer $length 长度 * @param integer $length 长度
* @param integer $mode 字串类型 * @param integer $mode 字串类型
* 0 字母 1 数字 其它 混合 * 0 字母 1 数字 其它 混合
* @return string * @return array
*/ */
static public function buildCountRand($number, $length = 4, $mode = 1) { public static function buildCountRand(int $number, int $length = 4, int $mode = 1): array {
if ($mode == 1 && $length < strlen($number)) { if ($mode == 1 && $length < strlen($number)) {
//不足以生成一定数量的不重复数字 //不足以生成一定数量的不重复数字
return false; return [];
} }
$rand = array(); $rand = [];
for ($i = 0; $i < $number; $i++) { for ($i = 0; $i < $number; $i++) {
$rand[] = self::randString($length, $mode); $rand[] = self::randString($length, $mode);
} }
@ -180,10 +182,10 @@ class Strs {
* @param string $format 字符格式 * @param string $format 字符格式
* # 表示数字 * 表示字母和数字 $ 表示字母 * # 表示数字 * 表示字母和数字 $ 表示字母
* @param integer $number 生成数量 * @param integer $number 生成数量
* @return string | array * @return array
*/ */
static public function buildFormatRand($format, $number = 1) { public static function buildFormatRand(string $format, int $number = 1): array {
$str = array(); $str = [];
$length = strlen($format); $length = strlen($format);
for ($j = 0; $j < $number; $j++) { for ($j = 0; $j < $number; $j++) {
$strTemp = ''; $strTemp = '';
@ -207,7 +209,7 @@ class Strs {
$str[] = $strTemp; $str[] = $strTemp;
} }
return $number == 1 ? $strTemp : $str; return $str;
} }
/** /**
@ -216,12 +218,12 @@ class Strs {
* @param integer $max 最大值 * @param integer $max 最大值
* @return string * @return string
*/ */
static public function randNumber($min, $max) { public static function randNumber(int $min, int $max): string {
return sprintf("%0" . strlen($max) . "d", mt_rand($min, $max)); return sprintf("%0" . strlen($max) . "d", mt_rand($min, $max));
} }
// 自动转换字符集 支持数组转换 // 自动转换字符集 支持数组转换
static public function autoCharset($string, $from = 'gbk', $to = 'utf-8') { public static function autoCharset(string $string, string $from = 'gbk', string $to = 'utf-8'): string {
$from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from; $from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from;
$to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to; $to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to;
if (strtoupper($from) === strtoupper($to) || empty($string) || (is_scalar($string) && !is_string($string))) { if (strtoupper($from) === strtoupper($to) || empty($string) || (is_scalar($string) && !is_string($string))) {

192
app/util/Tools.php Normal file
View File

@ -0,0 +1,192 @@
<?php
declare (strict_types=1);
/**
*
* @since 2017-11-01
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\util;
class Tools {
/**
* 获取相对时间
* @param int $timestamp
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function getDate(int $timestamp): string {
$now = time();
$diff = $now - $timestamp;
if ($diff <= 60) {
return $diff . '秒前';
} elseif ($diff <= 3600) {
return floor($diff / 60) . '分钟前';
} elseif ($diff <= 86400) {
return floor($diff / 3600) . '小时前';
} elseif ($diff <= 2592000) {
return floor($diff / 86400) . '天前';
} else {
return '一个月前';
}
}
/**
* 二次封装的密码加密
* @param $str
* @param string $auth_key
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function userMd5(string $str, string $auth_key = ''): string {
if (!$auth_key) {
$auth_key = config('apiadmin.AUTH_KEY');
}
return '' === $str ? '' : md5(sha1($str) . $auth_key);
}
/**
* 判断当前用户是否是超级管理员
* @param int $uid
* @return bool
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function isAdministrator(int $uid = 0): bool {
if (!empty($uid)) {
$adminConf = config('apiadmin.USER_ADMINISTRATOR');
if (is_array($adminConf)) {
if (is_array($uid)) {
$m = array_intersect($adminConf, $uid);
if (count($m)) {
return true;
}
} else {
if (in_array($uid, $adminConf)) {
return true;
}
}
} else {
if (is_array($uid)) {
if (in_array($adminConf, $uid)) {
return true;
}
} else {
if ($uid == $adminConf) {
return true;
}
}
}
}
return false;
}
/**
* 将查询的二维对象转换成二维数组
* @param $res
* @param string $key 允许指定索引值
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function buildArrFromObj($res, string $key = ''): array {
$arr = [];
foreach ($res as $value) {
$value = $value->toArray();
if ($key) {
$arr[$value[$key]] = $value;
} else {
$arr[] = $value;
}
}
return $arr;
}
/**
* 将二维数组变成指定key
* @param $array
* @param string $keyName
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function buildArrByNewKey($array, string $keyName = 'id'): array {
$list = [];
foreach ($array as $item) {
$list[$item[$keyName]] = $item;
}
return $list;
}
/**
* 把返回的数据集转换成Tree
* @param $list
* @param string $pk
* @param string $pid
* @param string $child
* @param string $root
* @return array
*/
public static function listToTree(
array $list,
string $pk = 'id',
string $pid = 'fid',
string $child = 'children',
string $root = '0'
): array {
$tree = [];
if (is_array($list)) {
$refer = [];
foreach ($list as $key => $data) {
$refer[$data[$pk]] = &$list[$key];
}
foreach ($list as $key => $data) {
$parentId = $data[$pid];
if ($root == $parentId) {
$tree[] = &$list[$key];
} else {
if (isset($refer[$parentId])) {
$parent = &$refer[$parentId];
$parent[$child][] = &$list[$key];
}
}
}
}
return $tree;
}
/**
* 将层级数组遍历成一维数组
* @param array $list
* @param int $lv
* @param string $title
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function formatTree(array $list, int $lv = 0, string $title = 'title'): array {
$formatTree = [];
foreach ($list as $key => $val) {
$title_prefix = '';
for ($i = 0; $i < $lv; $i++) {
$title_prefix .= "|---";
}
$val['lv'] = $lv;
$val['namePrefix'] = $lv == 0 ? '' : $title_prefix;
$val['showName'] = $lv == 0 ? $val[$title] : $title_prefix . $val[$title];
if (!array_key_exists('children', $val)) {
array_push($formatTree, $val);
} else {
$child = $val['children'];
unset($val['children']);
array_push($formatTree, $val);
$middle = self::formatTree($child, $lv + 1, $title); //进行下一层递归
$formatTree = array_merge($formatTree, $middle);
}
}
return $formatTree;
}
}

View File

@ -1,52 +0,0 @@
<?php
/**
* 后台操作日志记录
* @since 2018-02-28
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\behavior;
use app\model\AdminMenu;
use app\model\AdminUserAction;
use app\util\ReturnCode;
use think\Request;
class AdminLog {
/**
* 后台操作日志记录
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return \think\response\Json
* @throws \think\Exception
* @throws \think\exception\DbException
*/
public function run() {
$header = config('apiAdmin.CROSS_DOMAIN');
$request = Request::instance();
$route = $request->routeInfo();
$userToken = $request->header('ApiAuth', '');
$userInfo = cache($userToken);
$userInfo = json_decode($userInfo, true);
$menuInfo = AdminMenu::get(['url' => $route['route']]);
if ($menuInfo) {
$menuInfo = $menuInfo->toArray();
} else {
$data = ['code' => ReturnCode::INVALID, 'msg' => '当前路由非法:'. $route['route'], 'data' => []];
return json($data, 200, $header);
}
AdminUserAction::create([
'actionName' => $menuInfo['name'],
'uid' => $userInfo['id'],
'nickname' => $userInfo['nickname'],
'addTime' => time(),
'url' => $route['route'],
'data' => json_encode($request->param())
]);
}
}

View File

@ -1,38 +0,0 @@
<?php
/**
* 处理Api接入认证
* @since 2017-07-25
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\behavior;
use app\util\ReturnCode;
use think\Request;
class ApiAuth {
/**
* 默认行为函数
* @return \think\response\Json
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function run() {
$request = Request::instance();
$header = config('apiAdmin.CROSS_DOMAIN');
$ApiAuth = $request->header('ApiAuth', '');
if ($ApiAuth) {
$userInfo = cache($ApiAuth);
$userInfo = json_decode($userInfo, true);
if (!$userInfo || !isset($userInfo['id'])) {
$data = ['code' => ReturnCode::AUTH_ERROR, 'msg' => 'ApiAuth不匹配', 'data' => []];
return json($data, 200, $header);
}
} else {
$data = ['code' => ReturnCode::AUTH_ERROR, 'msg' => '缺少ApiAuth', 'data' => []];
return json($data, 200, $header);
}
}
}

View File

@ -1,26 +0,0 @@
<?php
/**
* 统一支持跨域
* @since 2017-07-25
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\behavior;
use think\Config;
use think\Response;
class BuildResponse {
/**
* 返回参数过滤(主要是将返回参数的数据类型给规范)
* @param $response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function run(Response $response) {
$header = Config::get('apiAdmin.CROSS_DOMAIN');
$response->header($header);
}
}

View File

@ -1,182 +0,0 @@
<?php
/**
* 应用管理
* @since 2018-02-11
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\model\AdminApp;
use app\model\AdminList;
use app\model\AdminGroup;
use app\util\ReturnCode;
use app\util\Strs;
use app\util\Tools;
class App extends Base {
/**
* 获取应用列表
* @return array
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$keywords = $this->request->get('keywords', '');
$type = $this->request->get('type', '');
$status = $this->request->get('status', '');
$where = [];
if ($status === '1' || $status === '0') {
$where['app_status'] = $status;
}
if ($type) {
switch ($type) {
case 1:
$where['app_id'] = $keywords;
break;
case 2:
$where['app_name'] = ['like', "%{$keywords}%"];
break;
}
}
$listInfo = (new AdminApp())->where($where)->order('app_addTime', 'DESC')->limit($start, $limit)->select();
$count = (new AdminApp())->where($where)->count();
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count
]);
}
/**
* 获取AppId,AppSecret,接口列表,应用接口权限细节
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\Exception
* @throws \think\exception\DbException
*/
public function getAppInfo() {
$apiArr = AdminList::all();
foreach ($apiArr as $api) {
$res['apiList'][$api['groupHash']][] = $api;
}
$groupArr = AdminGroup::all();
$groupArr = Tools::buildArrFromObj($groupArr);
$res['groupInfo'] = array_column($groupArr, 'name', 'hash');
$id = $this->request->get('id', 0);
if ($id) {
$appInfo = AdminApp::get($id)->toArray();
$res['app_detail'] = json_decode($appInfo['app_api_show'], true);
} else {
$res['app_id'] = mt_rand(1, 9) . Strs::randString(7, 1);
$res['app_secret'] = Strs::randString(32);
}
return $this->buildSuccess($res);
}
/**
* 新增应用
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add() {
$postData = $this->request->post();
$data = [
'app_id' => $postData['app_id'],
'app_secret' => $postData['app_secret'],
'app_name' => $postData['app_name'],
'app_info' => $postData['app_info'],
'app_api' => '',
'app_api_show' => '',
];
if (isset($postData['app_api']) && $postData['app_api']) {
$appApi = [];
$data['app_api_show'] = json_encode($postData['app_api']);
foreach ($postData['app_api'] as $value) {
$appApi = array_merge($appApi, $value);
}
$data['app_api'] = implode(',', $appApi);
}
$res = AdminApp::create($data);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 应用状态编辑
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus() {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminApp::update([
'app_status' => $status
], [
'id' => $id
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 编辑应用
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit() {
$postData = $this->request->post();
$data = [
'id' => $postData['id'],
'app_id' => $postData['app_id'],
'app_secret' => $postData['app_secret'],
'app_name' => $postData['app_name'],
'app_info' => $postData['app_info'],
'app_api' => '',
'app_api_show' => '',
];
if (isset($postData['app_api']) && $postData['app_api']) {
$appApi = [];
$data['app_api_show'] = json_encode($postData['app_api']);
foreach ($postData['app_api'] as $value) {
$appApi = array_merge($appApi, $value);
}
$data['app_api'] = implode(',', $appApi);
}
$res = AdminApp::update($data);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 删除应用
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del() {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
AdminApp::destroy($id);
return $this->buildSuccess([]);
}
}

View File

@ -1,299 +0,0 @@
<?php
/**
* 权限相关配置
* @since 2018-02-06
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\model\AdminAuthGroup;
use app\model\AdminAuthGroupAccess;
use app\model\AdminAuthRule;
use app\model\AdminMenu;
use app\util\ReturnCode;
use app\util\Tools;
class Auth extends Base {
/**
* 获取权限组列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$keywords = $this->request->get('keywords', '');
$status = $this->request->get('status', '');
$where['name'] = ['like', "%{$keywords}%"];
if ($status === '1' || $status === '0') {
$where['status'] = $status;
}
$listInfo = (new AdminAuthGroup())->where($where)->order('id', 'DESC')->limit($start, $limit)->select();
$count = (new AdminAuthGroup())->where($where)->count();
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count
]);
}
/**
* 获取全部已开放的可选组
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function getGroups() {
$listInfo = (new AdminAuthGroup())->where(['status' => 1])->order('id', 'DESC')->select();
$count = count($listInfo);
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count
]);
}
/**
* 获取组所在权限列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function getRuleList() {
$groupId = $this->request->get('groupId', 0);
$list = (new AdminMenu)->where([])->order('sort', 'ASC')->select();
$list = Tools::buildArrFromObj($list);
$list = listToTree($list);
$rules = [];
if ($groupId) {
$rules = (new AdminAuthRule())->where(['groupId' => $groupId])->select();
$rules = array_column($rules, 'url');
}
$newList = $this->buildList($list, $rules);
return $this->buildSuccess([
'list' => $newList
]);
}
/**
* 新增组
* @return array
* @throws \Exception
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add() {
$rules = [];
$postData = $this->request->post();
if ($postData['rules']) {
$rules = $postData['rules'];
$rules = array_filter($rules);
}
unset($postData['rules']);
$res = AdminAuthGroup::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
if ($rules) {
$insertData = [];
foreach ($rules as $value) {
if ($value) {
$insertData[] = [
'groupId' => $res->id,
'url' => $value
];
}
}
(new AdminAuthRule())->saveAll($insertData);
}
return $this->buildSuccess([]);
}
}
/**
* 权限组状态编辑
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus() {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminAuthGroup::update([
'id' => $id,
'status' => $status
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 编辑用户
* @return array
* @throws \Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit() {
$postData = $this->request->post();
if ($postData['rules']) {
$this->editRule();
}
unset($postData['rules']);
$res = AdminAuthGroup::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 删除组
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del() {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$listInfo = (new AdminAuthGroupAccess())->where(['groupId' => ['like', "%{$id}%"]])->select();
if ($listInfo) {
foreach ($listInfo as $value) {
$valueArr = $value->toArray();
$oldGroupArr = explode(',', $valueArr['groupId']);
$key = array_search($id, $oldGroupArr);
unset($oldGroupArr[$key]);
$newData = implode(',', $oldGroupArr);
$value->groupId = $newData;
$value->save();
}
}
AdminAuthGroup::destroy($id);
AdminAuthRule::destroy(['groupId' => $id]);
return $this->buildSuccess([]);
}
/**
* 从指定组中删除指定用户
* @return array
* @throws \think\Exception
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function delMember() {
$gid = $this->request->get('gid', 0);
$uid = $this->request->get('uid', 0);
if (!$gid || !$uid) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
$oldInfo = AdminAuthGroupAccess::get(['uid' => $uid])->toArray();
$oldGroupArr = explode(',', $oldInfo['groupId']);
$key = array_search($gid, $oldGroupArr);
unset($oldGroupArr[$key]);
$newData = implode(',', $oldGroupArr);
$res = AdminAuthGroupAccess::update([
'groupId' => $newData
], [
'uid' => $uid
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 构建适用前端的权限数据
* @param $list
* @param $rules
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function buildList($list, $rules) {
$newList = [];
foreach ($list as $key => $value) {
$newList[$key]['title'] = $value['name'];
$newList[$key]['key'] = $value['url'];
if (isset($value['_child'])) {
$newList[$key]['expand'] = true;
$newList[$key]['children'] = $this->buildList($value['_child'], $rules);
} else {
if (in_array($value['url'], $rules)) {
$newList[$key]['checked'] = true;
}
}
}
return $newList;
}
/**
* 编辑权限细节
* @throws \Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function editRule() {
$postData = $this->request->post();
$needAdd = [];
$has = (new AdminAuthRule())->where(['groupId' => $postData['id']])->select();
$has = Tools::buildArrFromObj($has);
$hasRule = array_column($has, 'url');
$needDel = array_flip($hasRule);
foreach ($postData['rules'] as $key => $value) {
if (!empty($value)) {
if (!in_array($value, $hasRule)) {
$data['url'] = $value;
$data['groupId'] = $postData['id'];
$needAdd[] = $data;
} else {
unset($needDel[$value]);
}
}
}
if (count($needAdd)) {
(new AdminAuthRule())->saveAll($needAdd);
}
if (count($needDel)) {
$urlArr = array_keys($needDel);
AdminAuthRule::destroy([
'groupId' => $postData['id'],
'url' => ['in', $urlArr]
]);
}
}
}

View File

@ -1,57 +0,0 @@
<?php
/**
* 工程基类
* @since 2017/02/28 创建
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\util\ReturnCode;
use think\Controller;
class Base extends Controller {
private $debug = [];
protected $userInfo;
public function _initialize() {
$ApiAuth = $this->request->header('ApiAuth');
if ($ApiAuth) {
$userInfo = cache($ApiAuth);
$this->userInfo = json_decode($userInfo, true);
}
}
public function buildSuccess($data, $msg = '操作成功', $code = ReturnCode::SUCCESS) {
$return = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
if ($this->debug) {
$return['debug'] = $this->debug;
}
return $return;
}
public function buildFailed($code, $msg, $data = []) {
$return = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
if ($this->debug) {
$return['debug'] = $this->debug;
}
return $return;
}
protected function debug($data) {
if ($data) {
$this->debug[] = $data;
}
}
}

View File

@ -1,248 +0,0 @@
<?php
/**
* 接口输入输出字段维护
* @since 2018-02-21
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\model\AdminFields;
use app\model\AdminList;
use app\util\DataType;
use app\util\ReturnCode;
use app\util\Tools;
class Fields extends Base {
private $dataType = array(
DataType::TYPE_INTEGER => 'Integer',
DataType::TYPE_STRING => 'String',
DataType::TYPE_BOOLEAN => 'Boolean',
DataType::TYPE_ENUM => 'Enum',
DataType::TYPE_FLOAT => 'Float',
DataType::TYPE_FILE => 'File',
DataType::TYPE_MOBILE => 'Mobile',
DataType::TYPE_OBJECT => 'Object',
DataType::TYPE_ARRAY => 'Array'
);
public function index() {
return $this->buildSuccess($this->dataType);
}
/**
* 获取请求参数
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function request() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$hash = $this->request->get('hash', '');
if (!empty($hash)) {
$listInfo = (new AdminFields())->where(['hash' => $hash, 'type' => 0])->limit($start, $limit)->select();
$count = (new AdminFields())->where(['hash' => $hash, 'type' => 0])->count();
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count,
'dataType' => $this->dataType
]);
} else {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
}
/**
* 获取返回参数
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function response() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$hash = $this->request->get('hash', '');
if (!empty($hash)) {
$listInfo = (new AdminFields())->where(['hash' => $hash, 'type' => 1])->limit($start, $limit)->select();
$count = (new AdminFields())->where(['hash' => $hash, 'type' => 1])->count();
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count,
'dataType' => $this->dataType
]);
} else {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
}
/**
* 新增字段
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/
public function add() {
$postData = $this->request->post();
$postData['showName'] = $postData['fieldName'];
$postData['default'] = $postData['defaults'];
unset($postData['defaults']);
$res = AdminFields::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess('操作成功');
}
}
/**
* 字段编辑
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/
public function edit() {
$postData = $this->request->post();
$postData['showName'] = $postData['fieldName'];
$postData['default'] = $postData['defaults'];
unset($postData['defaults']);
$res = AdminFields::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 字段删除
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/
public function del() {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
AdminFields::destroy($id);
return $this->buildSuccess([]);
}
/**
* 批量上传返回字段
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function upload() {
$hash = $this->request->post('hash');
$type = $this->request->post('type');
$jsonStr = $this->request->post('jsonStr');
$jsonStr = html_entity_decode($jsonStr);
$data = json_decode($jsonStr, true);
if ($data === null) {
return $this->buildFailed(ReturnCode::EXCEPTION, 'JSON数据格式有误');
}
AdminList::update(['returnStr' => json_encode($data)], ['hash' => $hash]);
$this->handle($data['data'], $dataArr);
$old = (new AdminFields())->where([
'hash' => $hash,
'type' => $type
])->select();
$old = Tools::buildArrFromObj($old);
$oldArr = array_column($old, 'showName');
$newArr = array_column($dataArr, 'showName');
$addArr = array_diff($newArr, $oldArr);
$delArr = array_diff($oldArr, $newArr);
if ($delArr) {
AdminFields::destroy(['showName' => ['in', $delArr]]);
}
if ($addArr) {
$addData = [];
foreach ($dataArr as $item) {
if (in_array($item['showName'], $addArr)) {
$addData[] = $item;
}
}
(new AdminFields())->insertAll($addData);
}
return $this->buildSuccess([]);
}
private function handle($data, &$dataArr, $prefix = 'data', $index = 'data') {
if (!$this->isAssoc($data)) {
$addArr = array(
'fieldName' => $index,
'showName' => $prefix,
'hash' => $this->request->post('hash'),
'isMust' => 1,
'dataType' => DataType::TYPE_ARRAY,
'type' => $this->request->post('type')
);
$dataArr[] = $addArr;
$prefix .= '[]';
if (is_array($data[0])) {
$this->handle($data[0], $dataArr, $prefix);
}
} else {
$addArr = array(
'fieldName' => $index,
'showName' => $prefix,
'hash' => $this->request->post('hash'),
'isMust' => 1,
'dataType' => DataType::TYPE_OBJECT,
'type' => $this->request->post('type')
);
$dataArr[] = $addArr;
$prefix .= '{}';
foreach ($data as $index => $datum) {
$myPre = $prefix . $index;
$addArr = array(
'fieldName' => $index,
'showName' => $myPre,
'hash' => $this->request->post('hash'),
'isMust' => 1,
'dataType' => DataType::TYPE_STRING,
'type' => $this->request->post('type')
);
if (is_numeric($datum)) {
if (preg_match('/^\d*$/', $datum)) {
$addArr['dataType'] = DataType::TYPE_INTEGER;
} else {
$addArr['dataType'] = DataType::TYPE_FLOAT;
}
$dataArr[] = $addArr;
} elseif (is_array($datum)) {
$this->handle($datum, $dataArr, $myPre, $index);
} else {
$addArr['dataType'] = DataType::TYPE_STRING;
$dataArr[] = $addArr;
}
}
}
}
/**
* 判断是否是关联数组true表示是关联数组
* @param array $arr
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return bool
*/
private function isAssoc(array $arr) {
if (array() === $arr) return false;
return array_keys($arr) !== range(0, count($arr) - 1);
}
}

View File

@ -1,137 +0,0 @@
<?php
/**
* 接口组维护
* @since 2018-02-11
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\model\AdminGroup;
use app\util\ReturnCode;
use app\util\Tools;
class InterfaceGroup extends Base {
/**
* 获取接口组列表
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function index() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$keywords = $this->request->get('keywords', '');
$type = $this->request->get('type', '');
$status = $this->request->get('status', '');
$where = [];
if ($status === '1' || $status === '0') {
$where['status'] = $status;
}
if ($type) {
switch ($type) {
case 1:
$where['hash'] = $keywords;
break;
case 2:
$where['name'] = ['like', "%{$keywords}%"];
break;
}
}
$listInfo = (new AdminGroup())->where($where)->limit($start, $limit)->select();
$count = (new AdminGroup())->where($where)->count();
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count
]);
}
/**
* 获取全部有效的接口组
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function getAll() {
$listInfo = (new AdminGroup())->where(['status' => 1])->select();
return $this->buildSuccess([
'list' => $listInfo
]);
}
/**
* 接口组状态编辑
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus() {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminGroup::update([
'status' => $status
], [
'id' => $id
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 添加接口组
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/
public function add() {
$postData = $this->request->post();
$postData['addTime'] = $postData['updateTime'] = time();
$res = AdminGroup::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 接口组编辑
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/
public function edit() {
$postData = $this->request->post();
$postData['updateTime'] = time();
$res = AdminGroup::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 接口组删除
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/
public function del() {
$hash = $this->request->get('hash');
if (!$hash) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
AdminGroup::destroy(['hash' => $hash]);
return $this->buildSuccess([]);
}
}

View File

@ -1,158 +0,0 @@
<?php
/**
* 接口管理
* @since 2018-02-11
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\model\AdminFields;
use app\model\AdminList;
use app\util\ReturnCode;
use app\util\Tools;
class InterfaceList extends Base {
/**
* 获取接口列表
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function index() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$keywords = $this->request->get('keywords', '');
$type = $this->request->get('type', '');
$status = $this->request->get('status', '');
$where = [];
if ($status === '1' || $status === '0') {
$where['status'] = $status;
}
if ($type) {
switch ($type) {
case 1:
$where['hash'] = $keywords;
break;
case 2:
$where['info'] = ['like', "%{$keywords}%"];
break;
case 3:
$where['apiClass'] = ['like', "%{$keywords}%"];
break;
}
}
$listInfo = (new AdminList())->where($where)->order('id', 'DESC')->limit($start, $limit)->select();
$count = (new AdminList())->where($where)->count();
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count
]);
}
/**
* 获取接口唯一标识
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/
public function getHash() {
$res['hash'] = uniqid();
return $this->buildSuccess($res);
}
/**
* 新增接口
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add() {
$postData = $this->request->post();
$res = AdminList::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 接口状态编辑
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus() {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminList::update([
'status' => $status
], [
'id' => $id
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 编辑应用
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function edit() {
$postData = $this->request->post();
$res = AdminList::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 删除接口
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del() {
$hash = $this->request->get('hash');
if (!$hash) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
AdminList::destroy(['hash' => $hash]);
AdminFields::destroy(['hash' => $hash]);
return $this->buildSuccess([]);
}
/**
* 刷新接口路由
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\exception\DbException
*/
public function refresh() {
$apiRoutePath = ROOT_PATH . 'application/apiRoute.php';
$tplPath = ROOT_PATH . 'data/apiRoute.tpl';
$methodArr = ['*','POST','GET'];
$tplStr = file_get_contents($tplPath);
$listInfo = AdminList::all(['status' => 1]);
foreach ($listInfo as $value) {
$tplStr .= 'Route::rule(\'api/'.$value->hash.'\',\'api/'.$value->apiClass.'\', \''.$methodArr[$value->method].'\', [\'after_behavior\' => $afterBehavior]);';
}
file_put_contents($apiRoutePath, $tplStr);
return $this->buildSuccess([]);
}
}

View File

@ -1,76 +0,0 @@
<?php
/**
* 后台操作日志管理
* @since 2018-02-06
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\model\AdminAuthGroupAccess;
use app\model\AdminUser;
use app\model\AdminUserAction;
use app\model\AdminUserData;
use app\util\ReturnCode;
use app\util\Tools;
class Log extends Base {
/**
* 获取操作日志列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$type = $this->request->get('type', '');
$keywords = $this->request->get('keywords', '');
$where = [];
if ($type) {
switch ($type) {
case 1:
$where['url'] = ['like', "%{$keywords}%"];
break;
case 2:
$where['nickname'] = ['like', "%{$keywords}%"];
break;
case 3:
$where['uid'] = $keywords;
break;
}
}
$listInfo = (new AdminUserAction())->where($where)->order('addTime', 'DESC')->limit($start, $limit)->select();
$count = (new AdminUserAction())->where($where)->count();
$listInfo = Tools::buildArrFromObj($listInfo);
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count
]);
}
/**
* 删除日志
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del() {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
AdminUserAction::destroy($id);
return $this->buildSuccess([]);
}
}

View File

@ -1,101 +0,0 @@
<?php
/**
* 登录登出
* @since 2017-11-02
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\model\AdminAuthGroupAccess;
use app\model\AdminAuthRule;
use app\model\AdminMenu;
use app\model\AdminUser;
use app\model\AdminUserData;
use app\util\ReturnCode;
use app\util\Tools;
class Login extends Base {
/**
* 用户登录
* @return array
* @throws \think\Exception
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index() {
$username = $this->request->post('username');
$password = $this->request->post('password');
if (!$username) {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '缺少用户名!');
}
if (!$password) {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '缺少密码!');
} else {
$password = Tools::userMd5($password);
}
$userInfo = AdminUser::get(['username' => $username, 'password' => $password]);
if (!empty($userInfo)) {
if ($userInfo['status']) {
//更新用户数据
$userData = AdminUserData::get(['uid' => $userInfo['id']]);
$data = [];
if ($userData) {
$userData->loginTimes ++;
$userData->lastLoginIp = $this->request->ip(1);
$userData->lastLoginTime = time();
$return['headImg'] = $userData['headImg'];
$userData->save();
} else {
$data['loginTimes'] = 1;
$data['uid'] = $userInfo['id'];
$data['lastLoginIp'] = $this->request->ip(1);
$data['lastLoginTime'] = time();
$data['headImg'] = '';
$return['headImg'] = '';
AdminUserData::create($data);
}
} else {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '用户已被封禁,请联系管理员');
}
} else {
return $this->buildFailed(ReturnCode::LOGIN_ERROR, '用户名密码不正确');
}
$apiAuth = md5(uniqid() . time());
cache($apiAuth, json_encode($userInfo), config('apiAdmin.ONLINE_TIME'));
cache($userInfo['id'], $apiAuth, config('apiAdmin.ONLINE_TIME'));
$return['access'] = 1000000;
$isSupper = Tools::isAdministrator($userInfo['id']);
if ($isSupper) {
$access = AdminMenu::all(['hide' => 0]);
$access = Tools::buildArrFromObj($access);
$return['access'] = array_values(array_filter(array_column($access, 'url')));
} else {
$groups = AdminAuthGroupAccess::get(['uid' => $userInfo['id']]);
if (isset($groups) || $groups->groupId) {
$access = (new AdminAuthRule())->whereIn('groupId', $groups->groupId)->select();
$access = Tools::buildArrFromObj($access);
$return['access'] = array_values(array_unique(array_column($access, 'url')));
}
}
$return['id'] = $userInfo['id'];
$return['username'] = $userInfo['username'];
$return['nickname'] = $userInfo['nickname'];
$return['apiAuth'] = $apiAuth;
return $this->buildSuccess($return, '登录成功');
}
public function logout() {
$ApiAuth = $this->request->header('ApiAuth');
cache($ApiAuth, null);
cache($this->userInfo['id'], null);
return $this->buildSuccess([], '登出成功');
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace app\admin\controller;
use app\util\ReturnCode;
use think\Request;
class Miss extends Base {
public function index() {
if (Request::instance()->isOptions()) {
return $this->buildSuccess([]);
} else {
return $this->buildFailed(ReturnCode::INVALID, '接口地址异常', []);
}
}
}

View File

@ -1,274 +0,0 @@
<?php
/**
* 用户管理
* @since 2018-02-06
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\controller;
use app\model\AdminAuthGroupAccess;
use app\model\AdminUser;
use app\model\AdminUserData;
use app\util\ReturnCode;
use app\util\Tools;
class User extends Base {
/**
* 获取用户列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function index() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$type = $this->request->get('type', '');
$keywords = $this->request->get('keywords', '');
$status = $this->request->get('status', '');
$where = [];
if ($status === '1' || $status === '0') {
$where['status'] = $status;
}
if ($type) {
switch ($type) {
case 1:
$where['username'] = ['like', "%{$keywords}%"];
break;
case 2:
$where['nickname'] = ['like', "%{$keywords}%"];
break;
}
}
$listInfo = (new AdminUser())->where($where)->order('regTime', 'DESC')->limit($start, $limit)->select();
$count = (new AdminUser())->where($where)->count();
$listInfo = Tools::buildArrFromObj($listInfo);
$idArr = array_column($listInfo, 'id');
$userData = AdminUserData::all(function($query) use ($idArr) {
$query->whereIn('uid', $idArr);
});
$userData = Tools::buildArrFromObj($userData);
$userData = Tools::buildArrByNewKey($userData, 'uid');
$userGroup = AdminAuthGroupAccess::all(function($query) use ($idArr) {
$query->whereIn('uid', $idArr);
});
$userGroup = Tools::buildArrFromObj($userGroup);
$userGroup = Tools::buildArrByNewKey($userGroup, 'uid');
foreach ($listInfo as $key => $value) {
if (isset($userData[$value['id']])) {
$listInfo[$key]['lastLoginIp'] = long2ip($userData[$value['id']]['lastLoginIp']);
$listInfo[$key]['loginTimes'] = $userData[$value['id']]['loginTimes'];
$listInfo[$key]['lastLoginTime'] = date('Y-m-d H:i:s', $userData[$value['id']]['lastLoginTime']);
}
$listInfo[$key]['regIp'] = long2ip($listInfo[$key]['regIp']);
if (isset($userGroup[$value['id']])) {
$listInfo[$key]['groupId'] = explode(',', $userGroup[$value['id']]['groupId']);
} else {
$listInfo[$key]['groupId'] = [];
}
}
return $this->buildSuccess([
'list' => $listInfo,
'count' => $count
]);
}
/**
* 新增用户
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add() {
$groups = '';
$postData = $this->request->post();
$postData['regIp'] = request()->ip(1);
$postData['regTime'] = time();
$postData['password'] = Tools::userMd5($postData['password']);
if ($postData['groupId']) {
$groups = trim(implode(',', $postData['groupId']), ',');
}
unset($postData['groupId']);
$res = AdminUser::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
AdminAuthGroupAccess::create([
'uid' => $res->id,
'groupId' => $groups
]);
return $this->buildSuccess([]);
}
}
/**
* 获取当前组的全部用户
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function getUsers() {
$limit = $this->request->get('size', config('apiAdmin.ADMIN_LIST_DEFAULT'));
$start = $limit * ($this->request->get('page', 1) - 1);
$gid = $this->request->get('gid', 0);
if (!$gid) {
return $this->buildFailed(ReturnCode::PARAM_INVALID, '非法操作');
}
$listInfo = (new AdminAuthGroupAccess())->where(['groupId' => ['like', "%{$gid}%"]])->select();
$listInfo = Tools::buildArrFromObj($listInfo);
$uidArr = array_column($listInfo, 'uid');
$userInfo = (new AdminUser())->whereIn('id', $uidArr)->order('regTime', 'DESC')->limit($start, $limit)->select();
$count = (new AdminUser())->whereIn('id', $uidArr)->count();
$userInfo = Tools::buildArrFromObj($userInfo);
$userData = AdminUserData::all(function($query) use ($uidArr) {
$query->whereIn('uid', $uidArr);
});
$userData = Tools::buildArrFromObj($userData);
$userData = Tools::buildArrByNewKey($userData, 'uid');
foreach ($userInfo as $key => $value) {
if (isset($userData[$value['id']])) {
$userInfo[$key]['lastLoginIp'] = long2ip($userData[$value['id']]['lastLoginIp']);
$userInfo[$key]['loginTimes'] = $userData[$value['id']]['loginTimes'];
$userInfo[$key]['lastLoginTime'] = date('Y-m-d H:i:s', $userData[$value['id']]['lastLoginTime']);
}
$userInfo[$key]['regIp'] = long2ip($userInfo[$key]['regIp']);
}
return $this->buildSuccess([
'list' => $userInfo,
'count' => $count
]);
}
/**
* 用户状态编辑
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function changeStatus() {
$id = $this->request->get('id');
$status = $this->request->get('status');
$res = AdminUser::update([
'id' => $id,
'status' => $status,
'updateTime' => time()
]);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
return $this->buildSuccess([]);
}
}
/**
* 编辑用户
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\exception\DbException
*/
public function edit() {
$groups = '';
$postData = $this->request->post();
if ($postData['password'] === 'ApiAdmin') {
unset($postData['password']);
} else {
$postData['password'] = Tools::userMd5($postData['password']);
}
if ($postData['groupId']) {
$groups = trim(implode(',', $postData['groupId']), ',');
}
$postData['updateTime'] = time();
unset($postData['groupId']);
$res = AdminUser::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
$has = AdminAuthGroupAccess::get(['uid' => $postData['id']]);
if ($has) {
AdminAuthGroupAccess::update([
'groupId' => $groups
], [
'uid' => $postData['id'],
]);
} else {
AdminAuthGroupAccess::create([
'uid' => $postData['id'],
'groupId' => $groups
]);
}
return $this->buildSuccess([]);
}
}
/**
* 修改自己的信息
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
* @throws \think\exception\DbException
*/
public function own() {
$postData = $this->request->post();
$headImg = $postData['headImg'];
if ($postData['password'] && $postData['oldPassword']) {
$oldPass = Tools::userMd5($postData['oldPassword']);
unset($postData['oldPassword']);
if ($oldPass === $this->userInfo['password']) {
$postData['password'] = Tools::userMd5($postData['password']);
} else {
return $this->buildFailed(ReturnCode::INVALID, '原始密码不正确');
}
} else {
unset($postData['password']);
unset($postData['oldPassword']);
}
$postData['id'] = $this->userInfo['id'];
$postData['updateTime'] = time();
unset($postData['headImg']);
$res = AdminUser::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '操作失败');
} else {
$userData = AdminUserData::get(['uid' => $postData['id']]);
$userData->headImg = $headImg;
$userData->save();
return $this->buildSuccess([]);
}
}
/**
* 删除用户
* @return array
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del() {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
AdminUser::destroy($id);
AdminAuthGroupAccess::destroy(['uid' => $id]);
return $this->buildSuccess([]);
}
}

View File

@ -1,18 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 应用行为扩展定义文件
return [
// 输出结束
'response_send' => [
'app\\admin\\behavior\\BuildResponse',
],
];

View File

@ -1,240 +0,0 @@
<?php
$afterBehavior = [
'\app\admin\behavior\ApiAuth',
'\app\admin\behavior\ApiPermission',
'\app\admin\behavior\AdminLog'
];
return [
'[admin]' => [
'Login/index' => [
'admin/Login/index',
['method' => 'post']
],
'Index/upload' => [
'admin/Index/upload',
['method' => 'post', 'after_behavior' => ['\app\admin\behavior\ApiAuth', '\app\admin\behavior\AdminLog']]
],
'Login/logout' => [
'admin/Login/logout',
['method' => 'get', 'after_behavior' => ['\app\admin\behavior\ApiAuth', '\app\admin\behavior\AdminLog']]
],
'Menu/index' => [
'admin/Menu/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Menu/changeStatus' => [
'admin/Menu/changeStatus',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Menu/add' => [
'admin/Menu/add',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'Menu/edit' => [
'admin/Menu/edit',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'Menu/del' => [
'admin/Menu/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'User/index' => [
'admin/User/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'User/getUsers' => [
'admin/User/getUsers',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'User/changeStatus' => [
'admin/User/changeStatus',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'User/add' => [
'admin/User/add',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'User/own' => [
'admin/User/own',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'User/edit' => [
'admin/User/edit',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'User/del' => [
'admin/User/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Auth/index' => [
'admin/Auth/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Auth/changeStatus' => [
'admin/Auth/changeStatus',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Auth/delMember' => [
'admin/Auth/delMember',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Auth/add' => [
'admin/Auth/add',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'Auth/edit' => [
'admin/Auth/edit',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'Auth/del' => [
'admin/Auth/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Auth/getGroups' => [
'admin/Auth/getGroups',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Auth/getRuleList' => [
'admin/Auth/getRuleList',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'App/index' => [
'admin/App/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'App/changeStatus' => [
'admin/App/changeStatus',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'App/getAppInfo' => [
'admin/App/getAppInfo',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'App/add' => [
'admin/App/add',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'App/edit' => [
'admin/App/edit',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'App/del' => [
'admin/App/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceList/index' => [
'admin/InterfaceList/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceList/refresh' => [
'admin/InterfaceList/refresh',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceList/changeStatus' => [
'admin/InterfaceList/changeStatus',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceList/getHash' => [
'admin/InterfaceList/getHash',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceList/add' => [
'admin/InterfaceList/add',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'InterfaceList/edit' => [
'admin/InterfaceList/edit',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'InterfaceList/del' => [
'admin/InterfaceList/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Fields/index' => [
'admin/Fields/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Fields/request' => [
'admin/Fields/request',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Fields/response' => [
'admin/Fields/response',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Fields/add' => [
'admin/Fields/add',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'Fields/upload' => [
'admin/Fields/upload',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'Fields/edit' => [
'admin/Fields/edit',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'Fields/del' => [
'admin/Fields/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceGroup/index' => [
'admin/InterfaceGroup/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceGroup/add' => [
'admin/InterfaceGroup/add',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'InterfaceGroup/edit' => [
'admin/InterfaceGroup/edit',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'InterfaceGroup/del' => [
'admin/InterfaceGroup/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceGroup/getAll' => [
'admin/InterfaceGroup/getAll',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'InterfaceGroup/changeStatus' => [
'admin/InterfaceGroup/changeStatus',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'AppGroup/index' => [
'admin/AppGroup/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'AppGroup/add' => [
'admin/AppGroup/add',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'AppGroup/edit' => [
'admin/AppGroup/edit',
['method' => 'post', 'after_behavior' => $afterBehavior]
],
'AppGroup/del' => [
'admin/AppGroup/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'AppGroup/getAll' => [
'admin/AppGroup/getAll',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'AppGroup/changeStatus' => [
'admin/AppGroup/changeStatus',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Log/index' => [
'admin/Log/index',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'Log/del' => [
'admin/Log/del',
['method' => 'get', 'after_behavior' => $afterBehavior]
],
'__miss__' => ['admin/Miss/index'],
],
];

View File

@ -1,112 +0,0 @@
<?php
/**
* 处理Api接入认证
* @since 2017-07-25
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\api\behavior;
use app\model\AdminList;
use app\util\ApiLog;
use app\util\ReturnCode;
use think\Request;
class ApiAuth {
/**
* @var Request
*/
private $request;
private $apiInfo;
/**
* 默认行为函数
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return \think\response\Json
* @throws \think\Exception
* @throws \think\exception\DbException
*/
public function run() {
$this->request = Request::instance();
$hash = $this->request->routeInfo();
if (isset($hash['rule'][1])) {
$hash = $hash['rule'][1];
$this->apiInfo = AdminList::get(['hash' => $hash]);
if ($this->apiInfo) {
$this->apiInfo = $this->apiInfo->toArray();
} else {
return json(['code' => ReturnCode::DB_READ_ERROR, 'msg' => '获取接口配置数据失败', 'data' => []]);
}
if ($this->apiInfo['accessToken'] && !$this->apiInfo['isTest']) {
$accessRes = $this->checkAccessToken();
if ($accessRes) {
return $accessRes;
}
}
if (!$this->apiInfo['isTest']) {
$versionRes = $this->checkVersion();
if ($versionRes) {
return $versionRes;
}
}
$loginRes = $this->checkLogin();
if ($loginRes) {
return $loginRes;
}
ApiLog::setApiInfo($this->apiInfo);
}
}
/**
* Api接口合法性检测
*/
private function checkAccessToken() {
$access_token = $this->request->header('access-token');
if (!isset($access_token) || !$access_token) {
return json(['code' => ReturnCode::ACCESS_TOKEN_TIMEOUT, 'msg' => '缺少参数access-token', 'data' => []]);
} else {
$appInfo = cache($access_token);
if (!$appInfo) {
return json(['code' => ReturnCode::ACCESS_TOKEN_TIMEOUT, 'msg' => 'access-token已过期', 'data' => []]);
}
ApiLog::setAppInfo($appInfo);
}
}
/**
* Api版本参数校验
*/
private function checkVersion() {
$version = $this->request->header('version');
if (!isset($version) || !$version) {
return json(['code' => ReturnCode::EMPTY_PARAMS, 'msg' => '缺少参数version', 'data' => []]);
} else {
if ($version != config('apiAdmin.APP_VERSION')) {
return json(['code' => ReturnCode::VERSION_INVALID, 'msg' => 'API版本不匹配', 'data' => []]);
}
}
}
/**
* 检测用户登录情况 检测通过请赋予USER_INFO值
*/
private function checkLogin() {
$userToken = $this->request->header('user-token', '');
if ($this->apiInfo['needLogin']) {
if (!$userToken) {
return json(['code' => ReturnCode::AUTH_ERROR, 'msg' => '缺少user-token', 'data' => []]);
}
}
if ($userToken) {
$userInfo = cache('wx:openId:' . $userToken);
if (!is_array($userInfo) || !isset($userInfo['openId'])) {
return json(['code' => ReturnCode::AUTH_ERROR, 'msg' => 'user-token不匹配', 'data' => []]);
}
ApiLog::setUserInfo($userInfo);
}
}
}

View File

@ -1,45 +0,0 @@
<?php
/**
* 处理app_id接入接口权限 需要重新签发AccessToken才能生效新的权限
* @since 2017-07-25
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\api\behavior;
use app\util\ReturnCode;
use think\Request;
class ApiPermission {
/**
* @var Request
*/
private $request;
/**
* 接口鉴权
* @return \think\response\Json
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function run() {
$this->request = Request::instance();
$hash = $this->request->routeInfo();
if (isset($hash['rule'][1])) {
$hash = $hash['rule'][1];
$access_token = $this->request->header('access-token');
if ($access_token) {
$appInfo = cache($access_token);
$allRules = explode(',', $appInfo['app_api']);
if (!in_array($hash, $allRules)) {
$data = ['code' => ReturnCode::INVALID, 'msg' => '非常抱歉,您没有权限怎么做!', 'data' => []];
return json($data);
}
}
}
}
}

View File

@ -1,88 +0,0 @@
<?php
/**
* 输出结果规整
* @since 2017-07-25
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\api\behavior;
use app\model\AdminFields;
use app\util\ApiLog;
use app\util\DataType;
use think\Request;
class BuildResponse {
/**
* 返回参数过滤(主要是将返回参数的数据类型给规范)
* @param $response \think\Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @throws \think\exception\DbException
*/
public function run($response) {
$data = $response->getData();
$request = Request::instance();
$hash = $request->routeInfo();
if (isset($hash['rule'][1])) {
$hash = $hash['rule'][1];
$rule = AdminFields::all(['hash' => $hash, 'type' => 1]);
if ($rule) {
$rule = json_decode(json_encode($rule), true);
$newRule = array_column($rule, 'dataType', 'showName');
if (is_array($data)) {
$this->handle($data['data'], $newRule);
} elseif (empty($data)) {
if ($newRule['data'] == DataType::TYPE_OBJECT) {
$data = (object)[];
} elseif ($newRule['data'] == DataType::TYPE_ARRAY) {
$data = [];
}
}
$response->data($data);
}
}
ApiLog::setResponse($data);
ApiLog::save();
}
private function handle(&$data, $rule, $prefix = 'data') {
if (empty($data)) {
if ($rule[$prefix] == DataType::TYPE_OBJECT) {
$data = (object)[];
}
} else {
if ($rule[$prefix] == DataType::TYPE_OBJECT) {
$prefix .= '{}';
foreach ($data as $index => &$datum) {
$myPre = $prefix . $index;
if (isset($rule[$myPre])) {
switch ($rule[$myPre]) {
case DataType::TYPE_INTEGER:
$datum = intval($datum);
break;
case DataType::TYPE_FLOAT:
$datum = floatval($datum);
break;
case DataType::TYPE_STRING:
$datum = strval($datum);
break;
default:
$this->handle($datum, $rule, $myPre);
break;
}
}
}
} else {
$prefix .= '[]';
if (is_array($data[0])) {
foreach ($data as &$datum) {
$this->handle($datum, $rule, $prefix);
}
}
}
}
}
}

View File

@ -1,168 +0,0 @@
<?php
/**
* 输入参数过滤行为
* TODO::Route异常捕获、规则缓存
* @since 2017-07-25
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\api\behavior;
use app\model\AdminFields;
use app\util\ApiLog;
use app\util\ReturnCode;
use app\util\DataType;
use think\Request;
use think\Validate;
class RequestFilter {
/**
* 默认行为函数
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function run() {
$request = Request::instance();
$method = strtoupper($request->method());
switch ($method) {
case 'GET':
$data = $request->get();
break;
case 'POST':
$data = $request->post();
break;
case 'DELETE':
$data = $request->delete();
break;
case 'PUT':
$data = $request->put();
break;
default :
$data = [];
break;
}
ApiLog::setRequest($data);
$hash = $request->routeInfo();
if (isset($hash['rule'][1])) {
$hash = $hash['rule'][1];
$rule = AdminFields::all(['hash' => $hash, 'type' => 0]);
$newRule = $this->buildValidateRule($rule);
if ($newRule) {
$validate = new Validate($newRule);
if (!$validate->check($data)) {
return json(['code' => ReturnCode::PARAM_INVALID, 'msg' => $validate->getError(), 'data' => []]);
}
}
$newData = [];
foreach ($rule as $item) {
$newData[$item['fieldName']] = $data[$item['fieldName']];
if (!$item['isMust'] && $item['default'] !== '' && !isset($data[$item['fieldName']])) {
$newData[$item['fieldName']] = $item['default'];
}
}
switch ($method) {
case 'GET':
$request->get($newData);
break;
case 'POST':
$request->post($newData);
break;
case 'DELETE':
$request->delete($newData);
break;
case 'PUT':
$request->put($newData);
break;
}
ApiLog::setRequestAfterFilter($newData);
}
ApiLog::setHeader($request->header());
}
/**
* 将数据库中的规则转换成TP_Validate使用的规则数组
* @param array $rule
* @author zhaoxiang <zhaoxiang051405@gmail.com>
* @return array
*/
public function buildValidateRule($rule = array()) {
$newRule = [];
if ($rule) {
foreach ($rule as $value) {
if ($value['isMust']) {
$newRule[$value['fieldName']][] = 'require';
}
switch ($value['dataType']) {
case DataType::TYPE_INTEGER:
$newRule[$value['fieldName']][] = 'number';
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
if (isset($range['min'])) {
$newRule[$value['fieldName']]['egt'] = $range['min'];
}
if (isset($range['max'])) {
$newRule[$value['fieldName']]['elt'] = $range['max'];
}
}
break;
case DataType::TYPE_STRING:
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
if (isset($range['min'])) {
$newRule[$value['fieldName']]['min'] = $range['min'];
}
if (isset($range['max'])) {
$newRule[$value['fieldName']]['max'] = $range['max'];
}
}
break;
case DataType::TYPE_ENUM:
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
$newRule[$value['fieldName']]['in'] = implode(',', $range);
}
break;
case DataType::TYPE_FLOAT:
$newRule[$value['fieldName']][] = 'float';
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
if (isset($range['min'])) {
$newRule[$value['fieldName']]['egt'] = $range['min'];
}
if (isset($range['max'])) {
$newRule[$value['fieldName']]['elt'] = $range['max'];
}
}
break;
case DataType::TYPE_ARRAY:
$newRule[$value['fieldName']][] = 'array';
if ($value['range']) {
$range = htmlspecialchars_decode($value['range']);
$range = json_decode($range, true);
if (isset($range['min'])) {
$newRule[$value['fieldName']]['min'] = $range['min'];
}
if (isset($range['max'])) {
$newRule[$value['fieldName']]['max'] = $range['max'];
}
}
break;
case DataType::TYPE_MOBILE:
$newRule[$value['fieldName']]['regex'] = '/^1[34578]\d{9}$/';
break;
}
}
}
return $newRule;
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace app\api\controller;
use Curl\Curl;
class Index extends Base {
public function index() {
$curl = new Curl();
dump($curl->get('http://www.apiadmin.org'));exit;
$this->debug([
'TpVersion' => THINK_VERSION
]);
return $this->buildSuccess([
'Product' => config('apiAdmin.APP_NAME'),
'Version' => config('apiAdmin.APP_VERSION'),
'Company' => config('apiAdmin.COMPANY_NAME'),
'ToYou' => "I'm glad to meet you终于等到你"
]);
}
}

View File

@ -1,12 +0,0 @@
<?php
namespace app\api\controller;
use app\util\ReturnCode;
class Miss extends Base {
public function index() {
return $this->buildFailed(ReturnCode::NOT_EXISTS, '接口Hash异常');
}
}

View File

@ -1,18 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 应用行为扩展定义文件
return [
// 输出结束
'response_send' => [
'app\\api\\behavior\\BuildResponse',
],
];

View File

@ -1,8 +0,0 @@
<?php
/**
* Api路由
*/
use think\Route;
Route::miss('api/Index/index');
$afterBehavior = ['\app\api\behavior\ApiAuth', '\app\api\behavior\ApiPermission', '\app\api\behavior\RequestFilter'];

View File

@ -1,12 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
return [];

View File

@ -1,65 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------
// 应用公共文件
/**
* 把返回的数据集转换成Tree
* @param $list
* @param string $pk
* @param string $pid
* @param string $child
* @param string $root
* @return array
*/
function listToTree($list, $pk='id', $pid = 'fid', $child = '_child', $root = '0') {
$tree = array();
if(is_array($list)) {
$refer = array();
foreach ($list as $key => $data) {
$refer[$data[$pk]] = &$list[$key];
}
foreach ($list as $key => $data) {
$parentId = $data[$pid];
if ($root == $parentId) {
$tree[] = &$list[$key];
}else{
if (isset($refer[$parentId])) {
$parent = &$refer[$parentId];
$parent[$child][] = &$list[$key];
}
}
}
}
return $tree;
}
function formatTree($list, $lv = 0, $title = 'name'){
$formatTree = array();
foreach($list as $key => $val){
$title_prefix = '';
for( $i=0;$i<$lv;$i++ ){
$title_prefix .= "|---";
}
$val['lv'] = $lv;
$val['namePrefix'] = $lv == 0 ? '' : $title_prefix;
$val['showName'] = $lv == 0 ? $val[$title] : $title_prefix.$val[$title];
if(!array_key_exists('_child', $val)){
array_push($formatTree, $val);
}else{
$child = $val['_child'];
unset($val['_child']);
array_push($formatTree, $val);
$middle = formatTree($child, $lv+1, $title); //进行下一层递归
$formatTree = array_merge($formatTree, $middle);
}
}
return $formatTree;
}

View File

@ -1,241 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
// 应用命名空间
'app_namespace' => 'app',
// 应用调试模式
'app_debug' => true,
// 应用Trace
'app_trace' => false,
// 应用模式状态
'app_status' => '',
// 是否支持多模块
'app_multi_module' => true,
// 入口自动绑定模块
'auto_bind_module' => false,
// 注册的根命名空间
'root_namespace' => [],
// 扩展函数文件
'extra_file_list' => [THINK_PATH . 'helper' . EXT],
// 默认输出类型
'default_return_type' => 'json',
// 默认AJAX 数据返回格式,可选json xml ...
'default_ajax_return' => 'json',
// 默认JSONP格式返回的处理方法
'default_jsonp_handler' => 'jsonpReturn',
// 默认JSONP处理方法
'var_jsonp_handler' => 'callback',
// 默认时区
'default_timezone' => 'PRC',
// 是否开启多语言
'lang_switch_on' => false,
// 默认全局过滤方法 用逗号分隔多个
'default_filter' => '',
// 默认语言
'default_lang' => 'zh-cn',
// 应用类库后缀
'class_suffix' => false,
// 控制器类后缀
'controller_suffix' => false,
// +----------------------------------------------------------------------
// | 模块设置
// +----------------------------------------------------------------------
// 默认模块名
'default_module' => 'api',
// 禁止访问模块
'deny_module_list' => ['common'],
// 默认控制器名
'default_controller' => 'Index',
// 默认操作名
'default_action' => 'index',
// 默认验证器
'default_validate' => '',
// 默认的空控制器名
'empty_controller' => 'Error',
// 操作方法后缀
'action_suffix' => '',
// 自动搜索控制器
'controller_auto_search' => false,
// +----------------------------------------------------------------------
// | URL设置
// +----------------------------------------------------------------------
// PATHINFO变量名 用于兼容模式
'var_pathinfo' => 's',
// 兼容PATH_INFO获取
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
// pathinfo分隔符
'pathinfo_depr' => '/',
// URL伪静态后缀
'url_html_suffix' => 'html',
// URL普通方式参数 用于自动生成
'url_common_param' => false,
// URL参数方式 0 按名称成对解析 1 按顺序解析
'url_param_type' => 0,
// 是否开启路由
'url_route_on' => true,
// 路由使用完整匹配
'route_complete_match' => false,
// 路由配置文件(支持配置多个)
'route_config_file' => ['adminRoute', 'apiRoute', 'wikiRoute'],
// 是否强制使用路由
'url_route_must' => true,
// 域名部署
'url_domain_deploy' => false,
// 域名根如thinkphp.cn
'url_domain_root' => '',
// 是否自动转换URL中的控制器和操作名
'url_convert' => true,
// 默认的访问控制器层
'url_controller_layer' => 'controller',
// 表单请求类型伪装变量
'var_method' => '_method',
// 表单ajax伪装变量
'var_ajax' => '_ajax',
// 表单pjax伪装变量
'var_pjax' => '_pjax',
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
'request_cache' => false,
// 请求缓存有效期
'request_cache_expire' => null,
// 全局请求缓存排除规则
'request_cache_except' => [],
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
'template' => [
// 模板引擎类型 支持 php think 支持扩展
'type' => 'Think',
// 模板路径
'view_path' => '',
// 模板后缀
'view_suffix' => 'html',
// 模板文件名分隔符
'view_depr' => DS,
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '{',
// 标签库标签结束标记
'taglib_end' => '}',
],
// 视图输出字符串内容替换
'view_replace_str' => [],
// 默认跳转页面对应的模板文件
'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
'dispatch_error_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
// +----------------------------------------------------------------------
// | 异常及错误设置
// +----------------------------------------------------------------------
// 异常页面的模板文件
'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',
// 显示错误信息
'show_error_msg' => false,
// 异常处理handle类 留空使用 \think\exception\Handle
'exception_handle' => '',
// +----------------------------------------------------------------------
// | 日志设置
// +----------------------------------------------------------------------
'log' => [
// 日志记录方式,内置 file socket 支持扩展
'type' => 'File',
// 日志保存目录
'path' => LOG_PATH,
// 日志记录级别
'level' => [],
],
// +----------------------------------------------------------------------
// | Trace设置 开启 app_trace 后 有效
// +----------------------------------------------------------------------
'trace' => [
// 内置Html Console 支持扩展
'type' => 'Html',
],
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
'cache' => [
// 驱动方式
'type' => 'Redis',
// 缓存保存目录
'path' => CACHE_PATH,
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
],
// +----------------------------------------------------------------------
// | 会话设置
// +----------------------------------------------------------------------
'session' => [
'id' => '',
// SESSION_ID的提交变量,解决flash上传跨域
'var_session_id' => '',
// SESSION 前缀
'prefix' => 'think',
// 驱动方式 支持redis memcache memcached
'type' => '',
// 是否自动开启 SESSION
'auto_start' => true,
],
// +----------------------------------------------------------------------
// | Cookie设置
// +----------------------------------------------------------------------
'cookie' => [
// cookie 名称前缀
'prefix' => '',
// cookie 保存时间
'expire' => 0,
// cookie 保存路径
'path' => '/',
// cookie 有效域名
'domain' => '',
// cookie 启用安全传输
'secure' => false,
// httponly设置
'httponly' => '',
// 是否使用 setcookie
'setcookie' => true,
],
//分页配置
'paginate' => [
'type' => 'bootstrap',
'var_page' => 'page',
'list_rows' => 15,
],
];

View File

@ -1,53 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'apiadmin',
// 用户名
'username' => 'root',
// 密码
'password' => '123456',
// 端口
'hostport' => '',
// 连接dsn
'dsn' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => '',
// 数据库调试模式
'debug' => true,
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 数据集返回类型
'resultset_type' => 'array',
// 自动写入时间戳字段
'auto_timestamp' => false,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 是否需要进行SQL性能分析
'sql_explain' => false,
];

View File

@ -1,38 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
return [
'APP_VERSION' => 'v3.0',
'APP_NAME' => 'ApiAdmin',
//鉴权相关
'USER_ADMINISTRATOR' => [1],
//安全秘钥
'AUTH_KEY' => 'I&TC{pft>L,C`wFQ>&#ROW>k{Kxlt1>ryW(>r<#R',
//后台登录状态维持时间[目前只有登录和解锁会重置登录时间]
'ONLINE_TIME' => 7200,
//AccessToken失效时间
'ACCESS_TOKEN_TIME_OUT' => 7200,
'COMPANY_NAME' => 'ApiAdmin开发维护团队',
//跨域配置
'CROSS_DOMAIN' => [
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'POST,PUT,GET,DELETE',
'Access-Control-Allow-Headers' => 'ApiAuth, User-Agent, Keep-Alive, Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With',
'Access-Control-Allow-Credentials' => 'true'
],
//后台列表默认一页显示数量
'ADMIN_LIST_DEFAULT' => 20,
];

View File

@ -1,17 +0,0 @@
<?php
/**
*
* @since 2018-02-08
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\model;
class AdminAuthGroup extends Base {
public function rules() {
return $this->hasMany('AdminAuthRule', 'groupId', 'id');
}
}

View File

@ -1,12 +0,0 @@
<?php
/**
* @since 2017-11-02
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\model;
class AdminUser extends Base {
}

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