first commit
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = tab
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[docker-compose.yml]
|
||||
indent_size = 4
|
||||
@@ -0,0 +1,70 @@
|
||||
APP_NAME=sentos
|
||||
VERSION=1.0.0
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=Asia/Shanghai
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=laravel
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=file
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
OSS_ACCESS_KEY_ID=
|
||||
OSS_ACCESS_KEY_SECRET=
|
||||
OSS_BUCKET=nowart
|
||||
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
@@ -0,0 +1,11 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
*.html diff=html
|
||||
*.md diff=markdown
|
||||
*.php diff=php
|
||||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
.styleci.yml export-ignore
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/.phpunit.cache
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/public/static
|
||||
/public/assets
|
||||
/public/*.js
|
||||
/public/.user.ini
|
||||
/storage/*.key
|
||||
/vendor
|
||||
/resources/admin-bak
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.phpactor.json
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
auth.json
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
/.fleet
|
||||
/.idea
|
||||
/.vscode
|
||||
composer.lock
|
||||
bootstrap/cache/*
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
/resources/antdvadmin
|
||||
@@ -0,0 +1,194 @@
|
||||
木兰宽松许可证,第2版
|
||||
|
||||
木兰宽松许可证,第2版
|
||||
|
||||
2020年1月 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束:
|
||||
|
||||
0. 定义
|
||||
|
||||
“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
|
||||
|
||||
“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
|
||||
|
||||
“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
|
||||
|
||||
“法人实体” 是指提交贡献的机构及其“关联实体”。
|
||||
|
||||
“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是
|
||||
指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
|
||||
|
||||
1. 授予版权许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可
|
||||
以复制、使用、修改、分发其“贡献”,不论修改与否。
|
||||
|
||||
2. 授予专利许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定
|
||||
撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡
|
||||
献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软
|
||||
件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“
|
||||
关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或
|
||||
其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权
|
||||
行动之日终止。
|
||||
|
||||
3. 无商标许可
|
||||
|
||||
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定
|
||||
的声明义务而必须使用除外。
|
||||
|
||||
4. 分发限制
|
||||
|
||||
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“
|
||||
本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
|
||||
|
||||
5. 免责声明与责任限制
|
||||
|
||||
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对
|
||||
任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于
|
||||
何种法律理论,即使其曾被建议有此种损失的可能性。
|
||||
|
||||
6. 语言
|
||||
|
||||
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文
|
||||
版为准。
|
||||
|
||||
条款结束
|
||||
|
||||
如何将木兰宽松许可证,第2版,应用到您的软件
|
||||
|
||||
如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
|
||||
|
||||
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
|
||||
|
||||
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
|
||||
|
||||
3, 请将如下声明文本放入每个源文件的头部注释中。
|
||||
|
||||
Copyright (c) [Year] [name of copyright holder]
|
||||
[Software Name] is licensed under Mulan PSL v2.
|
||||
You can use this software according to the terms and conditions of the Mulan
|
||||
PSL v2.
|
||||
You may obtain a copy of Mulan PSL v2 at:
|
||||
http://license.coscl.org.cn/MulanPSL2
|
||||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
||||
|
||||
Mulan Permissive Software License,Version 2
|
||||
|
||||
Mulan Permissive Software License,Version 2 (Mulan PSL v2)
|
||||
|
||||
January 2020 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
Your reproduction, use, modification and distribution of the Software shall
|
||||
be subject to Mulan PSL v2 (this License) with the following terms and
|
||||
conditions:
|
||||
|
||||
0. Definition
|
||||
|
||||
Software means the program and related documents which are licensed under
|
||||
this License and comprise all Contribution(s).
|
||||
|
||||
Contribution means the copyrightable work licensed by a particular
|
||||
Contributor under this License.
|
||||
|
||||
Contributor means the Individual or Legal Entity who licenses its
|
||||
copyrightable work under this License.
|
||||
|
||||
Legal Entity means the entity making a Contribution and all its
|
||||
Affiliates.
|
||||
|
||||
Affiliates means entities that control, are controlled by, or are under
|
||||
common control with the acting entity under this License, ‘control’ means
|
||||
direct or indirect ownership of at least fifty percent (50%) of the voting
|
||||
power, capital or other securities of controlled or commonly controlled
|
||||
entity.
|
||||
|
||||
1. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to you a perpetual, worldwide, royalty-free, non-exclusive,
|
||||
irrevocable copyright license to reproduce, use, modify, or distribute its
|
||||
Contribution, with modification or not.
|
||||
|
||||
2. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to you a perpetual, worldwide, royalty-free, non-exclusive,
|
||||
irrevocable (except for revocation under this Section) patent license to
|
||||
make, have made, use, offer for sale, sell, import or otherwise transfer its
|
||||
Contribution, where such patent license is only limited to the patent claims
|
||||
owned or controlled by such Contributor now or in future which will be
|
||||
necessarily infringed by its Contribution alone, or by combination of the
|
||||
Contribution with the Software to which the Contribution was contributed.
|
||||
The patent license shall not apply to any modification of the Contribution,
|
||||
and any other combination which includes the Contribution. If you or your
|
||||
Affiliates directly or indirectly institute patent litigation (including a
|
||||
cross claim or counterclaim in a litigation) or other patent enforcement
|
||||
activities against any individual or entity by alleging that the Software or
|
||||
any Contribution in it infringes patents, then any patent license granted to
|
||||
you under this License for the Software shall terminate as of the date such
|
||||
litigation or activity is filed or taken.
|
||||
|
||||
3. No Trademark License
|
||||
|
||||
No trademark license is granted to use the trade names, trademarks, service
|
||||
marks, or product names of Contributor, except as required to fulfill notice
|
||||
requirements in section 4.
|
||||
|
||||
4. Distribution Restriction
|
||||
|
||||
You may distribute the Software in any medium with or without modification,
|
||||
whether in source or executable forms, provided that you provide recipients
|
||||
with a copy of this License and retain copyright, patent, trademark and
|
||||
disclaimer statements in the Software.
|
||||
|
||||
5. Disclaimer of Warranty and Limitation of Liability
|
||||
|
||||
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR
|
||||
COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT
|
||||
LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO
|
||||
MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
6. Language
|
||||
|
||||
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION
|
||||
AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF
|
||||
DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION
|
||||
SHALL PREVAIL.
|
||||
|
||||
END OF THE TERMS AND CONDITIONS
|
||||
|
||||
How to Apply the Mulan Permissive Software License,Version 2
|
||||
(Mulan PSL v2) to Your Software
|
||||
|
||||
To apply the Mulan PSL v2 to your work, for easy identification by
|
||||
recipients, you are suggested to complete following three steps:
|
||||
|
||||
i. Fill in the blanks in following statement, including insert your software
|
||||
name, the year of the first publication of your software, and your name
|
||||
identified as the copyright owner;
|
||||
|
||||
ii. Create a file named "LICENSE" which contains the whole context of this
|
||||
License in the first directory of your software package;
|
||||
|
||||
iii. Attach the statement to the appropriate annotated syntax at the
|
||||
beginning of each source file.
|
||||
|
||||
Copyright (c) [Year] [name of copyright holder]
|
||||
[Software Name] is licensed under Mulan PSL v2.
|
||||
You can use this software according to the terms and conditions of the Mulan
|
||||
PSL v2.
|
||||
You may obtain a copy of Mulan PSL v2 at:
|
||||
http://license.coscl.org.cn/MulanPSL2
|
||||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
||||
@@ -0,0 +1,56 @@
|
||||
### Laradmin
|
||||
Laradmin是一个基于Laravel + Vue 开发的后台管理系统,基础功能包括:用户管理、角色管理、菜单管理、部门管理、日志管理、字典管理、参数管理、定时任务、城市管理、客户端管理、图片上传、富文本编辑器
|
||||
|
||||
### 演示地址
|
||||
http://www.sentcms.com
|
||||
账号:admin
|
||||
密码:admin888
|
||||
(请勿修改密码,数据定期清理)
|
||||
|
||||
### 运行环境
|
||||
|
||||
1. PHP >= 7.2.0
|
||||
2. MySQL >= 5.7.0
|
||||
3. Redis >= 4.0.0
|
||||
4. Laravel >= 11.0.0
|
||||
5. Vue >= 3.0.0
|
||||
6. Node >= 16.0.0
|
||||
7. Vite >= 4.0.0
|
||||
|
||||
### 服务器端安装
|
||||
1. 运行composer install
|
||||
2. 运行composer install-project
|
||||
3. 运行php artisan migrate
|
||||
4. 运行php artisan module:seed
|
||||
5. 运行php artisan serve
|
||||
6. 访问http://localhost:8000
|
||||
|
||||
### 前端安装
|
||||
1. cd resources/admin
|
||||
2. yarn install
|
||||
3. yarn run serve
|
||||
4. 访问http://localhost:8080
|
||||
|
||||
### 线上部署
|
||||
1. 运行composer install
|
||||
2. 运行composer install-project
|
||||
3. 运行php artisan migrate
|
||||
4. 运行php artisan module:seed
|
||||
5. 运行cd resources/admin && yarn install && yarn run build
|
||||
6. 访问http://域名/admin
|
||||
|
||||
|
||||
### 功能
|
||||
- [x] 用户管理 后台用户管理
|
||||
- [x] 部门管理 配置公司的部门结构,支持树形结构
|
||||
- [x] 菜单管理 配置系统菜单,按钮等等
|
||||
- [x] 角色管理 配置用户担当的角色,分配权限
|
||||
- [x] 配置管理 参数的管理
|
||||
- [x] 字典管理 字典数据管理
|
||||
- [x] 城市数据 城市数据管理
|
||||
- [x] 客户端管理 客户端管理
|
||||
- [x] 定时任务 定时任务管理
|
||||
- [x] 操作日志 后台用户操作记录
|
||||
- [x] 图片上传 图片上传管理
|
||||
- [x] 富文本编辑器 富文本编辑器管理
|
||||
- [ ] 应用管理 应用管理
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use GatewayWorker\BusinessWorker;
|
||||
use GatewayWorker\Gateway;
|
||||
use GatewayWorker\Register;
|
||||
use Workerman\Worker;
|
||||
use App\Events\WorkermanEvent;
|
||||
|
||||
class Workerman extends Command {
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'work {action} {--d}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Start a Workerman server.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle() {
|
||||
global $argv;
|
||||
$action = $this->argument('action');
|
||||
|
||||
$argv[0] = 'work';
|
||||
$argv[1] = $action;
|
||||
$argv[2] = $this->option('d') ? '-d' : '';
|
||||
|
||||
$this->start();
|
||||
}
|
||||
|
||||
public function start() {
|
||||
$this->startGateWay();
|
||||
$this->startBusinessWorker();
|
||||
$this->startRegister();
|
||||
|
||||
$workerPath = storage_path('workerman/');
|
||||
if (!is_dir($workerPath))
|
||||
mkdir($workerPath, 0755, true);
|
||||
Worker::$pidFile = $workerPath . config('app.name') . '_workman.pid';
|
||||
$logPath = $workerPath . date('Ym') . '/';
|
||||
if (!is_dir($logPath))
|
||||
mkdir($logPath, 0755, true);
|
||||
Worker::$logFile = $logPath . date('d') . '.log';
|
||||
|
||||
Worker::runAll();
|
||||
}
|
||||
|
||||
public function startGateWay() {
|
||||
$gateway = new Gateway("websocket://0.0.0.0:2346");
|
||||
$gateway->name = 'Gateway';
|
||||
$gateway->count = 4;
|
||||
$gateway->lanIp = '127.0.0.1';
|
||||
$gateway->startPort = 2900;
|
||||
$gateway->pingInterval = 10;
|
||||
$gateway->pingNotResponseLimit = 1;
|
||||
$gateway->pingData = '{"type":"pong"}';
|
||||
$gateway->registerAddress = '127.0.0.1:1236';
|
||||
}
|
||||
|
||||
public function startBusinessWorker() {
|
||||
$worker = new BusinessWorker();
|
||||
$worker->name = 'BusinessWorker';
|
||||
$worker->count = 3;
|
||||
$worker->registerAddress = '127.0.0.1:1236';
|
||||
$worker->eventHandler = WorkermanEvent::class;
|
||||
}
|
||||
|
||||
public function startRegister() {
|
||||
$register = new Register('text://0.0.0.0:1236');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use GatewayWorker\BusinessWorker;
|
||||
use GatewayWorker\Gateway;
|
||||
use GatewayWorker\Register;
|
||||
use Workerman\Worker;
|
||||
use App\Events\WorkermanEvent;
|
||||
|
||||
class WorkermanWin extends Command {
|
||||
|
||||
// 兼容windows
|
||||
protected $signature = 'wk {action : action} {--start=all : start} {--d : daemon mode}';
|
||||
|
||||
protected $description = 'Start a Workerman server.';
|
||||
|
||||
public function handle() {
|
||||
global $argv;
|
||||
$action = $this->argument('action');
|
||||
|
||||
|
||||
//针对 Windows 一次执行,无法注册多个协议的特殊处理
|
||||
if ($action === 'single') {
|
||||
$start = $this->option('start');
|
||||
if ($start === 'register') {
|
||||
$this->startRegister();
|
||||
} elseif ($start === 'gateway') {
|
||||
$this->startGateWay();
|
||||
} elseif ($start === 'worker') {
|
||||
$this->startBusinessWorker();
|
||||
}
|
||||
Worker::runAll();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$argv[1] = $action;
|
||||
$argv[2] = $this->option('d') ? '-d' : '';
|
||||
|
||||
$this->start();
|
||||
}
|
||||
|
||||
public function start() {
|
||||
$this->startGateWay();
|
||||
$this->startBusinessWorker();
|
||||
$this->startRegister();
|
||||
Worker::runAll();
|
||||
}
|
||||
|
||||
public function startGateWay() {
|
||||
$gateway = new Gateway("websocket://0.0.0.0:2346");
|
||||
$gateway->name = 'Gateway';
|
||||
$gateway->count = 4;
|
||||
$gateway->lanIp = '127.0.0.1';
|
||||
$gateway->startPort = 2900;
|
||||
$gateway->pingInterval = 10;
|
||||
$gateway->pingNotResponseLimit = 1;
|
||||
$gateway->pingData = '{"type":"pong"}';
|
||||
$gateway->registerAddress = '127.0.0.1:1236';
|
||||
}
|
||||
|
||||
public function startBusinessWorker() {
|
||||
$worker = new BusinessWorker();
|
||||
$worker->name = 'BusinessWorker';
|
||||
$worker->count = 3;
|
||||
$worker->registerAddress = '127.0.0.1:1236';
|
||||
$worker->eventHandler = WorkermanEvent::class;
|
||||
}
|
||||
|
||||
public function startRegister() {
|
||||
$register = new Register('text://0.0.0.0:1236');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Events;
|
||||
|
||||
use GatewayWorker\BusinessWorker;
|
||||
use GatewayWorker\Lib\Gateway;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Workerman\Lib\Timer;
|
||||
|
||||
class WorkermanEvent {
|
||||
|
||||
/**
|
||||
* @title worker 启动时触发
|
||||
*
|
||||
* @param BusinessWorker $businessWorker
|
||||
* @return void
|
||||
*/
|
||||
public static function onWorkerStart(BusinessWorker $businessWorker) {
|
||||
|
||||
self::log(__FUNCTION__, $businessWorker->workerId);
|
||||
// 向所有客户端连接发送数据
|
||||
// Gateway::sendToAll("worker started");
|
||||
// 定时向所有客户端连接发送数据
|
||||
Timer::add(1, function() use ($businessWorker) {
|
||||
$time_now = time();
|
||||
foreach ($businessWorker->connections as $connection) {
|
||||
if (empty($connection->lastMessageTime)){
|
||||
$connection->lastMessageTime = $time_now;
|
||||
continue;
|
||||
}
|
||||
if ($time_now - $connection->lastMessageTime > 10) {
|
||||
$connection->lastMessageTime = $time_now;
|
||||
Gateway::sendToClient($connection->id, 'pong');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 当客户端连接时触发
|
||||
*
|
||||
* @param int $client_id 连接id
|
||||
* @return void
|
||||
*/
|
||||
public static function onConnect($client_id) {
|
||||
self::log(__FUNCTION__, $client_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 客户端连接时触发
|
||||
*
|
||||
* @param int $client_id 连接id
|
||||
* @param mixed $message 具体消息
|
||||
* @return void
|
||||
*/
|
||||
public static function onWebSocketConnect($client_id, $data) {
|
||||
self::log(__FUNCTION__, $client_id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 当客户端发来消息时触发
|
||||
*
|
||||
* @param int $client_id 连接id
|
||||
* @param mixed $message 具体消息
|
||||
* @return void
|
||||
*/
|
||||
public static function onMessage(string $client_id, string $message) {
|
||||
self::log(__FUNCTION__, $client_id, $message);
|
||||
|
||||
if (empty($message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Gateway::sendToAll($message);
|
||||
if ($message == 'ping') {
|
||||
Gateway::sendToClient($client_id, 'pong');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 当用户断开连接时触发
|
||||
*
|
||||
* @param int $client_id 连接id
|
||||
* @return void
|
||||
*/
|
||||
public static function onClose(string $client_id) {
|
||||
self::log(__FUNCTION__, $client_id);
|
||||
Gateway::destoryClient($client_id);
|
||||
}
|
||||
|
||||
protected static function log(string $title, ...$data): void{
|
||||
if (config('app.debug')) {
|
||||
Log::info("{$title} | " . json_encode($data, 256));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\Auth\DepartmentService;
|
||||
|
||||
class Department extends BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* @title 部门列表
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request, DepartmentService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加部门
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Department $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, DepartmentService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改部门
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DepartmentService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, DepartmentService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除部门
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DepartmentService $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request, DepartmentService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\Auth;
|
||||
|
||||
use App\Http\Controllers\BaseController;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
|
||||
class Index extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 用户登录
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function login() {
|
||||
$credentials = request(['username', 'password']);
|
||||
|
||||
$token = auth('admin')->attempt($credentials);
|
||||
|
||||
if (!$token) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = '登录失败!';
|
||||
}else{
|
||||
$this->data['code'] = 1;
|
||||
$this->data['message'] = '登录成功!';
|
||||
$this->data['data'] = [
|
||||
'access_token' => $token,
|
||||
'token_type' => 'bearer',
|
||||
'expires_in' => auth('admin')->factory()->getTTL() * 60
|
||||
];
|
||||
event(new Login('admin', auth('admin')->user(), false));
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取用户信息
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function user() {
|
||||
try {
|
||||
$user = auth('admin')->userOrFail();
|
||||
$user->roles = $user->roles()->get();
|
||||
$this->data['data'] = $user;
|
||||
} catch (\Tymon\JWTAuth\Exceptions\UserNotDefinedException $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 退出
|
||||
* @desc 退出
|
||||
* @method POST
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function logout() {
|
||||
auth('admin')->logout();
|
||||
$this->data['message'] = '退出成功';
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 刷新token
|
||||
* @desc 刷新token
|
||||
* @method POST
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function refresh() {
|
||||
$this->data['data'] = auth('admin')->refresh();
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\Auth\MenuService;
|
||||
|
||||
class Menu extends BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* @title 权限节点列表
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request, MenuService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取我的权限节点
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function my(Request $request, MenuService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getMyMenuList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加权限节点
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Department $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, MenuService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改权限节点
|
||||
*
|
||||
* @param Request $request
|
||||
* @param MenuService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, MenuService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除权限节点
|
||||
*
|
||||
* @param Request $request
|
||||
* @param MenuService $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request, MenuService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\Auth\RoleService;
|
||||
|
||||
class Role extends BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* @title 角色列表
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request, RoleService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加角色
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Department $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, RoleService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改角色
|
||||
*
|
||||
* @param Request $request
|
||||
* @param RoleService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, RoleService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除角色
|
||||
*
|
||||
* @param Request $request
|
||||
* @param RoleService $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request, RoleService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 角色权限
|
||||
*
|
||||
* @param Request $request
|
||||
* @param RoleService $service
|
||||
* @return void
|
||||
*/
|
||||
public function auth(Request $request, RoleService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->auth($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\Auth\UsersService;
|
||||
|
||||
class Users extends BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* @title 用户列表
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request, UsersService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加用户
|
||||
*
|
||||
* @param Request $request
|
||||
* @param UsersService $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, UsersService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改用户
|
||||
*
|
||||
* @param Request $request
|
||||
* @param UsersService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, UsersService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除用户
|
||||
*
|
||||
* @param Request $request
|
||||
* @param UsersService $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request, UsersService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改密码
|
||||
*
|
||||
* @param Request $request
|
||||
* @param UsersService $service
|
||||
* @return void
|
||||
*/
|
||||
public function passwd(Request $request, UsersService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->upPassword($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 角色分配
|
||||
*
|
||||
* @param Request $request
|
||||
* @param UsersService $service
|
||||
* @return void
|
||||
*/
|
||||
public function uprole(Request $request, UsersService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->uprole($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\System\AreaService;
|
||||
|
||||
class Area extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 地区列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AreaService $service
|
||||
* @return void
|
||||
*/
|
||||
public function index(Request $request, AreaService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getAreaList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加地区
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AreaService $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, AreaService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 编辑地区
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AreaService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, AreaService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Traits\AdminController;
|
||||
use App\Services\System\ClientService;
|
||||
|
||||
class Client extends BaseController {
|
||||
|
||||
use AdminController;
|
||||
protected $service = null;
|
||||
|
||||
public function __construct(ClientService $service) {
|
||||
$this->service = $service;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Traits\AdminController;
|
||||
use App\Services\System\CrontabService;
|
||||
|
||||
class Crontab extends BaseController {
|
||||
|
||||
use AdminController;
|
||||
protected $service = null;
|
||||
|
||||
public function __construct(CrontabService $service) {
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function reload(Request $request){
|
||||
try {
|
||||
$this->data['data'] = $this->service->reload($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\System\DictService;
|
||||
|
||||
class Dict extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 字典列表
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function all(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDictionaryAll($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 字典列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DictService $service
|
||||
* @return void
|
||||
*/
|
||||
public function lists(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 字段分类
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DictService $service
|
||||
* @return void
|
||||
*/
|
||||
public function category(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getCategoryList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加字典
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DictService $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改字典
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DictService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除字典
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DictService $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加字典分类
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DictService $service
|
||||
* @return void
|
||||
*/
|
||||
public function addcate(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->createCategory($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改字典分类
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DictService $service
|
||||
* @return void
|
||||
*/
|
||||
public function editcate(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->updateCategory($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除字典分类
|
||||
*
|
||||
* @param Request $request
|
||||
* @param DictService $service
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCate(Request $request, DictService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->deleteCategory($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Http\Controllers\BaseController;
|
||||
|
||||
class File extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 上传文件
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function upload(Request $request){
|
||||
$type = $request->input('type', 'images');
|
||||
|
||||
try {
|
||||
switch ($type) {
|
||||
case 'avatar':
|
||||
$this->data['data'] = $this->avatar($request);
|
||||
break;
|
||||
case 'images':
|
||||
$this->data['data'] = $this->images($request);
|
||||
break;
|
||||
case 'files':
|
||||
$this->data['data'] = $this->files($request);
|
||||
break;
|
||||
default:
|
||||
$this->data['data'] = $this->images($request);
|
||||
break;
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $th->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 文件列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function lists(Request $request){
|
||||
$path = $request->input('groupId', 'images');
|
||||
|
||||
$files = Storage::allFiles($path);
|
||||
|
||||
$data = [];
|
||||
foreach ($files as $key => $value) {
|
||||
$data[] = [
|
||||
'path' => $value,
|
||||
'url' => Storage::disk()->url($path),
|
||||
'name'=> explode('/', $value)[2],
|
||||
];
|
||||
}
|
||||
$this->data['data'] = ['data' => $data];
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @title 列表菜单
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function menu(Request $request){
|
||||
$file = [
|
||||
['id'=> 'images','title'=>'图片', 'children' => []],
|
||||
['id'=> 'files','title'=>'文件', 'children' => []],
|
||||
['id'=> 'videos','title'=>'视频', 'children' => []],
|
||||
['id'=> 'audios','title'=>'音频', 'children' => []],
|
||||
];
|
||||
|
||||
foreach ($file as $key => $value) {
|
||||
$paths = Storage::disk()->allDirectories($value['id']);
|
||||
foreach ($paths as $key => $value) {
|
||||
$file[$key]['children'][] = ['id'=> $value, 'title'=>explode('/', $value)[1]];
|
||||
}
|
||||
}
|
||||
|
||||
$this->data['data'] = $file;
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除文件
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request){
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 上传头像
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
protected function avatar(Request $request){
|
||||
$file = $request->file('file');
|
||||
|
||||
if ($file->isValid()) {
|
||||
$ext = $file->extension();
|
||||
$name = $file->hashName();
|
||||
|
||||
$path = $file->store('avatar/'.date('Ymd'));
|
||||
|
||||
$data = [
|
||||
'path' => $path,
|
||||
'url' => Storage::disk()->url($path),
|
||||
'src' => Storage::disk()->url($path),
|
||||
'name'=> $name,
|
||||
'size'=> $file->getSize(),
|
||||
'ext' => $ext,
|
||||
];
|
||||
return $data;
|
||||
}else{
|
||||
throw new \Exception('上传失败');
|
||||
}
|
||||
}
|
||||
|
||||
protected function images(Request $request){
|
||||
$file = $request->file('file');
|
||||
|
||||
if ($file->isValid()) {
|
||||
$ext = $file->extension();
|
||||
$name = $file->hashName();
|
||||
|
||||
$path = $file->store('images/'.date('Ymd'));
|
||||
|
||||
$data = [
|
||||
'path' => $path,
|
||||
'url' => Storage::disk()->url($path),
|
||||
'src' => Storage::disk()->url($path),
|
||||
'name'=> $name,
|
||||
'size'=> $file->getSize(),
|
||||
'ext' => $ext,
|
||||
];
|
||||
return $data;
|
||||
}else{
|
||||
throw new \Exception('上传失败');
|
||||
}
|
||||
}
|
||||
|
||||
protected function files(Request $request){
|
||||
$file = $request->file('file');
|
||||
|
||||
if ($file->isValid()) {
|
||||
$ext = $file->extension();
|
||||
$name = $file->hashName();
|
||||
|
||||
$path = $file->store('files/'.date('Ymd'));
|
||||
|
||||
$data = [
|
||||
'path' => $path,
|
||||
'url' => Storage::disk()->url($path),
|
||||
'src' => Storage::disk()->url($path),
|
||||
'name'=> $name,
|
||||
'size'=> $file->getSize(),
|
||||
'ext' => $ext,
|
||||
];
|
||||
return $data;
|
||||
}else{
|
||||
throw new \Exception('上传失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
|
||||
class Index extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 系统信息
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function version(Request $request){
|
||||
$system_info_mysql = \Illuminate\Support\Facades\DB::select("select version() as v;");
|
||||
|
||||
$this->data['data'] = [
|
||||
['label' => '系统核心版本', 'values' => env('VERSION', '0.0.1')],
|
||||
['label' => '服务器操作系统', 'values' => PHP_OS],
|
||||
['label' => '运行环境', 'values' => $_SERVER['SERVER_SOFTWARE']],
|
||||
['label' => 'MYSQL版本', 'values' => $system_info_mysql[0]->v],
|
||||
['label' => '上传限制', 'values' => '10']
|
||||
];
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 系统信息
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function info(Request $request){
|
||||
$this->data['data'] = [
|
||||
['label' => '系统名称', 'values' => env('APP_NAME', 'LarAdmin')],
|
||||
['label' => '后端框架', 'values' => 'PHP8 + Laravel ' . \Illuminate\Foundation\Application::VERSION],
|
||||
['label' => '前端框架', 'values' => 'VITE + VUE3 + Element Plus'],
|
||||
['label' => '系统后台UI', 'values' => 'SentUI 1.0.0'],
|
||||
['label' => 'Development', 'values' => 'molong']
|
||||
];
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 清理缓存
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearcache(Request $request){
|
||||
$this->data['data'] = cache()->flush();
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\System\LogService;
|
||||
|
||||
class Log extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 日志列表
|
||||
* @param Request $request
|
||||
* @param LogService $service
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request, LogService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 我的日志列表
|
||||
* @param Request $request
|
||||
* @param LogService $service
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function my(Request $request, LogService $service){
|
||||
try {
|
||||
$request->merge(['is_my' => 1]);
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除日志
|
||||
* @param Request $request
|
||||
* @param LogService $service
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function delete(Request $request, LogService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Traits\AdminController;
|
||||
use App\Services\System\ClientMenuService;
|
||||
|
||||
class Menu extends BaseController {
|
||||
|
||||
use AdminController;
|
||||
protected $service = null;
|
||||
|
||||
public function __construct(ClientMenuService $service) {
|
||||
$this->service = $service;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2025 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Traits\AdminController;
|
||||
use App\Services\System\ModulesService;
|
||||
|
||||
class Modules extends BaseController {
|
||||
|
||||
use AdminController;
|
||||
protected $service = null;
|
||||
|
||||
public function __construct(ModulesService $service) {
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function update(Request $request){
|
||||
try {
|
||||
$this->data['data'] = $this->service->update($request);
|
||||
} catch (\Throwable $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\System\SettingService;
|
||||
|
||||
class Setting extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 获取配置列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @param SettingService $service
|
||||
* @return void
|
||||
*/
|
||||
public function index(Request $request, SettingService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 创建配置
|
||||
*
|
||||
* @param Request $request
|
||||
* @param SettingService $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, SettingService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
public function edit(Request $request, SettingService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 更新配置
|
||||
*
|
||||
* @param Request $request
|
||||
* @param SettingService $service
|
||||
* @return void
|
||||
*/
|
||||
public function save(Request $request, SettingService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->saveSetting($request);
|
||||
$this->data['message'] = "保存成功!";
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取配置字段
|
||||
*
|
||||
* @param Request $request
|
||||
* @param SettingService $service
|
||||
* @return void
|
||||
*/
|
||||
public function fields(Request $request, SettingService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getFields($request);
|
||||
} catch (\Throwable $th) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $th->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Admin\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\System\TasksService;
|
||||
|
||||
class Tasks extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 任务列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TasksService $service
|
||||
* @return void
|
||||
*/
|
||||
public function index(Request $request, TasksService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加任务
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TasksService $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, TasksService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 编辑任务
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TasksService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, TasksService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除任务
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TasksService $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request, TasksService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Api\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\System\AreaService;
|
||||
|
||||
class Area extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 获取地区数据
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function index(Request $request, AreaService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers\Api\System;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\System\QrcodeService;
|
||||
|
||||
class Index extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 生成二维码
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function qrcode(Request $request, QrcodeService $service){
|
||||
try {
|
||||
$this->data['data'] = $service->getQrcode($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
|
||||
class BaseController {
|
||||
|
||||
protected $data = ['code' => 1, 'message' => 'success', 'data' => []];
|
||||
|
||||
public function __construct(Request $request){
|
||||
if ($request->filled('page')) {
|
||||
$offset = ($request->input('page', 1) - 1) * $request->input('limit', 30);
|
||||
$request->mergeIfMissing(['offset' => $offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use App\Services\System\LogService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class AuthCheckMiddleware {
|
||||
|
||||
public function handle(Request $request, Closure $next, string $guard = 'admin'): Response {
|
||||
$response = $next($request);
|
||||
if (auth($guard)->check()) {
|
||||
if($guard == 'admin'){
|
||||
app(LogService::class)->createLog($request);
|
||||
}
|
||||
return $response;
|
||||
}else{
|
||||
return response()->json(['code' => 2000, 'message' => '未登录,请重新登录!']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Listeners;
|
||||
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use App\Models\Auth\Admin;
|
||||
|
||||
class AdminLogin {
|
||||
|
||||
/**
|
||||
* Create the event listener.
|
||||
*/
|
||||
public function __construct() {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*/
|
||||
public function handle(Login $event): void {
|
||||
$admin = $event->user;
|
||||
|
||||
$admin->last_login_ip = request()->ip();
|
||||
$admin->last_login_at = date('Y-m-d H:i:s');
|
||||
$admin->save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\Auth;
|
||||
|
||||
use Tymon\JWTAuth\Contracts\JWTSubject;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use App\Traits\ModelTrait;
|
||||
|
||||
class Admin extends Authenticatable implements JWTSubject {
|
||||
use Notifiable, ModelTrait;
|
||||
|
||||
protected $table = 'auth_admins';
|
||||
protected $primaryKey = 'uid';
|
||||
protected $fillable = ['username', 'nickname', 'email', 'mobile', 'password', 'department_id', 'status', 'last_login_at', 'last_login_ip'];
|
||||
protected $hidden = ['password', 'deleted_at'];
|
||||
protected $with = ['department', 'roles'];
|
||||
|
||||
// Rest omitted for brevity
|
||||
|
||||
/**
|
||||
* Get the identifier that will be stored in the subject claim of the JWT.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getJWTIdentifier() {
|
||||
return $this->getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a key value array, containing any custom claims to be added to the JWT.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJWTCustomClaims() {
|
||||
return [];
|
||||
}
|
||||
|
||||
public function password() : Attribute {
|
||||
return new Attribute(
|
||||
set: fn ($value) => Hash::make($value),
|
||||
);
|
||||
}
|
||||
|
||||
public function department(){
|
||||
return $this->belongsTo(Department::class, 'department_id', 'id');
|
||||
}
|
||||
|
||||
public function roles(){
|
||||
return $this->belongsToMany(Role::class, 'auth_admins_roles', 'uid', 'role_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\Auth;
|
||||
|
||||
class Department extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'auth_departments';
|
||||
protected $fillable = ['title', 'name', 'parent_id', 'status', 'sort'];
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
protected function casts(): array {
|
||||
return [
|
||||
'parent_id' => 'integer',
|
||||
'sort' => 'integer',
|
||||
];
|
||||
}
|
||||
|
||||
public function members(){
|
||||
return $this->hasMany(Admin::class, 'department_id', 'uid');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\Auth;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
class Permission extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'auth_permissions';
|
||||
protected $fillable = ['title', 'name', 'parent_id', 'hiddenBreadcrumb', 'hidden', 'affix', 'color', 'fullpage', 'icon', 'status', 'sort'];
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
public function meta() : Attribute {
|
||||
return Attribute::make(
|
||||
get: fn (mixed $value, array $data) => [
|
||||
'id' => $data['id'],
|
||||
'parent_id' => $data['parent_id'],
|
||||
'title' => $data['title'],
|
||||
'hiddenBreadcrumb' => $data['hiddenBreadcrumb'],
|
||||
'hidden' => $data['hidden'],
|
||||
'affix' => $data['affix'],
|
||||
'color' => $data['color'],
|
||||
'fullpage' => $data['fullpage'],
|
||||
'icon' => isset($data['icon']) && $data['icon'] ? $data['icon'] : 'el-icon-document',
|
||||
// 'icon' => isset($data['icon']) && $data['icon'] ? $data['icon'] : 'AIconFileTextOutlined',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function roles(){
|
||||
return $this->belongsToMany(Role::class, 'auth_roles_permissions', 'permission_id', 'role_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\Auth;
|
||||
|
||||
class Role extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'auth_roles';
|
||||
protected $fillable = ['title', 'name', 'data_range', 'sort', 'status', 'description'];
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
public function admins(){
|
||||
return $this->belongsToMany(Admin::class, 'auth_admins_roles', 'role_id', 'uid');
|
||||
}
|
||||
public function permissions(){
|
||||
return $this->belongsToMany(Permission::class, 'auth_roles_permissions', 'role_id', 'permission_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class BaseModel extends Model {
|
||||
|
||||
protected $dateFormat = 'Y-m-d H:i:s';
|
||||
|
||||
protected function casts(): array {
|
||||
return [
|
||||
'created_at' => 'datetime:Y-m-d H:i:s',
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s',
|
||||
'deleted_at' => 'datetime:Y-m-d H:i:s',
|
||||
];
|
||||
}
|
||||
|
||||
protected function serializeDate($data){
|
||||
return $data->timezone('Asia/Shanghai')->format('Y-m-d H:i:s');
|
||||
}
|
||||
/**
|
||||
* 过滤移除非当前表的字段参数
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function setFilterFields(array $params) : array {
|
||||
$fields = Schema::getColumnListing($this->getTable());
|
||||
foreach ($params as $key => $param) {
|
||||
if ( !in_array($key, $fields) ) unset($params[$key]);
|
||||
}
|
||||
// 同时过滤时间戳字段【时间戳只允许自动更改,不允许手动设置】
|
||||
if ( $this->timestamps === true && isset($params[self::CREATED_AT]) ) unset($params[self::CREATED_AT]);
|
||||
if ( $this->timestamps === true && isset($params[self::UPDATED_AT]) ) unset($params[self::UPDATED_AT]);
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
class Area extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_areas';
|
||||
protected $fillable = ['title', 'parent_id', 'status'];
|
||||
protected $hidden = ['deleted_at'];
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
class Client extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_client';
|
||||
protected $fillable = ['title', 'app_id', 'secret', 'redirect', 'status'];
|
||||
|
||||
protected function casts(): array {
|
||||
return [
|
||||
'status' => 'integer',
|
||||
];
|
||||
}
|
||||
|
||||
public function appId() : Attribute {
|
||||
return Attribute::make(
|
||||
set: function (mixed $value, array $data){
|
||||
return uniqid();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function secret() : Attribute {
|
||||
return Attribute::make(
|
||||
set: function (mixed $value, array $data){
|
||||
return md5(uniqid());
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
class ClientMenu extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_client_menu';
|
||||
protected $with = ['client'];
|
||||
|
||||
protected function casts(): array {
|
||||
return [
|
||||
'status' => 'integer',
|
||||
'sort' => 'integer',
|
||||
];
|
||||
}
|
||||
public function client(){
|
||||
return $this->belongsTo(Client::class, 'client_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
class Config extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_configs';
|
||||
protected $fillable = ['values', 'name', 'title', 'group', 'remark', 'type', 'status', 'sort'];
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
protected function casts(): array {
|
||||
return [
|
||||
'option' => 'json',
|
||||
];
|
||||
}
|
||||
|
||||
public function options(): Attribute {
|
||||
return Attribute::make(
|
||||
get: fn (mixed $value, array $data) => [
|
||||
'placeholder' => $data['title'],
|
||||
'options' => $data['option'] ? json_decode($data['option'], true) : [],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function label() : Attribute {
|
||||
return Attribute::make(
|
||||
get: fn (mixed $value, array $data) => $data['title'],
|
||||
);
|
||||
}
|
||||
|
||||
public function prop() : Attribute {
|
||||
return Attribute::make(
|
||||
get: fn (mixed $value, array $data) => $data['title'],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
class Crontab extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_crontabs';
|
||||
protected $fillable = [];
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
protected function casts(): array {
|
||||
return [
|
||||
'status' => 'integer',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
class Dict extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_dicts';
|
||||
protected $fillable = ['title', 'values', 'group_id', 'group_name', 'sort', 'status'];
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
public function group(){
|
||||
return $this->belongsTo(DictGroup::class, 'group_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
class DictGroup extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_dict_groups';
|
||||
protected $fillable = ['title', 'name', 'parent_id', 'sort', 'status'];
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
protected function casts(): array {
|
||||
return [
|
||||
'parent_id' => 'integer',
|
||||
'status' => 'integer',
|
||||
'sort' => 'integer',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
use App\Models\Auth\Admin;
|
||||
|
||||
class Log extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_logs';
|
||||
protected $fillable = ['title', 'name', 'url', 'method', 'client_ip', 'browser', 'user_id', 'data', 'remark', 'status'];
|
||||
protected $hidden = ['deleted_at'];
|
||||
|
||||
public function user() {
|
||||
return $this->belongsTo(Admin::class, 'user_id', 'uid');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
class Modules extends \App\Models\BaseModel {
|
||||
//
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Models\System;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Models\Auth\Admin;
|
||||
|
||||
class Tasks extends \App\Models\BaseModel {
|
||||
|
||||
protected $table = 'system_tasks';
|
||||
protected $fillable = [];
|
||||
protected $hidden = ['deleted_at'];
|
||||
protected $append = ['url'];
|
||||
|
||||
public function url(): Attribute{
|
||||
return Attribute::make(
|
||||
get: fn (mixed $value, array $data) => Storage::disk('public')->url($data['file']),
|
||||
);
|
||||
}
|
||||
|
||||
public function user() {
|
||||
return $this->belongsTo(Admin::class, 'user_id', 'uid');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
|
||||
$loader->alias('Debugbar', \Barryvdh\Debugbar\Facades\Debugbar::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\Department;
|
||||
use App\Support\Tree;
|
||||
|
||||
class DepartmentService {
|
||||
|
||||
/**
|
||||
* @title 获取部门列表
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request) {
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
|
||||
}
|
||||
if ($request->filled('pid')) {
|
||||
$map[] = ['parent_id', '=', $request->input('pid')];
|
||||
}
|
||||
|
||||
$query = Department::where($map)->orderBy('id', 'desc');
|
||||
|
||||
if($request->filled('is_tree') && $request->filled('is_tree') == 1){
|
||||
$query = $query->get()->toArray();
|
||||
$tree = new Tree();
|
||||
$data = $tree->list_to_tree($query, 0, 'id', 'parent_id');
|
||||
}else{
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加部门
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function create($request) {
|
||||
$request->validate([
|
||||
'title' => 'required|unique:auth_departments',
|
||||
'name' => 'required|unique:auth_departments',
|
||||
]);
|
||||
$data = $request->all();
|
||||
$data['status'] = 1;
|
||||
|
||||
return Department::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改部门
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function update($request) {
|
||||
try {
|
||||
$department = Department::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("部门不存在!", 1);
|
||||
}
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$department->title = $request->input('title');
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$department->name = $request->input('name');
|
||||
}
|
||||
if ($request->filled('parent_id')) {
|
||||
$department->parent_id = $request->input('parent_id');
|
||||
}
|
||||
if ($request->filled('status')) {
|
||||
$department->status = $request->input('status');
|
||||
}
|
||||
if ($request->filled('sort')) {
|
||||
$department->sort = $request->input('sort');
|
||||
}
|
||||
|
||||
$department->save();
|
||||
return $department;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除部门
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function delete($request) {
|
||||
if($request->filled('id')){
|
||||
try {
|
||||
$department = Department::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("角色不存在!", 1);
|
||||
}
|
||||
$department->delete();
|
||||
}
|
||||
if($request->filled('ids')){
|
||||
try {
|
||||
$ids = $request->input('ids');
|
||||
$department = Department::whereIn('id', $ids)->delete();
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $department;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\Permission;
|
||||
use App\Models\Auth\Admin;
|
||||
use App\Support\Tree;
|
||||
|
||||
class MenuService {
|
||||
|
||||
/**
|
||||
* @title 获取权限节点列表
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request) {
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
|
||||
}
|
||||
if ($request->filled('pid')) {
|
||||
$map[] = ['parent_id', '=', $request->input('pid')];
|
||||
}
|
||||
|
||||
$query = Permission::where($map)->orderBy('sort', 'asc')->orderBy('id', 'desc');
|
||||
|
||||
|
||||
if($request->filled('is_tree') && $request->filled('is_tree') == 1){
|
||||
$query = $query->get()->toArray();
|
||||
$tree = new Tree();
|
||||
$data = $tree->list_to_tree($query, 0, 'id', 'parent_id');
|
||||
}else{
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取我的权限节点
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getMyMenuList($request){
|
||||
$map = [];
|
||||
$data = [];
|
||||
$uid = auth('admin')->user()['uid'];
|
||||
|
||||
$tree = new Tree();
|
||||
if($uid != env('ADMIN_ID', 1)){
|
||||
$map[] = ['uid', '=', $uid];
|
||||
|
||||
$admin = Admin::with(['roles'])->where($map)->first();
|
||||
$permission = [];
|
||||
$menu = [];
|
||||
foreach ($admin->roles as $key => $role) {
|
||||
$menu = array_merge($menu, $role->permissions->append(['meta'])->toArray());
|
||||
$permission = array_merge($permission, $role->permissions->pluck('name')->toArray());
|
||||
}
|
||||
$data = [
|
||||
'menu' => $tree->list_to_tree($menu, 0, 'id', 'parent_id'),
|
||||
'permissions' => $permission
|
||||
];
|
||||
}else{
|
||||
$query = Permission::where($map)->orderBy('sort', 'asc');
|
||||
|
||||
$data = [
|
||||
'menu' => $tree->list_to_tree($query->where('type', '=', 'menu')->get()->append(['meta'])->toArray(), 0, 'id', 'parent_id'),
|
||||
'permissions' => $query->pluck('name')
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加权限节点
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function create($request) {
|
||||
$request->validate([
|
||||
'title' => 'required|unique:auth_permissions',
|
||||
'name' => 'required|unique:auth_permissions',
|
||||
]);
|
||||
$data = $request->all();
|
||||
$data['status'] = 1;
|
||||
|
||||
return Permission::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改权限节点
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function update($request) {
|
||||
try {
|
||||
$permission = Permission::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("权限节点不存在!", 1);
|
||||
}
|
||||
|
||||
$data = $request->all();
|
||||
foreach ($data as $key => $value) {
|
||||
if (in_array($key, ['affix', 'color', 'component', 'fullpage', 'hidden', 'hiddenBreadcrumb', 'icon', 'name', 'parent_id', 'redirect', 'sort', 'title', 'type', 'path', 'status'])) {
|
||||
$permission->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$permission->save();
|
||||
return $permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除权限节点
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function delete($request) {
|
||||
if($request->filled('id')){
|
||||
try {
|
||||
$permission = Permission::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("权限节点不存在!", 1);
|
||||
}
|
||||
|
||||
$permission->roles()->detach();
|
||||
$permission->delete();
|
||||
}
|
||||
if($request->filled('ids')){
|
||||
try {
|
||||
$permission = Permission::whereIn('id', $request->input('ids'));
|
||||
foreach ($permission->get() as $item) {
|
||||
$item->roles()->detach();
|
||||
}
|
||||
$permission->delete();
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 批量导入
|
||||
*
|
||||
* @param [array] $data
|
||||
* @return void
|
||||
*/
|
||||
public function importMenu($data, $parent_id = 0){
|
||||
foreach ($data as $key => $value) {
|
||||
$save = [
|
||||
'title' => $value['title'],
|
||||
'name' => $value['name'],
|
||||
'path' => $value['path'],
|
||||
'component' => $value['component'],
|
||||
'type' => $value['type'],
|
||||
'affix' => isset($value['affix']) ? $value['affix'] : 0,
|
||||
'parent_id' => $parent_id,
|
||||
'status' => 1,
|
||||
'sort' => isset($value['sort']) ? $value['sort'] : $key,
|
||||
'icon' => isset($value['icon']) ? $value['icon'] : '',
|
||||
'hidden' => isset($value['hidden']) ? $value['hidden'] : 0,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
$res = Permission::insertGetId($save);
|
||||
if (isset($value['children']) && !empty($value['children'])) {
|
||||
$this->importMenu($value['children'], $res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\Role;
|
||||
use App\Support\Tree;
|
||||
|
||||
class RoleService {
|
||||
|
||||
/**
|
||||
* @title 获取角色列表
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request) {
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
|
||||
}
|
||||
|
||||
$query = Role::with(['permissions'])->where($map)->orderBy('id', 'desc');
|
||||
|
||||
if($request->filled('is_tree') && $request->filled('is_tree') == 1){
|
||||
$query = $query->get()->toArray();
|
||||
$tree = new Tree();
|
||||
$data = $tree->list_to_tree($query, 0, 'id', 'parent_id');
|
||||
}else{
|
||||
if ($request->filled('page')){
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}else{
|
||||
$data = $query->get();
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加角色
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function create($request) {
|
||||
$request->validate([
|
||||
'title' => 'required|unique:auth_roles',
|
||||
'name' => 'required|alpha_dash:ascii|unique:auth_roles',
|
||||
]);
|
||||
$data = $request->all();
|
||||
$data['status'] = 1;
|
||||
|
||||
return Role::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改角色
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function update($request) {
|
||||
$request->validate([
|
||||
'title' => 'required|unique:auth_roles,title,' . $request->input('id'),
|
||||
'name' => 'required|alpha_dash:ascii|unique:auth_roles,name,' . $request->input('id'),
|
||||
]);
|
||||
try {
|
||||
$role = Role::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("角色不存在!", 1);
|
||||
}
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$role->title = $request->input('title');
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$role->name = $request->input('name');
|
||||
}
|
||||
if ($request->filled('status')) {
|
||||
$role->status = $request->input('status');
|
||||
}
|
||||
if ($request->filled('sort')) {
|
||||
$role->sort = $request->input('sort');
|
||||
}
|
||||
|
||||
$role->save();
|
||||
return $role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除角色
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function delete($request) {
|
||||
if($request->filled('id')){
|
||||
try {
|
||||
$role = Role::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("角色不存在!", 1);
|
||||
}
|
||||
$role->permissions()->detach();
|
||||
$role->admins()->detach();
|
||||
$role->delete();
|
||||
}
|
||||
if($request->filled('ids')){
|
||||
try {
|
||||
$role = Role::whereIn('id', $request->input('ids'));
|
||||
foreach ($role->get() as $item) {
|
||||
$item->permissions()->detach(); //删除关联
|
||||
$item->admins()->detach(); //删除关联
|
||||
}
|
||||
|
||||
$role->delete();
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 角色授权
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function auth($request){
|
||||
try {
|
||||
$role = Role::with(['permissions'])->findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("角色不存在!", 1);
|
||||
}
|
||||
|
||||
|
||||
if($request->filled('data_range')){
|
||||
$role->data_range = $request->input('data_range');
|
||||
}
|
||||
|
||||
$role->permissions()->sync($request->input('permissions'));
|
||||
$role->save();
|
||||
return $role;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\Admin;
|
||||
|
||||
class UsersService {
|
||||
|
||||
/**
|
||||
* @title 获取用户列表
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request) {
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('username')) {
|
||||
$map[] = ['username', 'like', '%' . $request->input('username') . '%'];
|
||||
}
|
||||
if ($request->filled('mobile')) {
|
||||
$map[] = ['mobile', 'like', '%' . $request->input('mobile') . '%'];
|
||||
}
|
||||
if ($request->filled('email')) {
|
||||
$map[] = ['email', 'like', '%' . $request->input('email') . '%'];
|
||||
}
|
||||
if ($request->filled('department_id')) {
|
||||
$map[] = ['department_id', '=', $request->input('department_id')];
|
||||
}
|
||||
|
||||
$query = Admin::where($map)->orderBy('uid', 'desc');
|
||||
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加用户
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function create($request) {
|
||||
$request->validate([
|
||||
'username' => 'required|unique:auth_admins,username',
|
||||
// 'email' => 'required|unique:auth_admins',
|
||||
// 'mobile' => 'required|unique:auth_admins',
|
||||
'password' => 'required|min:8',
|
||||
]);
|
||||
|
||||
$data = $request->all();
|
||||
$data['status'] = 1;
|
||||
$data['last_login_at'] = date('Y-m-d H:i:s');
|
||||
$data['last_login_ip'] = $request->ip();
|
||||
|
||||
$admins = Admin::create($data);
|
||||
$request->whenFilled('roles_id', function ($value) use ($admins) {
|
||||
$admins->roles()->sync($value);
|
||||
});
|
||||
return $admins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改用户
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function update($request) {
|
||||
$request->validate([
|
||||
'username' => 'required|unique:auth_admins,username,' . $request->input('uid').',uid',
|
||||
]);
|
||||
try {
|
||||
$admins = Admin::findOrFail($request->input('uid'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("用户不存在!", 1);
|
||||
}
|
||||
|
||||
if ($request->filled('username')) {
|
||||
$admins->username = $request->input('username');
|
||||
}
|
||||
if ($request->filled('email')) {
|
||||
$admins->email = $request->input('email');
|
||||
}
|
||||
if ($request->filled('mobile')) {
|
||||
$admins->mobile = $request->input('mobile');
|
||||
}
|
||||
if ($request->filled('nickname')) {
|
||||
$admins->nickname = $request->input('nickname');
|
||||
}
|
||||
if ($request->filled('department_id')) {
|
||||
$admins->department_id = $request->input('department_id');
|
||||
}
|
||||
if ($request->filled('avatar')) {
|
||||
$admins->avatar = $request->input('avatar');
|
||||
}
|
||||
if ($request->filled('remark')) {
|
||||
$admins->remark = $request->input('remark');
|
||||
}
|
||||
if ($request->filled('status')) {
|
||||
$admins->status = $request->input('status');
|
||||
}
|
||||
if ($request->filled('password')) {
|
||||
$admins->password = $request->input('password');
|
||||
}
|
||||
$request->whenFilled('roles_id', function ($value) use ($admins) {
|
||||
$admins->roles()->sync($value);
|
||||
});
|
||||
|
||||
$admins->save();
|
||||
return $admins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除用户
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function delete($request) {
|
||||
if($request->filled('id')){
|
||||
if($request->input('id') == env('ADMIN_ID', 1)){
|
||||
throw new \Exception("超级管理员不能删除!", 1);
|
||||
}
|
||||
try {
|
||||
$admins = Admin::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("角色不存在!", 1);
|
||||
}
|
||||
$admins->roles()->detach();
|
||||
$admins->delete();
|
||||
}
|
||||
if($request->filled('ids')){
|
||||
if(in_array(env('ADMIN_ID', 1), $request->input('ids'))){
|
||||
throw new \Exception("超级管理员不能删除!", 1);
|
||||
}
|
||||
try {
|
||||
$admins = Admin::whereIn('uid', $request->input('ids'));
|
||||
foreach ($admins->get() as $item) {
|
||||
$item->roles()->detach(); //删除关联
|
||||
}
|
||||
$admins = $admins->delete();
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage(), 1);
|
||||
}
|
||||
}
|
||||
return $admins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 修改密码
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function upPassword($request) {
|
||||
try {
|
||||
$admins = Admin::findOrFail($request->input('uid'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("用户不存在!", 1);
|
||||
}
|
||||
|
||||
$admins->password = $request->input('password');
|
||||
$admins->save();
|
||||
return $admins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 设置角色
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function uprole($request){
|
||||
try {
|
||||
$admins = Admin::with(['roles'])->findOrFail($request->input('uid'));
|
||||
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $th) {
|
||||
throw new \Exception($th->getMessage(), 1);
|
||||
}
|
||||
|
||||
$admins->roles()->sync($request->input('roles'));
|
||||
return $admins;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Area;
|
||||
use App\Support\Tree;
|
||||
|
||||
class AreaService {
|
||||
|
||||
/**
|
||||
* @title 区域列表
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getAreaList($request){
|
||||
$map = [];
|
||||
if($request->filled('title')){
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if($request->filled('id')){
|
||||
$map[] = ['id', '=', $request->input('id')];
|
||||
}
|
||||
if($request->filled('parent_code')){
|
||||
$map[] = ['parent_code', '=', $request->input('parent_code')];
|
||||
}
|
||||
|
||||
$query = Area::where($map)->orderBy('id', 'asc');
|
||||
|
||||
if($request->filled('page')){
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}else{
|
||||
if($request->filled('is_tree') && $request->filled('is_tree') == 1){
|
||||
$query = $query->get()->toArray();
|
||||
$tree = new Tree();
|
||||
$data = $tree->list_to_tree($query, 0, 'code', 'parent_code');
|
||||
}else{
|
||||
$data = $query->get();
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加区域
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function create($request){
|
||||
$request->validate([
|
||||
'title' => 'required',
|
||||
'code' => 'required|unique:system_areas',
|
||||
], [
|
||||
'code.unique' => '编码已存在',
|
||||
'title.required' => '请输入标题',
|
||||
'code.required' => '请输入编码',
|
||||
]);
|
||||
|
||||
$area = new Area;
|
||||
|
||||
foreach ($area->setFilterFields($request->all()) as $key => $value) {
|
||||
$area->$key = $value;
|
||||
}
|
||||
|
||||
$area->save();
|
||||
return $area;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 编辑区域
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function update($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
'title' => 'required',
|
||||
'code' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
'title.required' => '请输入标题',
|
||||
'code.required' => '请输入编码',
|
||||
]);
|
||||
|
||||
$area = Area::where('id', '=', $request->input('id'))->first();
|
||||
|
||||
foreach ($area->setFilterFields($request->all()) as $key => $value) {
|
||||
$area->$key = $value;
|
||||
}
|
||||
|
||||
$area->save();
|
||||
return $area;
|
||||
}
|
||||
|
||||
public function delete($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
]);
|
||||
|
||||
$area = Area::where('id', '=', $request->input('id'))->first();
|
||||
$area->delete();
|
||||
return $area;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\ClientMenu;
|
||||
use App\Support\Tree;
|
||||
|
||||
class ClientMenuService {
|
||||
|
||||
public function getDataList($request){
|
||||
$map = [];
|
||||
|
||||
if($request->filled('title')){
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
|
||||
$query = ClientMenu::where($map)->orderBy('id', 'asc');
|
||||
|
||||
if($request->filled('page')){
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}else{
|
||||
if($request->filled('is_tree') && $request->filled('is_tree') == 1){
|
||||
$query = $query->get()->toArray();
|
||||
$tree = new Tree();
|
||||
$data = $tree->list_to_tree($query, 0, 'id', 'parent_id');
|
||||
}else{
|
||||
$data = $query->get();
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function create($request){
|
||||
$request->validate([
|
||||
'title' => 'required',
|
||||
]);
|
||||
$menu = new ClientMenu();
|
||||
|
||||
foreach ($menu->setFilterFields($request->all()) as $key => $value) {
|
||||
$menu->$key = $value;
|
||||
}
|
||||
$menu->save();
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
public function update($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
'title' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
'title.required' => '请输入标题',
|
||||
]);
|
||||
|
||||
$menu = ClientMenu::where('id', $request->input('id'))->first();
|
||||
|
||||
foreach ($menu->setFilterFields($request->all()) as $key => $value) {
|
||||
$menu->$key = $value;
|
||||
}
|
||||
|
||||
$menu->save();
|
||||
return $menu;
|
||||
}
|
||||
|
||||
public function delete($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
]);
|
||||
|
||||
$menu = ClientMenu::where('id', $request->input('id'))->first();
|
||||
|
||||
$menu->delete();
|
||||
return $menu;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Client;
|
||||
|
||||
class ClientService {
|
||||
|
||||
public function getDataList($request){
|
||||
$map = [];
|
||||
|
||||
if($request->filled('title')){
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
|
||||
$query = Client::where($map)->orderBy('id', 'asc');
|
||||
|
||||
if($request->filled('page')){
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}else{
|
||||
$data = $query->get();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function create($request){
|
||||
$request->validate([
|
||||
'title' => 'required',
|
||||
]);
|
||||
$client = new Client();
|
||||
|
||||
foreach ($client->setFilterFields($request->all()) as $key => $value) {
|
||||
$client->$key = $value;
|
||||
}
|
||||
|
||||
$client->app_id = '';
|
||||
$client->secret = '';
|
||||
$client->redirect = '';
|
||||
$client->save();
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
public function update($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
'title' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
'title.required' => '请输入标题',
|
||||
]);
|
||||
|
||||
$client = Client::where('id', $request->input('id'))->first();
|
||||
|
||||
$client->title = $request->input('title');
|
||||
$client->status = $request->input('status', 0);
|
||||
|
||||
$client->save();
|
||||
return $client;
|
||||
}
|
||||
|
||||
public function delete($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
]);
|
||||
|
||||
$client = Client::where('id', $request->input('id'))->first();
|
||||
|
||||
$client->delete();
|
||||
return $client;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Crontab;
|
||||
|
||||
class CrontabService {
|
||||
|
||||
public function getDataList($request){
|
||||
$map = [];
|
||||
|
||||
if($request->filled('title')){
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if($request->filled('type')){
|
||||
$map[] = ['type', '=', $request->input('type')];
|
||||
}
|
||||
|
||||
$query = Crontab::where($map)->orderBy('id', 'asc');
|
||||
|
||||
if($request->filled('page')){
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}else{
|
||||
$data = $query->get();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function create($request){
|
||||
$request->validate([
|
||||
'title' => 'required',
|
||||
'type' => 'required',
|
||||
'expression' => 'required',
|
||||
'command' => 'required',
|
||||
], [
|
||||
'title.required' => '请输入标题',
|
||||
'type.required' => '请选择类型',
|
||||
'expression.required' => '请输入表达式',
|
||||
'command.required' => '请输入命令',
|
||||
]);
|
||||
|
||||
$crontab = new Crontab;
|
||||
|
||||
foreach ($crontab->setFilterFields($request->all()) as $key => $value) {
|
||||
$crontab->$key = $value;
|
||||
}
|
||||
|
||||
$crontab->save();
|
||||
|
||||
return $crontab;
|
||||
}
|
||||
|
||||
public function update($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
'title' => 'required',
|
||||
'type' => 'required',
|
||||
'expression' => 'required',
|
||||
'command' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
'title.required' => '请输入标题',
|
||||
'type.required' => '请选择类型',
|
||||
'expression.required' => '请输入表达式',
|
||||
'command.required' => '请输入命令',
|
||||
]);
|
||||
|
||||
$crontab = Crontab::where('id', $request->input('id'))->first();
|
||||
|
||||
foreach ($crontab->setFilterFields($request->all()) as $key => $value) {
|
||||
$crontab->$key = $value;
|
||||
}
|
||||
|
||||
$crontab->save();
|
||||
|
||||
return $crontab;
|
||||
}
|
||||
|
||||
public function delete($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
]);
|
||||
|
||||
$crontab = Crontab::where('id', $request->input('id'))->first();
|
||||
|
||||
$crontab->delete();
|
||||
return $crontab;
|
||||
}
|
||||
|
||||
public function reload($request){
|
||||
$request->validate([
|
||||
'id' => 'required',
|
||||
'status' => 'required',
|
||||
], [
|
||||
'id.required' => '参数错误',
|
||||
'status.required' => '参数错误',
|
||||
]);
|
||||
|
||||
$crontab = Crontab::where('id', $request->input('id'))->first();
|
||||
|
||||
$crontab->status = $request->input('status');
|
||||
|
||||
$crontab->save();
|
||||
return $crontab;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Dict;
|
||||
use App\Models\System\DictGroup;
|
||||
use App\Support\Tree;
|
||||
|
||||
class DictService {
|
||||
|
||||
/**
|
||||
* @title 获取列表数据
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request) {
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$map[] = ['group_name', '=', $request->input('name')];
|
||||
}
|
||||
if ($request->filled('group_id')) {
|
||||
$map[] = ['group_id', '=', $request->input('group_id')];
|
||||
}
|
||||
|
||||
$query = Dict::where($map)->orderBy('sort', 'asc')->orderBy('id', 'desc');
|
||||
|
||||
if($request->filled('page')){
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}else{
|
||||
$data = $query->get();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 字段分类数据
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getCategoryList($request){
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
|
||||
}
|
||||
|
||||
$query = DictGroup::where($map)->orderBy('id', 'desc');
|
||||
|
||||
|
||||
if($request->filled('is_tree') && $request->filled('is_tree') == 1){
|
||||
$query = $query->get()->toArray();
|
||||
$tree = new Tree();
|
||||
$data = $tree->list_to_tree($query, 0, 'id', 'parent_id');
|
||||
}else{
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->limit($request->input('limit', 10))->offset($request->input('page', 1) - 1)->get(),
|
||||
];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 创建字典
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function create($request){
|
||||
$request->validate([
|
||||
'title' => 'required',
|
||||
'values' => 'required',
|
||||
]);
|
||||
|
||||
$data = $request->all();
|
||||
|
||||
$data['group_name'] = DictGroup::where('id', '=', $data['group_id'])->value('name');
|
||||
|
||||
$dict = Dict::create($data);
|
||||
|
||||
if($dict->values == ''){
|
||||
$dict->values = $dict->id;
|
||||
$dict->save();
|
||||
}
|
||||
$this->setDictCache(true);
|
||||
return $dict;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 更新字典
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function update($request){
|
||||
try {
|
||||
$dict = Dict::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("改字典不存在", 1);
|
||||
}
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$dict->title = $request->input('title');
|
||||
}
|
||||
if ($request->filled('values')) {
|
||||
$dict->values = $request->input('values');
|
||||
}
|
||||
if ($request->filled('sort')) {
|
||||
$dict->sort = $request->input('sort');
|
||||
}
|
||||
if ($request->filled('status')) {
|
||||
$dict->status = $request->input('status');
|
||||
}
|
||||
if ($request->filled('group_id')) {
|
||||
$dict->group_id = $request->input('group_id');
|
||||
$dict->group_name = DictGroup::where('id', '=', $request->input('group_id'))->value('name');
|
||||
}
|
||||
|
||||
$dict->save();
|
||||
$this->setDictCache(true);
|
||||
return $dict;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除字典
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function delete($request){
|
||||
try {
|
||||
$dict = Dict::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("改字典不存在", 1);
|
||||
}
|
||||
|
||||
$dict->delete();
|
||||
$this->setDictCache(true);
|
||||
return $dict;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 创建字典分类
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function createCategory($request){
|
||||
$request->validate([
|
||||
'title' => 'required|unique:system_dict_groups',
|
||||
'name' => 'required|unique:system_dict_groups',
|
||||
]);
|
||||
|
||||
$data = $request->all();
|
||||
$data['status'] = 1;
|
||||
$group = DictGroup::create($data);
|
||||
|
||||
$this->setDictCache(true);
|
||||
return $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 更新字典分类
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function updateCategory($request){
|
||||
try {
|
||||
$dict = DictGroup::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("改字典不存在", 1);
|
||||
}
|
||||
|
||||
if ($request->filled('parent_id')) {
|
||||
$dict->parent_id = $request->input('parent_id');
|
||||
}
|
||||
if ($request->filled('title')) {
|
||||
$dict->title = $request->input('title');
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$dict->name = $request->input('name');
|
||||
}
|
||||
if ($request->filled('sort')) {
|
||||
$dict->sort = $request->input('sort');
|
||||
}
|
||||
if ($request->filled('status')) {
|
||||
$dict->status = $request->input('status');
|
||||
}
|
||||
|
||||
$dict->save();
|
||||
$this->setDictCache(true);
|
||||
return $dict;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除字典
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCategory($request){
|
||||
try {
|
||||
$dict = DictGroup::findOrFail($request->input('id'));
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("改字典不存在", 1);
|
||||
}
|
||||
|
||||
$dict->delete();
|
||||
$this->setDictCache(true);
|
||||
return $dict;
|
||||
}
|
||||
|
||||
public function getDictionaryAll(){
|
||||
$map = [];
|
||||
|
||||
$map[] = ['status', '=', 1];
|
||||
|
||||
$list = Dict::where($map)->get();
|
||||
|
||||
$data = [];
|
||||
foreach ($list as $key => $value) {
|
||||
$data[$value['group_name']][] = $value;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function setDictCache($refresh = false){
|
||||
if (!cache('dict') || $refresh){
|
||||
$data = $this->getDictionaryAll();
|
||||
cache('dict', $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Log;
|
||||
|
||||
class LogService {
|
||||
|
||||
/**
|
||||
* @title 获取日志列表
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request) {
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
|
||||
}
|
||||
if ($request->filled('url')) {
|
||||
$map[] = ['url', 'like', '%' . $request->input('url') . '%'];
|
||||
}
|
||||
if ($request->filled('method')) {
|
||||
$map[] = ['method', 'like', '%' . $request->input('method') . '%'];
|
||||
}
|
||||
if ($request->filled('ip')) {
|
||||
$map[] = ['ip', 'like', '%' . $request->input('ip') . '%'];
|
||||
}
|
||||
if ($request->filled('user_id')) {
|
||||
$map[] = ['user_id', '=', $request->input('user_id')];
|
||||
}
|
||||
if ($request->filled('remark')) {
|
||||
$map[] = ['remark', 'like', '%' . $request->input('remark') . '%'];
|
||||
}
|
||||
if ($request->filled('status')) {
|
||||
$map[] = ['status', '=', $request->input('status')];
|
||||
}
|
||||
if ($request->filled('is_my')) {
|
||||
$user = auth('admin')->user();
|
||||
$map[] = ['user_id', '=', $user->uid];
|
||||
}
|
||||
|
||||
$query = Log::with(['user:nickname,username,uid'])->where($map)->orderBy('id', 'desc');
|
||||
|
||||
if ($request->filled('date')) {
|
||||
$query->whereBetween('created_at', $request->input('date'));
|
||||
}
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function createLog($request){
|
||||
list($class, $method) = explode('@', $request->route()->getActionName());
|
||||
$reflection = new \ReflectionMethod("\\" . $class, $method);
|
||||
$docComment = $reflection->getDocComment();
|
||||
$matches = [];
|
||||
preg_match("/@title(.*)(\\r\\n|\\r|\\n)/U", $docComment, $matches);
|
||||
|
||||
$data = [
|
||||
'user_id' => auth('admin')->user()->uid,
|
||||
'title' => isset($matches[1]) ? trim($matches[1]) : '',
|
||||
'name' => $request->route()->getName() ?? '',
|
||||
'client_ip' => $request->ip(),
|
||||
'url' => $request->path(),
|
||||
'method' => $request->method(),
|
||||
'data' => json_encode($request->all()),
|
||||
'browser' => $request->userAgent(),
|
||||
'remark' => $request->input('remark', ''),
|
||||
'status' => 1,
|
||||
];
|
||||
$log = Log::create($data);
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除日志
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($request){
|
||||
$map = [];
|
||||
if($request->filled('id')){
|
||||
$map[] = ['id', '=', $request->input('id')];
|
||||
}
|
||||
if($request->filled('ids')){
|
||||
$map[] = ['id', 'IN', $request->input('ids')];
|
||||
}
|
||||
|
||||
$query = Log::where($map);
|
||||
|
||||
if($request->filled('date')){
|
||||
$query->whereBetween('created_at', $request->input('date'));
|
||||
}
|
||||
|
||||
$query->delete();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2025 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use Nwidart\Modules\Contracts\ActivatorInterface;
|
||||
use Nwidart\Modules\Module;
|
||||
use Nwidart\Modules\Facades\Module as ModuleFacade;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use App\Models\System\Modules;
|
||||
|
||||
class ModulesService implements ActivatorInterface {
|
||||
|
||||
/**
|
||||
* 模块管理的模型
|
||||
* @var class-string<Model> $modelClass
|
||||
*/
|
||||
private string $modelClass;
|
||||
/**
|
||||
* Laravel Filesystem instance
|
||||
*
|
||||
* @var Filesystem
|
||||
*/
|
||||
private $files;
|
||||
|
||||
public function __construct(Container $app) {
|
||||
$this->modelClass = $app['config']['modules.activators.database.model'];
|
||||
$this->files = $app['files'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a module
|
||||
*/
|
||||
public function enable(Module $module): void {
|
||||
$this->setActiveByName($module->getName(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables a module
|
||||
*/
|
||||
public function disable(Module $module): void {
|
||||
$this->setActiveByName($module->getName(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given status same with a module status.
|
||||
*/
|
||||
public function hasStatus(Module|string $module, bool $status): bool {
|
||||
$name = $module instanceof Module ? $module->getName() : $module;
|
||||
$moduleRecord = $this->modelClass::where('name', $name)->first();
|
||||
if ($moduleRecord) {
|
||||
return boolval($moduleRecord['status']) === $status;
|
||||
} else {
|
||||
return $status === false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set active state for a module.
|
||||
*/
|
||||
public function setActive(Module $module, bool $active): void {
|
||||
$this->setActiveByName($module->getName(), $active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a module status by its name
|
||||
*/
|
||||
public function setActiveByName(string $name, bool $active): void {
|
||||
$module = ModuleFacade::getModulePath($name);
|
||||
$json = $this->readJson($module . 'module.json');
|
||||
$this->modelClass::upsert(['name' => $name, 'status' => $active, 'title' => $json['alias']], ['name'], ['status', 'title']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a module activation status
|
||||
*/
|
||||
public function delete(Module $module): void {
|
||||
$moduleRecord = $this->modelClass::where('name', $module->getName())->first();
|
||||
if ($moduleRecord) {
|
||||
$moduleRecord->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes any module activation statuses created by this class.
|
||||
*/
|
||||
public function reset(): void {
|
||||
$this->modelClass::truncate();
|
||||
}
|
||||
|
||||
|
||||
public function getDataList($request){
|
||||
$map = [];
|
||||
|
||||
if($request->filled('title')){
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
|
||||
$query = Modules::where($map)->orderBy('id', 'asc');
|
||||
|
||||
if($request->filled('page')){
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
|
||||
];
|
||||
}else{
|
||||
$data = $query->get();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function update($request){
|
||||
if($request->filled('name')){
|
||||
$name = $request->input('name');
|
||||
$module = ModuleFacade::getModulePath($name);
|
||||
$json = $this->readJson($module . 'module.json');
|
||||
|
||||
$module = Modules::where('name', $name)->first();
|
||||
|
||||
$module->title = $json['alias'];
|
||||
|
||||
$module->save();
|
||||
return $module;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the json file that contains the activation statuses.
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
private function readJson($file): array {
|
||||
if (! $this->files->exists($file)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->files->json($file);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Config;
|
||||
|
||||
class SettingService {
|
||||
|
||||
/**
|
||||
* @title 获取配置列表
|
||||
*
|
||||
* @param [type] $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request){
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('group_name')) {
|
||||
$map[] = ['group', '=', $request->input('group_name')];
|
||||
}
|
||||
|
||||
$data = Config::where($map)->orderBy('sort', 'asc')->pluck('values', 'name');
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function create($request){
|
||||
$request->validate([
|
||||
'title' => 'required',
|
||||
'name' => 'required',
|
||||
'values' => 'required',
|
||||
]);
|
||||
|
||||
$data = $request->all();
|
||||
$config = Config::create($data);
|
||||
|
||||
$this->setConfigCache(true);
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function update($request){
|
||||
$request->validate([
|
||||
'title' => 'required',
|
||||
'name' => 'required',
|
||||
]);
|
||||
$config = Config::where('id', $request->input('id'))->first();
|
||||
|
||||
|
||||
foreach ($config->setFilterFields($request->all()) as $key => $value) {
|
||||
$config->$key = $value;
|
||||
}
|
||||
$config->save();
|
||||
|
||||
$this->setConfigCache(true);
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function saveSetting($request){
|
||||
$data = $request->all();
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
Config::where('name', $key)->update(['values' => $value]);
|
||||
}
|
||||
|
||||
$this->setConfigCache(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function delete($request){
|
||||
$data = $request->all();
|
||||
$config = Config::find($data['id']);
|
||||
$config->delete();
|
||||
|
||||
$this->setConfigCache(true);
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function getFields($request){
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('group_name')) {
|
||||
$map[] = ['group', '=', $request->input('group_name')];
|
||||
}
|
||||
|
||||
$config = Config::where($map)->orderBy('sort', 'asc')->get()->append(['options', 'label']);
|
||||
return $config;
|
||||
}
|
||||
|
||||
public static function setConfigCache($refresh = false){
|
||||
if (!cache('config') || $refresh){
|
||||
$config = Config::orderBy('sort', 'asc')->pluck('values', 'name');
|
||||
cache('config', $config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Services\System;
|
||||
|
||||
use App\Models\System\Tasks;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class TasksService {
|
||||
|
||||
public function getDataList($request){
|
||||
$map = [];
|
||||
|
||||
if ($request->filled('title')) {
|
||||
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
|
||||
}
|
||||
if ($request->filled('name')) {
|
||||
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
|
||||
}
|
||||
if ($request->filled('url')) {
|
||||
$map[] = ['url', 'like', '%' . $request->input('url') . '%'];
|
||||
}
|
||||
if ($request->filled('method')) {
|
||||
$map[] = ['method', 'like', '%' . $request->input('method') . '%'];
|
||||
}
|
||||
if ($request->filled('ip')) {
|
||||
$map[] = ['ip', 'like', '%' . $request->input('ip') . '%'];
|
||||
}
|
||||
if ($request->filled('user_id')) {
|
||||
$map[] = ['user_id', '=', $request->input('user_id')];
|
||||
}
|
||||
if ($request->filled('data')) {
|
||||
$map[] = ['data', 'like', '%' . $request->input('data') . '%'];
|
||||
}
|
||||
if ($request->filled('remark')) {
|
||||
$map[] = ['remark', 'like', '%' . $request->input('remark') . '%'];
|
||||
}
|
||||
if ($request->filled('status')) {
|
||||
$map[] = ['status', '=', $request->input('status')];
|
||||
}
|
||||
if ($request->filled('is_my')) {
|
||||
$user = auth('admin')->user();
|
||||
$map[] = ['user_id', '=', $user->uid];
|
||||
}
|
||||
|
||||
$query = Tasks::with(['user:nickname,username,uid'])->where($map)->orderBy('id', 'desc');
|
||||
|
||||
if ($request->filled('page')) {
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get()->append(['url']),
|
||||
];
|
||||
}else{
|
||||
$data = $query->get()->append(['url']);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function create($data){
|
||||
$task = new Tasks();
|
||||
|
||||
$task->type = $data['type'] ? $data['type'] : 'export';
|
||||
$task->title = $data['title'] ? $data['title'] : $task->type . '任务';
|
||||
$task->file = $data['file'] ? $data['file'] : '';
|
||||
$task->status = $data['status'] ? $data['status'] : 0;
|
||||
$task->user_id = auth('admin')->user()->uid;
|
||||
|
||||
$task->save();
|
||||
return $task;
|
||||
}
|
||||
|
||||
public function update($data){
|
||||
$task = Tasks::where('id', $data['id'])->first();
|
||||
|
||||
if ($data['status'] != '') {
|
||||
$task->status = $data['status'];
|
||||
}
|
||||
if ($data['file'] != '') {
|
||||
$task->file = $data['file'];
|
||||
}
|
||||
if (in_array($data['type'], ['import', 'export'])) {
|
||||
$task->type = $data['type'];
|
||||
}
|
||||
if ($data['title'] != '') {
|
||||
$task->title = $data['title'];
|
||||
}
|
||||
|
||||
$task->save();
|
||||
}
|
||||
|
||||
public function delete($data){
|
||||
$task = Tasks::where('id', $data['id'])->first();
|
||||
|
||||
if ($task->status == 0) {
|
||||
throw new \Exception("该任务正在执行中,无法删除");
|
||||
}
|
||||
|
||||
if ($task->file) {
|
||||
Storage::disk('public')->delete($task->file);
|
||||
}
|
||||
|
||||
$task->delete();
|
||||
return $task;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Support;
|
||||
|
||||
class Regex {
|
||||
|
||||
|
||||
/**
|
||||
* 验证用户名
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @param int $minLen 最小长度
|
||||
* @param int $maxLen 最大长度
|
||||
* @param string $type 验证类型,默认‘ALL’,EN.验证英文,CN.验证中文,ALL.验证中文和英文
|
||||
* @return bool
|
||||
*/
|
||||
public static function isUsername($value, $minLen = 2, $maxLen = 48, $type = 'ALL')
|
||||
{
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'EN' :
|
||||
$match = '/^[_\w\d]{' . $minLen . ',' . $maxLen . '}$/iu';
|
||||
break;
|
||||
case 'CN' :
|
||||
$match = '/^[_\x{4e00}-\x{9fa5}\d]{' . $minLen . ',' . $maxLen . '}$/iu';
|
||||
break;
|
||||
default :
|
||||
$match = '/^[_\w\d\x{4e00}-\x{9fa5}]{' . $minLen . ',' . $maxLen . '}$/iu';
|
||||
}
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证密码
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @param int $minLen 最小长度
|
||||
* @param int $maxLen 最大长度
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPassword($value, $minLen = 6, $maxLen = 16)
|
||||
{
|
||||
$value = trim($value);
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$match = '/^[\\~!@#$%^&*()-_=+|{}\[\],.?\/:;\'\"\d\w]{' . $minLen . ',' . $maxLen . '}$/';
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证eamil
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return bool
|
||||
*/
|
||||
public static function isEmail($value)
|
||||
{
|
||||
$value = trim($value);
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$match = '/^[\w\d]+[\w\d-.]*@[\w\d-.]+\.[\w\d]{2,10}$/i';
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证电话号码
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTelephone($value)
|
||||
{
|
||||
$value = trim($value);
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$match = '/^0[0-9]{2,3}[-]?\d{7,8}$/';
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证手机
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return bool
|
||||
*/
|
||||
public static function isMobile($value)
|
||||
{
|
||||
$value = trim($value);
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$match = '/^[(86)|0]?(1\d{10})$/';
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证邮政编码
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPostCode($value)
|
||||
{
|
||||
$value = trim($value);
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$match = '/\d{6}/';
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证IP
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isIp($value)
|
||||
{
|
||||
$value = trim($value);
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$match = '/^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])' .
|
||||
'\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)' .
|
||||
'\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)' .
|
||||
'\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$/';
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证身份证号码
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isIDCard($value)
|
||||
{
|
||||
$value = trim($value);
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen($value) > 18) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$match = '/^\d{6}((1[89])|(2\d))\d{2}((0\d)|(1[0-2]))((3[01])|([0-2]\d))\d{3}(\d|X)$/i';
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证URL
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isUrl($value)
|
||||
{
|
||||
$value = strtolower(trim($value));
|
||||
if (empty ($value)) {
|
||||
return false;
|
||||
}
|
||||
$match = '/^(http:\/\/)?(https:\/\/)?([\w\d-]+\.)+[\w-]+(\/[\d\w-.\/?%&=]*)?$/';
|
||||
|
||||
return preg_match($match, $value) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有数字
|
||||
* 说明:如果字符串中含有非法字符返回假,没有返回真
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return int
|
||||
*/
|
||||
public static function hasNumber($value)
|
||||
{
|
||||
return preg_match("/[0-9]/", $value) != false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否含有英文
|
||||
* 说明:如果字符串中含有非法字符返回假,没有返回真
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasEnglish($value)
|
||||
{
|
||||
return preg_match("/[a-zA-Z]/", $value) != false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有中文
|
||||
* 说明:如果字符串中含有非法字符返回假,没有返回真
|
||||
*
|
||||
* @param string $value 验证的值
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasChinese($value)
|
||||
{
|
||||
return preg_match("/[\x7f-\xff]/", $value) != false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Support;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class Time {
|
||||
|
||||
/**
|
||||
* 返回今日开始和结束的时间戳
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function today($data = '') {
|
||||
[$y, $m, $d] = explode('-', $data ? $data : date('Y-m-d'));
|
||||
|
||||
return [
|
||||
mktime(0, 0, 0, $m, $d, $y),
|
||||
mktime(23, 59, 59, $m, $d, $y),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回昨日开始和结束的时间戳
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function yesterday() {
|
||||
$yesterday = date('d') - 1;
|
||||
|
||||
return [
|
||||
mktime(0, 0, 0, date('m'), $yesterday, date('Y')),
|
||||
mktime(23, 59, 59, date('m'), $yesterday, date('Y')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回本周开始和结束的时间戳
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function week() {
|
||||
[$y, $m, $d, $w] = explode('-', date('Y-m-d-w'));
|
||||
if ($w == 0) $w = 7; //修正周日的问题
|
||||
|
||||
return [
|
||||
mktime(0, 0, 0, $m, $d - $w + 1, $y), mktime(23, 59, 59, $m, $d - $w + 7, $y),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回上周开始和结束的时间戳
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function lastWeek() {
|
||||
$timestamp = time();
|
||||
|
||||
return [
|
||||
strtotime(date('Y-m-d', strtotime("last week Monday", $timestamp))),
|
||||
strtotime(date('Y-m-d', strtotime("last week Sunday", $timestamp))) + 24 * 3600 - 1,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回本月开始和结束的时间戳
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function month($data = '') {
|
||||
$res = [];
|
||||
$data = $data ? $data : date('Y-m-d');
|
||||
$nextMoth = date('Y-m-d', strtotime($data . ' +1 month'));
|
||||
|
||||
return [
|
||||
mktime(0, 0, 0, date('m', strtotime($data)), 1, date('Y', strtotime($data))),
|
||||
mktime(0, 0, 0, date('m', strtotime($nextMoth)), 1, date('Y', strtotime($nextMoth))),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回上个月开始和结束的时间戳
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function lastMonth() {
|
||||
$y = date('Y');
|
||||
$m = date('m');
|
||||
$begin = mktime(0, 0, 0, $m - 1, 1, $y);
|
||||
$end = mktime(23, 59, 59, $m - 1, date('t', $begin), $y);
|
||||
|
||||
return [$begin, $end];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回今年开始和结束的时间戳
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function year() {
|
||||
$y = date('Y');
|
||||
|
||||
return [
|
||||
mktime(0, 0, 0, 1, 1, $y),
|
||||
mktime(23, 59, 59, 12, 31, $y),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回去年开始和结束的时间戳
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function lastYear() {
|
||||
$year = date('Y') - 1;
|
||||
|
||||
return [
|
||||
mktime(0, 0, 0, 1, 1, $year),
|
||||
mktime(23, 59, 59, 12, 31, $year),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取几天前零点到现在/昨日结束的时间戳
|
||||
*
|
||||
* @param int $day 天数
|
||||
* @param bool $now 返回现在或者昨天结束时间戳
|
||||
* @return array
|
||||
*/
|
||||
public static function dayToNow($day = 1, $now = true) {
|
||||
$end = time();
|
||||
if (!$now) {
|
||||
[$foo, $end] = self::yesterday();
|
||||
}
|
||||
|
||||
return [
|
||||
mktime(0, 0, 0, date('m'), date('d') - $day, date('Y')),
|
||||
$end,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回几天前的时间戳
|
||||
*
|
||||
* @param int $day
|
||||
* @return int
|
||||
*/
|
||||
public static function daysAgo($day = 1) {
|
||||
$nowTime = time();
|
||||
|
||||
return $nowTime - self::daysToSecond($day);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回几天后的时间戳
|
||||
*
|
||||
* @param int $day
|
||||
* @return int
|
||||
*/
|
||||
public static function daysAfter($day = 1) {
|
||||
$nowTime = time();
|
||||
|
||||
return $nowTime + self::daysToSecond($day);
|
||||
}
|
||||
|
||||
/**
|
||||
* 天数转换成秒数
|
||||
*
|
||||
* @param int $day
|
||||
* @return int
|
||||
*/
|
||||
public static function daysToSecond($day = 1) {
|
||||
return $day * 86400;
|
||||
}
|
||||
|
||||
/**
|
||||
* 周数转换成秒数
|
||||
*
|
||||
* @param int $week
|
||||
* @return int
|
||||
*/
|
||||
public static function weekToSecond($week = 1) {
|
||||
return self::daysToSecond() * 7 * $week;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取毫秒级别的时间戳
|
||||
*/
|
||||
public static function getMillisecond() {
|
||||
$time = explode(" ", microtime());
|
||||
$time = $time[1] . ($time[0] * 1000);
|
||||
$time2 = explode(".", $time);
|
||||
$time = $time2[0];
|
||||
|
||||
return $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相对时间
|
||||
*
|
||||
* @param int $timeStamp
|
||||
* @return string
|
||||
*/
|
||||
public static function formatRelative($timeStamp) {
|
||||
$currentTime = time();
|
||||
|
||||
// 判断传入时间戳是否早于当前时间戳
|
||||
$isEarly = $timeStamp <= $currentTime;
|
||||
|
||||
// 获取两个时间戳差值
|
||||
$diff = abs($currentTime - $timeStamp);
|
||||
|
||||
$dirStr = $isEarly ? '前' : '后';
|
||||
|
||||
if ($diff < 60) { // 一分钟之内
|
||||
$resStr = $diff . '秒' . $dirStr;
|
||||
} elseif ($diff >= 60 && $diff < 3600) { // 多于59秒,少于等于59分钟59秒
|
||||
$resStr = floor($diff / 60) . '分钟' . $dirStr;
|
||||
} elseif ($diff >= 3600 && $diff < 86400) { // 多于59分钟59秒,少于等于23小时59分钟59秒
|
||||
$resStr = floor($diff / 3600) . '小时' . $dirStr;
|
||||
} elseif ($diff >= 86400 && $diff < 2623860) { // 多于23小时59分钟59秒,少于等于29天59分钟59秒
|
||||
$resStr = floor($diff / 86400) . '天' . $dirStr;
|
||||
} elseif ($diff >= 2623860 && $diff <= 31567860 && $isEarly) { // 多于29天59分钟59秒,少于364天23小时59分钟59秒,且传入的时间戳早于当前
|
||||
$resStr = date('m-d H:i', $timeStamp);
|
||||
} else {
|
||||
$resStr = date('Y-m-d', $timeStamp);
|
||||
}
|
||||
|
||||
return $resStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 范围日期转换时间戳
|
||||
*
|
||||
* @param string $rangeDatetime
|
||||
* @param int $maxRange 最大时间间隔
|
||||
* @param string $delimiter
|
||||
* @return array
|
||||
*/
|
||||
public static function parseRange($rangeDatetime, $maxRange = 0, $delimiter = ' - ') {
|
||||
$rangeDatetime = explode($delimiter, $rangeDatetime, 2);
|
||||
$rangeDatetime[0] = strtotime($rangeDatetime[0]);
|
||||
$rangeDatetime[1] = isset($rangeDatetime[1]) ? strtotime($rangeDatetime[1]) : time();
|
||||
$rangeDatetime = [
|
||||
min($rangeDatetime[0], $rangeDatetime[1]),
|
||||
max($rangeDatetime[0], $rangeDatetime[1]),
|
||||
];
|
||||
|
||||
// 如果结束时间小于或等于开始时间 直接返回null
|
||||
// if ($rangeDatetime[1] < $rangeDatetime[0]) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// 如果大于最大时间间隔 则用结束时间减去最大时间间隔获得开始时间
|
||||
if ($maxRange > 0 && $rangeDatetime[1] - $rangeDatetime[0] > $maxRange) {
|
||||
$rangeDatetime[0] = $rangeDatetime[1] - $maxRange;
|
||||
}
|
||||
|
||||
return $rangeDatetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定时间范围内的日期数组
|
||||
* @param int $startTime
|
||||
* @param int $endTime
|
||||
* @return \Carbon\CarbonPeriod
|
||||
*/
|
||||
public static function daysUntilOfTimestamp($startTime, $endTime) {
|
||||
$startTime = Carbon::createFromTimestamp($startTime);
|
||||
$endTime = Carbon::createFromTimestamp($endTime);
|
||||
|
||||
return $startTime->daysUntil($endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间排序
|
||||
*
|
||||
* @param array $times
|
||||
* @return array
|
||||
*/
|
||||
public static function sort($times) {
|
||||
usort($times, function ($com1, $com2) {
|
||||
$com1 = strtotime($com1);
|
||||
$com2 = strtotime($com2);
|
||||
|
||||
return $com1 < $com2 ? -1 : 1;
|
||||
});
|
||||
|
||||
return $times;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Support;
|
||||
|
||||
class Tree {
|
||||
|
||||
public static function list_to_tree($list, $root = 0, $pk = 'id', $pid = 'parent_id', $children = 'children') {
|
||||
// 创建Tree
|
||||
$tree = array();
|
||||
if (is_array($list)) {
|
||||
// 创建基于主键的数组引用
|
||||
$refer = array();
|
||||
foreach ($list as $key => $data) {
|
||||
$refer[$data[$pk]] = &$list[$key];
|
||||
}
|
||||
foreach ($list as $key => $data) {
|
||||
// 判断是否存在parent
|
||||
$parentId = 0;
|
||||
if (isset($data[$pid])) {
|
||||
$parentId = $data[$pid];
|
||||
}
|
||||
if ((string)$root == $parentId) {
|
||||
$tree[] = &$list[$key];
|
||||
} else {
|
||||
if (isset($refer[$parentId])) {
|
||||
$parent = &$refer[$parentId];
|
||||
$parent[$children][] = &$list[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
public static function tree_to_list($tree = [], $children = 'children') {
|
||||
if (empty($tree) || !is_array($tree)) {
|
||||
return $tree;
|
||||
}
|
||||
$arrRes = [];
|
||||
foreach ($tree as $k => $v) {
|
||||
$arrTmp = $v;
|
||||
unset($arrTmp[$children]);
|
||||
$arrRes[] = $arrTmp;
|
||||
if (!empty($v[$children])) {
|
||||
$arrTmp = self::tree_to_list($v[$children], $children);
|
||||
$arrRes = array_merge($arrRes, $arrTmp);
|
||||
}
|
||||
}
|
||||
return $arrRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得所有的子
|
||||
*/
|
||||
public static function get_children($data, $id = 0, $pk = 'id', $pid = 'parent_id') {
|
||||
$array = [];
|
||||
foreach ($data as $k => $v) {
|
||||
if ($v[$pid] == $id) {
|
||||
$array[] = $v[$pk];
|
||||
array_merge($array, self::get_children($data, $v[$pk], $pk, $pid));
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取id的所有父,包含自己
|
||||
*/
|
||||
public static function get_parents($data, $id = 0, $pk = 'id', $pid = 'parent_id', $field = '') {
|
||||
$temp = [];
|
||||
foreach ($data as $k => $v) {
|
||||
if ($v[$pk] == $id) {
|
||||
$temp[] = $v;
|
||||
$temp = array_merge($temp, self::get_parents($data, $v[$pid]), $pk, $pid, $field);
|
||||
}
|
||||
}
|
||||
if($field){
|
||||
$temp = array_column($temp, $field);
|
||||
}
|
||||
return $temp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
trait AdminController {
|
||||
|
||||
protected $service = null;
|
||||
|
||||
/**
|
||||
* @title 列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @param $service
|
||||
* @return void
|
||||
*/
|
||||
public function index(Request $request){
|
||||
try {
|
||||
$this->data['data'] = $this->service->getDataList($request);
|
||||
} catch (\Throwable $th) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $th->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加
|
||||
*
|
||||
* @param Request $request
|
||||
* @param $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request){
|
||||
try {
|
||||
$this->data['data'] = $this->service->create($request);
|
||||
} catch (\Throwable $th) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $th->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 编辑
|
||||
*
|
||||
* @param Request $request
|
||||
* @param $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request){
|
||||
try {
|
||||
$this->data['data'] = $this->service->update($request);
|
||||
} catch (\Throwable $th) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $th->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除
|
||||
*
|
||||
* @param Request $request
|
||||
* @param $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request){
|
||||
try {
|
||||
$this->data['data'] = $this->service->delete($request);
|
||||
} catch (\Throwable $th) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $th->getMessage();
|
||||
}
|
||||
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
trait ModelTrait {
|
||||
|
||||
protected function casts(): array {
|
||||
return [
|
||||
'created_at' => 'datetime:Y-m-d H:i:s',
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s',
|
||||
'deleted_at' => 'datetime:Y-m-d H:i:s',
|
||||
];
|
||||
}
|
||||
|
||||
protected function serializeDate($data){
|
||||
return $data->timezone('Asia/Shanghai')->format('Y-m-d H:i:s');
|
||||
}
|
||||
/**
|
||||
* 过滤移除非当前表的字段参数
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function setFilterFields(array $params) : array {
|
||||
$fields = Schema::getColumnListing($this->getTable());
|
||||
foreach ($params as $key => $param) {
|
||||
if ( !in_array($key, $fields) ) unset($params[$key]);
|
||||
}
|
||||
// 同时过滤时间戳字段【时间戳只允许自动更改,不允许手动设置】
|
||||
if ( $this->timestamps === true && isset($params[self::CREATED_AT]) ) unset($params[self::CREATED_AT]);
|
||||
if ( $this->timestamps === true && isset($params[self::UPDATED_AT]) ) unset($params[self::UPDATED_AT]);
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the command...
|
||||
$status = (require_once __DIR__.'/bootstrap/app.php')
|
||||
->handleCommand(new ArgvInput);
|
||||
|
||||
exit($status);
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Middleware\AuthCheckMiddleware;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
then: function(){
|
||||
Route::middleware(['api'])
|
||||
->prefix('admin')
|
||||
->name('admin.')
|
||||
->group(base_path('routes/admin.php'));
|
||||
},
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->alias([
|
||||
'auth.check' => AuthCheckMiddleware::class
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
$exceptions->shouldRenderJsonWhen(function(Request $request, Throwable $e){
|
||||
// if($request->is('admin/*')){
|
||||
// return true;
|
||||
// }
|
||||
return $request->expectsJson();
|
||||
});
|
||||
})
|
||||
->withEvents(discover: [
|
||||
__DIR__ . '/../app/Listeners'
|
||||
])
|
||||
->create();
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
];
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"name": "laravel/laravel",
|
||||
"type": "project",
|
||||
"description": "The skeleton application for the Laravel framework.",
|
||||
"keywords": ["laravel", "framework"],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"alphasnow/aliyun-oss-laravel": "^4.9",
|
||||
"dcat/easy-excel": "^1.1",
|
||||
"kitloong/laravel-migrations-generator": "^7.1",
|
||||
"laravel/framework": "^11.0",
|
||||
"nwidart/laravel-modules": "^11.0",
|
||||
"tymon/jwt-auth": "^2.1",
|
||||
"w7corp/easywechat": "^6.15",
|
||||
"workerman/gateway-worker": "^3.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.13",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"laravel/pint": "^1.13",
|
||||
"laravel/sail": "^1.26",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.0",
|
||||
"phpunit/phpunit": "^11.0.1",
|
||||
"spatie/laravel-ignition": "^2.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi",
|
||||
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
|
||||
"@php artisan migrate --graceful --ansi"
|
||||
],
|
||||
"install-project": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
|
||||
"@php artisan key:generate --ansi",
|
||||
"@php artisan jwt:secret --ansi",
|
||||
"@php artisan storage:link --ansi"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": []
|
||||
},
|
||||
"merge-plugin": {
|
||||
"include": [
|
||||
"modules/*/composer.json"
|
||||
]
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true,
|
||||
"php-http/discovery": true,
|
||||
"wikimedia/composer-merge-plugin": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value is the name of your application, which will be used when the
|
||||
| framework needs to place the application's name in a notification or
|
||||
| other UI elements where an application name needs to be displayed.
|
||||
|
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Laravel'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Environment
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the "environment" your application is currently
|
||||
| running in. This may determine how you prefer to configure various
|
||||
| services the application utilizes. Set this in your ".env" file.
|
||||
|
|
||||
*/
|
||||
|
||||
'env' => env('APP_ENV', 'production'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Debug Mode
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When your application is in debug mode, detailed error messages with
|
||||
| stack traces will be shown on every error that occurs within your
|
||||
| application. If disabled, a simple generic error page is shown.
|
||||
|
|
||||
*/
|
||||
|
||||
'debug' => (bool) env('APP_DEBUG', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This URL is used by the console to properly generate URLs when using
|
||||
| the Artisan command line tool. You should set this to the root of
|
||||
| the application so that it's available within Artisan commands.
|
||||
|
|
||||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default timezone for your application, which
|
||||
| will be used by the PHP date and date-time functions. The timezone
|
||||
| is set to "UTC" by default as it is suitable for most use cases.
|
||||
|
|
||||
*/
|
||||
|
||||
'timezone' => env('APP_TIMEZONE', 'UTC'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Locale Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The application locale determines the default locale that will be used
|
||||
| by Laravel's translation / localization methods. This option can be
|
||||
| set to any locale for which you plan to have translation strings.
|
||||
|
|
||||
*/
|
||||
|
||||
'locale' => env('APP_LOCALE', 'en'),
|
||||
|
||||
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
|
||||
|
||||
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This key is utilized by Laravel's encryption services and should be set
|
||||
| to a random, 32 character string to ensure that all encrypted values
|
||||
| are secure. You should do this prior to deploying the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'cipher' => 'AES-256-CBC',
|
||||
|
||||
'key' => env('APP_KEY'),
|
||||
|
||||
'previous_keys' => [
|
||||
...array_filter(
|
||||
explode(',', env('APP_PREVIOUS_KEYS', ''))
|
||||
),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Maintenance Mode Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These configuration options determine the driver used to determine and
|
||||
| manage Laravel's "maintenance mode" status. The "cache" driver will
|
||||
| allow maintenance mode to be controlled across multiple machines.
|
||||
|
|
||||
| Supported drivers: "file", "cache"
|
||||
|
|
||||
*/
|
||||
|
||||
'maintenance' => [
|
||||
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
|
||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||
],
|
||||
|
||||
];
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Defaults
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default authentication "guard" and password
|
||||
| reset "broker" for your application. You may change these values
|
||||
| as required, but they're a perfect start for most applications.
|
||||
|
|
||||
*/
|
||||
|
||||
'defaults' => [
|
||||
'guard' => env('AUTH_GUARD', 'web'),
|
||||
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, you may define every authentication guard for your application.
|
||||
| Of course, a great default configuration has been defined for you
|
||||
| which utilizes session storage plus the Eloquent user provider.
|
||||
|
|
||||
| All authentication guards have a user provider, which defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| system used by the application. Typically, Eloquent is utilized.
|
||||
|
|
||||
| Supported: "session"
|
||||
|
|
||||
*/
|
||||
|
||||
'guards' => [
|
||||
'web' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'members',
|
||||
],
|
||||
'admin' => [
|
||||
'driver' => 'jwt',
|
||||
'provider' => 'admins'
|
||||
],
|
||||
'api' => [
|
||||
'driver' => 'jwt',
|
||||
'provider' => 'members',
|
||||
]
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| User Providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| All authentication guards have a user provider, which defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| system used by the application. Typically, Eloquent is utilized.
|
||||
|
|
||||
| If you have multiple user tables or models you may configure multiple
|
||||
| providers to represent the model / table. These providers may then
|
||||
| be assigned to any extra authentication guards you have defined.
|
||||
|
|
||||
| Supported: "database", "eloquent"
|
||||
|
|
||||
*/
|
||||
|
||||
'providers' => [
|
||||
'admins' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => App\Models\Auth\Admin::class,
|
||||
],
|
||||
'members' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => App\Member\Models\Member::class,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Resetting Passwords
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These configuration options specify the behavior of Laravel's password
|
||||
| reset functionality, including the table utilized for token storage
|
||||
| and the user provider that is invoked to actually retrieve users.
|
||||
|
|
||||
| The expiry time is the number of minutes that each reset token will be
|
||||
| considered valid. This security feature keeps tokens short-lived so
|
||||
| they have less time to be guessed. You may change this as needed.
|
||||
|
|
||||
| The throttle setting is the number of seconds a user must wait before
|
||||
| generating more password reset tokens. This prevents the user from
|
||||
| quickly generating a very large amount of password reset tokens.
|
||||
|
|
||||
*/
|
||||
|
||||
'passwords' => [
|
||||
'users' => [
|
||||
'provider' => 'members',
|
||||
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
|
||||
'expire' => 60,
|
||||
'throttle' => 60,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Confirmation Timeout
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the amount of seconds before a password confirmation
|
||||
| window expires and users are asked to re-enter their password via the
|
||||
| confirmation screen. By default, the timeout lasts for three hours.
|
||||
|
|
||||
*/
|
||||
|
||||
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
|
||||
|
||||
];
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default cache store that will be used by the
|
||||
| framework. This connection is utilized if another isn't explicitly
|
||||
| specified when running a cache operation inside the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('CACHE_STORE', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Stores
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of the cache "stores" for your application as
|
||||
| well as their drivers. You may even define multiple stores for the
|
||||
| same cache driver to group types of items stored in your caches.
|
||||
|
|
||||
| Supported drivers: "array", "database", "file", "memcached",
|
||||
| "redis", "dynamodb", "octane", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'stores' => [
|
||||
|
||||
'array' => [
|
||||
'driver' => 'array',
|
||||
'serialize' => false,
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'table' => env('DB_CACHE_TABLE', 'cache'),
|
||||
'connection' => env('DB_CACHE_CONNECTION'),
|
||||
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
|
||||
],
|
||||
|
||||
'file' => [
|
||||
'driver' => 'file',
|
||||
'path' => storage_path('framework/cache/data'),
|
||||
'lock_path' => storage_path('framework/cache/data'),
|
||||
],
|
||||
|
||||
'memcached' => [
|
||||
'driver' => 'memcached',
|
||||
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
|
||||
'sasl' => [
|
||||
env('MEMCACHED_USERNAME'),
|
||||
env('MEMCACHED_PASSWORD'),
|
||||
],
|
||||
'options' => [
|
||||
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
|
||||
],
|
||||
'servers' => [
|
||||
[
|
||||
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
||||
'port' => env('MEMCACHED_PORT', 11211),
|
||||
'weight' => 100,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
|
||||
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
|
||||
],
|
||||
|
||||
'dynamodb' => [
|
||||
'driver' => 'dynamodb',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
|
||||
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
||||
],
|
||||
|
||||
'octane' => [
|
||||
'driver' => 'octane',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Key Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When utilizing the APC, database, memcached, Redis, and DynamoDB cache
|
||||
| stores, there might be other applications using the same cache. For
|
||||
| that reason, you may prefix every cache key to avoid collisions.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),
|
||||
|
||||
];
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cross-Origin Resource Sharing (CORS) Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure your settings for cross-origin resource sharing
|
||||
| or "CORS". This determines what cross-origin operations may execute
|
||||
| in web browsers. You are free to adjust these settings as needed.
|
||||
|
|
||||
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
|
|
||||
*/
|
||||
|
||||
'paths' => ['api/*', 'admin/*'],
|
||||
|
||||
'allowed_methods' => ['*'],
|
||||
|
||||
'allowed_origins' => ['*'],
|
||||
|
||||
'allowed_origins_patterns' => [],
|
||||
|
||||
'allowed_headers' => ['*'],
|
||||
|
||||
'exposed_headers' => [],
|
||||
|
||||
'max_age' => 0,
|
||||
|
||||
'supports_credentials' => false,
|
||||
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Database Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which of the database connections below you wish
|
||||
| to use as your default connection for database operations. This is
|
||||
| the connection which will be utilized unless another connection
|
||||
| is explicitly specified when you execute a query / statement.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('DB_CONNECTION', 'sqlite'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Database Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Below are all of the database connections defined for your application.
|
||||
| An example configuration is provided for each database system which
|
||||
| is supported by Laravel. You're free to add / remove connections.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'url' => env('DB_URL'),
|
||||
'database' => env('DB_DATABASE', database_path('database.sqlite')),
|
||||
'prefix' => '',
|
||||
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
|
||||
],
|
||||
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||
'prefix' => 'sent_',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'mariadb' => [
|
||||
'driver' => 'mariadb',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '5432'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'search_path' => 'public',
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
|
||||
'sqlsrv' => [
|
||||
'driver' => 'sqlsrv',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', 'localhost'),
|
||||
'port' => env('DB_PORT', '1433'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
|
||||
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migration Repository Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This table keeps track of all the migrations that have already run for
|
||||
| your application. Using this information, we can determine which of
|
||||
| the migrations on disk haven't actually been run on the database.
|
||||
|
|
||||
*/
|
||||
|
||||
'migrations' => [
|
||||
'table' => 'migrations',
|
||||
'update_date_on_publish' => true,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Redis Databases
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Redis is an open source, fast, and advanced key-value store that also
|
||||
| provides a richer body of commands than a typical key-value system
|
||||
| such as Memcached. You may define your connection settings here.
|
||||
|
|
||||
*/
|
||||
|
||||
'redis' => [
|
||||
|
||||
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||
|
||||
'options' => [
|
||||
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
|
||||
],
|
||||
|
||||
'default' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
],
|
||||
|
||||
'cache' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_CACHE_DB', '1'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Debugbar Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Debugbar is enabled by default, when debug is set to true in app.php.
|
||||
| You can override the value by setting enable to true or false instead of null.
|
||||
|
|
||||
| You can provide an array of URI's that must be ignored (eg. 'api/*')
|
||||
|
|
||||
*/
|
||||
|
||||
'enabled' => env('DEBUGBAR_ENABLED', null),
|
||||
'except' => [
|
||||
'telescope*',
|
||||
'horizon*',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Storage settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| DebugBar stores data for session/ajax requests.
|
||||
| You can disable this, so the debugbar stores data in headers/session,
|
||||
| but this can cause problems with large data collectors.
|
||||
| By default, file storage (in the storage folder) is used. Redis and PDO
|
||||
| can also be used. For PDO, run the package migrations first.
|
||||
|
|
||||
| Warning: Enabling storage.open will allow everyone to access previous
|
||||
| request, do not enable open storage in publicly available environments!
|
||||
| Specify a callback if you want to limit based on IP or authentication.
|
||||
| Leaving it to null will allow localhost only.
|
||||
*/
|
||||
'storage' => [
|
||||
'enabled' => true,
|
||||
'open' => env('DEBUGBAR_OPEN_STORAGE'), // bool/callback.
|
||||
'driver' => 'file', // redis, file, pdo, socket, custom
|
||||
'path' => storage_path('debugbar'), // For file driver
|
||||
'connection' => null, // Leave null for default connection (Redis/PDO)
|
||||
'provider' => '', // Instance of StorageInterface for custom driver
|
||||
'hostname' => '127.0.0.1', // Hostname to use with the "socket" driver
|
||||
'port' => 2304, // Port to use with the "socket" driver
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Editor
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Choose your preferred editor to use when clicking file name.
|
||||
|
|
||||
| Supported: "phpstorm", "vscode", "vscode-insiders", "vscode-remote",
|
||||
| "vscode-insiders-remote", "vscodium", "textmate", "emacs",
|
||||
| "sublime", "atom", "nova", "macvim", "idea", "netbeans",
|
||||
| "xdebug", "espresso"
|
||||
|
|
||||
*/
|
||||
|
||||
'editor' => env('DEBUGBAR_EDITOR') ?: env('IGNITION_EDITOR', 'phpstorm'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Remote Path Mapping
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you are using a remote dev server, like Laravel Homestead, Docker, or
|
||||
| even a remote VPS, it will be necessary to specify your path mapping.
|
||||
|
|
||||
| Leaving one, or both of these, empty or null will not trigger the remote
|
||||
| URL changes and Debugbar will treat your editor links as local files.
|
||||
|
|
||||
| "remote_sites_path" is an absolute base path for your sites or projects
|
||||
| in Homestead, Vagrant, Docker, or another remote development server.
|
||||
|
|
||||
| Example value: "/home/vagrant/Code"
|
||||
|
|
||||
| "local_sites_path" is an absolute base path for your sites or projects
|
||||
| on your local computer where your IDE or code editor is running on.
|
||||
|
|
||||
| Example values: "/Users/<name>/Code", "C:\Users\<name>\Documents\Code"
|
||||
|
|
||||
*/
|
||||
|
||||
'remote_sites_path' => env('DEBUGBAR_REMOTE_SITES_PATH'),
|
||||
'local_sites_path' => env('DEBUGBAR_LOCAL_SITES_PATH', env('IGNITION_LOCAL_SITES_PATH')),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Vendors
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Vendor files are included by default, but can be set to false.
|
||||
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
|
||||
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
|
||||
| and for js: jquery and highlight.js
|
||||
| So if you want syntax highlighting, set it to true.
|
||||
| jQuery is set to not conflict with existing jQuery scripts.
|
||||
|
|
||||
*/
|
||||
|
||||
'include_vendors' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Capture Ajax Requests
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
|
||||
| you can use this option to disable sending the data through the headers.
|
||||
|
|
||||
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
|
||||
|
|
||||
| Note for your request to be identified as ajax requests they must either send the header
|
||||
| X-Requested-With with the value XMLHttpRequest (most JS libraries send this), or have application/json as a Accept header.
|
||||
|
|
||||
| By default `ajax_handler_auto_show` is set to true allowing ajax requests to be shown automatically in the Debugbar.
|
||||
| Changing `ajax_handler_auto_show` to false will prevent the Debugbar from reloading.
|
||||
*/
|
||||
|
||||
'capture_ajax' => true,
|
||||
'add_ajax_timing' => false,
|
||||
'ajax_handler_auto_show' => true,
|
||||
'ajax_handler_enable_tab' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Error Handler for Deprecated warnings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When enabled, the Debugbar shows deprecated warnings for Symfony components
|
||||
| in the Messages tab.
|
||||
|
|
||||
*/
|
||||
'error_handler' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Clockwork integration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The Debugbar can emulate the Clockwork headers, so you can use the Chrome
|
||||
| Extension, without the server-side code. It uses Debugbar collectors instead.
|
||||
|
|
||||
*/
|
||||
'clockwork' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DataCollectors
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable/disable DataCollectors
|
||||
|
|
||||
*/
|
||||
|
||||
'collectors' => [
|
||||
'phpinfo' => true, // Php version
|
||||
'messages' => true, // Messages
|
||||
'time' => true, // Time Datalogger
|
||||
'memory' => true, // Memory usage
|
||||
'exceptions' => true, // Exception displayer
|
||||
'log' => true, // Logs from Monolog (merged in messages if enabled)
|
||||
'db' => true, // Show database (PDO) queries and bindings
|
||||
'views' => true, // Views with their data
|
||||
'route' => true, // Current route information
|
||||
'auth' => false, // Display Laravel authentication status
|
||||
'gate' => true, // Display Laravel Gate checks
|
||||
'session' => true, // Display session data
|
||||
'symfony_request' => true, // Only one can be enabled..
|
||||
'mail' => true, // Catch mail messages
|
||||
'laravel' => false, // Laravel version and environment
|
||||
'events' => false, // All events fired
|
||||
'default_request' => false, // Regular or special Symfony request logger
|
||||
'logs' => false, // Add the latest log messages
|
||||
'files' => false, // Show the included files
|
||||
'config' => false, // Display config settings
|
||||
'cache' => false, // Display cache events
|
||||
'models' => true, // Display models
|
||||
'livewire' => true, // Display Livewire (when available)
|
||||
'jobs' => false, // Display dispatched jobs
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Extra options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configure some DataCollectors
|
||||
|
|
||||
*/
|
||||
|
||||
'options' => [
|
||||
'time' => [
|
||||
'memory_usage' => false, // Calculated by subtracting memory start and end, it may be inaccurate
|
||||
],
|
||||
'messages' => [
|
||||
'trace' => true, // Trace the origin of the debug message
|
||||
],
|
||||
'memory' => [
|
||||
'reset_peak' => false, // run memory_reset_peak_usage before collecting
|
||||
'with_baseline' => false, // Set boot memory usage as memory peak baseline
|
||||
'precision' => 0, // Memory rounding precision
|
||||
],
|
||||
'auth' => [
|
||||
'show_name' => true, // Also show the users name/email in the debugbar
|
||||
'show_guards' => true, // Show the guards that are used
|
||||
],
|
||||
'db' => [
|
||||
'with_params' => true, // Render SQL with the parameters substituted
|
||||
'backtrace' => true, // Use a backtrace to find the origin of the query in your files.
|
||||
'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults)
|
||||
'timeline' => false, // Add the queries to the timeline
|
||||
'duration_background' => true, // Show shaded background on each query relative to how long it took to execute.
|
||||
'explain' => [ // Show EXPLAIN output on queries
|
||||
'enabled' => false,
|
||||
'types' => ['SELECT'], // Deprecated setting, is always only SELECT
|
||||
],
|
||||
'hints' => false, // Show hints for common mistakes
|
||||
'show_copy' => false, // Show copy button next to the query,
|
||||
'slow_threshold' => false, // Only track queries that last longer than this time in ms
|
||||
'memory_usage' => false, // Show queries memory usage
|
||||
'soft_limit' => 100, // After the soft limit, no parameters/backtrace are captured
|
||||
'hard_limit' => 500, // After the hard limit, queries are ignored
|
||||
],
|
||||
'mail' => [
|
||||
'timeline' => false, // Add mails to the timeline
|
||||
'show_body' => true,
|
||||
],
|
||||
'views' => [
|
||||
'timeline' => false, // Add the views to the timeline (Experimental)
|
||||
'data' => false, //true for all data, 'keys' for only names, false for no parameters.
|
||||
'group' => 50, // Group duplicate views. Pass value to auto-group, or true/false to force
|
||||
'exclude_paths' => [ // Add the paths which you don't want to appear in the views
|
||||
'vendor/filament' // Exclude Filament components by default
|
||||
],
|
||||
],
|
||||
'route' => [
|
||||
'label' => true, // show complete route on bar
|
||||
],
|
||||
'session' => [
|
||||
'hiddens' => [], // hides sensitive values using array paths
|
||||
],
|
||||
'symfony_request' => [
|
||||
'hiddens' => [], // hides sensitive values using array paths, example: request_request.password
|
||||
],
|
||||
'events' => [
|
||||
'data' => false, // collect events data, listeners
|
||||
],
|
||||
'logs' => [
|
||||
'file' => null,
|
||||
],
|
||||
'cache' => [
|
||||
'values' => true, // collect cache values
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Inject Debugbar in Response
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Usually, the debugbar is added just before </body>, by listening to the
|
||||
| Response after the App is done. If you disable this, you have to add them
|
||||
| in your template yourself. See http://phpdebugbar.com/docs/rendering.html
|
||||
|
|
||||
*/
|
||||
|
||||
'inject' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DebugBar route prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Sometimes you want to set route prefix to be used by DebugBar to load
|
||||
| its resources from. Usually the need comes from misconfigured web server or
|
||||
| from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97
|
||||
|
|
||||
*/
|
||||
'route_prefix' => '_debugbar',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DebugBar route middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Additional middleware to run on the Debugbar routes
|
||||
*/
|
||||
'route_middleware' => [],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DebugBar route domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default DebugBar route served from the same domain that request served.
|
||||
| To override default domain, specify it as a non-empty value.
|
||||
*/
|
||||
'route_domain' => null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DebugBar theme
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Switches between light and dark theme. If set to auto it will respect system preferences
|
||||
| Possible values: auto, light, dark
|
||||
*/
|
||||
'theme' => env('DEBUGBAR_THEME', 'auto'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Backtrace stack limit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default, the DebugBar limits the number of frames returned by the 'debug_backtrace()' function.
|
||||
| If you need larger stacktraces, you can increase this number. Setting it to 0 will result in no limit.
|
||||
*/
|
||||
'debug_backtrace_limit' => 50,
|
||||
];
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Filesystem Disk
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default filesystem disk that should be used
|
||||
| by the framework. The "local" disk, as well as a variety of cloud
|
||||
| based disks are available to your application for file storage.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('FILESYSTEM_DISK', 'local'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filesystem Disks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Below you may configure as many filesystem disks as necessary, and you
|
||||
| may even configure multiple disks for the same driver. Examples for
|
||||
| most supported storage drivers are configured here for reference.
|
||||
|
|
||||
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
||||
|
|
||||
*/
|
||||
|
||||
'disks' => [
|
||||
|
||||
'local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app'),
|
||||
'throw' => false,
|
||||
],
|
||||
|
||||
'public' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/public'),
|
||||
'url' => env('APP_URL').'/storage',
|
||||
'visibility' => 'public',
|
||||
'throw' => false,
|
||||
],
|
||||
|
||||
's3' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION'),
|
||||
'bucket' => env('AWS_BUCKET'),
|
||||
'url' => env('AWS_URL'),
|
||||
'endpoint' => env('AWS_ENDPOINT'),
|
||||
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
|
||||
'throw' => false,
|
||||
],
|
||||
|
||||
'oss' => [
|
||||
"driver" => "oss",
|
||||
"access_key_id" => env("OSS_ACCESS_KEY_ID"), // Required, yourAccessKeyId
|
||||
"access_key_secret" => env("OSS_ACCESS_KEY_SECRET"), // Required, yourAccessKeySecret
|
||||
"bucket" => env("OSS_BUCKET"), // Required, for example: my-bucket
|
||||
"endpoint" => env("OSS_ENDPOINT"), // Required, for example: oss-cn-shanghai.aliyuncs.com
|
||||
"internal" => env("OSS_INTERNAL", null), // Optional, for example: oss-cn-shanghai-internal.aliyuncs.com
|
||||
"domain" => env("OSS_DOMAIN", null), // Optional, for example: oss.my-domain.com
|
||||
"is_cname" => env("OSS_CNAME", false), // Optional, if the Endpoint is a custom domain name, this must be true, see: https://github.com/aliyun/aliyun-oss-php-sdk/blob/572d0f8e099e8630ae7139ed3fdedb926c7a760f/src/OSS/OssClient.php#L113C1-L122C78
|
||||
"prefix" => env("OSS_PREFIX", ""), // Optional, the prefix of the store path
|
||||
"use_ssl" => env("OSS_SSL", false), // Optional, whether to use HTTPS
|
||||
"throw" => env("OSS_THROW", false), // Optional, whether to throw an exception that causes an error
|
||||
"signatureVersion" => env("OSS_SIGNATURE_VERSION", "v1"), // Optional, select v1 or v4 as the signature version
|
||||
"region" => env("OSS_REGION", ""), // Optional, for example: cn-shanghai, used only when v4 signature version is selected
|
||||
"options" => [], // Optional, add global configuration parameters, For example: [\OSS\OssClient::OSS_CHECK_MD5 => false]
|
||||
"macros" => [] // Optional, add custom Macro, For example: [\App\Macros\ListBuckets::class, \App\Macros\CreateBucket::class]
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Symbolic Links
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the symbolic links that will be created when the
|
||||
| `storage:link` Artisan command is executed. The array keys should be
|
||||
| the locations of the links and the values should be their targets.
|
||||
|
|
||||
*/
|
||||
|
||||
'links' => [
|
||||
public_path('storage') => storage_path('app/public'),
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return[
|
||||
// 扩展自身需要的配置
|
||||
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
|
||||
'host' => '0.0.0.0', // 监听地址
|
||||
'port' => 2348, // 监听端口
|
||||
'socket' => '', // 完整监听地址
|
||||
'context' => [], // socket 上下文选项
|
||||
'register_deploy' => true, // 是否需要部署register
|
||||
'businessWorker_deploy' => true, // 是否需要部署businessWorker
|
||||
'gateway_deploy' => true, // 是否需要部署gateway
|
||||
|
||||
// Register配置
|
||||
'registerAddress' => '127.0.0.1:1236',
|
||||
|
||||
// Gateway配置
|
||||
'name' => 'workerman',
|
||||
'count' => 1,
|
||||
'lanIp' => '127.0.0.1',
|
||||
'startPort' => 2000,
|
||||
'daemonize' => false,
|
||||
'pingInterval' => 30,
|
||||
'pingNotResponseLimit' => 0,
|
||||
'pingData' => '{"type":"ping"}',
|
||||
|
||||
// BusinsessWorker配置
|
||||
'businessWorker' => [
|
||||
'name' => 'BusinessWorker',
|
||||
'count' => 1,
|
||||
'eventHandler' => '\Modules\Workerman\Events\WorkermanEvent',
|
||||
],
|
||||
];
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of jwt-auth.
|
||||
*
|
||||
* (c) Sean Tymon <tymon148@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT Authentication Secret
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Don't forget to set this in your .env file, as it will be used to sign
|
||||
| your tokens. A helper command is provided for this:
|
||||
| `php artisan jwt:secret`
|
||||
|
|
||||
| Note: This will be used for Symmetric algorithms only (HMAC),
|
||||
| since RSA and ECDSA use a private/public key combo (See below).
|
||||
|
|
||||
*/
|
||||
|
||||
'secret' => env('JWT_SECRET'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT Authentication Keys
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The algorithm you are using, will determine whether your tokens are
|
||||
| signed with a random string (defined in `JWT_SECRET`) or using the
|
||||
| following public & private keys.
|
||||
|
|
||||
| Symmetric Algorithms:
|
||||
| HS256, HS384 & HS512 will use `JWT_SECRET`.
|
||||
|
|
||||
| Asymmetric Algorithms:
|
||||
| RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below.
|
||||
|
|
||||
*/
|
||||
|
||||
'keys' => [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Public Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| A path or resource to your public key.
|
||||
|
|
||||
| E.g. 'file://path/to/public/key'
|
||||
|
|
||||
*/
|
||||
|
||||
'public' => env('JWT_PUBLIC_KEY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Private Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| A path or resource to your private key.
|
||||
|
|
||||
| E.g. 'file://path/to/private/key'
|
||||
|
|
||||
*/
|
||||
|
||||
'private' => env('JWT_PRIVATE_KEY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Passphrase
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The passphrase for your private key. Can be null if none set.
|
||||
|
|
||||
*/
|
||||
|
||||
'passphrase' => env('JWT_PASSPHRASE'),
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT time to live
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the length of time (in minutes) that the token will be valid for.
|
||||
| Defaults to 1 hour.
|
||||
|
|
||||
| You can also set this to null, to yield a never expiring token.
|
||||
| Some people may want this behaviour for e.g. a mobile app.
|
||||
| This is not particularly recommended, so make sure you have appropriate
|
||||
| systems in place to revoke the token if necessary.
|
||||
| Notice: If you set this to null you should remove 'exp' element from 'required_claims' list.
|
||||
|
|
||||
*/
|
||||
|
||||
'ttl' => env('JWT_TTL', 60 * 60 * 24 * 7 ),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Refresh time to live
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the length of time (in minutes) that the token can be refreshed
|
||||
| within. I.E. The user can refresh their token within a 2 week window of
|
||||
| the original token being created until they must re-authenticate.
|
||||
| Defaults to 2 weeks.
|
||||
|
|
||||
| You can also set this to null, to yield an infinite refresh time.
|
||||
| Some may want this instead of never expiring tokens for e.g. a mobile app.
|
||||
| This is not particularly recommended, so make sure you have appropriate
|
||||
| systems in place to revoke the token if necessary.
|
||||
|
|
||||
*/
|
||||
|
||||
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT hashing algorithm
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the hashing algorithm that will be used to sign the token.
|
||||
|
|
||||
*/
|
||||
|
||||
'algo' => env('JWT_ALGO', Tymon\JWTAuth\Providers\JWT\Provider::ALGO_HS256),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Required Claims
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the required claims that must exist in any token.
|
||||
| A TokenInvalidException will be thrown if any of these claims are not
|
||||
| present in the payload.
|
||||
|
|
||||
*/
|
||||
|
||||
'required_claims' => [
|
||||
'iss',
|
||||
'iat',
|
||||
'exp',
|
||||
'nbf',
|
||||
'sub',
|
||||
'jti',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Persistent Claims
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the claim keys to be persisted when refreshing a token.
|
||||
| `sub` and `iat` will automatically be persisted, in
|
||||
| addition to the these claims.
|
||||
|
|
||||
| Note: If a claim does not exist then it will be ignored.
|
||||
|
|
||||
*/
|
||||
|
||||
'persistent_claims' => [
|
||||
// 'foo',
|
||||
// 'bar',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Lock Subject
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This will determine whether a `prv` claim is automatically added to
|
||||
| the token. The purpose of this is to ensure that if you have multiple
|
||||
| authentication models e.g. `App\User` & `App\OtherPerson`, then we
|
||||
| should prevent one authentication request from impersonating another,
|
||||
| if 2 tokens happen to have the same id across the 2 different models.
|
||||
|
|
||||
| Under specific circumstances, you may want to disable this behaviour
|
||||
| e.g. if you only have one authentication model, then you would save
|
||||
| a little on token size.
|
||||
|
|
||||
*/
|
||||
|
||||
'lock_subject' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Leeway
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This property gives the jwt timestamp claims some "leeway".
|
||||
| Meaning that if you have any unavoidable slight clock skew on
|
||||
| any of your servers then this will afford you some level of cushioning.
|
||||
|
|
||||
| This applies to the claims `iat`, `nbf` and `exp`.
|
||||
|
|
||||
| Specify in seconds - only if you know you need it.
|
||||
|
|
||||
*/
|
||||
|
||||
'leeway' => env('JWT_LEEWAY', 0),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Blacklist Enabled
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| In order to invalidate tokens, you must have the blacklist enabled.
|
||||
| If you do not want or need this functionality, then set this to false.
|
||||
|
|
||||
*/
|
||||
|
||||
'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------------
|
||||
| Blacklist Grace Period
|
||||
| -------------------------------------------------------------------------
|
||||
|
|
||||
| When multiple concurrent requests are made with the same JWT,
|
||||
| it is possible that some of them fail, due to token regeneration
|
||||
| on every request.
|
||||
|
|
||||
| Set grace period in seconds to prevent parallel request failure.
|
||||
|
|
||||
*/
|
||||
|
||||
'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cookies encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default Laravel encrypt cookies for security reason.
|
||||
| If you decide to not decrypt cookies, you will have to configure Laravel
|
||||
| to not encrypt your cookie token by adding its name into the $except
|
||||
| array available in the middleware "EncryptCookies" provided by Laravel.
|
||||
| see https://laravel.com/docs/master/responses#cookies-and-encryption
|
||||
| for details.
|
||||
|
|
||||
| Set it to true if you want to decrypt cookies.
|
||||
|
|
||||
*/
|
||||
|
||||
'decrypt_cookies' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the various providers used throughout the package.
|
||||
|
|
||||
*/
|
||||
|
||||
'providers' => [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JWT Provider
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the provider that is used to create and decode the tokens.
|
||||
|
|
||||
*/
|
||||
|
||||
'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Provider
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the provider that is used to authenticate users.
|
||||
|
|
||||
*/
|
||||
|
||||
'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Storage Provider
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specify the provider that is used to store tokens in the blacklist.
|
||||
|
|
||||
*/
|
||||
|
||||
'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\SyslogUdpHandler;
|
||||
use Monolog\Processor\PsrLogMessageProcessor;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default log channel that is utilized to write
|
||||
| messages to your logs. The value provided here should match one of
|
||||
| the channels present in the list of "channels" configured below.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LOG_CHANNEL', 'stack'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Deprecations Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the log channel that should be used to log warnings
|
||||
| regarding deprecated PHP and library features. This allows you to get
|
||||
| your application ready for upcoming major versions of dependencies.
|
||||
|
|
||||
*/
|
||||
|
||||
'deprecations' => [
|
||||
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
|
||||
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Channels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log channels for your application. Laravel
|
||||
| utilizes the Monolog PHP logging library, which includes a variety
|
||||
| of powerful log handlers and formatters that you're free to use.
|
||||
|
|
||||
| Available Drivers: "single", "daily", "slack", "syslog",
|
||||
| "errorlog", "monolog", "custom", "stack"
|
||||
|
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => explode(',', env('LOG_STACK', 'single')),
|
||||
'ignore_exceptions' => false,
|
||||
],
|
||||
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'days' => env('LOG_DAILY_DAYS', 14),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'driver' => 'slack',
|
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
|
||||
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
|
||||
'level' => env('LOG_LEVEL', 'critical'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_URL'),
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
'processors' => [PsrLogMessageProcessor::class],
|
||||
],
|
||||
|
||||
'stderr' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'handler' => StreamHandler::class,
|
||||
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||
'with' => [
|
||||
'stream' => 'php://stderr',
|
||||
],
|
||||
'processors' => [PsrLogMessageProcessor::class],
|
||||
],
|
||||
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => NullHandler::class,
|
||||
],
|
||||
|
||||
'emergency' => [
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Mailer
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default mailer that is used to send all email
|
||||
| messages unless another mailer is explicitly specified when sending
|
||||
| the message. All additional mailers can be configured within the
|
||||
| "mailers" array. Examples of each type of mailer are provided.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('MAIL_MAILER', 'log'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mailer Configurations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure all of the mailers used by your application plus
|
||||
| their respective settings. Several examples have been configured for
|
||||
| you and you are free to add your own as your application requires.
|
||||
|
|
||||
| Laravel supports a variety of mail "transport" drivers that can be used
|
||||
| when delivering an email. You may specify which one you're using for
|
||||
| your mailers below. You may also add additional mailers if needed.
|
||||
|
|
||||
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
|
||||
| "postmark", "resend", "log", "array",
|
||||
| "failover", "roundrobin"
|
||||
|
|
||||
*/
|
||||
|
||||
'mailers' => [
|
||||
|
||||
'smtp' => [
|
||||
'transport' => 'smtp',
|
||||
'url' => env('MAIL_URL'),
|
||||
'host' => env('MAIL_HOST', '127.0.0.1'),
|
||||
'port' => env('MAIL_PORT', 2525),
|
||||
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'timeout' => null,
|
||||
'local_domain' => env('MAIL_EHLO_DOMAIN'),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'transport' => 'ses',
|
||||
],
|
||||
|
||||
'postmark' => [
|
||||
'transport' => 'postmark',
|
||||
// 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
|
||||
// 'client' => [
|
||||
// 'timeout' => 5,
|
||||
// ],
|
||||
],
|
||||
|
||||
'resend' => [
|
||||
'transport' => 'resend',
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
'transport' => 'sendmail',
|
||||
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'transport' => 'log',
|
||||
'channel' => env('MAIL_LOG_CHANNEL'),
|
||||
],
|
||||
|
||||
'array' => [
|
||||
'transport' => 'array',
|
||||
],
|
||||
|
||||
'failover' => [
|
||||
'transport' => 'failover',
|
||||
'mailers' => [
|
||||
'smtp',
|
||||
'log',
|
||||
],
|
||||
],
|
||||
|
||||
'roundrobin' => [
|
||||
'transport' => 'roundrobin',
|
||||
'mailers' => [
|
||||
'ses',
|
||||
'postmark',
|
||||
],
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global "From" Address
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You may wish for all emails sent by your application to be sent from
|
||||
| the same address. Here you may specify a name and address that is
|
||||
| used globally for all emails that are sent by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'from' => [
|
||||
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
|
||||
'name' => env('MAIL_FROM_NAME', 'Example'),
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
use Nwidart\Modules\Activators\FileActivator;
|
||||
use Nwidart\Modules\Providers\ConsoleServiceProvider;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Module Namespace
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Default module namespace.
|
||||
|
|
||||
*/
|
||||
'namespace' => 'Modules',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Module Stubs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Default module stubs.
|
||||
|
|
||||
*/
|
||||
'stubs' => [
|
||||
'enabled' => false,
|
||||
'path' => base_path('storage/stubs'),
|
||||
'files' => [
|
||||
'routes/web' => 'routes/web.php',
|
||||
'routes/api' => 'routes/api.php',
|
||||
'routes/admin' => 'routes/admin.php',
|
||||
// 'views/index' => 'resources/views/index.blade.php',
|
||||
// 'views/master' => 'resources/views/layouts/master.blade.php',
|
||||
'scaffold/config' => 'config/config.php',
|
||||
'composer' => 'composer.json',
|
||||
// 'assets/js/app' => 'resources/assets/js/app.js',
|
||||
// 'assets/sass/app' => 'resources/assets/sass/app.scss',
|
||||
// 'vite' => 'vite.config.js',
|
||||
// 'package' => 'package.json',
|
||||
],
|
||||
'replacements' => [
|
||||
'routes/web' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'CONTROLLER_NAMESPACE'],
|
||||
'routes/api' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'CONTROLLER_NAMESPACE'],
|
||||
'routes/admin' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'CONTROLLER_NAMESPACE'],
|
||||
'vite' => ['LOWER_NAME', 'STUDLY_NAME'],
|
||||
'json' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'PROVIDER_NAMESPACE'],
|
||||
'views/index' => ['LOWER_NAME'],
|
||||
'views/master' => ['LOWER_NAME', 'STUDLY_NAME'],
|
||||
'scaffold/config' => ['STUDLY_NAME'],
|
||||
'composer' => [
|
||||
'LOWER_NAME',
|
||||
'STUDLY_NAME',
|
||||
'VENDOR',
|
||||
'AUTHOR_NAME',
|
||||
'AUTHOR_EMAIL',
|
||||
'MODULE_NAMESPACE',
|
||||
'PROVIDER_NAMESPACE',
|
||||
'APP_FOLDER_NAME',
|
||||
],
|
||||
],
|
||||
'gitkeep' => true,
|
||||
],
|
||||
'paths' => [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Modules path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This path is used to save the generated module.
|
||||
| This path will also be added automatically to the list of scanned folders.
|
||||
|
|
||||
*/
|
||||
'modules' => base_path('modules'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Modules assets path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may update the modules' assets path.
|
||||
|
|
||||
*/
|
||||
'assets' => public_path('modules'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| The migrations' path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Where you run the 'module:publish-migration' command, where do you publish the
|
||||
| the migration files?
|
||||
|
|
||||
*/
|
||||
'migration' => base_path('database/migrations'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| The app path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| app folder name
|
||||
| for example can change it to 'src' or 'App'
|
||||
*/
|
||||
'app_folder' => 'app/',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Generator path
|
||||
|--------------------------------------------------------------------------
|
||||
| Customise the paths where the folders will be generated.
|
||||
| Setting the generate key to false will not generate that folder
|
||||
*/
|
||||
'generator' => [
|
||||
// app/
|
||||
'actions' => ['path' => 'app/Actions', 'generate' => false],
|
||||
'casts' => ['path' => 'app/Casts', 'generate' => false],
|
||||
'channels' => ['path' => 'app/Broadcasting', 'generate' => false],
|
||||
'class' => ['path' => 'app/Classes', 'generate' => false],
|
||||
'command' => ['path' => 'app/Console', 'generate' => false],
|
||||
'component-class' => ['path' => 'app/View/Components', 'generate' => false],
|
||||
'emails' => ['path' => 'app/Emails', 'generate' => false],
|
||||
'event' => ['path' => 'app/Events', 'generate' => false],
|
||||
'enums' => ['path' => 'app/Enums', 'generate' => false],
|
||||
'exceptions' => ['path' => 'app/Exceptions', 'generate' => false],
|
||||
'jobs' => ['path' => 'app/Jobs', 'generate' => false],
|
||||
'helpers' => ['path' => 'app/Helpers', 'generate' => false],
|
||||
'interfaces' => ['path' => 'app/Interfaces', 'generate' => false],
|
||||
'listener' => ['path' => 'app/Listeners', 'generate' => false],
|
||||
'model' => ['path' => 'app/Models', 'generate' => true],
|
||||
'notifications' => ['path' => 'app/Notifications', 'generate' => false],
|
||||
'observer' => ['path' => 'app/Observers', 'generate' => false],
|
||||
'policies' => ['path' => 'app/Policies', 'generate' => false],
|
||||
'provider' => ['path' => 'app/Providers', 'generate' => true],
|
||||
'repository' => ['path' => 'app/Repositories', 'generate' => false],
|
||||
'resource' => ['path' => 'app/Transformers', 'generate' => false],
|
||||
'route-provider' => ['path' => 'app/Providers', 'generate' => true],
|
||||
'rules' => ['path' => 'app/Rules', 'generate' => false],
|
||||
'services' => ['path' => 'app/Services', 'generate' => true],
|
||||
'scopes' => ['path' => 'app/Models/Scopes', 'generate' => false],
|
||||
'traits' => ['path' => 'app/Traits', 'generate' => false],
|
||||
|
||||
// app/Http/
|
||||
'controller' => ['path' => 'app/Controllers', 'generate' => true],
|
||||
'filter' => ['path' => 'app/Http/Middleware', 'generate' => false],
|
||||
'request' => ['path' => 'app/Http/Requests', 'generate' => false],
|
||||
|
||||
// config/
|
||||
'config' => ['path' => 'config', 'generate' => true],
|
||||
|
||||
// database/
|
||||
'factory' => ['path' => 'database/factories', 'generate' => true],
|
||||
'migration' => ['path' => 'database/migrations', 'generate' => true],
|
||||
'seeder' => ['path' => 'database/seeders', 'generate' => true],
|
||||
|
||||
// lang/
|
||||
'lang' => ['path' => 'lang', 'generate' => false],
|
||||
|
||||
// resource/
|
||||
'assets' => ['path' => 'resources/assets', 'generate' => false],
|
||||
'component-view' => ['path' => 'resources/views/components', 'generate' => false],
|
||||
'views' => ['path' => 'resources/views', 'generate' => false],
|
||||
|
||||
// routes/
|
||||
'routes' => ['path' => 'routes', 'generate' => true],
|
||||
|
||||
// tests/
|
||||
'test-feature' => ['path' => 'tests/Feature', 'generate' => false],
|
||||
'test-unit' => ['path' => 'tests/Unit', 'generate' => false],
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Package commands
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you can define which commands will be visible and used in your
|
||||
| application. You can add your own commands to merge section.
|
||||
|
|
||||
*/
|
||||
'commands' => ConsoleServiceProvider::defaultCommands()
|
||||
->merge([
|
||||
// New commands go here
|
||||
])->toArray(),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Scan Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you define which folder will be scanned. By default will scan vendor
|
||||
| directory. This is useful if you host the package in packagist website.
|
||||
|
|
||||
*/
|
||||
'scan' => [
|
||||
'enabled' => false,
|
||||
'paths' => [
|
||||
base_path('vendor/*/*'),
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Composer File Template
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is the config for the composer.json file, generated by this package
|
||||
|
|
||||
*/
|
||||
'composer' => [
|
||||
'vendor' => env('MODULE_VENDOR', 'tensent'),
|
||||
'author' => [
|
||||
'name' => env('MODULE_AUTHOR_NAME', 'molong'),
|
||||
'email' => env('MODULE_AUTHOR_EMAIL', 'molong@tensent.cn'),
|
||||
],
|
||||
'composer-output' => false,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Caching
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is the config for setting up the caching feature.
|
||||
|
|
||||
*/
|
||||
'cache' => [
|
||||
'enabled' => env('MODULES_CACHE_ENABLED', false),
|
||||
'driver' => env('MODULES_CACHE_DRIVER', 'file'),
|
||||
'key' => env('MODULES_CACHE_KEY', 'laravel-modules'),
|
||||
'lifetime' => env('MODULES_CACHE_LIFETIME', 60),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Choose what laravel-modules will register as custom namespaces.
|
||||
| Setting one to false will require you to register that part
|
||||
| in your own Service Provider class.
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'register' => [
|
||||
'translations' => true,
|
||||
/**
|
||||
* load files on boot or register method
|
||||
*/
|
||||
'files' => 'register',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Activators
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You can define new types of activators here, file, database, etc. The only
|
||||
| required parameter is 'class'.
|
||||
| The file activator will store the activation status in storage/installed_modules
|
||||
*/
|
||||
'activators' => [
|
||||
'file' => [
|
||||
'class' => FileActivator::class,
|
||||
'statuses-file' => base_path('storage/modules_statuses.json'),
|
||||
'cache-key' => 'activator.installed',
|
||||
'cache-lifetime' => 604800,
|
||||
],
|
||||
'database' => [
|
||||
'class' => \App\Services\System\ModulesService::class,
|
||||
'model' => \App\Models\System\Modules::class
|
||||
]
|
||||
],
|
||||
|
||||
'activator' => 'file',
|
||||
];
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Queue Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Laravel's queue supports a variety of backends via a single, unified
|
||||
| API, giving you convenient access to each backend using identical
|
||||
| syntax for each. The default queue connection is defined below.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('QUEUE_CONNECTION', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the connection options for every queue backend
|
||||
| used by your application. An example configuration is provided for
|
||||
| each backend supported by Laravel. You're also free to add more.
|
||||
|
|
||||
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sync' => [
|
||||
'driver' => 'sync',
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'connection' => env('DB_QUEUE_CONNECTION'),
|
||||
'table' => env('DB_QUEUE_TABLE', 'jobs'),
|
||||
'queue' => env('DB_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'beanstalkd' => [
|
||||
'driver' => 'beanstalkd',
|
||||
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
|
||||
'queue' => env('BEANSTALKD_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
|
||||
'block_for' => 0,
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'sqs' => [
|
||||
'driver' => 'sqs',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
|
||||
'queue' => env('SQS_QUEUE', 'default'),
|
||||
'suffix' => env('SQS_SUFFIX'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
|
||||
'queue' => env('REDIS_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
|
||||
'block_for' => null,
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Job Batching
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following options configure the database and table that store job
|
||||
| batching information. These options can be updated to any database
|
||||
| connection and table which has been defined by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'batching' => [
|
||||
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||
'table' => 'job_batches',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Failed Queue Jobs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These options configure the behavior of failed queue job logging so you
|
||||
| can control how and where failed jobs are stored. Laravel ships with
|
||||
| support for storing failed jobs in a simple file or in a database.
|
||||
|
|
||||
| Supported drivers: "database-uuids", "dynamodb", "file", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => [
|
||||
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
|
||||
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||
'table' => 'failed_jobs',
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Third Party Services
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is for storing the credentials for third party services such
|
||||
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
||||
| location for this type of information, allowing packages to have
|
||||
| a conventional file to locate the various service credentials.
|
||||
|
|
||||
*/
|
||||
|
||||
'postmark' => [
|
||||
'token' => env('POSTMARK_TOKEN'),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'resend' => [
|
||||
'key' => env('RESEND_KEY'),
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'notifications' => [
|
||||
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
|
||||
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Session Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines the default session driver that is utilized for
|
||||
| incoming requests. Laravel supports a variety of storage options to
|
||||
| persist session data. Database storage is a great default choice.
|
||||
|
|
||||
| Supported: "file", "cookie", "database", "apc",
|
||||
| "memcached", "redis", "dynamodb", "array"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('SESSION_DRIVER', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Lifetime
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the number of minutes that you wish the session
|
||||
| to be allowed to remain idle before it expires. If you want them
|
||||
| to expire immediately when the browser is closed then you may
|
||||
| indicate that via the expire_on_close configuration option.
|
||||
|
|
||||
*/
|
||||
|
||||
'lifetime' => env('SESSION_LIFETIME', 120),
|
||||
|
||||
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to easily specify that all of your session data
|
||||
| should be encrypted before it's stored. All encryption is performed
|
||||
| automatically by Laravel and you may use the session like normal.
|
||||
|
|
||||
*/
|
||||
|
||||
'encrypt' => env('SESSION_ENCRYPT', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session File Location
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When utilizing the "file" session driver, the session files are placed
|
||||
| on disk. The default storage location is defined here; however, you
|
||||
| are free to provide another location where they should be stored.
|
||||
|
|
||||
*/
|
||||
|
||||
'files' => storage_path('framework/sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" or "redis" session drivers, you may specify a
|
||||
| connection that should be used to manage these sessions. This should
|
||||
| correspond to a connection in your database configuration options.
|
||||
|
|
||||
*/
|
||||
|
||||
'connection' => env('SESSION_CONNECTION'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" session driver, you may specify the table to
|
||||
| be used to store sessions. Of course, a sensible default is defined
|
||||
| for you; however, you're welcome to change this to another table.
|
||||
|
|
||||
*/
|
||||
|
||||
'table' => env('SESSION_TABLE', 'sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using one of the framework's cache driven session backends, you may
|
||||
| define the cache store which should be used to store the session data
|
||||
| between requests. This must match one of your defined cache stores.
|
||||
|
|
||||
| Affects: "apc", "dynamodb", "memcached", "redis"
|
||||
|
|
||||
*/
|
||||
|
||||
'store' => env('SESSION_STORE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Sweeping Lottery
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Some session drivers must manually sweep their storage location to get
|
||||
| rid of old sessions from storage. Here are the chances that it will
|
||||
| happen on a given request. By default, the odds are 2 out of 100.
|
||||
|
|
||||
*/
|
||||
|
||||
'lottery' => [2, 100],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may change the name of the session cookie that is created by
|
||||
| the framework. Typically, you should not need to change this value
|
||||
| since doing so does not grant a meaningful security improvement.
|
||||
|
|
||||
*/
|
||||
|
||||
'cookie' => env(
|
||||
'SESSION_COOKIE',
|
||||
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
|
||||
),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The session cookie path determines the path for which the cookie will
|
||||
| be regarded as available. Typically, this will be the root path of
|
||||
| your application, but you're free to change this when necessary.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => env('SESSION_PATH', '/'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the domain and subdomains the session cookie is
|
||||
| available to. By default, the cookie will be available to the root
|
||||
| domain and all subdomains. Typically, this shouldn't be changed.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('SESSION_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTPS Only Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By setting this option to true, session cookies will only be sent back
|
||||
| to the server if the browser has a HTTPS connection. This will keep
|
||||
| the cookie from being sent to you when it can't be done securely.
|
||||
|
|
||||
*/
|
||||
|
||||
'secure' => env('SESSION_SECURE_COOKIE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTP Access Only
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will prevent JavaScript from accessing the
|
||||
| value of the cookie and the cookie will only be accessible through
|
||||
| the HTTP protocol. It's unlikely you should disable this option.
|
||||
|
|
||||
*/
|
||||
|
||||
'http_only' => env('SESSION_HTTP_ONLY', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Same-Site Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines how your cookies behave when cross-site requests
|
||||
| take place, and can be used to mitigate CSRF attacks. By default, we
|
||||
| will set this value to "lax" to permit secure cross-site requests.
|
||||
|
|
||||
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
|
||||
|
|
||||
| Supported: "lax", "strict", "none", null
|
||||
|
|
||||
*/
|
||||
|
||||
'same_site' => env('SESSION_SAME_SITE', 'lax'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Partitioned Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will tie the cookie to the top-level site for
|
||||
| a cross-site context. Partitioned cookies are accepted by the browser
|
||||
| when flagged "secure" and the Same-Site attribute is set to "none".
|
||||
|
|
||||
*/
|
||||
|
||||
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
|
||||
|
||||
];
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'wx' => [
|
||||
'app_id' => 'wx8729bae07a068c87',
|
||||
'secret' => 'bd76508353688757296ce1e8c1307758',
|
||||
|
||||
'token' => '',
|
||||
],
|
||||
/**
|
||||
* OAuth 配置
|
||||
*
|
||||
* scopes:公众平台(snsapi_userinfo / snsapi_base),开放平台:snsapi_login
|
||||
* callback:OAuth授权完成后的回调页地址
|
||||
*/
|
||||
'oauth' => [
|
||||
'scopes' => ['snsapi_userinfo'],
|
||||
'callback' => '/examples/oauth_callback.php',
|
||||
],
|
||||
|
||||
/**
|
||||
* 接口请求相关配置,超时时间等,具体可用参数请参考:
|
||||
* https://github.com/symfony/symfony/blob/5.3/src/Symfony/Contracts/HttpClient/HttpClientInterface.php
|
||||
*/
|
||||
'http' => [
|
||||
'timeout' => 5.0,
|
||||
// 'base_uri' => 'https://api.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
|
||||
|
||||
'retry' => true, // 使用默认重试配置
|
||||
// 'retry' => [
|
||||
// // 仅以下状态码重试
|
||||
// 'status_codes' => [429, 500]
|
||||
// // 最大重试次数
|
||||
// 'max_retries' => 3,
|
||||
// // 请求间隔 (毫秒)
|
||||
// 'delay' => 1000,
|
||||
// // 如果设置,每次重试的等待时间都会增加这个系数
|
||||
// // (例如. 首次:1000ms; 第二次: 3 * 1000ms; etc.)
|
||||
// 'multiplier' => 3
|
||||
// ],
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1 @@
|
||||
*.sqlite*
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'remember_token' => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
|
||||
Schema::create('job_batches', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->string('name');
|
||||
$table->integer('total_jobs');
|
||||
$table->integer('pending_jobs');
|
||||
$table->integer('failed_jobs');
|
||||
$table->longText('failed_job_ids');
|
||||
$table->mediumText('options')->nullable();
|
||||
$table->integer('cancelled_at')->nullable();
|
||||
$table->integer('created_at');
|
||||
$table->integer('finished_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
Schema::dropIfExists('job_batches');
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void {
|
||||
Schema::create('auth_admins', function (Blueprint $table) {
|
||||
$table->id('uid')->unique()->comment('用户ID');
|
||||
$table->string('username')->unique()->comment('用户名');
|
||||
$table->string('nickname')->nullable()->comment('昵称');
|
||||
$table->string('email')->nullable()->comment('邮箱');
|
||||
$table->string('mobile')->nullable()->comment('手机号码');
|
||||
$table->string('password')->comment('密码');
|
||||
$table->string('avatar')->nullable()->comment('头像');
|
||||
$table->unsignedBigInteger('department_id')->nullable()->comment('部门id');
|
||||
$table->unsignedTinyInteger('gender')->default(1)->comment('性别 1男 2女');
|
||||
$table->text('remark')->nullable()->comment('备注,个性签名');
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('状态 1正常 2禁用');
|
||||
$table->string('last_login_ip')->nullable()->comment('最后登录ip');
|
||||
$table->timestamp('last_login_at')->nullable()->comment('最后登录时间');
|
||||
$table->timestamp('email_verified_at')->nullable()->comment('邮箱验证时间');
|
||||
$table->timestamp('mobile_verified_at')->nullable()->comment('手机验证时间');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
$table->timestamp('deleted_at')->nullable()->comment('删除时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('后台管理员表');
|
||||
});
|
||||
Schema::create('auth_admins_roles', function (Blueprint $table) {
|
||||
$table->unsignedBigInteger('role_id')->comment('角色id');
|
||||
$table->unsignedBigInteger('uid')->comment('用户id');
|
||||
$table->primary(['role_id', 'uid']);
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('后台管理员角色对应表');
|
||||
});
|
||||
Schema::create('auth_roles', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('title', 50)->comment('角色名称');
|
||||
$table->string('name', 50)->comment('角色标识');
|
||||
$table->string('data_range')->default('all')->comment('数据范围 all全部 department本部门 department_sub本部门及以下 self仅自己');
|
||||
$table->integer('sort')->default(0)->comment('排序');
|
||||
$table->unsignedTinyInteger('status')->default(1)->comment('状态 1正常 2禁用');
|
||||
$table->string('description', 255)->nullable()->comment('角色描述');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
$table->timestamp('deleted_at')->nullable()->comment('删除时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('后台管理员角色表');
|
||||
});
|
||||
Schema::create('auth_roles_permissions', function (Blueprint $table) {
|
||||
$table->bigInteger('role_id')->unsigned()->comment('角色ID');
|
||||
$table->bigInteger('permission_id')->unsigned()->comment('权限ID');
|
||||
$table->primary(['role_id', 'permission_id']);
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('后台管理员角色权限表');
|
||||
});
|
||||
Schema::create('auth_permissions', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->integer('parent_id')->default(0)->comment('父级id');
|
||||
$table->string('title', 50)->comment('权限标题');
|
||||
$table->string('name', 50)->comment('权限名称');
|
||||
$table->string('icon', 50)->nullable()->comment('图标');
|
||||
$table->string('path', 100)->nullable()->comment('权限链接');
|
||||
$table->string('redirect', 100)->nullable()->comment('重定向');
|
||||
$table->string('component', 200)->nullable()->comment('组件');
|
||||
$table->string('type', 20)->default('menu')->comment('类型 menu菜单 button按钮 link外链 iframeIframe');
|
||||
$table->string('color', 20)->nullable()->comment('颜色');
|
||||
$table->tinyInteger('hidden')->default(0)->comment('是否显示 1显示 2不显示');
|
||||
$table->tinyInteger('hiddenBreadcrumb')->default(0)->comment('是否显示面包屑 1显示 2不显示');
|
||||
$table->tinyInteger('affix')->default(0)->comment('是否固定 1固定 2不固定');
|
||||
$table->tinyInteger('fullpage')->default(0)->comment('是否全屏 1全屏 2不全屏');
|
||||
$table->text('apiList')->nullable()->comment('接口列表');
|
||||
$table->integer('sort')->default(0)->comment('排序');
|
||||
$table->tinyInteger('status')->default(1)->comment('状态 1正常 2禁用');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
$table->timestamp('deleted_at')->nullable()->comment('删除时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('权限表');
|
||||
});
|
||||
Schema::create('auth_departments', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('parent_id')->default(0)->comment('父级id');
|
||||
$table->string('title')->comment('部门名称');
|
||||
$table->string('name')->comment('部门标识');
|
||||
$table->string('sort')->default(0)->comment('排序');
|
||||
$table->tinyInteger('status')->default(1)->comment('状态 1正常 2禁用');
|
||||
$table->string('description', 255)->nullable()->comment('部门描述');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
$table->timestamp('deleted_at')->nullable()->comment('删除时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('部门表');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::dropIfExists('auth_admins');
|
||||
Schema::dropIfExists('auth_admins_roles');
|
||||
Schema::dropIfExists('auth_roles');
|
||||
Schema::dropIfExists('auth_roles_permissions');
|
||||
Schema::dropIfExists('auth_permissions');
|
||||
Schema::dropIfExists('auth_departments');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void {
|
||||
Schema::create('system_logs', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->unsignedBigInteger('user_id')->comment('用户ID');
|
||||
$table->string('title')->comment('日志标题');
|
||||
$table->string('name')->comment('日志名称');
|
||||
$table->string('url')->comment('请求地址');
|
||||
$table->string('method')->comment('请求方法');
|
||||
$table->string('client_ip')->nullable()->comment('请求IP');
|
||||
$table->text('data')->nullable()->comment('请求数据');
|
||||
$table->text('remark')->nullable()->comment('备注');
|
||||
$table->text('browser')->nullable()->comment('浏览器');
|
||||
$table->tinyInteger('status')->default(1)->comment('状态码');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统日志表');
|
||||
});
|
||||
Schema::create('system_configs', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('title')->comment('配置标题');
|
||||
$table->string('name')->comment('配置名称');
|
||||
$table->string('values')->nullable()->comment('配置值');
|
||||
$table->string('type')->comment('配置类型');
|
||||
$table->string('group')->comment('配置分组');
|
||||
$table->jsonb('option')->nullable()->comment('配置选项');
|
||||
$table->string('remark')->nullable()->comment('配置备注');
|
||||
$table->string('sort')->default(0)->comment('排序');
|
||||
$table->tinyInteger('status')->default(1)->comment('状态');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统配置表');
|
||||
});
|
||||
Schema::create('system_dicts', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('title')->comment('字典标题');
|
||||
$table->string('values')->comment('字典值');
|
||||
$table->string('group_id')->comment('字典分组');
|
||||
$table->string('group_name')->comment('字典分组标识');
|
||||
$table->string('sort')->default(0)->comment('排序');
|
||||
$table->tinyInteger('status')->default(1)->comment('状态');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统字典表');
|
||||
});
|
||||
Schema::create('system_dict_groups', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('parent_id')->default(0)->comment('父级id');
|
||||
$table->string('title')->comment('字典分组标题');
|
||||
$table->string('name')->comment('字典分组名称');
|
||||
$table->string('sort')->default(0)->comment('排序');
|
||||
$table->tinyInteger('status')->default(1)->comment('状态');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统字典分组表');
|
||||
});
|
||||
Schema::create('system_areas', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('code')->comment('城市编码');
|
||||
$table->string('parent_code')->default(0)->comment('父级id');
|
||||
$table->string('title')->comment('城市名称');
|
||||
$table->tinyInteger('status')->default(1)->comment('状态');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统城市数据表');
|
||||
});
|
||||
|
||||
Schema::create('system_messages', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->unsignedBigInteger('send_uid')->comment('发送人uid');
|
||||
$table->string('receive_uid')->comment('接受人uid');
|
||||
$table->string('receive_group')->nullable()->comment('接受组');
|
||||
$table->string('type')->default(1)->comment('消息类型 1系统消息 2用户消息');
|
||||
$table->string('title')->comment('消息标题');
|
||||
$table->text('content')->comment('消息内容');
|
||||
$table->text('params')->nullable()->comment('消息参数');
|
||||
$table->string('url')->nullable()->comment('消息链接');
|
||||
$table->string('status')->default(1)->comment('状态 1未读 2已读');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
$table->timestamp('read_at')->nullable()->comment('已读时间');
|
||||
$table->timestamp('deleted_at')->nullable()->comment('删除时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统消息表');
|
||||
});
|
||||
|
||||
Schema::create('system_tasks', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->unsignedBigInteger('user_id')->default(0)->comment('用户id');
|
||||
$table->string('title')->comment('任务名称');
|
||||
$table->string('file')->comment('文件路径');
|
||||
$table->string('type')->default('export')->comment('任务类型 import export');
|
||||
$table->string('status')->default(1)->comment('状态 1正常 2禁用');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统excel任务表');
|
||||
});
|
||||
Schema::create('system_crontabs', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('title')->comment('定时任务标题');
|
||||
$table->string('command')->comment('定时任务命令');
|
||||
$table->string('expression')->comment('定时任务表达式');
|
||||
$table->string('status')->default(1)->comment('状态 1正常 2禁用');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统定时任务表');
|
||||
});
|
||||
Schema::create('system_client', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('title')->comment('客户端名称');
|
||||
$table->string('app_id')->comment('客户端ID');
|
||||
$table->string('secret')->comment('客户端密钥');
|
||||
$table->string('redirect')->comment('回调地址');
|
||||
$table->string('status')->default(1)->comment('状态 1正常 2禁用');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统客户端表');
|
||||
});
|
||||
Schema::create('system_client_menu', function (Blueprint $table) {
|
||||
$table->id()->uniqid()->comment('主键id');
|
||||
$table->string('client_id')->comment('客户端ID');
|
||||
$table->unsignedBigInteger('parent_id')->default(0)->comment('父级id');
|
||||
$table->string('position')->comment('菜单位置');
|
||||
$table->string('name')->nullable()->comment('菜单名称标识');
|
||||
$table->string('title')->comment('菜单标题');
|
||||
$table->string('url')->comment('菜单链接');
|
||||
$table->string('cover')->nullable()->comment('菜单图片');
|
||||
$table->string('icon')->nullable()->comment('菜单图标');
|
||||
$table->string('sort')->default(0)->comment('排序');
|
||||
$table->tinyInteger('is_show')->default(1)->comment('是否显示 1显示 2不显示');
|
||||
$table->tinyInteger('is_blank')->default(1)->comment('是否新窗口打开 1是 2否');
|
||||
$table->string('status')->default(1)->comment('状态 1正常 2禁用');
|
||||
$table->timestamp('created_at')->nullable()->comment('创建时间');
|
||||
$table->timestamp('updated_at')->nullable()->comment('更新时间');
|
||||
|
||||
$table->engine = 'InnoDB';
|
||||
$table->charset = 'utf8mb4';
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->comment('系统客户端菜单表');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::dropIfExists('system_logs');
|
||||
Schema::dropIfExists('system_configs');
|
||||
Schema::dropIfExists('system_dicts');
|
||||
Schema::dropIfExists('system_dict_groups');
|
||||
Schema::dropIfExists('system_areas');
|
||||
Schema::dropIfExists('system_messages');
|
||||
Schema::dropIfExists('system_tasks');
|
||||
Schema::dropIfExists('system_crontabs');
|
||||
Schema::dropIfExists('system_client');
|
||||
Schema::dropIfExists('system_client_menu');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void {
|
||||
Schema::create('modules', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title', 50)->nullable()->comment('模块标题');
|
||||
$table->string('name')->unique()->comment('模块标识');
|
||||
$table->text('description')->nullable()->comment('模块描述');
|
||||
$table->boolean('status')->comment('模块状态');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::dropIfExists('modules');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use App\Services\Auth\MenuService;
|
||||
|
||||
class AdminSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void {
|
||||
DB::table('auth_admins')->insert([
|
||||
'username' => 'admin',
|
||||
'nickname' => '超级管理员',
|
||||
'email' => 'admin@admin.com',
|
||||
'mobile' => '13888888888',
|
||||
'password' => Hash::make('admin888'),
|
||||
'department_id' => 1,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
DB::table('auth_departments')->insert([
|
||||
'title' => '总部',
|
||||
'name' => 'root',
|
||||
'parent_id' => 0,
|
||||
'sort' => 0,
|
||||
'description' => '总部',
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
DB::table('auth_roles')->insert([
|
||||
'title' => '超级管理员',
|
||||
'name' => 'admin',
|
||||
'description' => '超级管理员',
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
app(MenuService::class)->importMenu($this->getPermissions(), 0);
|
||||
}
|
||||
|
||||
public function getPermissions(){
|
||||
$permissions = [
|
||||
['title' => '首页', 'name' => 'home', 'path' => '/home', 'component' => '', 'type' => 'menu', 'sort' => 0, 'children' => [
|
||||
['title' => '仪表盘', 'name' => 'dashboard', 'path' => '/dashboard', 'component' => 'home', 'type' => 'menu', 'affix' => 1],
|
||||
['title' => '个人中心', 'name' => 'ucenter', 'path' => '/ucenter', 'component' => 'ucenter', 'type' => 'menu'],
|
||||
]],
|
||||
['title' => '权限', 'name' => 'auth', 'path' => '/auth', 'component' => '', 'type' => 'menu', 'sort' => 99, 'children' => [
|
||||
['title' => '用户管理', 'name' => 'auth.user', 'path' => '/auth/user', 'component' => 'auth/user', 'type' => 'menu'],
|
||||
['title' => '角色管理', 'name' => 'auth.role', 'path' => '/auth/role', 'component' => 'auth/role', 'type' => 'menu'],
|
||||
['title' => '权限管理', 'name' => 'auth.permission', 'path' => '/auth/permission', 'component' => 'auth/permission', 'type' => 'menu'],
|
||||
['title' => '部门管理', 'name' => 'auth.department', 'path' => '/auth/department', 'component' => 'auth/department', 'type' => 'menu'],
|
||||
]]
|
||||
];
|
||||
return $permissions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\System\Area;
|
||||
|
||||
class CitySeeder extends Seeder{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void {
|
||||
$area = json_decode(file_get_contents(database_path('seeders/area.json')), true);
|
||||
$data = [];
|
||||
foreach ($area as $value) {
|
||||
$value['created_at'] = date('Y-m-d H:i:s');
|
||||
$value['updated_at'] = date('Y-m-d H:i:s');
|
||||
$data[] = $value;
|
||||
}
|
||||
Area::insert($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder {
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*/
|
||||
public function run(): void {
|
||||
$this->call([
|
||||
AdminSeeder::class,
|
||||
SystemSeeder::class,
|
||||
CitySeeder::class
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Services\Auth\MenuService;
|
||||
|
||||
class SystemSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void {
|
||||
$this->insertSettingDict();
|
||||
$this->insertDataAuthDict();
|
||||
$this->insertAdsDict();
|
||||
$this->addModelFieldTypeDict();
|
||||
$this->insertClientMenuPosition();
|
||||
$this->insertPermissions();
|
||||
}
|
||||
|
||||
public function insertSettingDict(){
|
||||
$group_id = DB::table('system_dict_groups')->insertGetId([
|
||||
'parent_id' => 0,
|
||||
'title' => '配置分组',
|
||||
'name' => 'setting_group',
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
if($group_id){
|
||||
$dict = DB::table('system_dicts')->insert([
|
||||
['group_id' => $group_id, 'group_name' => 'setting_group', 'title' => '基础配置', 'values' => 'base', 'sort' => 1, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['group_id' => $group_id, 'group_name' => 'setting_group', 'title' => '上传配置', 'values' => 'upload', 'sort' => 1, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
]);
|
||||
DB::table('system_configs')->insert([
|
||||
['name' => 'system_name', 'title' => '系统名称', 'values' => 'SentOS', 'type' => 'string', 'group' => 'base', 'sort' => 1, 'status' => 1, 'remark' => '系统名称', 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['name' => 'system_logo', 'title' => '系统Logo', 'values' => '', 'type' => 'image', 'group' => 'base', 'sort' => 2, 'status' => 1, 'remark' => '系统Logo', 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['name' => 'system_email', 'title' => '邮箱', 'values' => '', 'type' => 'string', 'group' => 'base', 'sort' => 6, 'status' => 1, 'remark' => '邮箱', 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['name' => 'system_copyright', 'title' => '版权信息', 'values' => 'Copyright © 2019-2024 SentCMS All Rights Reserved.', 'type' => 'string', 'group' => 'base', 'sort' => 3, 'status' => 1, 'remark' => '版权信息', 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['name' => 'system_icp', 'title' => '备案信息', 'values' => '', 'type' => 'string', 'group' =>'base', 'sort' => 4, 'status' => 1, 'remark' => '备案信息', 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['name' => 'upload_way', 'title' => '上传引擎', 'values' => 'public', 'type' => 'radio', 'group' =>'upload', 'sort' => 1, 'status' => 1, 'remark' => '上传引擎', 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function insertDataAuthDict(){
|
||||
$group_id = DB::table('system_dict_groups')->insertGetId([
|
||||
'parent_id' => 0,
|
||||
'title' => '数据权限分组',
|
||||
'name' => 'data_auth',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
if($group_id){
|
||||
DB::table('system_dicts')->insert([
|
||||
[
|
||||
'group_id' => $group_id,
|
||||
'group_name' => 'data_auth',
|
||||
'title' => '全部数据',
|
||||
'values' => 'all',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
],
|
||||
[
|
||||
'group_id' => $group_id,
|
||||
'group_name' => 'data_auth',
|
||||
'title' => '本部门数据',
|
||||
'values' => 'department',
|
||||
'sort' => 2,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
],
|
||||
[
|
||||
'group_id' => $group_id,
|
||||
'group_name' => 'data_auth',
|
||||
'title' => '本部门及以下数据',
|
||||
'values' => 'department_sub',
|
||||
'sort' => 3,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
],
|
||||
[
|
||||
'group_id' => $group_id,
|
||||
'group_name' => 'data_auth',
|
||||
'title' => '仅自己数据',
|
||||
'values' => 'self',
|
||||
'sort' => 4,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function insertAdsDict(){
|
||||
$group_id = DB::table('system_dict_groups')->insertGetId([
|
||||
'parent_id' => 0,
|
||||
'title' => '广告位',
|
||||
'name' => 'ads_places',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
if($group_id){
|
||||
DB::table('system_dicts')->insert([
|
||||
[
|
||||
'group_id' => $group_id,
|
||||
'group_name' => 'ads_places',
|
||||
'title' => '首页轮播',
|
||||
'values' => 'index_banner',
|
||||
'sort' => 2,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function insertClientMenuPosition(){
|
||||
$group_id = DB::table('system_dict_groups')->insertGetId([
|
||||
'parent_id' => 0,
|
||||
'title' => '菜单位置',
|
||||
'name' => 'client_menu_position',
|
||||
'sort' => 3,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
if($group_id){
|
||||
DB::table('system_dicts')->insert([
|
||||
[
|
||||
'group_id' => $group_id,
|
||||
'group_name' => 'client_menu_position',
|
||||
'title' => '顶部菜单',
|
||||
'values' => 'top',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @title 添加字典
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addModelFieldTypeDict(){
|
||||
$group_id = DB::table('system_dict_groups')->insertGetId([
|
||||
'parent_id' => 0,
|
||||
'title' => '字段类型',
|
||||
'name' => 'field_type',
|
||||
'status' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
if($group_id){
|
||||
$dict = DB::table('system_dicts')->insert([
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '单行文本', 'values' => 'string', 'sort' =>1, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '多行文本', 'values' => 'text', 'sort' => 2, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '单选按钮', 'values' => 'radio', 'sort' => 3, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '多选按钮', 'values' => 'checkbox', 'sort' => 4, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '下拉列表', 'values' => 'select', 'sort' => 5, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '字典选择', 'values' => 'sSelect', 'sort' => 5, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' =>date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '树形选择', 'values' => 'sSelectTree', 'sort' => 6, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '日期', 'values' => 'date', 'sort' => 6, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '日期时间', 'values' => 'datetime', 'sort' => 7, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '文件', 'values' => 'file', 'sort' => 8, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '图片', 'values' => 'image', 'sort' => 9, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '多图', 'values' => 'images', 'sort' => 10, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '富文本', 'values' => 'editor', 'sort' => 10, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '视频', 'values' => 'video', 'sort' => 10, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '音频', 'values' => 'audio', 'sort' => 10, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')],
|
||||
['group_id' => $group_id, 'group_name' => 'field_type', 'title' => '数字', 'values' => 'number', 'sort' => 3, 'status' => 1, 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s')]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function insertPermissions(){
|
||||
$permissions = [
|
||||
['title' => '系统', 'name' => 'system', 'path' => '/system', 'component' => '', 'type' => 'menu', 'sort' => 100, 'children' => [
|
||||
['title' => '系统设置', 'name' => 'system.setting', 'path' => '/system/setting', 'component' => 'system/setting', 'type' => 'menu'],
|
||||
['title' => '城市数据', 'name' => 'system.area', 'path' => '/system/area', 'component' => 'system/area', 'type' => 'menu'],
|
||||
['title' => '字典管理', 'name' => 'system.dic', 'path' => '/system/dic', 'component' => 'system/dic', 'type' => 'menu'],
|
||||
['title' => '客户端管理', 'name' => 'system.client', 'path' => '/system/client', 'component' => 'system/client', 'type' => 'menu'],
|
||||
['title' => '模块管理', 'name' => 'system.modules', 'path' => '/system/modules', 'component' => 'system/modules', 'type' => 'menu'],
|
||||
['title' => '系统日志', 'name' => 'system.log', 'path' => '/system/log', 'component' => 'system/log', 'type' => 'menu'],
|
||||
['title' => '定时任务', 'name' => 'system.crontab', 'path' => '/system/crontab', 'component' => 'system/crontab', 'type' => 'menu'],
|
||||
]]
|
||||
];
|
||||
app(MenuService::class)->importMenu($permissions, 0);
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,960 @@
|
||||
# 记账功能模块文档
|
||||
|
||||
## 概述
|
||||
|
||||
记账功能模块提供了完整的多用户多家庭记账功能,支持:
|
||||
- 多家庭管理(每个用户可以加入多个家庭)
|
||||
- 家庭成员管理(owner/admin/member角色)
|
||||
- 收支记录管理
|
||||
- 账户管理
|
||||
- 数据权限控制
|
||||
|
||||
## 模块架构
|
||||
|
||||
本模块采用Laravel模块化架构,所有代码位于 `modules/Account` 目录下:
|
||||
|
||||
```
|
||||
modules/Account/
|
||||
├── app/
|
||||
│ ├── Controllers/
|
||||
│ │ ├── Api/ # 前端API控制器
|
||||
│ │ └── Admin/ # 后台管理控制器
|
||||
│ ├── Models/ # 数据模型
|
||||
│ ├── Providers/ # 服务提供者
|
||||
│ └── Services/ # 业务逻辑服务层
|
||||
├── database/
|
||||
│ └── migrations/ # 数据库迁移文件
|
||||
├── routes/
|
||||
│ ├── api.php # 前端API路由
|
||||
│ └── admin.php # 后台管理路由
|
||||
└── module.json # 模块配置文件
|
||||
```
|
||||
|
||||
### 命名空间
|
||||
|
||||
- 模型:`Modules\Account\Models\`
|
||||
- 控制器:`Modules\Account\Controllers\Api\` 或 `Modules\Account\Controllers\Admin\`
|
||||
- 服务:`Modules\Account\Services\`
|
||||
- 路由:自动加载,无需手动配置
|
||||
|
||||
### 路由说明
|
||||
|
||||
模块路由已自动注册,无需在主路由文件中配置:
|
||||
|
||||
- 前端API路由位于 `modules/Account/routes/api.php`
|
||||
- 后台管理路由位于 `modules/Account/routes/admin.php`
|
||||
|
||||
所有路由由模块的 RouteServiceProvider 自动加载。
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
### 1. account_families(家庭表)
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | bigint | 主键ID |
|
||||
| name | varchar(50) | 家庭名称 |
|
||||
| description | text | 家庭描述 |
|
||||
| avatar | varchar(255) | 家庭头像 |
|
||||
| created_at | datetime | 创建时间 |
|
||||
| updated_at | datetime | 更新时间 |
|
||||
| deleted_at | datetime | 删除时间(软删除) |
|
||||
|
||||
### 2. account_family_members(家庭成员关系表)
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | bigint | 主键ID |
|
||||
| family_id | bigint | 家庭ID |
|
||||
| user_id | bigint | 用户ID |
|
||||
| role | varchar(20) | 角色:owner-拥有者,admin-管理员,member-成员 |
|
||||
| created_at | datetime | 创建时间 |
|
||||
| updated_at | datetime | 更新时间 |
|
||||
| deleted_at | datetime | 删除时间(软删除) |
|
||||
|
||||
**唯一索引**: `family_id` + `user_id`(防止重复加入)
|
||||
|
||||
### 3. account_records(记账记录表)
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | bigint | 主键ID |
|
||||
| user_id | bigint | 用户ID |
|
||||
| family_id | bigint | 家庭ID |
|
||||
| member_id | bigint | 成员ID |
|
||||
| account_id | bigint | 账户ID |
|
||||
| type | varchar(20) | 类型:income-收入,expense-支出 |
|
||||
| amount | decimal(10,2) | 金额 |
|
||||
| category | varchar(50) | 分类 |
|
||||
| date | date | 日期 |
|
||||
| time | varchar(10) | 时间 |
|
||||
| remark | text | 备注 |
|
||||
| created_at | datetime | 创建时间 |
|
||||
| updated_at | datetime | 更新时间 |
|
||||
| deleted_at | datetime | 删除时间(软删除) |
|
||||
|
||||
### 2. account_members(家庭成员表)
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | bigint | 主键ID |
|
||||
| user_id | bigint | 用户ID |
|
||||
| family_id | bigint | 家庭ID |
|
||||
| name | varchar(50) | 成员名称 |
|
||||
| avatar | varchar(255) | 头像 |
|
||||
| created_at | datetime | 创建时间 |
|
||||
| updated_at | datetime | 更新时间 |
|
||||
| deleted_at | datetime | 删除时间(软删除) |
|
||||
|
||||
### 3. accounts(账户表)
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | bigint | 主键ID |
|
||||
| user_id | bigint | 用户ID |
|
||||
| family_id | bigint | 家庭ID |
|
||||
| name | varchar(50) | 账户名称 |
|
||||
| type | varchar(20) | 账户类型:cash-现金,bank-银行卡,alipay-支付宝,wechat-微信 |
|
||||
| balance | decimal(10,2) | 余额 |
|
||||
| icon | varchar(255) | 图标 |
|
||||
| created_at | datetime | 创建时间 |
|
||||
| updated_at | datetime | 更新时间 |
|
||||
| deleted_at | datetime | 删除时间(软删除) |
|
||||
|
||||
## 前端API接口
|
||||
|
||||
### 基础URL
|
||||
`/api/account`
|
||||
|
||||
### 记账记录接口
|
||||
|
||||
#### 1. 获取记账记录列表
|
||||
- **路径**: `GET /api/account/records`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `family_id` (可选): 家庭ID,不传则返回当前用户所有家庭的记录
|
||||
- `member_id` (可选): 成员ID
|
||||
- `account_id` (可选): 账户ID
|
||||
- `type` (可选): 类型(income/expense)
|
||||
- `start_date` (可选): 开始日期
|
||||
- `end_date` (可选): 结束日期
|
||||
- `page` (可选): 页码
|
||||
- `limit` (可选): 每页数量,默认30
|
||||
- **响应**:
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"list": [...],
|
||||
"total": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 获取记账记录详情
|
||||
- **路径**: `GET /api/account/records/{id}`
|
||||
- **认证**: 需要
|
||||
- **响应**: 单条记录详情
|
||||
|
||||
#### 3. 创建记账记录
|
||||
- **路径**: `POST /api/account/records`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `member_id` (必需): 成员ID
|
||||
- `account_id` (必需): 账户ID
|
||||
- `type` (必需): 类型(income/expense)
|
||||
- `amount` (必需): 金额
|
||||
- `category` (必需): 分类
|
||||
- `date` (必需): 日期
|
||||
- `time` (必需): 时间
|
||||
- `remark` (可选): 备注
|
||||
- **响应**: 创建的记录
|
||||
|
||||
#### 4. 更新记账记录
|
||||
- **路径**: `PUT /api/account/records/{id}`
|
||||
- **认证**: 需要
|
||||
- **参数**: 同创建接口(所有字段可选)
|
||||
- **响应**: 更新后的记录
|
||||
|
||||
#### 5. 删除记账记录
|
||||
- **路径**: `DELETE /api/account/records/{id}`
|
||||
- **认证**: 需要
|
||||
- **响应**: 删除成功
|
||||
|
||||
#### 6. 获取统计数据
|
||||
- **路径**: `GET /api/account/records/statistics`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `start_date` (可选): 开始日期
|
||||
- `end_date` (可选): 结束日期
|
||||
- **响应**:
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total_income": 10000.00,
|
||||
"total_expense": 5000.00,
|
||||
"balance": 5000.00,
|
||||
"category_stats": [...],
|
||||
"date_stats": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 家庭管理接口
|
||||
|
||||
#### 1. 获取用户的家庭列表
|
||||
- **路径**: `GET /api/account/families`
|
||||
- **认证**: 需要
|
||||
- **响应**:
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"list": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "我的家",
|
||||
"description": "温馨的家",
|
||||
"avatar": "avatar.jpg",
|
||||
"user_role": "owner",
|
||||
"is_owner": true,
|
||||
"can_manage": true,
|
||||
"family_members": [...],
|
||||
"created_at": "2025-01-01 00:00:00"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 获取家庭详情
|
||||
- **路径**: `GET /api/account/families/{id}`
|
||||
- **认证**: 需要
|
||||
- **权限**: 用户必须属于该家庭
|
||||
- **响应**: 家庭详情(包含成员、账户、记录信息)
|
||||
|
||||
#### 3. 创建家庭
|
||||
- **路径**: `POST /api/account/families`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `name` (必需): 家庭名称(最多50字符)
|
||||
- `description` (可选): 家庭描述(最多255字符)
|
||||
- `avatar` (可选): 家庭头像
|
||||
- **响应**: 创建的家庭(创建者自动成为owner)
|
||||
|
||||
#### 4. 更新家庭
|
||||
- **路径**: `PUT /api/account/families/{id}`
|
||||
- **认证**: 需要
|
||||
- **权限**: owner或admin
|
||||
- **参数**: 同创建接口(所有字段可选)
|
||||
- **响应**: 更新后的家庭
|
||||
|
||||
#### 5. 删除家庭
|
||||
- **路径**: `DELETE /api/account/families/{id}`
|
||||
- **认证**: 需要
|
||||
- **权限**: 仅owner
|
||||
- **限制**: 家庭下不能有关联账户
|
||||
- **响应**: 删除成功
|
||||
|
||||
#### 6. 邀请成员加入家庭
|
||||
- **路径**: `POST /api/account/families/{familyId}/invite`
|
||||
- **认证**: 需要
|
||||
- **权限**: owner或admin
|
||||
- **参数**:
|
||||
- `user_id` (必需): 被邀请用户ID
|
||||
- **限制**: 用户不能已经在家庭中
|
||||
- **响应**: 邀请成功
|
||||
|
||||
#### 7. 移除家庭成员
|
||||
- **路径**: `DELETE /api/account/families/{familyId}/members/{memberId}`
|
||||
- **认证**: 需要
|
||||
- **权限**: owner或admin
|
||||
- **限制**: 不能移除owner
|
||||
- **响应**: 移除成功
|
||||
|
||||
#### 8. 更新成员角色
|
||||
- **路径**: `PUT /api/account/families/{familyId}/members/{memberId}/role`
|
||||
- **认证**: 需要
|
||||
- **权限**: 仅owner
|
||||
- **参数**:
|
||||
- `role` (必需): 新角色(owner/admin/member)
|
||||
- **限制**: 不能修改owner的角色
|
||||
- **响应**: 更新成功
|
||||
|
||||
#### 9. 退出家庭
|
||||
- **路径**: `POST /api/account/families/{id}/leave`
|
||||
- **认证**: 需要
|
||||
- **限制**: owner不能退出,只能删除家庭
|
||||
- **响应**: 退出成功
|
||||
|
||||
### 家庭成员接口
|
||||
|
||||
#### 1. 获取成员列表
|
||||
- **路径**: `GET /api/account/members`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `family_id` (可选): 家庭ID,不传则返回当前用户所有家庭的成员
|
||||
- **响应**:
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"list": [...],
|
||||
"total": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 获取成员详情
|
||||
- **路径**: `GET /api/account/members/{id}`
|
||||
- **认证**: 需要
|
||||
- **响应**: 成员详情
|
||||
|
||||
#### 3. 创建成员
|
||||
- **路径**: `POST /api/account/members`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `name` (必需): 成员名称
|
||||
- `avatar` (可选): 头像
|
||||
- **响应**: 创建的成员
|
||||
|
||||
#### 4. 更新成员
|
||||
- **路径**: `PUT /api/account/members/{id}`
|
||||
- **认证**: 需要
|
||||
- **参数**: 同创建接口(所有字段可选)
|
||||
- **响应**: 更新后的成员
|
||||
|
||||
#### 5. 删除成员
|
||||
- **路径**: `DELETE /api/account/members/{id}`
|
||||
- **认证**: 需要
|
||||
- **响应**: 删除成功
|
||||
|
||||
### 账户管理接口
|
||||
|
||||
#### 1. 获取账户列表
|
||||
- **路径**: `GET /api/account/accounts`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `family_id` (可选): 家庭ID,不传则返回当前用户所有家庭的账户
|
||||
- **响应**:
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"list": [...],
|
||||
"total": 5,
|
||||
"total_balance": 10000.00
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 获取账户详情
|
||||
- **路径**: `GET /api/account/accounts/{id}`
|
||||
- **认证**: 需要
|
||||
- **响应**: 账户详情
|
||||
|
||||
#### 3. 创建账户
|
||||
- **路径**: `POST /api/account/accounts`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `name` (必需): 账户名称
|
||||
- `type` (必需): 账户类型(cash/bank/alipay/wechat)
|
||||
- `balance` (可选): 初始余额
|
||||
- `icon` (可选): 图标
|
||||
- **响应**: 创建的账户
|
||||
|
||||
#### 4. 更新账户
|
||||
- **路径**: `PUT /api/account/accounts/{id}`
|
||||
- **认证**: 需要
|
||||
- **参数**: 同创建接口(所有字段可选)
|
||||
- **响应**: 更新后的账户
|
||||
|
||||
#### 5. 删除账户
|
||||
- **路径**: `DELETE /api/account/accounts/{id}`
|
||||
- **认证**: 需要
|
||||
- **响应**: 删除成功
|
||||
|
||||
#### 6. 重新计算账户余额
|
||||
- **路径**: `POST /api/account/accounts/{id}/recalculate`
|
||||
- **认证**: 需要
|
||||
- **响应**: 更新后的账户
|
||||
|
||||
## 后台管理接口
|
||||
|
||||
### 基础URL
|
||||
`/admin/account`
|
||||
|
||||
### 记账记录管理
|
||||
|
||||
#### 1. 获取记账记录列表
|
||||
- **路径**: `GET /admin/account/records/index`
|
||||
- **认证**: 需要
|
||||
- **参数**: 同前端API,额外支持
|
||||
- `user_id` (可选): 用户ID
|
||||
- **响应**: 记录列表(包含用户、成员、账户信息)
|
||||
|
||||
#### 2. 获取记账记录详情
|
||||
- **路径**: `GET /admin/account/records/show`
|
||||
- **认证**: 需要
|
||||
- **响应**: 记录详情
|
||||
|
||||
#### 3. 删除记账记录
|
||||
- **路径**: `DELETE /admin/account/records/delete`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 记录ID
|
||||
- **响应**: 删除成功(软删除)
|
||||
|
||||
#### 4. 恢复记账记录
|
||||
- **路径**: `PUT /admin/account/records/restore`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 记录ID
|
||||
- **响应**: 恢复成功
|
||||
|
||||
#### 5. 获取统计数据
|
||||
- **路径**: `GET /admin/account/records/statistics`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `user_id` (可选): 用户ID
|
||||
- `start_date` (可选): 开始日期
|
||||
- `end_date` (可选): 结束日期
|
||||
- **响应**:
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total_income": 10000.00,
|
||||
"total_expense": 5000.00,
|
||||
"balance": 5000.00,
|
||||
"user_stats": [...],
|
||||
"category_stats": [...],
|
||||
"total_records": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 家庭成员管理
|
||||
|
||||
#### 1. 获取成员列表
|
||||
- **路径**: `GET /admin/account/members/index`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `user_id` (可选): 用户ID
|
||||
- **响应**: 成员列表(包含统计信息)
|
||||
|
||||
#### 2. 获取成员详情
|
||||
- **路径**: `GET /admin/account/members/show`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 成员ID
|
||||
- **响应**: 成员详情(包含关联记录)
|
||||
|
||||
#### 3. 创建成员
|
||||
- **路径**: `POST /admin/account/members/add`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `user_id` (必需): 用户ID
|
||||
- `name` (必需): 成员名称
|
||||
- `avatar` (可选): 头像
|
||||
- **响应**: 创建的成员
|
||||
|
||||
#### 4. 更新成员
|
||||
- **路径**: `PUT /admin/account/members/edit`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `id` (必需): 成员ID
|
||||
- 其他字段同创建接口
|
||||
- **响应**: 更新后的成员
|
||||
|
||||
#### 5. 删除成员
|
||||
- **路径**: `DELETE /admin/account/members/delete`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 成员ID
|
||||
- **响应**: 删除成功(软删除)
|
||||
|
||||
#### 6. 恢复成员
|
||||
- **路径**: `PUT /admin/account/members/restore`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 成员ID
|
||||
- **响应**: 恢复成功
|
||||
|
||||
### 账户管理
|
||||
|
||||
#### 1. 获取账户列表
|
||||
- **路径**: `GET /admin/account/accounts/index`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `user_id` (可选): 用户ID
|
||||
- `type` (可选): 账户类型
|
||||
- **响应**: 账户列表(包含统计信息)
|
||||
|
||||
#### 2. 获取账户详情
|
||||
- **路径**: `GET /admin/account/accounts/show`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 账户ID
|
||||
- **响应**: 账户详情(包含关联记录)
|
||||
|
||||
#### 3. 创建账户
|
||||
- **路径**: `POST /admin/account/accounts/add`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `user_id` (必需): 用户ID
|
||||
- `name` (必需): 账户名称
|
||||
- `type` (必需): 账户类型
|
||||
- `balance` (可选): 初始余额
|
||||
- `icon` (可选): 图标
|
||||
- **响应**: 创建的账户
|
||||
|
||||
#### 4. 更新账户
|
||||
- **路径**: `PUT /admin/account/accounts/edit`
|
||||
- **认证**: 需要
|
||||
- **参数**:
|
||||
- `id` (必需): 账户ID
|
||||
- 其他字段同创建接口
|
||||
- **响应**: 更新后的账户
|
||||
|
||||
#### 5. 删除账户
|
||||
- **路径**: `DELETE /admin/account/accounts/delete`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 账户ID
|
||||
- **响应**: 删除成功(软删除)
|
||||
|
||||
#### 6. 恢复账户
|
||||
- **路径**: `PUT /admin/account/accounts/restore`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 账户ID
|
||||
- **响应**: 恢复成功
|
||||
|
||||
#### 7. 重新计算账户余额
|
||||
- **路径**: `POST /admin/account/accounts/recalculate`
|
||||
- **认证**: 需要
|
||||
- **参数**: `id` (必需): 账户ID
|
||||
- **响应**: 更新后的账户
|
||||
|
||||
#### 8. 获取账户类型列表
|
||||
- **路径**: `GET /admin/account/accounts/types`
|
||||
- **认证**: 需要
|
||||
- **响应**:
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"cash": "现金",
|
||||
"bank": "银行卡",
|
||||
"alipay": "支付宝",
|
||||
"wechat": "微信"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 后台管理系统
|
||||
|
||||
### 概述
|
||||
|
||||
后台管理系统提供了完整的管理功能,位于 `resources/admin` 目录下,使用 Vue 3 + Element Plus + Vite 技术栈。
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
resources/admin/src/
|
||||
├── api/
|
||||
│ ├── module/
|
||||
│ │ └── account.js # 记账模块API接口
|
||||
│ └── index.js # API自动导入
|
||||
├── pages/
|
||||
│ └── account/ # 记账模块页面
|
||||
│ ├── families/ # 家庭管理
|
||||
│ ├── accounts/ # 账户管理
|
||||
│ ├── members/ # 成员管理
|
||||
│ └── records/ # 记录管理
|
||||
└── router/
|
||||
├── accountRouter.js # 记账模块路由
|
||||
└── index.js # 路由主文件
|
||||
```
|
||||
|
||||
### 功能模块
|
||||
|
||||
#### 1. 家庭管理 (`/account/families`)
|
||||
|
||||
**功能特性**:
|
||||
- 家庭列表展示(支持搜索)
|
||||
- 查看家庭详情
|
||||
- 创建/编辑家庭
|
||||
- 删除家庭(含确认提示)
|
||||
- 显示成员数量和账户数量统计
|
||||
|
||||
**页面组件**:
|
||||
- `index.vue`: 家庭列表页
|
||||
- `save.vue`: 家庭添加/编辑/查看页
|
||||
|
||||
**搜索条件**:
|
||||
- 家庭名称
|
||||
|
||||
**操作权限**:
|
||||
- 添加家庭
|
||||
- 编辑家庭信息
|
||||
- 查看家庭详情
|
||||
- 删除家庭
|
||||
|
||||
#### 2. 账户管理 (`/account/accounts`)
|
||||
|
||||
**功能特性**:
|
||||
- 账户列表展示(支持搜索和筛选)
|
||||
- 查看账户详情
|
||||
- 创建/编辑账户
|
||||
- 删除账户(含确认提示)
|
||||
- 显示账户余额(正数绿色,负数红色)
|
||||
- 支持多种账户类型(现金、银行卡、信用卡、支付宝、微信等)
|
||||
|
||||
**页面组件**:
|
||||
- `index.vue`: 账户列表页
|
||||
- `save.vue`: 账户添加/编辑/查看页
|
||||
|
||||
**搜索条件**:
|
||||
- 账户名称
|
||||
- 账户类型
|
||||
|
||||
**表单字段**:
|
||||
- 账户名称(必填,2-50字符)
|
||||
- 账户类型(必填)
|
||||
- 所属家庭(必填,下拉选择)
|
||||
- 初始余额(可选,数字)
|
||||
- 备注(可选,最多200字符)
|
||||
|
||||
#### 3. 成员管理 (`/account/members`)
|
||||
|
||||
**功能特性**:
|
||||
- 成员列表展示(支持搜索和筛选)
|
||||
- 查看成员详情
|
||||
- 添加/编辑成员
|
||||
- 移除成员(含确认提示)
|
||||
- 显示成员角色(owner/admin/member)
|
||||
- 显示成员所属家庭
|
||||
|
||||
**页面组件**:
|
||||
- `index.vue`: 成员列表页
|
||||
- `save.vue`: 成员添加/编辑/查看页
|
||||
|
||||
**搜索条件**:
|
||||
- 成员昵称
|
||||
- 成员角色
|
||||
|
||||
**表单字段**:
|
||||
- 所属家庭(必填,下拉选择)
|
||||
- 用户手机号(必填,用于查找用户)
|
||||
- 角色(必填,下拉选择)
|
||||
- 自动显示用户详细信息
|
||||
|
||||
**角色说明**:
|
||||
- owner(家庭主):最高权限,红色标签
|
||||
- admin(管理员):管理权限,橙色标签
|
||||
- member(成员):普通权限,蓝色标签
|
||||
|
||||
#### 4. 记录管理 (`/account/records`)
|
||||
|
||||
**功能特性**:
|
||||
- 记录列表展示(支持搜索和筛选)
|
||||
- 查看记录详情
|
||||
- 创建/编辑记录
|
||||
- 删除记录(含确认提示)
|
||||
- 显示金额(收入绿色+号,支出红色-号)
|
||||
- 显示记录类型(收入/支出标签)
|
||||
- 支持日期范围筛选
|
||||
|
||||
**页面组件**:
|
||||
- `index.vue`: 记录列表页
|
||||
- `save.vue`: 记录添加/编辑/查看页
|
||||
|
||||
**搜索条件**:
|
||||
- 关键词
|
||||
- 记录类型(收入/支出)
|
||||
- 日期范围
|
||||
|
||||
**表单字段**:
|
||||
- 记录类型(必填,单选:收入/支出)
|
||||
- 所属家庭(必填,下拉选择)
|
||||
- 账户(必填,下拉选择,根据家庭筛选)
|
||||
- 分类(必填,下拉选择,根据记录类型筛选)
|
||||
- 金额(必填,数字)
|
||||
- 日期(必填,日期选择器)
|
||||
- 备注(可选,最多200字符)
|
||||
|
||||
**联动功能**:
|
||||
- 选择家庭后,自动加载该家庭的账户列表
|
||||
- 切换记录类型后,自动筛选对应的分类列表
|
||||
|
||||
### API接口封装
|
||||
|
||||
所有API接口统一封装在 `resources/admin/src/api/module/account.js` 中:
|
||||
|
||||
```javascript
|
||||
// 家庭管理
|
||||
this.$API.account.family.list.get(params)
|
||||
this.$API.account.family.detail.get(params)
|
||||
this.$API.account.family.add.post(params)
|
||||
this.$API.account.family.edit.post(params)
|
||||
this.$API.account.family.delete.post(params)
|
||||
|
||||
// 账户管理
|
||||
this.$API.account.accounts.list.get(params)
|
||||
this.$API.account.accounts.detail.get(params)
|
||||
this.$API.account.accounts.add.post(params)
|
||||
this.$API.account.accounts.edit.post(params)
|
||||
this.$API.account.accounts.delete.post(params)
|
||||
|
||||
// 成员管理
|
||||
this.$API.account.members.list.get(params)
|
||||
this.$API.account.members.detail.get(params)
|
||||
this.$API.account.members.add.post(params)
|
||||
this.$API.account.members.edit.post(params)
|
||||
this.$API.account.members.delete.post(params)
|
||||
|
||||
// 记录管理
|
||||
this.$API.account.records.list.get(params)
|
||||
this.$API.account.records.detail.get(params)
|
||||
this.$API.account.records.add.post(params)
|
||||
this.$API.account.records.edit.post(params)
|
||||
this.$API.account.records.delete.post(params)
|
||||
```
|
||||
|
||||
### 路由配置
|
||||
|
||||
记账模块路由已配置在 `resources/admin/src/router/accountRouter.js`:
|
||||
|
||||
```javascript
|
||||
{
|
||||
path: "/account",
|
||||
meta: {
|
||||
title: "记账管理",
|
||||
icon: "el-icon-wallet"
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/account/families",
|
||||
meta: { title: "家庭管理", icon: "el-icon-house" }
|
||||
},
|
||||
{
|
||||
path: "/account/accounts",
|
||||
meta: { title: "账户管理", icon: "el-icon-bank-card" }
|
||||
},
|
||||
{
|
||||
path: "/account/members",
|
||||
meta: { title: "成员管理", icon: "el-icon-user" }
|
||||
},
|
||||
{
|
||||
path: "/account/records",
|
||||
meta: { title: "记录管理", icon: "el-icon-notebook-2" }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
路由已自动注册到主路由文件 `index.js`,无需额外配置。
|
||||
|
||||
### 通用功能
|
||||
|
||||
#### 表格组件
|
||||
|
||||
使用 `scTable` 组件实现统一的表格功能:
|
||||
- 自动分页
|
||||
- 自动加载
|
||||
- 参数搜索
|
||||
- 行选择
|
||||
- 固定列
|
||||
|
||||
#### 抽屉组件
|
||||
|
||||
使用 `el-drawer` 组件实现表单弹窗:
|
||||
- 三种模式:add(添加)、edit(编辑)、show(查看)
|
||||
- 表单验证
|
||||
- 关闭时自动重置
|
||||
- 成功回调刷新列表
|
||||
|
||||
#### 权限控制
|
||||
|
||||
所有删除操作都使用 `el-popconfirm` 进行二次确认:
|
||||
- 防止误删除
|
||||
- 支持取消操作
|
||||
- 显示确认提示文字
|
||||
|
||||
#### 数据展示
|
||||
|
||||
- 金额显示:保留2位小数,根据正负值显示不同颜色
|
||||
- 日期显示:统一格式化
|
||||
- 角色标签:使用不同颜色区分
|
||||
- 头像显示:支持头像上传和展示
|
||||
|
||||
### 使用说明
|
||||
|
||||
#### 1. 启动开发服务器
|
||||
|
||||
```bash
|
||||
cd resources/admin
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
#### 2. 访问后台
|
||||
|
||||
启动后访问:`http://localhost:5173`
|
||||
|
||||
#### 3. 登录系统
|
||||
|
||||
使用管理员账号登录后台系统。
|
||||
|
||||
#### 4. 使用记账功能
|
||||
|
||||
1. 点击左侧菜单"记账管理"
|
||||
2. 选择子菜单进行操作:
|
||||
- 家庭管理:管理所有家庭信息
|
||||
- 账户管理:管理所有账户信息
|
||||
- 成员管理:管理所有家庭成员
|
||||
- 记录管理:管理所有收支记录
|
||||
|
||||
#### 5. 数据流转
|
||||
|
||||
```
|
||||
创建家庭 → 添加成员 → 创建账户 → 记录收支
|
||||
```
|
||||
|
||||
**注意事项**:
|
||||
- 必须先创建家庭,才能添加成员和账户
|
||||
- 创建账户时必须选择所属家庭
|
||||
- 创建记录时必须选择家庭、账户和成员
|
||||
- 所有删除操作都有确认提示
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 数据库迁移
|
||||
|
||||
运行以下命令创建数据库表:
|
||||
|
||||
```bash
|
||||
php artisan migrate
|
||||
```
|
||||
|
||||
### 多家庭架构
|
||||
|
||||
本模块支持多用户多家庭架构:
|
||||
|
||||
#### 数据隔离
|
||||
- 每个用户可以加入多个家庭
|
||||
- 每个家庭有独立的成员、账户和记录
|
||||
- 所有数据通过`family_id`字段关联到具体家庭
|
||||
- 用户只能访问自己所属家庭的数据
|
||||
|
||||
#### 家庭角色权限
|
||||
|
||||
| 角色 | 创建/编辑家庭 | 邀请成员 | 移除成员 | 修改角色 | 删除家庭 | 退出家庭 |
|
||||
|------|--------------|---------|---------|---------|---------|---------|
|
||||
| owner | ✅ | ✅ | ✅(不能移除owner) | ✅(不能修改owner) | ✅ | ❌(只能删除) |
|
||||
| admin | ✅ | ✅ | ✅(不能移除owner) | ❌ | ❌ | ✅ |
|
||||
| member | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||||
|
||||
#### 权限判断方法
|
||||
|
||||
AccountFamilyMember模型提供以下权限判断方法:
|
||||
|
||||
```php
|
||||
// 判断是否是拥有者
|
||||
$member->isOwner();
|
||||
|
||||
// 判断是否是管理员
|
||||
$member->isAdmin();
|
||||
|
||||
// 判断是否有管理权限(owner或admin)
|
||||
$member->hasManagePermission();
|
||||
```
|
||||
|
||||
### 账户余额自动更新
|
||||
|
||||
系统会自动维护账户余额:
|
||||
- 创建收入记录时,账户余额增加
|
||||
- 创建支出记录时,账户余额减少
|
||||
- 更新记录时,自动调整相关账户余额
|
||||
- 删除记录时,自动回滚账户余额
|
||||
|
||||
### 软删除
|
||||
|
||||
所有数据表都支持软删除:
|
||||
- 删除操作不会物理删除数据,只是标记为已删除
|
||||
- 后台管理可以查看和恢复已删除的数据
|
||||
- 永久删除需要额外操作
|
||||
|
||||
### 数据验证
|
||||
|
||||
所有接口都有严格的数据验证:
|
||||
- 必填字段检查
|
||||
- 数据类型验证
|
||||
- 业务逻辑验证(如删除成员前检查是否有关联记录)
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 所有接口都需要认证(除登录接口外)
|
||||
2. 前端API只能操作当前登录用户及其所属家庭的数据
|
||||
3. 后台API可以操作所有用户的数据
|
||||
4. 每个请求都应该指定`family_id`来操作特定家庭的数据
|
||||
5. 账户余额建议使用重新计算接口进行校准
|
||||
6. 删除成员或账户前,系统会检查是否有关联记录
|
||||
7. 家庭拥有者不能退出家庭,只能删除家庭
|
||||
8. 删除家庭前,必须先删除或转移该家庭下的所有账户
|
||||
9. 修改成员角色需要谨慎操作,可能影响其他成员的权限
|
||||
|
||||
## 多家庭使用示例
|
||||
|
||||
### 创建家庭并邀请成员
|
||||
|
||||
```javascript
|
||||
// 1. 创建家庭
|
||||
const family = await familyApi.createFamily({
|
||||
name: '温馨小家',
|
||||
description: '我们的家庭记账',
|
||||
avatar: 'avatar.jpg'
|
||||
})
|
||||
|
||||
// 2. 邀请成员(需要知道对方的用户ID)
|
||||
await familyApi.inviteMember(family.id, 123) // 123是被邀请用户的ID
|
||||
```
|
||||
|
||||
### 管理家庭成员
|
||||
|
||||
```javascript
|
||||
// 1. 获取家庭详情
|
||||
const family = await familyApi.getFamilyDetail(familyId)
|
||||
|
||||
// 2. 修改成员角色(仅owner可以)
|
||||
await familyApi.updateMemberRole(familyId, memberId, 'admin')
|
||||
|
||||
// 3. 移除成员(需要管理权限)
|
||||
await familyApi.removeMember(familyId, memberId)
|
||||
```
|
||||
|
||||
### 在记账时使用家庭
|
||||
|
||||
```javascript
|
||||
// 创建记账记录时指定家庭ID
|
||||
await recordApi.createRecord({
|
||||
family_id: 1, // 家庭ID
|
||||
member_id: 2, // 家庭成员ID
|
||||
account_id: 3, // 家庭账户ID
|
||||
type: 'expense',
|
||||
amount: 100,
|
||||
category: '餐饮',
|
||||
date: '2025-01-01',
|
||||
time: '12:00'
|
||||
})
|
||||
```
|
||||
|
||||
### 切换家庭
|
||||
|
||||
```javascript
|
||||
// 获取用户的所有家庭
|
||||
const families = await familyApi.getFamilies()
|
||||
|
||||
// 在应用中保存当前选择的家庭ID
|
||||
const currentFamilyId = families.list[0].id
|
||||
|
||||
// 后续操作都使用这个family_id
|
||||
```
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used during authentication for various
|
||||
| messages that we need to display to the user. You are free to modify
|
||||
| these language lines according to your application's requirements.
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => 'These credentials do not match our records.',
|
||||
'password' => 'The provided password is incorrect.',
|
||||
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
|
||||
|
||||
];
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user