Compare commits

...

No commits in common. "master" and "v1.0.0" have entirely different histories.

351 changed files with 77331 additions and 8033 deletions

1
.env
View File

@ -1 +0,0 @@
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

7
.gitignore vendored
View File

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

View File

@ -1,42 +0,0 @@
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

View File

@ -1,50 +0,0 @@
<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,21 +1,191 @@
MIT License Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright (c) 2021 Zhao TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Permission is hereby granted, free of charge, to any person obtaining a copy 1. Definitions.
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all "License" shall mean the terms and conditions for use, reproduction, and
copies or substantial portions of the Software. distribution as defined by Sections 1 through 9 of this document.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR "Licensor" shall mean the copyright owner or entity authorized by the copyright
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, owner that is granting the License.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER "Legal Entity" shall mean the union of the acting entity and all other entities
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, that control, are controlled by, or are under common control with that entity.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE For the purposes of this definition, "control" means (i) the power, direct or
SOFTWARE. indirect, to cause the direction or management of such entity, whether by
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 2016 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.

133
README.md
View File

@ -1,132 +1 @@
> 站在巨人的肩膀上,并不是高的表现,反而使自己变得渺小~只有吸收了巨人的营养,茁壮自己才是真正的高大! --笔者 This is my first website administrator
# ApiAdmin
[![ApiAdmin](https://img.shields.io/hexpm/l/plug.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/badge/build-passing-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及时提交我会随时关注及时更新
## 前端页面
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
```
## 灵 感
首先自我介绍下吧我是一个PHP程序员目前就职于某上市集团。我第一份工作是做微信开发的这也是我入行以来第一次做的商业上线项目虽然我只是充当了其中一个不是太重要的角色但是感谢它让我第一次接触了API也让我第一次对于API产生了浓厚的兴趣。之后的一段时间内甚至疯狂的收集过各种免费的API接口然而一直只是在用API却没有为API贡献过些什么。
开源框架用了很多开源代码看了很多github、git@osc、Stack Overflow这些优秀的平台帮助了我很多所以我觉得是时候为开源做点什么。更是给开源项目PhalApi贡献过代码也正是这一个契机使得我正式迈向开源社区。随着时间的推移PhalApi的战绩赫赫它的壮大更加坚定了Api的地位既然未来的互联网世界中API占了很重要的地位既然越来越多的人开始开发API那么无状态的API如何去管理呢因此**ApiAdmin**来了~
## 愿 景
> 希望有人用它,希望更多的人用它。
> 希望它能帮助到你,希望它能帮助到更多的你。
## 项目简介
**系统需求**
- PHP >= 7.2.5
- MySQL >= 5.5.3
- Redis
**项目构成**
- ThinkPHP v6.0.*
- Vue 2.*
- ...
**功能简介**
1. 接口文档自动生成
2. 接口输入参数自动检查
3. 接口输出参数数据类型自动规整
4. 灵活的参数规则设定
5. 支持三方Api无缝融合
6. 本地二次开发友好
7. ...
```
ApiAdminPHP部分
├─ 系统维护
| ├─ 菜单管理 - 编辑访客权限,处理菜单父子关系,被权限系统依赖(极为重要)
| ├─ 用户管理 - 添加新用户,封号,删号以及给账号分配权限组
| ├─ 权限管理 - 权限组管理,给权限组添加权限,将用户提出权限组
| └─ 操作日志 - 记录管理员的操作,用于追责,回溯和备案
| ...
```
**页面截图**
![输入图片说明](https://gitee.com/uploads/images/2018/0224/095358_19cb42d0_110856.png "api.png")
![输入图片说明](https://gitee.com/uploads/images/2018/0224/095410_55dc23e1_110856.png "app.png")
![输入图片说明](https://gitee.com/uploads/images/2018/0224/095420_bddff990_110856.png "auth1.png")
![输入图片说明](https://gitee.com/uploads/images/2018/0224/095427_fa86e42d_110856.png "auth2.png")
![输入图片说明](https://gitee.com/uploads/images/2018/0224/095436_3600de17_110856.png "lock.png")
![输入图片说明](https://gitee.com/uploads/images/2018/0224/095444_d2a88da0_110856.png "user.png")
**项目特性**
- 开放源码
- 保持生机
- 不断更新
- 响应市场
**开源,我们在路上!**
## 鸣谢
ApiAdmin走到今天也正式迈入4.1时代了我们怀着激动的心情迎来这次发布。在新版本发布之际我们真诚的感谢从1.0到5.0陪我们一路走来的朋友们。感谢你们的支持和信任!当然也感谢#开源中国#给大陆本土开源提供这样一个优秀的平台
## 附:升级指南
很抱歉的告诉大家虽然我们尽可能的和往期版本进行了兼容但是由于整体架构变化很大所以想要零成本升级有点困难。我们建议大家可以使用5.0做新接口慢慢的将4.1版本的接口移植到5.0。

View File

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

View File

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

View File

@ -1,94 +0,0 @@
<?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);
}
}

View File

@ -1,58 +0,0 @@
<?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'));
}
}

View File

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

View File

@ -1,26 +0,0 @@
<?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

@ -1,112 +0,0 @@
<?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

@ -1,31 +0,0 @@
<?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('路由构建成功');
}
}

View File

@ -1,120 +0,0 @@
<?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;
}
}

View File

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

View File

@ -1,218 +0,0 @@
<?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,140 +0,0 @@
<?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\AdminAppGroup;
use app\util\ReturnCode;
use think\Response;
class AppGroup extends Base {
/**
* 获取应用组列表
* @return \think\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 AdminAppGroup();
if (strlen($status)) {
$obj = $obj->where('status', $status);
}
if ($type) {
switch ($type) {
case 1:
if (strlen($keywords)) {
$obj = $obj->where('hash', $keywords);
}
break;
case 2:
$obj = $obj->whereLike('name', "%{$keywords}%");
break;
}
}
$listObj = $obj->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 AdminAppGroup())->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 = AdminAppGroup::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 = AdminAppGroup::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 = AdminAppGroup::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 应用组删除
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del(): Response {
$hash = $this->request->get('hash');
if (!$hash) {
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]);
return $this->buildSuccess();
}
}

View File

@ -1,277 +0,0 @@
<?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

@ -1,105 +0,0 @@
<?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

@ -1,285 +0,0 @@
<?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,51 +0,0 @@
<?php
declare (strict_types=1);
namespace app\controller\admin;
use app\util\ReturnCode;
use think\Response;
class Index extends Base {
public function upload(): Response {
$path = '/upload/' . date('Ymd', time()) . '/';
$name = $_FILES['file']['name'];
$tmp_name = $_FILES['file']['tmp_name'];
$error = $_FILES['file']['error'];
//过滤错误
if ($error) {
switch ($error) {
case 1:
$error_message = '您上传的文件超过了PHP.INI配置文件中UPLOAD_MAX-FILESIZE的大小';
break;
case 2:
$error_message = '您上传的文件超过了PHP.INI配置文件中的post_max_size的大小';
break;
case 3:
$error_message = '文件只被部分上传';
break;
case 4:
$error_message = '文件不能为空';
break;
default:
$error_message = '未知错误';
}
die($error_message);
}
$arr_name = explode('.', $name);
$hz = array_pop($arr_name);
$new_name = md5(time() . uniqid()) . '.' . $hz;
if (!file_exists($_SERVER['DOCUMENT_ROOT'] . $path)) {
mkdir($_SERVER['DOCUMENT_ROOT'] . $path, 0755, true);
}
if (move_uploaded_file($tmp_name, $_SERVER['DOCUMENT_ROOT'] . $path . $new_name)) {
return $this->buildSuccess([
'fileName' => $new_name,
'fileUrl' => $this->request->domain() . $path . $new_name
]);
} else {
return $this->buildFailed(ReturnCode::FILE_SAVE_ERROR, '文件上传失败');
}
}
}

View File

@ -1,158 +0,0 @@
<?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

@ -1,201 +0,0 @@
<?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

@ -1,65 +0,0 @@
<?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

@ -1,173 +0,0 @@
<?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,112 +0,0 @@
<?php
declare (strict_types=1);
/**
* 目录管理
* @since 2018-01-16
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\admin;
use app\model\AdminMenu;
use app\util\ReturnCode;
use app\util\Tools;
use think\Response;
class Menu extends Base {
/**
* 获取菜单列表
* @return \think\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 {
$keywords = $this->request->get('keywords', '');
$obj = new AdminMenu();
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([
'list' => $list
]);
}
/**
* 新增菜单
* @return \think\Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function add(): Response {
$postData = $this->request->post();
if ($postData['url']) {
$postData['url'] = 'admin/' . $postData['url'];
}
$res = AdminMenu::create($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
} else {
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 = AdminMenu::update([
'id' => $id,
'show' => $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 {
$postData = $this->request->post();
if ($postData['url']) {
$postData['url'] = 'admin/' . $postData['url'];
}
$res = AdminMenu::update($postData);
if ($res === false) {
return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
}
return $this->buildSuccess();
}
/**
* 删除菜单
* @return Response
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function del(): Response {
$id = $this->request->get('id');
if (!$id) {
return $this->buildFailed(ReturnCode::EMPTY_PARAMS, '缺少必要参数');
}
(new AdminMenu())->whereIn('id', $id)->delete();
return $this->buildSuccess();
}
}

View File

@ -1,18 +0,0 @@
<?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

@ -1,350 +0,0 @@
<?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

@ -1,277 +0,0 @@
<?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 +0,0 @@
<?php
declare (strict_types=1);
/**
* 工程基类
* @since 2017/02/28 创建
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\controller\api;
use app\BaseController;
use app\util\ReturnCode;
use think\facade\Env;
use think\Response;
class Base extends BaseController {
private $debug = [];
protected $userInfo = [];
public function _initialize() {
// $this->userInfo = ''; 这部分初始化用户信息可以参考admin模块下的Base去自行处理
}
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);
}
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);
}
protected function debug($data): void {
if ($data) {
$this->debug[] = $data;
}
}
}

View File

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

View File

@ -1,26 +0,0 @@
<?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终于等到你"
]);
}
}
}

View File

@ -1,188 +0,0 @@
<?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

@ -1,43 +0,0 @@
<?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);
}
}

View File

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

View File

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

View File

@ -1,45 +0,0 @@
<?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

@ -1,45 +0,0 @@
<?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,96 +0,0 @@
<?php
declare (strict_types=1);
namespace app\middleware;
use app\model\AdminAuthGroup;
use app\model\AdminAuthGroupAccess;
use app\model\AdminAuthRule;
use app\util\ReturnCode;
use app\util\Tools;
use think\Response;
class AdminPermission {
/**
* 用户权限检测
* @param \think\facade\Request $request
* @param \Closure $next
* @return mixed|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public function handle($request, \Closure $next): Response {
$userInfo = $request->API_ADMIN_USER_INFO;
// rule里包含了rule(路由规则), ruoter(完整路由)
if (!$this->checkAuth($userInfo['id'], $request->rule()->getRule())) {
return json([
'code' => ReturnCode::INVALID,
'msg' => '非常抱歉,您没有权限这么做!',
'data' => []
])->header(config('apiadmin.CROSS_DOMAIN'));
}
return $next($request);
}
/**
* 检测用户权限
* @param $uid
* @param $route
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function checkAuth($uid, $route) {
$isSupper = Tools::isAdministrator($uid);
if (!$isSupper) {
$rules = $this->getAuth($uid);
return in_array($route, $rules);
} else {
return true;
}
}
/**
* 根据用户ID获取全部权限节点
* @param $uid
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
private function getAuth($uid) {
$groups = (new AdminAuthGroupAccess())->where('uid', $uid)->find();
if (isset($groups) && $groups->group_id) {
$openGroup = (new AdminAuthGroup())->whereIn('id', $groups->group_id)->where(['status' => 1])->select();
if (isset($openGroup)) {
$openGroupArr = [];
foreach ($openGroup as $group) {
$openGroupArr[] = $group->id;
}
$allRules = (new AdminAuthRule())->whereIn('group_id', $openGroupArr)->select();
if (isset($allRules)) {
$rules = [];
foreach ($allRules as $rule) {
$rules[] = $rule->url;
}
$rules = array_unique($rules);
return $rules;
} else {
return [];
}
} else {
return [];
}
} else {
return [];
}
}
}

View File

@ -1,14 +0,0 @@
<?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'));
}
}

View File

@ -1,145 +0,0 @@
<?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;
}
}
}

View File

@ -1,31 +0,0 @@
<?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

@ -1,33 +0,0 @@
<?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

@ -1,13 +0,0 @@
<?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

@ -1,128 +0,0 @@
<?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

@ -1,47 +0,0 @@
<?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

@ -1,7 +0,0 @@
<?php
namespace app\model;
class AdminApp extends Base {
}

View File

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

View File

@ -1,17 +0,0 @@
<?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

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

View File

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

View File

@ -1,12 +0,0 @@
<?php
/**
* 接口字段规则模型
* @since 2017/07/25 创建
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\model;
class AdminFields extends Base {
}

View File

@ -1,13 +0,0 @@
<?php
/**
*
* @since 2018-02-11
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\model;
class AdminGroup extends Base {
protected $autoWriteTimestamp = true;
}

View File

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

View File

@ -1,7 +0,0 @@
<?php
namespace app\model;
class AdminMenu extends Base {
}

View File

@ -1,19 +0,0 @@
<?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

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

View File

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

View File

@ -1,14 +0,0 @@
<?php
/**
*
* @since 2019-04-23
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\model;
use think\Model;
class Base extends Model {
}

View File

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

View File

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

View File

@ -1,138 +0,0 @@
<?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);
}
}

View File

@ -1,203 +0,0 @@
<?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

@ -1,22 +0,0 @@
<?php
/**
* 数据类型维护
* 特别注意:这里的数据类型包含但不限于常规数据类型,可能会存在系统自己定义的数据类型
* @since 2017/03/01 创建
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\util;
class DataType {
const TYPE_INTEGER = 1;
const TYPE_STRING = 2;
const TYPE_ARRAY = 3;
const TYPE_FLOAT = 4;
const TYPE_BOOLEAN = 5;
const TYPE_FILE = 6;
const TYPE_ENUM = 7;
const TYPE_MOBILE = 8;
const TYPE_OBJECT = 9;
}

View File

@ -1,50 +0,0 @@
<?php
declare (strict_types=1);
/**
* 错误码统一维护
* @since 2017/02/28 创建
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\util;
class ReturnCode {
const SUCCESS = 1;
const INVALID = -1;
const DB_SAVE_ERROR = -2;
const DB_READ_ERROR = -3;
const CACHE_SAVE_ERROR = -4;
const CACHE_READ_ERROR = -5;
const FILE_SAVE_ERROR = -6;
const LOGIN_ERROR = -7;
const NOT_EXISTS = -8;
const JSON_PARSE_FAIL = -9;
const TYPE_ERROR = -10;
const NUMBER_MATCH_ERROR = -11;
const EMPTY_PARAMS = -12;
const DATA_EXISTS = -13;
const AUTH_ERROR = -14;
const OTHER_LOGIN = -16;
const VERSION_INVALID = -17;
const CURL_ERROR = -18;
const RECORD_NOT_FOUND = -19; // 记录未找到
const DELETE_FAILED = -20; // 删除失败
const ADD_FAILED = -21; // 添加记录失败
const UPDATE_FAILED = -22; // 添加记录失败
const PARAM_INVALID = -995; // 参数无效
const ACCESS_TOKEN_TIMEOUT = -996;
const SESSION_TIMEOUT = -997;
const UNKNOWN = -998;
const EXCEPTION = -999;
public static function getConstants(): array {
$oClass = new \ReflectionClass(__CLASS__);
return $oClass->getConstants();
}
}

View File

@ -1,107 +0,0 @@
<?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) . ']);';
}
}

View File

@ -1,185 +0,0 @@
<?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,254 +0,0 @@
<?php
declare (strict_types=1);
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace app\util;
class Strs {
/**
* 生成UUID 单机使用
* @access public
* @return string
*/
public static function uuid(): string {
$charId = md5(uniqid(strval(mt_rand()), true));
$hyphen = chr(45);
$uuid = chr(123)
. substr($charId, 0, 8) . $hyphen
. substr($charId, 8, 4) . $hyphen
. substr($charId, 12, 4) . $hyphen
. substr($charId, 16, 4) . $hyphen
. substr($charId, 20, 12)
. chr(125);
return $uuid;
}
/**
* 生成Guid主键
* @return Boolean
*/
public static function keyGen(): string {
return str_replace('-', '', substr(self::uuid(), 1, -1));
}
/**
* 检查字符串是否是UTF8编码
* @param string $string 字符串
* @return Boolean
*/
public static function isUtf8($string): bool {
$len = strlen($string);
for ($i = 0; $i < $len; $i++) {
$c = ord($string[$i]);
if ($c > 128) {
if (($c >= 254)) return false;
elseif ($c >= 252) $bits = 6;
elseif ($c >= 248) $bits = 5;
elseif ($c >= 240) $bits = 4;
elseif ($c >= 224) $bits = 3;
elseif ($c >= 192) $bits = 2;
else return false;
if (($i + $bits) > $len) return false;
while ($bits > 1) {
$i++;
$b = ord($string[$i]);
if ($b < 128 || $b > 191) return false;
$bits--;
}
}
}
return true;
}
/**
* 字符串截取,支持中文和其他编码
* @param string $str
* @param float $start
* @param int $length
* @param string $charset
* @param bool $suffix
* @return string
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
public static function mSubStr(string $str, int $length, float $start = 0, string $charset = "utf-8", bool $suffix = true): string {
if (function_exists("mb_substr"))
$slice = mb_substr($str, $start, $length, $charset);
elseif (function_exists('iconv_substr')) {
$slice = iconv_substr($str, $start, $length, $charset);
} else {
$re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
$re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
$re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
$re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
preg_match_all($re[$charset], $str, $match);
$slice = join("", array_slice($match[0], $start, $length));
}
return $suffix ? $slice . '...' : $slice;
}
/**
* 产生随机字串,可用来自动生成密码
* 默认长度6位 字母和数字混合 支持中文
* @param integer $len 长度
* @param int $type 字串类型
* 0 字母 1 数字 其它 混合
* @param string $addChars 额外字符
* @return string
*/
public static function randString(int $len = 6, int $type = 0, string $addChars = ''): string {
$str = '';
switch ($type) {
case 0:
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $addChars;
break;
case 1:
$chars = str_repeat('0123456789', 3);
break;
case 2:
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $addChars;
break;
case 3:
$chars = 'abcdefghijklmnopqrstuvwxyz' . $addChars;
break;
case 4:
$chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借" . $addChars;
break;
default :
// 默认去掉了容易混淆的字符oOLl和数字01要添加请使用addChars参数
$chars = 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $addChars;
break;
}
if ($len > 10) {//位数过长重复字符串一定次数
$chars = $type == 1 ? str_repeat($chars, $len) : str_repeat($chars, 5);
}
if ($type != 4) {
$chars = str_shuffle($chars);
$str = substr($chars, 0, $len);
} else {
// 中文随机字
for ($i = 0; $i < $len; $i++) {
$str .= self::msubstr($chars, 1, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 'utf-8', false);
}
}
return $str;
}
/**
* 生成一定数量的随机数,并且不重复
* @param integer $number 数量
* @param integer $length 长度
* @param integer $mode 字串类型
* 0 字母 1 数字 其它 混合
* @return array
*/
public static function buildCountRand(int $number, int $length = 4, int $mode = 1): array {
if ($mode == 1 && $length < strlen($number)) {
//不足以生成一定数量的不重复数字
return [];
}
$rand = [];
for ($i = 0; $i < $number; $i++) {
$rand[] = self::randString($length, $mode);
}
$unique = array_unique($rand);
if (count($unique) == count($rand)) {
return $rand;
}
$count = count($rand) - count($unique);
for ($i = 0; $i < $count * 3; $i++) {
$rand[] = self::randString($length, $mode);
}
$rand = array_slice(array_unique($rand), 0, $number);
return $rand;
}
/**
* 带格式生成随机字符 支持批量生成
* 但可能存在重复
* @param string $format 字符格式
* # 表示数字 * 表示字母和数字 $ 表示字母
* @param integer $number 生成数量
* @return array
*/
public static function buildFormatRand(string $format, int $number = 1): array {
$str = [];
$length = strlen($format);
for ($j = 0; $j < $number; $j++) {
$strTemp = '';
for ($i = 0; $i < $length; $i++) {
$char = substr($format, $i, 1);
switch ($char) {
case "*"://字母和数字混合
$strTemp .= self::randString(1);
break;
case "#"://数字
$strTemp .= self::randString(1, 1);
break;
case "$"://大写字母
$strTemp .= self::randString(1, 2);
break;
default://其他格式均不转换
$strTemp .= $char;
break;
}
}
$str[] = $strTemp;
}
return $str;
}
/**
* 获取一定范围内的随机数字 位数不足补零
* @param integer $min 最小值
* @param integer $max 最大值
* @return string
*/
public static function randNumber(int $min, int $max): string {
return sprintf("%0" . strlen($max) . "d", mt_rand($min, $max));
}
// 自动转换字符集 支持数组转换
public static function autoCharset(string $string, string $from = 'gbk', string $to = 'utf-8'): string {
$from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from;
$to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to;
if (strtoupper($from) === strtoupper($to) || empty($string) || (is_scalar($string) && !is_string($string))) {
//如果编码相同或者非字符串标量则不转换
return $string;
}
if (is_string($string)) {
if (function_exists('mb_convert_encoding')) {
return mb_convert_encoding($string, $to, $from);
} elseif (function_exists('iconv')) {
return iconv($from, $to, $string);
} else {
return $string;
}
} elseif (is_array($string)) {
foreach ($string as $key => $val) {
$_key = self::autoCharset($key, $from, $to);
$string[$_key] = self::autoCharset($val, $from, $to);
if ($key != $_key)
unset($string[$key]);
}
return $string;
} else {
return $string;
}
}
}

View File

@ -1,192 +0,0 @@
<?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

@ -0,0 +1 @@
<?php

View File

@ -0,0 +1,6 @@
<?php
//配置文件
return [
'auth_key' => 'mbvUenPqbpxT5WTAXXkFVPHF})0AOGfsMIN01XLu52SgS<R]DQDfj6TlThl897Qd',
'online_time' => 3600
];

View File

@ -0,0 +1,606 @@
<?php
/**
*
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\controller;
use app\admin\model\AuthGroup;
use app\admin\model\AuthGroupAccess;
use app\admin\model\AuthRule;
use app\admin\model\User;
use app\admin\model\UserData;
use think\Validate;
class Auth extends Base {
/**
* 用户组列表获取
*/
public function index(){
$data = [];
$dataObj = AuthGroup::all();
if( !is_null($dataObj) ){
foreach ($dataObj as $value){
$data[] = $value->toArray();
}
}
$table = [
'tempType' => 'table',
'header' => [
[
'field' => 'name',
'info' => '用户组'
],
[
'field' => 'description',
'info' => '描述'
],
[
'field' => 'access',
'info' => '访问授权'
],
[
'field' => 'userAuth',
'info' => '成员授权'
],
[
'field' => 'status',
'info' => '状态'
]
],
'topButton' => [
[
'href' => 'Auth/add',
'class'=> 'btn-success',
'info'=> '新增',
'icon' => 'fa fa-plus',
'confirm' => 0,
]
],
'rightButton' => [
[
'info' => '编辑',
'href' => 'Auth/edit',
'class'=> 'btn-info',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-pencil',
'confirm' => 0,
'show' => ''
],
[
'info' => '启用',
'href' => 'Auth/open',
'class'=> 'btn-success ajax-put-url',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-check',
'confirm' => 1,
'show' => ['status', 0]
],
[
'info' => '禁用',
'href' => 'Auth/close',
'class'=> 'btn-warning ajax-put-url',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-close',
'confirm' => 1,
'show' => ['status', 1]
],
[
'info' => '删除',
'href' => 'Auth/del',
'class'=> 'btn-danger ajax-delete',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-trash',
'confirm' => 1,
]
],
'typeRule' => [
'access' => [
'module' => 'a',
'rule' => [
'info' => '访问授权',
'href' => url('Auth/access'),
'param'=> [$this->primaryKey],
'class' => 'refresh'
]
],
'userAuth' => [
'module' => 'a',
'rule' => [
'info' => '成员授权',
'href' => url('Auth/userAuth'),
'param'=> [$this->primaryKey],
'class' => 'refresh'
]
],
'hide' => [
'module' => 'label',
'rule' => [
[
'info' => '显示',
'class' => 'label label-success'
],
[
'info' => '隐藏',
'class' => 'label label-warning'
]
]
],
'status' => [
'module' => 'label',
'rule' => [
[
'info' => '禁用',
'class' => 'label label-danger'
],
[
'info' => '启用',
'class' => 'label label-success'
]
]
]
],
'data' => $data
];
$table = $this->_prepareTemplate($table);
$this->result($table, ReturnCode::GET_TEMPLATE_SUCCESS);
}
/**
* 新增权限组
*/
public function add(){
if( $this->request->isPost() ){
$authGroupModel = new AuthGroup();
$result = $authGroupModel->allowField(true)->validate(
[
'name' => 'require',
],[
'name.require' => '用户组名不能为空',
]
)->save($this->request->post());
if(false === $result){
$this->error($authGroupModel->getError());
}else{
$this->success('操作成功!', url('Auth/index'));
}
}else {
$form = [
'formTitle' => $this->menuInfo['name'],
'tempType' => 'add',
'formAttr' => [
'target' => url('Auth/add'),
'formId' => 'add-authGroup-form',
'backUrl' => url('Auth/index'),
],
'formList' => [
[
'module' => 'text',
'description' => '',
'info' => '用户组名称:',
'attr' => [
'name' => 'name',
'value' => '',
'placeholder' => ''
]
],
[
'module' => 'textarea',
'description' => '',
'info' => '用户组描述:',
'attr' => [
'name' => 'description',
'value' => '',
'placeholder' => ''
]
]
]
];
$this->result($form, ReturnCode::GET_TEMPLATE_SUCCESS);
}
}
/**
* 编辑用户组
*/
public function edit(){
if( $this->request->isPut() ){
$data = $this->request->put();
$validate = new Validate([
'name' => 'require',
],[
'name.require' => '用户组名不能为空',
]);
if(!$validate->check($data)){
$this->error($validate->getError());
}else{
$menuModel = new AuthGroup();
$menuModel->allowField(true)->update($data);
$this->success('操作成功!', url('Auth/index'));
}
}else{
$detail = AuthGroup::get($this->request->get($this->primaryKey))->toArray();
$form = [
'formTitle' => $this->menuInfo['name'],
'tempType' => 'edit',
'formAttr' => [
'target' => url('Auth/edit'),
'formId' => 'edit-authGroup-form',
'backUrl' => url('Auth/index'),
],
'formList' => [
[
'module' => 'hidden',
'description' => '',
'info' => '',
'attr' => [
'name' => $this->primaryKey,
'value' => $detail['id'],
'placeholder' => ''
]
],
[
'module' => 'text',
'description' => '',
'info' => '用户组名称:',
'attr' => [
'name' => 'name',
'value' => $detail['name'],
'placeholder' => ''
]
],
[
'module' => 'textarea',
'description' => '',
'info' => '用户组描述:',
'attr' => [
'name' => 'description',
'value' => $detail['description'],
'placeholder' => ''
]
]
]
];
$this->result($form, ReturnCode::GET_TEMPLATE_SUCCESS);
}
}
/**
* 启用用户组
*/
public function open(){
if( $this->request->isPut() ){
$id = $this->request->put($this->primaryKey);
$authGroupObj = AuthGroup::get([$this->primaryKey => $id]);
if( is_null($authGroupObj) ){
$this->error('用户组不存在','');
}else{
$authGroupObj->status = 1;
$authGroupObj->save();
$this->success('操作成功', url('Auth/index'));
}
}
}
/**
* 禁用用户组
*/
public function close(){
if( $this->request->isPut() ){
$id = $this->request->put($this->primaryKey);
$authGroupObj = AuthGroup::get([$this->primaryKey => $id]);
if( is_null($authGroupObj) ){
$this->error('用户组不存在','');
}else{
$authGroupObj->status = 0;
$authGroupObj->save();
$this->success('操作成功', url('Auth/index'));
}
}
}
/**
* 删除用户组
*/
public function del(){
if( $this->request->isDelete() ){
$key = $this->request->delete($this->primaryKey);
$authAccessNum = AuthGroupAccess::where(['group_id' => $key])->count();
if( $authAccessNum ){
$this->error('当前用户组存在用户不能删除!');
}
AuthGroup::destroy([$this->primaryKey => $key]);
AuthRule::destroy(['group_id' => $key]);
$this->success('操作成功', url('Auth/index'));
}
}
/**
* 用户授权(加用户入组)
*/
public function group(){
if( $this->request->isPut() ){
$authAccessObj = AuthGroupAccess::get(['uid' => $this->request->put('uid')]);
if( is_null($authAccessObj) ){
$authAccessObj = new AuthGroupAccess();
}
$authAccessObj->group_id = $this->request->put('group_id');
$authAccessObj->uid = $this->request->put('uid');
$authAccessObj->save();
$this->success('操作成功', url('User/index'));
}else{
$authAccess = '';
$authGroupArr = [];
$authAccessObj = AuthGroupAccess::get(['uid' => $this->request->get($this->primaryKey)]);
if( !is_null($authAccessObj) ){
$authAccess = $authAccessObj->group_id;
}
$authGroupObj = AuthGroup::all(['status' => 1]);
if( !empty($authGroupObj) ){
foreach ( $authGroupObj as $value ){
$authGroupArr[$value[$this->primaryKey]] = $value->name;
}
}else{
$this->result('', ReturnCode::GET_TEMPLATE_ERROR, '没有可用用户组');
}
$form = [
'formTitle' => $this->menuInfo['name'],
'tempType' => 'edit',
'formAttr' => [
'target' => url('Auth/group'),
'formId' => 'add-authGroup-form',
'backUrl' => url('User/index'),
],
'formList' => [
[
'module' => 'hidden',
'description' => '',
'info' => '',
'attr' => [
'name' => 'uid',
'value' => $this->request->get($this->primaryKey),
'placeholder' => ''
]
],
[
'module' => 'radio',
'description' => '',
'info' => '请选择用户组:',
'attr' => [
'name' => 'group_id',
'value' => $authAccess,
'options' => $authGroupArr
]
],
]
];
$this->result($form, ReturnCode::GET_TEMPLATE_SUCCESS);
}
}
/**
* 权限组用户维护
*/
public function userAuth(){
if( $this->request->isDelete() ){
$key = $this->request->delete($this->primaryKey);
AuthGroupAccess::destroy([$this->primaryKey => $key]);
$this->success('操作成功', url('Auth/index'));
}else{
$data = [];
$dataArrObj = AuthGroupAccess::where(['group_id' => $this->request->get($this->primaryKey)])->select();
if( !empty($dataArrObj) ){
foreach ( $dataArrObj as $dataObj ){
$userObj = User::get([$this->primaryKey => $dataObj->uid]);
$userDataObj = UserData::get(['uid' => $dataObj->uid]);
$_data['id'] = $dataObj->id;
$_data['username'] = $userObj->username;
$_data['nickname'] = $userObj->nickname;
if( !is_null($userDataObj) ){
$userDataObj->toArray();
$_data['loginTimes'] = $userDataObj['loginTimes'];
$_data['lastLoginTime'] = $userDataObj['lastLoginTime'];
$_data['lastLoginIp'] = $userDataObj['lastLoginIp'];
}else{
$_data['loginTimes'] = 0;
$_data['lastLoginTime'] = 0;
$_data['lastLoginIp'] = 0;
}
$data[] = $_data;
}
}
$table = [
'tempType' => 'table',
'header' => [
[
'field' => 'username',
'info' => '用户账号'
],
[
'field' => 'nickname',
'info' => '用户昵称'
],
[
'field' => 'loginTimes',
'info' => '登录次数'
],
[
'field' => 'lastLoginTime',
'info' => '最后登录时间'
],
[
'field' => 'lastLoginIp',
'info' => '最后登录IP'
]
],
'rightButton' => [
[
'info' => '删除',
'href' => url('Auth/userAuth'),
'class'=> 'btn-danger ajax-delete',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-trash',
'confirm' => 1,
]
],
'typeRule' => [
'lastLoginTime' => [
'module' => 'date',
]
],
'data' => $data
];
$this->result($table, ReturnCode::GET_TEMPLATE_SUCCESS);
}
}
/**
* 加载权限因子
*/
public function access(){
$authList = cache('AuthRule');
if( !$authList ){
$authList = $this->refreshAuth();
}
if( $this->request->isPut() ){
$gid = session('authGid');
if( !$gid ){
$this->error('组ID丢失');
}
$url = $this->request->put('urlName');
$getAuth = $this->request->put('get');
$putAuth = $this->request->put('put');
$deleteAuth = $this->request->put('delete');
$postAuth = $this->request->put('post');
$auth = \Permission::AUTH_GET * $getAuth + \Permission::AUTH_DELETE * $deleteAuth + \Permission::AUTH_POST * $postAuth + \Permission::AUTH_PUT * $putAuth;
$authDetail = AuthRule::get( ['group_id' => $gid, 'url' => $url] );
if( $authDetail ){
$authDetail->auth = $auth;
$authDetail->save();
}else{
$newAuthDetail = new AuthRule();
$newAuthDetail->url = $url;
$newAuthDetail->group_id = $gid;
$newAuthDetail->auth = $auth;
$newAuthDetail->save();
}
$this->success('更新成功!', url('Auth/access'), '', 1);
}else{
$gid = $this->request->get('id')?$this->request->get('id'):session('authGid');
if( !$gid ){
$this->result('', ReturnCode::GET_TEMPLATE_ERROR, '组ID丢失');
}else{
session('authGid', $gid);
}
$authRuleArr = AuthRule::where(['group_id' => $gid])->select();
if( $authRuleArr ){
$authRule = [];
foreach ( $authRuleArr as $value ){
$authRule[$value->url] = $value->auth;
}
foreach ( $authList as &$authValue ){
$authRuleValue = isset($authRule[$authValue['url']])?$authRule[$authValue['url']]:0;
$authValue['get'] = \Permission::AUTH_GET & $authRuleValue;
$authValue['post'] = \Permission::AUTH_POST & $authRuleValue;
$authValue['put'] = \Permission::AUTH_PUT & $authRuleValue;
$authValue['delete'] = \Permission::AUTH_DELETE & $authRuleValue;
}
}
$table = [
'tempType' => 'table',
'header' => [
[
'field' => 'showName',
'info' => '权限名称'
],
[
'field' => 'url',
'info' => 'URL标识'
],
[
'field' => 'token',
'info' => '真实URL'
],
[
'field' => 'get',
'info' => 'Get'
],
[
'field' => 'put',
'info' => 'Put'
],
[
'field' => 'post',
'info' => 'Post'
],
[
'field' => 'delete',
'info' => 'Delete'
]
],
'typeRule' => [
'post' => [
'module' => 'auth',
'rule' => [
'value' => '',
'url' => url('Auth/access')
]
],
'get' => [
'module' => 'auth',
'rule' => [
'value' => '',
'url' => url('Auth/access')
]
],
'put' => [
'module' => 'auth',
'rule' => [
'value' => '',
'url' => url('Auth/access')
]
],
'delete' => [
'module' => 'auth',
'rule' => [
'value' => '',
'url' => url('Auth/access')
]
]
],
'data' => $authList
];
$this->result($table, ReturnCode::GET_TEMPLATE_SUCCESS);
}
}
/**
* 刷新权限因子缓存
* @param array $menu
* @return array
*/
public function refreshAuth( $menu = [] ){
if( empty($menu) ){
$menuObj = \app\admin\model\Menu::all(function($query){
$query->order('sort', 'asc');
});
foreach ($menuObj as $value){
$menuArr = $value->toArray();
if( $menuArr['url'] ){
$menuArr['token'] = url($menuArr['url']);
}else{
$menuArr['token'] = '';
}
$menu[] = $menuArr;
}
$menu = formatTree(listToTree($menu));
}
cache('AuthRule', $menu);
return $menu;
}
}

View File

@ -0,0 +1,146 @@
<?php
/**
*
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\controller;
use app\admin\model\Menu;
use app\admin\model\User;
use think\Controller;
class Base extends Controller {
public $primaryKey;
public $uid;
public $userInfo;
public $url;
public $menuInfo;
private $superUrl = [
'User/login',
'User/logout'
];
public function _initialize(){
$this->primaryKey = config('SQL_PRIMARY_KEY');
//初始化系统
$this->uid = session('uid');
$this->assign('uid',$this->uid);
$this->iniSystem();
//控制器初始化
if(method_exists($this,'_myInitialize')){
$this->_myInitialize();
}
}
/**
* 空方法默认的页面
*/
public function _empty(){
return (new PublicShow())->show_404();
}
/**
* 过滤没有权限和隐藏的菜单
* @param $temp
* @return mixed
*/
protected function _prepareTemplate( $temp ){
if( isAdministrator() ){
$MenuInfo = Menu::where([])->column('hide','url');
$authList = (new \Permission())->getAuthList($this->uid);
switch ( $temp['tempType'] ){
case 'table':
foreach ( $temp['topButton'] as $key => $value ){
if( !isset($authList[$value['href']]) || !$authList[$value['href']] ){
unset($temp['topButton'][$key]);
}else{
if( !isset($MenuInfo[$value['href']]) || $MenuInfo[$value['href']] ){
unset($temp['topButton'][$key]);
}else{
$temp['topButton'][$key]['href'] = url($value['href']);
}
}
}
$temp['topButton'] = array_values($temp['topButton']);
foreach ( $temp['rightButton'] as $k => $v ){
if( !isset($authList[$v['href']]) || !$authList[$v['href']] ){
unset($temp['rightButton'][$k]);
}else{
if( !isset($MenuInfo[$v['href']]) || $MenuInfo[$v['href']] ){
unset($temp['rightButton'][$k]);
}else{
$temp['rightButton'][$k]['href'] = url($v['href']);
}
}
}
$temp['rightButton'] = array_values($temp['rightButton']);
break;
case 'form':
break;
}
}
return $temp;
}
/**
* 系统初始化函数(登陆状态检测,权限检测,初始化菜单)
*/
private function iniSystem(){
$this->url = $this->request->controller().'/'.$this->request->action();
if( !in_array($this->url, $this->superUrl) ){
$menuInfo = Menu::where(['url' => $this->url])->find();
if( is_null($menuInfo) ){
$this->error( '目录:'.$this->url.'不存在!', '' );
}else{
$this->menuInfo = $menuInfo->toArray();
}
$this->checkLogin();
$this->checkRule();
}
}
/**
* 用户登录状态检测
*/
private function checkLogin(){
if( isset($this->uid) && !empty($this->uid) ){
$sidNow = session_id();
$sidOld = cache($this->uid);
if( isset($sidOld) && !empty($sidOld) ){
if( $sidOld != $sidNow ){
$this->error("您的账号在别的地方登录了,请重新登录!", url('User/login'));
}else{
cache($this->uid, $sidNow, config('online_time'));
$this->userInfo = User::get([ $this->primaryKey => $this->uid ])->toArray();
// if( $this->userInfo['updateTime'] === 0 ){
// $this->error('初次登录请重置用户密码!', url('User/changePassWord'));
// }else{
// if( empty($this->userInfo['nickName']) ){
// $this->error('初次登录请设置用户昵称!', url('User/changeNickname'));
// }
// }
}
}else{
$this->error("登录超时,请重新登录!", url('User/login'));
}
}else{
$this->redirect('User/login');
}
}
/**
* 权限检测&权限验证
*/
private function checkRule(){
$check = (new \Permission())->check($this->url, $this->uid);
if( !$check && !isAdministrator() ){
$this->error('权限认证失败!', '');
}
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace app\admin\controller;
use app\admin\model\Menu;
class Index extends Base {
public function index() {
$dataObj = Menu::all(function($query){
$query->order('sort', 'asc');
});
$authList = (new \Permission())->getAuthList($this->uid);
foreach ($dataObj as $value){
if( !$value->hide ){
if( isAdministrator() ){
$data[] = $value->toArray();
}else{
if( (isset($authList[$value->url]) && $authList[$value->url]) || empty($value->url) ){
$data[] = $value->toArray();
}
}
}
}
$data = listToTree($data);
$this->assign('title', '首页');
$this->assign('menuData', $data);
$this->assign('userInfo', $this->userInfo);
return $this->fetch();
}
}

View File

@ -0,0 +1,520 @@
<?php
namespace app\admin\controller;
use think\Validate;
/**
* 菜单管理控制器
* @since 2016-11-16
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
class Menu extends Base {
public function index(){
$data = [];
$dataObj = \app\admin\model\Menu::all(function($query){
$query->order('sort', 'asc');
});
foreach ($dataObj as $value){
$dataArr = $value->toArray();
if( $dataArr['url'] ){
$dataArr['token'] = url($dataArr['url']);
}else{
$dataArr['token'] = '';
}
$data[] = $dataArr;
}
$data = formatTree(listToTree($data));
(new Auth())->refreshAuth($data);
foreach( $data as &$value ){
$value['name'] = $value['showName'];
unset($value['showName']);
unset($value['namePrefix']);
unset($value['lv']);
unset($value['token']);
$value['post'] = intval(boolval($value['auth'] & \Permission::AUTH_POST));
$value['get'] = intval(boolval($value['auth'] & \Permission::AUTH_GET));
$value['put'] = intval(boolval($value['auth'] & \Permission::AUTH_PUT));
$value['delete'] = intval(boolval($value['auth'] & \Permission::AUTH_DELETE));
}
$table = [
'tempType' => 'table',
'header' => [
[
'field' => 'name',
'info' => '菜单名称'
],
[
'field' => 'url',
'info' => '菜单URL'
],
[
'field' => 'level',
'info' => '等级'
],
[
'field' => 'get',
'info' => 'Get'
],
[
'field' => 'put',
'info' => 'Put'
],
[
'field' => 'post',
'info' => 'Post'
],
[
'field' => 'delete',
'info' => 'Delete'
],
[
'field' => 'hide',
'info' => '隐藏'
],
[
'field' => 'sort',
'info' => '排序'
]
],
'topButton' => [
[
'href' => 'Menu/add',
'class'=> 'btn-success',
'info'=> '新增',
'icon' => 'fa fa-plus',
'confirm' => 0,
],
[
'href' => 'Menu/del',
'class'=> 'btn-danger ajax-delete',
'info'=> '删除',
'icon' => 'fa fa-trash',
'confirm' => 1,
]
],
'rightButton' => [
[
'info' => '编辑',
'href' => 'Menu/edit',
'class'=> 'btn-warning',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-pencil',
'confirm' => 0,
'show' => ''
],
[
'info' => '删除',
'href' => 'Menu/del',
'class'=> 'btn-danger ajax-delete',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-trash',
'confirm' => 1,
'show' => ''
]
],
'typeRule' => [
'name' => [
'module' => 'a',
'rule' => [
'info' => '',
'href' => url('Menu/add'),
'param'=> [$this->primaryKey],
'class' => 'refresh'
]
],
'hide' => [
'module' => 'label',
'rule' => [
[
'info' => '显示',
'class' => 'label label-success'
],
[
'info' => '隐藏',
'class' => 'label label-warning'
]
]
],
'post' => [
'module' => 'icon',
'rule' => [
[
'info' => '',
'class' => 'fa fa-close'
],
[
'info' => '',
'class' => 'fa fa-check'
]
]
],
'get' => [
'module' => 'icon',
'rule' => [
[
'info' => '',
'class' => 'fa fa-close'
],
[
'info' => '',
'class' => 'fa fa-check'
]
]
],
'put' => [
'module' => 'icon',
'rule' => [
[
'info' => '',
'class' => 'fa fa-close'
],
[
'info' => '',
'class' => 'fa fa-check'
]
]
],
'delete' => [
'module' => 'icon',
'rule' => [
[
'info' => '',
'class' => 'fa fa-close'
],
[
'info' => '',
'class' => 'fa fa-check'
]
]
]
],
'data' => $data
];
$table = $this->_prepareTemplate($table);
$this->result($table, ReturnCode::GET_TEMPLATE_SUCCESS);
}
public function add(){
if( $this->request->isPost() ){
$menuModel = new \app\admin\model\Menu();
$result = $menuModel->allowField(true)->validate(
[
'name' => 'require',
],[
'name.require' => '菜单名称不能为空',
]
)->save($this->request->post());
if(false === $result){
$this->error($menuModel->getError());
}else{
$this->success('操作成功!', url('Menu/index'));
}
}else{
$dataObj = \app\admin\model\Menu::all(function($query){
$query->order('sort', 'asc');
});
foreach ($dataObj as $value){
$data[] = $value->toArray();
}
$data = formatTree(listToTree($data));
foreach( $data as &$value ){
$value['name'] = $value['showName'];
unset($value['showName']);
unset($value['namePrefix']);
unset($value['lv']);
}
$data = array_column($data, 'name', $this->primaryKey);
$defaultFather = $this->request->get($this->primaryKey);
$form = [
'formTitle' => $this->menuInfo['name'],
'tempType' => 'add',
'formAttr' => [
'target' => url('Menu/add'),
'formId' => 'add-menu-form',
'backUrl' => url('Menu/index'),
],
'formList' => [
[
'module' => 'text',
'description' => '',
'info' => '菜单名称:',
'attr' => [
'name' => 'name',
'value' => '',
'placeholder' => ''
]
],
[
'module' => 'select',
'description' => '',
'info' => '父级菜单:',
'attr' => [
'name' => 'fid',
'value' => $defaultFather,
'options' => $data
]
],
[
'module' => 'select',
'description' => '',
'info' => '菜单等级:',
'attr' => [
'name' => 'level',
'value' => '',
'options' => [
'普通认证',
'Log记录'
]
]
],
[
'module' => 'checkbox',
'description' => '',
'info' => '访客权限:',
'attr' => [
[
'name' => 'auth[get]',
'desc' => 'GET',
'value' => ''
],
[
'name' => 'auth[put]',
'desc' => 'PUT',
'value' => ''
],
[
'name' => 'auth[post]',
'desc' => 'POST',
'value' => ''
],
[
'name' => 'auth[delete]',
'desc' => 'DELETE',
'value' => ''
]
]
],
[
'module' => 'radio',
'description' => '',
'info' => '是否显示:「该配置只对模块类功能生效」',
'attr' => [
'name' => 'hide',
'value' => '',
'options' => [
'显示菜单',
'隐藏菜单',
]
]
],
[
'module' => 'text',
'description' => '',
'info' => '菜单图标:「该配置只对模块类功能生效」',
'attr' => [
'name' => 'icon',
'value' => '',
'placeholder' => ''
]
],
[
'module' => 'text',
'description' => '',
'info' => '菜单URL「该配置只对无模块类功能子菜单的菜单生效」[具体格式为:控制器/方法名]',
'attr' => [
'name' => 'url',
'value' => '',
'placeholder' => ''
]
],
[
'module' => 'text',
'description' => '',
'info' => '排序:「数字越小顺序越靠前」',
'attr' => [
'name' => 'sort',
'value' => '0',
'placeholder' => ''
]
]
]
];
$this->result($form, ReturnCode::GET_TEMPLATE_SUCCESS);
}
}
public function edit(){
if( $this->request->isPut() ){
$data = $this->request->put();
$validate = new Validate([
'name' => 'require',
],[
'name.require' => '菜单名称不能为空',
]);
if(!$validate->check($data)){
$this->error($validate->getError());
}else{
$menuModel = new \app\admin\model\Menu();
$menuModel->allowField(true)->update($data);
$this->success('操作成功!', url('Menu/index'));
}
}else{
$dataObj = \app\admin\model\Menu::all(function($query){
$query->order('sort', 'asc');
});
foreach ($dataObj as $value){
$data[] = $value->toArray();
}
$data = formatTree(listToTree($data));
foreach( $data as &$value ){
$value['name'] = $value['showName'];
unset($value['showName']);
unset($value['namePrefix']);
unset($value['lv']);
}
$data = array_column($data, 'name', $this->primaryKey);
$detail = \app\admin\model\Menu::get($this->request->get($this->primaryKey))->toArray();
$form = [
'formTitle' => $this->menuInfo['name'],
'tempType' => 'edit',
'formAttr' => [
'target' => url('Menu/edit'),
'formId' => 'edit-menu-form',
'backUrl' => url('Menu/index'),
],
'formList' => [
[
'module' => 'text',
'description' => '',
'info' => '菜单名称:',
'attr' => [
'name' => 'name',
'value' => $detail['name'],
'placeholder' => ''
]
],
[
'module' => 'hidden',
'description' => '',
'info' => '',
'attr' => [
'name' => $this->primaryKey,
'value' => $detail['id'],
'placeholder' => ''
]
],
[
'module' => 'select',
'description' => '',
'info' => '父级菜单:',
'attr' => [
'name' => 'fid',
'value' => $detail['fid'],
'options' => $data
]
],
[
'module' => 'select',
'description' => '',
'info' => '菜单等级:',
'attr' => [
'name' => 'level',
'value' => $detail['level'],
'options' => [
'普通认证',
'Log记录'
]
]
],
[
'module' => 'checkbox',
'description' => '',
'info' => '访客权限:',
'attr' => [
[
'name' => 'auth[get]',
'desc' => 'GET',
'value' => $detail['auth'] & \Permission::AUTH_GET
],
[
'name' => 'auth[put]',
'desc' => 'PUT',
'value' => $detail['auth'] & \Permission::AUTH_PUT
],
[
'name' => 'auth[post]',
'desc' => 'POST',
'value' => $detail['auth'] & \Permission::AUTH_POST
],
[
'name' => 'auth[delete]',
'desc' => 'DELETE',
'value' => $detail['auth'] & \Permission::AUTH_DELETE
]
]
],
[
'module' => 'radio',
'description' => '',
'info' => '是否显示:「该配置只对模块类功能生效」',
'attr' => [
'name' => 'hide',
'value' => $detail['hide'],
'options' => [
'显示菜单',
'隐藏菜单',
]
]
],
[
'module' => 'text',
'description' => '',
'info' => '菜单图标:「该配置只对模块类功能生效」',
'attr' => [
'name' => 'icon',
'value' => $detail['icon'],
'placeholder' => ''
]
],
[
'module' => 'text',
'description' => '',
'info' => '菜单URL「该配置只对无模块类功能子菜单的菜单生效」[具体格式为:控制器/方法名]',
'attr' => [
'name' => 'url',
'value' => $detail['url'],
'placeholder' => ''
]
],
[
'module' => 'text',
'description' => '',
'info' => '排序:「数字越小顺序越靠前」',
'attr' => [
'name' => 'sort',
'value' => $detail['sort'],
'placeholder' => ''
]
]
]
];
$this->result($form, ReturnCode::GET_TEMPLATE_SUCCESS);
}
}
public function del(){
if( $this->request->isDelete() ){
$key = $this->request->delete($this->primaryKey);
$childNum = \app\admin\model\Menu::where(['fid' => $key])->count();
if( $childNum ){
$this->error('当前菜单存在子菜单,删除失败!');
}
$delNum = \app\admin\model\Menu::destroy($key);
if( $delNum ){
$this->success('操作成功!', url('Menu/index'));
}
}
$this->error('操作失败!');
}
}

View File

@ -0,0 +1,26 @@
<?php
/**
*
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\controller;
class PublicShow extends Base {
public function show_404(){
$this->assign('title', '页面丢失了!');
return $this->fetch('public/404');
}
public function show_500(){
return $this->fetch('public/500');
}
public function showBreadcrumb(){
}
}

View File

@ -0,0 +1,18 @@
<?php
/**
*
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\controller;
class ReturnCode {
const GET_TEMPLATE_SUCCESS = 200;
const SUCCESS = 1;
const ERROR = 0;
const GET_TEMPLATE_ERROR = 404;
}

View File

@ -0,0 +1,290 @@
<?php
/**
* 用户登录类
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\controller;
use app\admin\model\AuthGroupAccess;
use app\admin\model\UserData;
class User extends Base {
public function index(){
$data = [];
$dataObj = \app\admin\model\User::all();
foreach ( $dataObj as $value ){
$userInfo = $value->toArray();
$userData = UserData::get(['uid' => $userInfo[$this->primaryKey]]);
if( !is_null($userData) ){
$userData->toArray();
$userInfo['loginTimes'] = $userData['loginTimes'];
$userInfo['lastLoginTime'] = $userData['lastLoginTime'];
$userInfo['lastLoginIp'] = $userData['lastLoginIp'];
}else{
$userInfo['loginTimes'] = 0;
$userInfo['lastLoginTime'] = 0;
$userInfo['lastLoginIp'] = 0;
}
$data[] = $userInfo;
}
$table = [
'tempType' => 'table',
'header' => [
[
'field' => 'username',
'info' => '用户账号'
],
[
'field' => 'nickname',
'info' => '用户昵称'
],
[
'field' => 'loginTimes',
'info' => '登录次数'
],
[
'field' => 'lastLoginTime',
'info' => '最后登录时间'
],
[
'field' => 'lastLoginIp',
'info' => '最后登录IP'
],
[
'field' => 'status',
'info' => '状态'
]
],
'topButton' => [
[
'href' => 'User/add',
'class'=> 'btn-success',
'info'=> '新增',
'icon' => 'fa fa-plus',
'confirm' => 0,
]
],
'rightButton' => [
[
'info' => '启用',
'href' => 'User/open',
'class'=> 'btn-success ajax-put-url',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-check',
'confirm' => 1,
'show' => ['status', 0]
],
[
'info' => '禁用',
'href' => 'User/close',
'class'=> 'btn-warning ajax-put-url',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-close',
'confirm' => 1,
'show' => ['status', 1]
],
[
'info' => '授权',
'href' => 'Auth/group',
'class'=> 'btn-default',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-lock',
'confirm' => 0,
],
[
'info' => '删除',
'href' => 'User/del',
'class'=> 'btn-danger ajax-delete',
'param'=> [$this->primaryKey],
'icon' => 'fa fa-trash',
'confirm' => 1,
]
],
'typeRule' => [
'lastLoginTime' => [
'module' => 'date',
],
'status' => [
'module' => 'label',
'rule' => [
[
'info' => '禁用',
'class' => 'label label-danger'
],
[
'info' => '启用',
'class' => 'label label-success'
]
]
]
],
'data' => $data
];
$table = $this->_prepareTemplate($table);
$this->result($table, ReturnCode::GET_TEMPLATE_SUCCESS);
}
public function open(){
if( $this->request->isPut() ){
$id = $this->request->put($this->primaryKey);
$userObj = \app\admin\model\User::get([$this->primaryKey => $id]);
if( is_null($userObj) ){
$this->error('用户不存在','');
}else{
$userObj->status = 1;
$userObj->save();
$this->success('操作成功', url('User/index'));
}
}
}
public function close(){
if( $this->request->isPut() ){
$id = $this->request->put($this->primaryKey);
$userObj = \app\admin\model\User::get([$this->primaryKey => $id]);
if( is_null($userObj) ){
$this->error('用户不存在','');
}else{
$userObj->status = 0;
$userObj->save();
$this->success('操作成功', url('User/index'));
}
}
}
/**
* 用户登录函数
* @return mixed|void
*/
public function login(){
if( $this->request->isPost() ){
$username = $this->request->post('username');
$password = $this->request->post('password');
if( !$username || !$password ){
$this->error('缺少关键数据!','');
}
$userModel = new \app\admin\model\User();
$password = $userModel->getPwdHash($password);
$userInfo = $userModel->where(['username' => $username, 'password' => $password])->find();
if( empty($userInfo) ){
$this->error('用户名或者密码错误!','');
}else{
if( $userInfo['status'] ){
//保存用户信息和登录凭证
session('uid', $userInfo[$this->primaryKey]);
cache($userInfo[$this->primaryKey], session_id(), config('online_time'));
//获取跳转链接,做到从哪来到哪去
if( $this->request->has('from', 'get') ){
$url = $this->request->get('from');
}else{
$url = url('Index/index');
}
//更新用户数据
$userData = UserData::get(['uid' => $userInfo[$this->primaryKey]]);
if( $userData ){
$userData->loginTimes += 1;
$userData->save();
}else{
$newUserData = new UserData();
$newUserData->loginTimes = 1;
$newUserData->uid = $userInfo[$this->primaryKey];
$newUserData->save();
}
$this->success('登录成功', $url);
}else{
$this->error('用户已被封禁,请联系管理员','');
}
}
}else{
return $this->fetch();
}
}
public function logout(){
cache(session('uid'), null);
session('uid', null);
$this->success('登出成功',url('User/login'));
}
public function add(){
if( $this->request->isPost() ){
$userModel = new \app\admin\model\User();
$result = $userModel->allowField(true)->validate(
[
'username' => 'require',
],[
'username.require' => '用户名不能为空',
]
)->save($this->request->post());
if(false === $result){
$this->error($userModel->getError());
}else{
$this->success('操作成功!', url('User/index'));
}
}else{
$form = [
'formTitle' => $this->menuInfo['name'],
'tempType' => 'add',
'formAttr' => [
'target' => url('User/add'),
'formId' => 'add-user-form',
'backUrl' => url('User/index'),
],
'formList' => [
[
'module' => 'text',
'description' => '',
'info' => '用户名称:',
'attr' => [
'name' => 'username',
'value' => '',
'placeholder' => ''
]
],
[
'module' => 'text',
'description' => '',
'info' => '用户昵称:',
'attr' => [
'name' => 'nickname',
'value' => '',
'placeholder' => ''
]
],
[
'module' => 'password',
'description' => '',
'info' => '用户密码[默认123123]',
'attr' => [
'name' => 'password',
'value' => '123123',
'placeholder' => ''
]
]
]
];
$this->result($form, ReturnCode::GET_TEMPLATE_SUCCESS);
}
}
public function del(){
if( $this->request->isDelete() ){
$key = $this->request->delete($this->primaryKey);
if(!isAdministrator($key)){
$delNum = \app\admin\model\User::destroy($key);
if( $delNum ){
UserData::destroy(['uid' => $key]);
AuthGroupAccess::destroy(['uid' => $key]);
$this->success('操作成功!', url('User/index'));
}
}else{
$this->error('管理员不能被删除!');
}
}
$this->error('操作失败!');
}
}

View File

@ -0,0 +1,15 @@
<?php
/**
*
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\model;
use think\Model;
class AuthGroup extends Model {
}

View File

@ -0,0 +1,15 @@
<?php
/**
*
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\model;
use think\Model;
class AuthGroupAccess extends Model {
}

View File

@ -0,0 +1,15 @@
<?php
/**
*
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\model;
use think\Model;
class AuthRule extends Model {
}

View File

@ -0,0 +1,44 @@
<?php
/**
*
* @since 2016-02-18
* @author zhaoxiang <zhaoxiang051405@outlook.com>
*/
namespace app\admin\model;
use think\Model;
class Menu extends Model {
protected $type = [
'fid' => 'integer',
'type' => 'integer',
'sort' => 'integer',
'hide' => 'integer',
'auth' => 'integer',
'level' => 'integer',
];
protected function setAuthAttr($value){
if( is_array($value) ){
$authNum = 0;
if( isset($value['delete']) ){
$authNum += \Permission::AUTH_DELETE;
}
if( isset($value['put']) ){
$authNum += \Permission::AUTH_PUT;
}
if( isset($value['get']) ){
$authNum += \Permission::AUTH_GET;
}
if( isset($value['post']) ){
$authNum += \Permission::AUTH_POST;
}
return $authNum;
}else{
return 0;
}
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace app\admin\model;
use think\Model;
class User extends Model {
protected $autoWriteTimestamp = true;
protected $insert = ['regIp'];
protected $createTime = 'regTime';
protected $updateTime = 'updateTime';
protected function setRegIpAttr(){
return request()->ip(1);
}
protected function setPasswordAttr($value) {
return $this->getPwdHash($value);
}
public function getPwdHash( $pwd ){
$hashKey = config('auth_key');
$newPwd = $pwd.$hashKey;
return md5(sha1($newPwd).$hashKey);
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
* @since 2016-11-05
* @author zhaoxiang <zhaoxiang051405@gmail.com>
*/
namespace app\admin\model;
use think\Model;
class UserData extends Model {
protected $insert = ['lastLoginTime', 'lastLoginIp'];
protected $update = ['lastLoginIp', 'lastLoginTime'];
protected function setLastLoginIpAttr(){
return request()->ip(1);
}
protected function getLastLoginIpAttr( $value ){
return long2ip($value);
}
protected function setLastLoginTimeAttr(){
return time();
}
}

View File

@ -0,0 +1,79 @@
{extend name="public/base" /}
{block name="content"}
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">新增菜单</h3>
</div>
<form id="form-login">
<div class="box-body">
<div>
<div class="col-xs-8 form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
</div>
<div class="col-xs-4 form-group" style="margin-top: 30px">
<span class="label label-info">Info</span>
</div>
</div>
<div>
<div class="col-xs-8 form-group">
<label for="exampleInputEmail1">Email address</label>
<select class="form-control">
<option>option 1</option>
<option>option 2</option>
<option>option 3</option>
<option>option 4</option>
<option>option 5</option>
</select>
</div>
<div class="col-xs-4 form-group" style="margin-top: 30px">
<span class="label label-info">Info</span>
</div>
</div>
<div>
<div class="col-xs-8 form-group">
<label for="exampleInputEmail1">Email address</label>
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-dollar"></i></span>
<input type="text" class="form-control">
<span class="input-group-addon"><i class="fa fa-ambulance"></i></span>
</div>
</div>
<div class="col-xs-4 form-group" style="margin-top: 30px">
<span class="label label-info">Info</span>
</div>
</div>
<div>
<div class="form-group col-xs-8">
<label for="exampleInputEmail1">Email address</label>
<div class="input-group radio">
<label>
<input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked="">
Option one is this and that—be sure to include why it's great 
</label>
<label>
<input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked="">
Option one is this and that—be sure to include why it's great 
</label>
<label>
<input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked="">
Option one is this and that—be sure to include why it's great 
</label>
</div>
</div>
<div class="col-xs-4 form-group" style="margin-top: 30px">
<span class="label label-info">Info</span>
</div>
</div>
</div>
<div class="box-footer">
<button type="submit" target-form="form-login" class="btn btn-primary ajax-post">确认提交</button>
<a class="btn btn-default refe" url="{:url('Menu/index')}" >放弃返回</a>
</div>
</form>
</div>
{/block}
{block name="myScript"}
{/block}

View File

@ -0,0 +1,94 @@
{extend name="public/base" /}
{block name="myStyle"}
<style>
div.wrapper404 {
display:block;
width:100%;
text-align:left;
margin:0;
padding:0;
}
.row2 {
font-size:13px;
font-family:Georgia,"Times New Roman",Times,serif;
color:#919191;
margin:0;
padding:0;
}
.row2 a {
color:#F90;
outline:none;
text-decoration:none;
}
div.wrapper404 h1,div.wrapper404 h2,div.wrapper404 h3,div.wrapper404 h4,div.wrapper404 h5,div.wrapper404 h6 {
font-size:20px;
font-weight:400;
line-height:normal;
margin:0 0 15px;
padding:0;
}
#fof {
display:block;
width:100%;
line-height:1.6em;
text-align:center;
padding:150px 0;
}
#fof .hgroup {
margin-bottom:15px;
}
#fof .hgroup h1,#fof .hgroup h2 {
text-transform:uppercase;
margin:0;
padding:0;
}
#fof .hgroup h1 {
margin-bottom:15px;
font-size:40px;
}
#fof .hgroup h2 {
display:inline-block;
font-size:80px;
border:solid #CCC;
text-transform:lowercase;
border-width:1px 0;
padding:0 0 15px;
}
#fof p {
display:block;
font-size:16px;
margin:15px 0 0;
padding:0;
}
#fof p:first-child {
margin-top:0;
}
</style>
{/block}
{block name="main"}
<div class="wrapper404 row2">
<div id="container" class="clear">
<div id="fof" class="clear">
<div class="hgroup">
<h1>糟糕,系统出错了 !</h1>
<h2>404 Error</h2>
</div>
<p>由于一些原因,您访问的网页不存在!</p>
<p><a href="javascript:history.go(-1)">返回</a>上一页 或者 <a href="#">回到首页</a></p>
</div>
</div>
</div>
{/block}
{block name="myScript"}
{/block}

View File

View File

@ -0,0 +1,200 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{:config('PRODUCT_NAME')} | {block name="title"}{$title}{/block}</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="__PLUGIN__/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdn.bootcss.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" href="//cdn.bootcss.com/ionicons/2.0.1/css/ionicons.min.css">
<link rel="stylesheet" href="__CSS__/AdminLTE.min.css">
<link rel="stylesheet" href="__CSS__/skins/_all-skins.min.css">
<link rel="icon" href="__IMG__/favicon.ico">
<style>
body{
font-family: "Microsoft YaHei",FontAwesome,sans-serif;
}
.builder-data-empty {
margin-bottom: 20px;
background-color: #f9f9f9;
}
.no-data {
padding: 130px 0;
color: #555;
}
.am-text-center {
text-align: center !important;
}
a{
cursor:pointer;
}
</style>
{block name="myStyle"}{/block}
<!--[if lt IE 9]>
<script src="__PLUGIN__/compatible/html5shiv.js"></script>
<script src="__PLUGIN__/compatible/respond.min.js"></script>
<![endif]-->
</head>
<body class="hold-transition skin-blue sidebar-mini fixed">
<div class="wrapper">
<!--顶部banner-->
<header class="main-header">
<a href="{:url('Index/index')}" class="logo" style="height: 52px">
<span class="logo-mini">
<img src="__IMG__/logo.jpg" width="51px" alt="">
</span>
<span class="logo-lg">ApiAdmin</span>
</a>
<nav class="navbar navbar-static-top">
<a href="javascript:void(0);" class="sidebar-toggle" data-toggle="offcanvas" role="button">
<span class="sr-only">Toggle navigation</span>
</a>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="__IMG__/logo.jpg" class="user-image" alt="User Image">
<span class="hidden-xs">{$userInfo['username']}</span>
</a>
<ul class="dropdown-menu">
<!-- User image -->
<li class="user-header">
<img src="__IMG__/logo.jpg" class="img-circle" alt="User Image">
<p>
{$userInfo['username']} - {$userInfo['nickname']}
<small>注册时间:{$userInfo['regTime'] | date='Y-m-d',###}</small>
</p>
</li>
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="#" class="btn btn-default btn-flat">修改信息</a>
</div>
<div class="pull-right">
<a href="{:url('User/logout')}" class="btn btn-default btn-flat">退出登录</a>
</div>
</li>
</ul>
</li>
</ul>
</div>
</nav>
</header>
<!-- 左侧导航栏 -->
<aside class="main-sidebar" id="main-sidebar">
<section class="sidebar">
<!--管理员信息-->
<div class="user-panel">
<div class="pull-left image">
<img src="__IMG__/logo.jpg" class="img-circle" alt="头像">
</div>
<div class="pull-left info">
<p>{$userInfo['nickname']}</p>
<a href="javascript:void(0);"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
<!--搜索表单-->
<form action="#" method="get" class="sidebar-form">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="Search...">
<span class="input-group-btn">
<button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button>
</span>
</div>
</form>
<ul class="sidebar-menu">
<li class="header">主菜单</li>
{volist name="menuData" id="menuValue"}
{if condition="!empty($menuValue['url']) OR (isset($menuValue['_child']) AND count($menuValue['_child']))"}
{if condition="isset($menuValue['_child']) AND count($menuValue['_child'])"}
<li class="treeview">
<a href="javascript:void(0);">
<i class="fa {$menuValue['icon']}"></i> <span class="menuFather">{$menuValue['name']}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
{volist name="menuValue['_child']" id="childValue"}
<li class="menuChild"><a url="{:url($childValue['url'])}" class="refresh"><i class="fa {$childValue['icon']}"></i> {$childValue['name']}</a></li>
{/volist}
</ul>
</li>
{else /}
<li>
<a url="{:url($menuValue['url'])}" class="refresh">
<i class="fa {$menuValue['icon']}"></i> <span class="menuFather">{$menuValue['name']}</span>
</a>
</li>
{/if}
{/if}
{/volist}
</ul>
</section>
</aside>
<div class="content-wrapper">
<!-- 头部(面包屑导航) -->
<section class="content-header" id="content-header">
<h1>{$title}</h1>
<ol class="breadcrumb" id="breadcrumb">
<li><i class="fa fa-dashboard"></i> 首页</li>
</ol>
</section>
<section class="content" id="content">
{block name="content"}{/block}
</section>
</div>
<!-- 公用底部(完成适配) -->
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>Version</b> {:config('PRODUCT_VERSION')}
</div>
<strong>Copyright &copy; 2014-{:date('Y')} <a href="{:config('WEBSITE_DOMAIN')}">{:config('COMPANY_NAME')}</a>.</strong> All rights reserved.
</footer>
<!-- 主题适配相关(完成适配) -->
<div class="control-sidebar-bg"></div>
</div>
<!-- jQuery 2.2.3 -->
<script src="__PLUGIN__/jQuery/2.2.4/jquery.min.js"></script>
<!-- Bootstrap 3.3.6 -->
<script src="__PLUGIN__/bootstrap/js/bootstrap.min.js"></script>
<!-- FastClick -->
<script src="__PLUGIN__/fastClick/fastclick.js"></script>
<!-- slimScroll -->
<script src="__PLUGIN__/slimScroll/jquery.slimscroll.min.js"></script>
<!-- BootBox -->
<script src="__PLUGIN__/bootBox/bootbox.min.js"></script>
<!-- AdminLTE App -->
<script src="__JS__/app.min.js"></script>
<!-- AdminLTE for demo purposes -->
<script src="__JS__/demo.js"></script>
<script>
var JS_PATH = '__JS__';
var CSS_PATH = '__CSS__';
var STATIC_PATH = '__STATIC__';
var IMG_PATH = '__IMG__';
var PLUGIN_PATH = '__PLUGIN__';
var COMPANY_NAME = '{:config("COMPANY_NAME")}';
/**
* 自动适配面包屑导航
*/
$('body').on('click', '.menuChild', function() {
$('.menuChild').removeClass('active');
$(this).addClass('active');
var parentName = $.trim($(this).parent().prev().text());
var ownName = $(this).children('a').text();
var breadcrumb = $('#breadcrumb');
breadcrumb.html('<li><i class="fa fa-dashboard"></i> 首页</li>');
breadcrumb.append('<li>'+ parentName +'</li><li>'+ ownName +'</li>');
breadcrumb.prev().text(ownName);
});
</script>
<script src="__JS__/template.js"></script>
{block name="myScript"}{/block}
</body>
</html>

View File

@ -0,0 +1,63 @@
{__NOLAYOUT__}
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>ApiAdmin - 跳转提示</title>
<script src="__PLUGIN__/jQuery/3.1.1/jquery.min.js"></script>
<link href="//cdn.bootcss.com/semantic-ui/2.2.6/semantic.min.css" rel="stylesheet">
<script src="//cdn.bootcss.com/semantic-ui/2.2.6/semantic.js"></script>
<link rel="icon" href="__IMG__/favicon.ico">
</head>
<body>
<div class="ui card" style="text-align:center;width:40%;position: fixed;top: 20%;left: 30%">
<?php switch ($code) {?>
<?php case 1:?>
<div class="ui green inverted segment" style="margin: 0px;">
<i class="ui smile icon massive"></i>
</div>
<?php break;?>
<?php case 0:?>
<div class="ui red inverted segment" style="margin: 0px;">
<i class="ui frown icon massive"></i>
</div>
<?php break;?>
<?php } ?>
<div class="content" style="line-height: 2em">
<?php if(isset($msg)) {?>
<span class="header"><?php echo(strip_tags($msg));?></span>
<?php }else{?>
<span class="header"><?php echo($error); ?></span>
<?php }?>
<div class="meta">
将在<span id="left"><?php echo($wait); ?></span>S后自动跳转
</div>
</div>
<span style="display: none" id="href"><?php echo($url); ?></span>
<div class="ui bottom attached indicating progress" id="amanege-bar">
<div class="bar"></div>
</div>
</div>
</body>
<script type="text/javascript">
(function(){
var wait = 0,left = $('#left').text();
var href = $('#href').text();
var each = 100/left;
var interval = setInterval(function(){
wait = wait + each;
left = left - 1;
if(wait > 100) {
location.href = href;
clearInterval(interval);
return ;
}
$('#left').text(left);
$('#amanege-bar').progress({
percent: wait
});
}, 1000);
})();
</script>
</html>

View File

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{:config('PRODUCT_NAME')} | 登 录</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="__PLUGIN__/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="__CSS__/AdminLTE.min.css">
<link rel="icon" href="__IMG__/favicon.ico">
<!--[if lt IE 9]>
<script src="__PLUGIN__/compatible/html5shiv.min.js"></script>
<script src="__PLUGIN__/compatible/respond.min.js"></script>
<![endif]-->
</head>
<body class="hold-transition login-page">
<div class="login-box">
<div class="login-logo">
<a href="{:config('WEBSITE_DOMAIN')}"><b>Api</b> Admin</a>
</div>
<div class="login-box-body">
<p class="login-box-msg">
<span class="label label-info">请填写您的账号和密码admin/123123</span>
</p>
<form action="{:url('User/login')}" id="form-login">
<div class="form-group has-feedback">
<input type="text" class="form-control" name="username" placeholder="Username">
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="password" name="password" class="form-control" placeholder="Password">
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-12">
<button type="submit" target-form="form-login" class="btn btn-primary ajax-post redirect btn-block btn-flat">登 录</button>
</div>
</div>
</form>
</div>
</div>
<!-- jQuery 2.2.3 -->
<script src="__PLUGIN__/jQuery/2.2.4/jquery.min.js"></script>
<!-- Bootstrap 3.3.6 -->
<script src="__PLUGIN__/bootstrap/js/bootstrap.min.js"></script>
<!-- BootBox -->
<script src="__PLUGIN__/bootBox/bootbox.min.js"></script>
<script src="__JS__/template.js"></script>
</body>
</html>

25
application/build.php Normal file
View File

@ -0,0 +1,25 @@
<?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 [
// 生成应用公共文件
'__file__' => ['common.php', 'config.php', 'database.php'],
// 定义demo模块的自动生成 (按照实际定义的文件名生成)
'admin' => [
'__file__' => ['common.php'],
'__dir__' => ['behavior', 'controller', 'model', 'view'],
'controller' => ['Index', 'Test', 'UserType'],
'model' => ['User', 'UserType'],
'view' => ['index/index'],
],
// 其他更多的模块定义
];

12
application/command.php Normal file
View File

@ -0,0 +1,12 @@
<?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 [];

128
application/common.php Normal file
View File

@ -0,0 +1,128 @@
<?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>
// +----------------------------------------------------------------------
/**
* 判断是否是系统管理员
* @param mixed $uid
* @return bool
*/
function isAdministrator( $uid = '' ){
$uid = empty($uid) ? session('uid') : $uid;
if( is_array(config('USER_ADMINISTRATOR')) ){
if( is_array( $uid ) ){
$m = array_intersect( config('USER_ADMINISTRATOR'), $uid );
if( count($m) ){
return TRUE;
}
}else{
if( in_array( $uid, config('USER_ADMINISTRATOR') ) ){
return TRUE;
}
}
}else{
if( is_array( $uid ) ){
if( in_array(config('USER_ADMINISTRATOR'),$uid) ){
return TRUE;
}
}else{
if( $uid == config('USER_ADMINISTRATOR')){
return TRUE;
}
}
}
return FALSE;
}
/**
* CURL post数据
* @param $url
* @param $data
* @param array $urlParam
* @param array $header
* @return mixed
*/
function curlPost( $url, $data, $urlParam = [], $header = [] ){
$ch = curl_init();
if( !empty($urlParam) ){
$url = $url.'?'.http_build_query($urlParam);
}
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
if( !empty($header) ){
$headerStrArr = [];
foreach ($header as $key => $value){
$headerStrArr[] = "$key: $value";
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerStrArr);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
$return = curl_exec($ch);
curl_close($ch);
return $return;
}
/**
* 把返回的数据集转换成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 = [];
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;
}
function formatTree($list, $lv = 0, $title = 'name'){
$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('_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;
}

244
application/config.php Normal file
View File

@ -0,0 +1,244 @@
<?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 [
'PRODUCT_VERSION' => 'V1.0.0', //项目版本
'PRODUCT_NAME' => 'ApiAdmin', //产品名称
'WEBSITE_DOMAIN' => 'http://www.our-dream.cn', //官方网址
'COMPANY_NAME' => 'XXXXXXXX有限公司', //公司名称
'SQL_PRIMARY_KEY' => 'id',
'USER_ADMINISTRATOR' => 4,
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
// 应用命名空间
'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' => 'html',
// 默认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' => 'index',
// 禁止访问模块
'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' => ['route'],
// 是否强制使用路由
'url_route_must' => false,
// 域名部署
'url_domain_deploy' => false,
// 域名根如thinkphp.cn
'url_domain_root' => '',
// 是否自动转换URL中的控制器和操作名
'url_convert' => true,
// 默认的访问控制器层
'url_controller_layer' => 'controller',
// 表单请求类型伪装变量
'var_method' => '_method',
// +----------------------------------------------------------------------
// | 模板设置
// +----------------------------------------------------------------------
'template' => [
// 模板引擎类型 支持 php think 支持扩展
'type' => 'Think',
// 模板路径
'view_path' => '',
// 模板后缀
'view_suffix' => 'html',
// 模板文件名分隔符
'view_depr' => DS,
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '{',
// 标签库标签结束标记
'taglib_end' => '}',
],
// 视图输出字符串内容替换
'view_replace_str' => [
'__STATIC__'=>'/static',
'__CSS__'=>'/static/css',
'__JS__'=>'/static/js',
'__IMG__'=>'/static/img',
'__PLUGIN__'=>'/static/plugin',
],
// 默认跳转页面对应的模板文件
'dispatch_success_tmpl' => 'public/jump',
'dispatch_error_tmpl' => 'public/jump',
// +----------------------------------------------------------------------
// | 异常及错误设置
// +----------------------------------------------------------------------
// 异常页面的模板文件
'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' => 'File',
// 缓存保存目录
'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,
],
];

51
application/database.php Normal file
View File

@ -0,0 +1,51 @@
<?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 [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'admin',
// 用户名
'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,
// 数据集返回类型 array 数组 collection Collection对象
'resultset_type' => 'array',
// 是否自动写入时间戳字段
'auto_timestamp' => false,
// 是否需要进行SQL性能分析
'sql_explain' => false,
];

View File

@ -2,16 +2,14 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ] // | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com> // | Author: liu21st <liu21st@gmail.com>
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
use think\facade\Route;
Route::group('admin', function() { use \think\Route;
//Route::rule('Index/index', 'admin.Index/index', 'get');
//MISS路由定义 //Route::get('/','Index/Index/index');
Route::miss('admin.Miss/index'); //Route::get('/','Index/User/index');
});

28
application/tags.php Normal file
View File

@ -0,0 +1,28 @@
<?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_init' => [],
// 应用开始
'app_begin' => [],
// 模块初始化
'module_init' => [],
// 操作开始执行
'action_begin' => [],
// 视图内容过滤
'view_filter' => [],
// 日志写入
'log_write' => [],
// 应用结束
'app_end' => [],
];

25
build.php Normal file
View File

@ -0,0 +1,25 @@
<?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 [
// 生成应用公共文件
'__file__' => ['common.php', 'config.php', 'database.php'],
// 定义demo模块的自动生成 (按照实际定义的文件名生成)
'demo' => [
'__file__' => ['common.php'],
'__dir__' => ['behavior', 'controller', 'model', 'view'],
'controller' => ['Index', 'Test', 'UserType'],
'model' => ['User', 'UserType'],
'view' => ['index/index'],
],
// 其他更多的模块定义
];

View File

@ -1,46 +0,0 @@
{
"name": "apiadmin/apiadmin",
"description": "Just For Api",
"type": "project",
"keywords": [
"framework",
"thinkphp",
"api",
"apiadmin"
],
"homepage": "http://www.apiadmin.org/",
"license": "Apache-2.0",
"authors": [
{
"name": "zhaoxiang",
"email": "zhaoxiang051405@gmail.com"
}
],
"require": {
"php": ">=7.2.5",
"topthink/framework": "^6.0",
"topthink/think-orm": "^2.0",
"topthink/think-migration": "^3.0"
},
"require-dev": {
"symfony/var-dumper": "^4.2",
"topthink/think-trace":"^1.0"
},
"autoload": {
"psr-4": {
"app\\": "app"
},
"psr-0": {
"": "extend/"
}
},
"config": {
"preferred-install": "dist"
},
"scripts": {
"post-autoload-dump": [
"@php think service:discover",
"@php think vendor:publish"
]
}
}

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