first commit
This commit is contained in:
11
.example.env
Normal file
11
.example.env
Normal file
@@ -0,0 +1,11 @@
|
||||
APP_DEBUG = true
|
||||
|
||||
DB_TYPE = mysql
|
||||
DB_HOST = 127.0.0.1
|
||||
DB_NAME = test
|
||||
DB_USER = username
|
||||
DB_PASS = password
|
||||
DB_PORT = 3306
|
||||
DB_CHARSET = utf8
|
||||
|
||||
DEFAULT_LANG = zh-cn
|
||||
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
*.log
|
||||
.env
|
||||
composer.phar
|
||||
composer.lock
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
/.idea
|
||||
/.vscode
|
||||
/vendor
|
||||
/.settings
|
||||
/.buildpath
|
||||
/.project
|
||||
42
.travis.yml
Normal file
42
.travis.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
sudo: false
|
||||
|
||||
language: php
|
||||
|
||||
branches:
|
||||
only:
|
||||
- stable
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
before_install:
|
||||
- composer self-update
|
||||
|
||||
install:
|
||||
- composer install --no-dev --no-interaction --ignore-platform-reqs
|
||||
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
|
||||
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
|
||||
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
|
||||
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
|
||||
|
||||
script:
|
||||
- php think unit
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
|
||||
file:
|
||||
- ThinkPHP_Core.zip
|
||||
- ThinkPHP_Full.zip
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
32
LICENSE.txt
Normal file
32
LICENSE.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
||||
版权所有Copyright © 2006-2025 by ThinkPHP (http://thinkphp.cn)
|
||||
All rights reserved。
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
Apache Licence是著名的非盈利开源组织Apache采用的协议。
|
||||
该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
|
||||
允许代码修改,再作为开源或商业软件发布。需要满足
|
||||
的条件:
|
||||
1. 需要给代码的用户一份Apache Licence ;
|
||||
2. 如果你修改了代码,需要在被修改的文件中说明;
|
||||
3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
|
||||
带有原来代码中的协议,商标,专利声明和其他原来作者规
|
||||
定需要包含的说明;
|
||||
4. 如果再发布的产品中包含一个Notice文件,则在Notice文
|
||||
件中需要带有本协议内容。你可以在Notice中增加自己的
|
||||
许可,但不可以表现为对Apache Licence构成更改。
|
||||
具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
77
README.md
Normal file
77
README.md
Normal file
@@ -0,0 +1,77 @@
|
||||

|
||||
|
||||
ThinkPHP 8
|
||||
===============
|
||||
|
||||
## 特性
|
||||
|
||||
* 基于PHP`8.0+`重构
|
||||
* 升级`PSR`依赖
|
||||
* 依赖`think-orm`3.0+版本
|
||||
* 全新的`think-dumper`服务,支持远程调试
|
||||
* 支持`6.0`/`6.1`无缝升级
|
||||
|
||||
> ThinkPHP8的运行环境要求PHP8.0+
|
||||
|
||||
现在开始,你可以使用官方提供的[ThinkChat](https://chat.topthink.com/),让你在学习ThinkPHP的旅途中享受私人AI助理服务!
|
||||
|
||||

|
||||
|
||||
ThinkPHP生态服务由[顶想云](https://www.topthink.com)(TOPThink Cloud)提供,为生态提供专业的开发者服务和价值之选。
|
||||
|
||||
## 文档
|
||||
|
||||
[完全开发手册](https://doc.thinkphp.cn)
|
||||
|
||||
|
||||
## 赞助
|
||||
|
||||
全新的[赞助计划](https://www.thinkphp.cn/sponsor)可以让你通过我们的网站、手册、欢迎页及GIT仓库获得巨大曝光,同时提升企业的品牌声誉,也更好保障ThinkPHP的可持续发展。
|
||||
|
||||
[](https://www.thinkphp.cn/sponsor/special)
|
||||
|
||||
[](https://www.thinkphp.cn/sponsor)
|
||||
|
||||
## 安装
|
||||
|
||||
~~~
|
||||
composer create-project topthink/think tp
|
||||
~~~
|
||||
|
||||
启动服务
|
||||
|
||||
~~~
|
||||
cd tp
|
||||
php think run
|
||||
~~~
|
||||
|
||||
然后就可以在浏览器中访问
|
||||
|
||||
~~~
|
||||
http://localhost:8000
|
||||
~~~
|
||||
|
||||
如果需要更新框架使用
|
||||
~~~
|
||||
composer update topthink/framework
|
||||
~~~
|
||||
|
||||
## 命名规范
|
||||
|
||||
`ThinkPHP`遵循PSR-2命名规范和PSR-4自动加载规范。
|
||||
|
||||
## 参与开发
|
||||
|
||||
直接提交PR或者Issue即可
|
||||
|
||||
## 版权信息
|
||||
|
||||
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
|
||||
|
||||
本项目包含的第三方源码和二进制文件之版权信息另行标注。
|
||||
|
||||
版权所有Copyright © 2006-2024 by ThinkPHP (http://thinkphp.cn) All rights reserved。
|
||||
|
||||
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
|
||||
|
||||
更多细节参阅 [LICENSE.txt](LICENSE.txt)
|
||||
1
app/.htaccess
Normal file
1
app/.htaccess
Normal file
@@ -0,0 +1 @@
|
||||
deny from all
|
||||
22
app/AppService.php
Normal file
22
app/AppService.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\Service;
|
||||
|
||||
/**
|
||||
* 应用服务类
|
||||
*/
|
||||
class AppService extends Service
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
// 服务注册
|
||||
}
|
||||
|
||||
public function boot()
|
||||
{
|
||||
// 服务启动
|
||||
}
|
||||
}
|
||||
94
app/BaseController.php
Normal file
94
app/BaseController.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\App;
|
||||
use think\exception\ValidateException;
|
||||
use think\Validate;
|
||||
|
||||
/**
|
||||
* 控制器基础类
|
||||
*/
|
||||
abstract class BaseController
|
||||
{
|
||||
/**
|
||||
* Request实例
|
||||
* @var \think\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* 应用实例
|
||||
* @var \think\App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 是否批量验证
|
||||
* @var bool
|
||||
*/
|
||||
protected $batchValidate = false;
|
||||
|
||||
/**
|
||||
* 控制器中间件
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [];
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
* @param App $app 应用对象
|
||||
*/
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->request = $this->app->request;
|
||||
|
||||
// 控制器初始化
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
// 初始化
|
||||
protected function initialize()
|
||||
{}
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
* @access protected
|
||||
* @param array $data 数据
|
||||
* @param string|array $validate 验证器名或者验证规则数组
|
||||
* @param array $message 提示信息
|
||||
* @param bool $batch 是否批量验证
|
||||
* @return array|string|true
|
||||
* @throws ValidateException
|
||||
*/
|
||||
protected function validate(array $data, string|array $validate, array $message = [], bool $batch = false)
|
||||
{
|
||||
if (is_array($validate)) {
|
||||
$v = new Validate();
|
||||
$v->rule($validate);
|
||||
} else {
|
||||
if (strpos($validate, '.')) {
|
||||
// 支持场景
|
||||
[$validate, $scene] = explode('.', $validate);
|
||||
}
|
||||
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
|
||||
$v = new $class();
|
||||
if (!empty($scene)) {
|
||||
$v->scene($scene);
|
||||
}
|
||||
}
|
||||
|
||||
$v->message($message);
|
||||
|
||||
// 是否批量验证
|
||||
if ($batch || $this->batchValidate) {
|
||||
$v->batch(true);
|
||||
}
|
||||
|
||||
return $v->failException(true)->check($data);
|
||||
}
|
||||
|
||||
}
|
||||
58
app/ExceptionHandle.php
Normal file
58
app/ExceptionHandle.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace app;
|
||||
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\Handle;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\exception\ValidateException;
|
||||
use think\Response;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 应用异常处理类
|
||||
*/
|
||||
class ExceptionHandle extends Handle
|
||||
{
|
||||
/**
|
||||
* 不需要记录信息(日志)的异常类列表
|
||||
* @var array
|
||||
*/
|
||||
protected $ignoreReport = [
|
||||
HttpException::class,
|
||||
HttpResponseException::class,
|
||||
ModelNotFoundException::class,
|
||||
DataNotFoundException::class,
|
||||
ValidateException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 记录异常信息(包括日志或者其它方式记录)
|
||||
*
|
||||
* @access public
|
||||
* @param Throwable $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $exception): void
|
||||
{
|
||||
// 使用内置的方式记录异常日志
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @access public
|
||||
* @param \think\Request $request
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
*/
|
||||
public function render($request, Throwable $e): Response
|
||||
{
|
||||
// 添加自定义异常处理机制
|
||||
|
||||
// 其他错误交给系统处理
|
||||
return parent::render($request, $e);
|
||||
}
|
||||
}
|
||||
8
app/Request.php
Normal file
8
app/Request.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
namespace app;
|
||||
|
||||
// 应用请求对象类
|
||||
class Request extends \think\Request
|
||||
{
|
||||
|
||||
}
|
||||
2
app/admin/common.php
Normal file
2
app/admin/common.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// 这是系统自动生成的公共文件
|
||||
34
app/admin/controller/AccountManagement.php
Normal file
34
app/admin/controller/AccountManagement.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use app\admin\service\AccountService;
|
||||
|
||||
class AccountManagement extends BaseController
|
||||
{
|
||||
public function addAccount(AccountService $accountService)
|
||||
{
|
||||
|
||||
# 获取数据
|
||||
$params = $this->request->post();
|
||||
|
||||
# 参数校验
|
||||
if (empty($params['real_name'])) {
|
||||
return json(['code' => 400, 'message' => '缺少必要参数']);
|
||||
}
|
||||
|
||||
# 业务逻辑
|
||||
try {
|
||||
$result = $accountService->createAccount($params);
|
||||
return json(['code' => 200, 'message' => '账户创建成功', 'data' => $result]);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return json([
|
||||
'code' => 400,
|
||||
'message' => $e->getMessage(),
|
||||
'data' => null
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
84
app/admin/controller/Ticket.php
Normal file
84
app/admin/controller/Ticket.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
|
||||
use app\BaseController;
|
||||
use app\common\model\Tickets;
|
||||
use app\common\service\TicketService;
|
||||
use think\facade\Session;
|
||||
|
||||
class Ticket extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* 查询工单
|
||||
*/
|
||||
public function ticketsFind(TicketService $ticketService)
|
||||
{
|
||||
|
||||
// 在控制器明确接收参数
|
||||
$params = [
|
||||
"page" => $this->request->param('page', 1, 'intval'),
|
||||
"limit" => $this->request->param('limit', 20, 'intval'),
|
||||
"status" => $this->request->param('status', null),
|
||||
"operator_name" => $this->request->param('operator_name', null),
|
||||
"searchKeyword" => $this->request->param('search', null),
|
||||
"sortOrder" => $this->request->param('sort_order', 'desc'),
|
||||
];
|
||||
|
||||
$result = $ticketService->getTicketList($params);
|
||||
|
||||
|
||||
return json(['code' => 200, 'msg' => '查询成功', 'data' => $result]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新增工单
|
||||
*/
|
||||
public function createTicket(TicketService $ticketService)
|
||||
{
|
||||
$data = $this->request->post();
|
||||
|
||||
try {
|
||||
$result = $ticketService->createTicket($data);
|
||||
return json(['code' => 200, 'msg' => '创建成功', 'data' => $result]);
|
||||
} catch (\Exception $e) {
|
||||
return json(['code' => 400, 'msg' => $e->getMessage(), 'data' => null]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新工单(后台调用)
|
||||
*/
|
||||
public function updateTicket(TicketService $ticketService, $id)
|
||||
{
|
||||
|
||||
$adminId = Session::get('id'); // 获取当前登录管理员ID
|
||||
$data = $this->request->post();
|
||||
|
||||
$allowFields = ['company_id', 'operator_id', 'user_id', 'website', 'datanum', 'progress', 'status', 'remark'];
|
||||
|
||||
try {
|
||||
$result = $ticketService->updateTicket($id, $data, $allowFields, $adminId, true);
|
||||
return json(['code' => 200, 'msg' => '更新成功', 'data' => $result]);
|
||||
} catch (\Exception $e) {
|
||||
return json(['code' => 400, 'msg' => $e->getMessage(), 'data' => []]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个工单(仅后台可调用)
|
||||
*/
|
||||
public function deleteTicket($id)
|
||||
{
|
||||
$ticket = Tickets::find($id);
|
||||
if (!$ticket) return json(['code' => false, 'msg' => '工单不存在', 'data' => []]);
|
||||
|
||||
return $ticket->delete()
|
||||
? json(['code' => true, 'msg' => '删除成功', 'data' => []])
|
||||
: json(['code' => false, 'msg' => '删除失败', 'data' => []]);
|
||||
}
|
||||
}
|
||||
30
app/admin/controller/TicketFilter.php
Normal file
30
app/admin/controller/TicketFilter.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use app\common\service\TicketService;
|
||||
|
||||
class TicketFilter extends BaseController
|
||||
{
|
||||
/**
|
||||
* 获取所有运营人员名称 (下拉筛选用)
|
||||
*/
|
||||
public function getAllOperators(TicketService $ticketService)
|
||||
{
|
||||
|
||||
$result = $ticketService->getAllOperators();
|
||||
|
||||
return json(['code' => 200, 'msg' => '查询成功', 'data' => $result]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取我方员工列表 (下拉选择用)
|
||||
*/
|
||||
public function getStaffList(TicketService $ticketService)
|
||||
{
|
||||
$result = $ticketService->getStaffList();
|
||||
return json(['code' => 200, 'msg' => '查询成功', 'data' => $result]);
|
||||
}
|
||||
}
|
||||
5
app/admin/event.php
Normal file
5
app/admin/event.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
// 这是系统自动生成的event定义文件
|
||||
return [
|
||||
|
||||
];
|
||||
5
app/admin/middleware.php
Normal file
5
app/admin/middleware.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
return [
|
||||
// \app\admin\middleware\Cors::class, // 全局中间件
|
||||
// \app\middleware\Auth::class,
|
||||
];
|
||||
31
app/admin/middleware/Auth.php
Normal file
31
app/admin/middleware/Auth.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\middleware;
|
||||
|
||||
use thans\jwt\facade\JWTAuth;
|
||||
use thans\jwt\exception\TokenExpiredException;
|
||||
|
||||
class Auth
|
||||
{
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
try {
|
||||
// 1. 核心:必须先执行 auth(),它会自动从 Header 读取 Bearer Token 并验证
|
||||
// 如果过期或非法,这里会直接抛出异常
|
||||
|
||||
$payload = JWTAuth::auth();
|
||||
// $payload = JWTAuth::getPayload(); 这个是获取数据,进行解码token
|
||||
$request->login_user_id = (int)$payload['user_id'] ?? null;
|
||||
$request->login_role = $payload['role'] ?? null;
|
||||
|
||||
return $next($request);
|
||||
}catch (TokenExpiredException $e){
|
||||
// 捕获token过期异常
|
||||
return json(['code' => 401, 'msg' => '登录已过期,请重新登录'],401);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// 如果报错,返回具体的错误信息,方便我们排查
|
||||
return json(['code' => 400, 'msg' => '权限校验失败:' . $e->getMessage()], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
app/admin/route/app.php
Normal file
19
app/admin/route/app.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
use think\facade\Route;
|
||||
use app\admin\middleware\Auth;
|
||||
|
||||
Route::get('ticketsfind', 'Ticket/ticketsFind'); // 通用查询方法
|
||||
// Route::group(function () {
|
||||
// // Route::get('ticketsfind', 'Ticket/ticketsFind'); // 通用查询方法
|
||||
// Route::post('addticket', 'Ticket/save'); // 保存工单
|
||||
// Route::put('ticket/:id', 'Ticket/updateTicket'); // 更新工单
|
||||
// Route::delete('ticket/:id', 'Ticket/deleteTicket'); // 删除工单
|
||||
// Route::get('operators', 'Ticket/getAllOperators'); // 根据运营人员查询
|
||||
// Route::get('customers', 'Customers/getList');
|
||||
// Route::post('addcustomername', 'Customers/addCustomer'); //添加客户名称
|
||||
// Route::post('addemployee', 'Customers/addEmployee');
|
||||
// Route::get('getStaffList', 'Ticket/getStaffList');
|
||||
// Route::delete('deleteemployee/:empId', 'Customers/deleteEmployee');
|
||||
// Route::delete('deletecustomer/:customerId', 'Customers/deleteCustomer');
|
||||
// Route::get('getticketstatuscount', 'Ticket/getTicketStatusCount');
|
||||
// })->middleware(Auth::class); // 只有这里需要 Token
|
||||
34
app/admin/service/AccountService.php
Normal file
34
app/admin/service/AccountService.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\service;
|
||||
|
||||
use app\common\model\User as UserModel;
|
||||
|
||||
class AccountService
|
||||
{
|
||||
public function createAccount($data)
|
||||
{
|
||||
if (empty($data['username'])) {
|
||||
$data['username'] = $data['real_name'];
|
||||
}
|
||||
|
||||
# 检查数据库中是否有相同用户名账户
|
||||
$exist = UserModel::where('username', $data['username'])->find();
|
||||
if ($exist) {
|
||||
throw new \Exception('用户名已存在');
|
||||
}
|
||||
|
||||
$insertData = [
|
||||
'username' => $data['username'] ?? $data['real_name'],
|
||||
'real_name' => $data['real_name'],
|
||||
'password' => password_hash('123456', PASSWORD_DEFAULT),
|
||||
'role' => $data['role'] ?? 'user',
|
||||
'status' => 1,
|
||||
];
|
||||
|
||||
$user = UserModel::create($insertData);
|
||||
|
||||
/** @var \think\Model $user */
|
||||
return $user->visible(['id', 'username', 'real_name', 'role', 'status'])->toArray();
|
||||
}
|
||||
}
|
||||
48
app/admin/service/CustomersService.php
Normal file
48
app/admin/service/CustomersService.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\service;
|
||||
|
||||
use app\common\model\Customers as CustomersModel;
|
||||
use app\common\model\CustomerEmployees;
|
||||
|
||||
class CustomersService
|
||||
{
|
||||
public function selectCustomersWithEmployees()
|
||||
{
|
||||
//with 预载入 ,解决N+1问题
|
||||
$list = CustomersModel::with('employees')->select();
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function addCustomer($companyName)
|
||||
{
|
||||
$id = CustomersModel::create([
|
||||
'company_name' => $companyName
|
||||
]);
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function addEmployee($empName, $Id)
|
||||
{
|
||||
$id = CustomersModel::where('id', $Id)->find()->employees()->save([
|
||||
'employee_name' => $empName
|
||||
]);
|
||||
return $id;
|
||||
}
|
||||
|
||||
|
||||
public function deleteEmployee($empId)
|
||||
{
|
||||
$result = CustomerEmployees::destroy($empId);
|
||||
return $result; // 返回受影响的行数,删除一行就1,没有删除就是0
|
||||
}
|
||||
|
||||
public function deleteCustomer($customerId)
|
||||
{
|
||||
// 删除客户单位会自动删除关联的员工(假设你在模型中设置了级联删除)
|
||||
$result = CustomersModel::destroy($customerId);
|
||||
return $result; // 返回受影响的行数,删除一行就1,没有删除就是0
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
2
app/common.php
Normal file
2
app/common.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// 应用公共文件
|
||||
66
app/common/Trait/ApiResponse.php
Normal file
66
app/common/Trait/ApiResponse.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\Trait;
|
||||
|
||||
use think\Response;
|
||||
|
||||
/**
|
||||
* API 响应 Trait
|
||||
* 提供统一的 JSON 响应格式
|
||||
*/
|
||||
trait ApiResponse
|
||||
{
|
||||
/**
|
||||
* 成功响应
|
||||
*
|
||||
* @param mixed $data 响应数据
|
||||
* @param string $msg 响应消息
|
||||
* @param int $code 响应码
|
||||
* @param int $httpCode HTTP状态码
|
||||
* @return Response
|
||||
*/
|
||||
protected function successResponse($data = [], $msg = '成功', $code = 200, $httpCode = 200)
|
||||
{
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'data' => $data
|
||||
], $httpCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应
|
||||
*
|
||||
* @param string $msg 错误消息
|
||||
* @param mixed $data 错误数据
|
||||
* @param int $code 错误码
|
||||
* @param int $httpCode HTTP状态码
|
||||
* @return Response
|
||||
*/
|
||||
protected function errorResponse($msg = '失败', $data = null, $code = 400, $httpCode = 400)
|
||||
{
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'data' => $data
|
||||
], $httpCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义响应
|
||||
*
|
||||
* @param int $code 响应码
|
||||
* @param string $msg 响应消息
|
||||
* @param mixed $data 响应数据
|
||||
* @param int $httpCode HTTP状态码
|
||||
* @return Response
|
||||
*/
|
||||
protected function customResponse($code, $msg, $data = [], $httpCode = 200)
|
||||
{
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'data' => $data
|
||||
], $httpCode);
|
||||
}
|
||||
}
|
||||
26
app/common/middleware/Cors.php
Normal file
26
app/common/middleware/Cors.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
// app/middleware/Cors.php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\admin\middleware;
|
||||
|
||||
class Cors
|
||||
{
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
// 设置CORS响应头
|
||||
header('Access-Control-Allow-Origin: *'); // 允许的源
|
||||
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Authorization, Content-Type, X-Requested-With, X-CSRF-Token');
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
header('Access-Control-Max-Age: 1728000');
|
||||
|
||||
// 处理CORS预检请求
|
||||
if ($request->isOptions()) {
|
||||
return response()->code(200); // 预检请求,允许通过
|
||||
}
|
||||
|
||||
return $next($request); // 继续处理请求
|
||||
}
|
||||
}
|
||||
22
app/common/model/CompanyOperators.php
Normal file
22
app/common/model/CompanyOperators.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
|
||||
class CompanyOperators extends Model
|
||||
{
|
||||
protected $table = 'company_operators';
|
||||
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Companys::class, 'company_id', 'id');
|
||||
}
|
||||
|
||||
|
||||
public function getCompanyNameAttr($value, $data)
|
||||
{
|
||||
return $this->company->company_name ?? null;
|
||||
}
|
||||
}
|
||||
12
app/common/model/Companys.php
Normal file
12
app/common/model/Companys.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
|
||||
class Companys extends Model
|
||||
{
|
||||
protected $table = 'companys';
|
||||
|
||||
}
|
||||
32
app/common/model/Customers(待删除).php
Normal file
32
app/common/model/Customers(待删除).php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
use app\common\model\CustomerEmployees;
|
||||
|
||||
class Customers extends Model
|
||||
{
|
||||
protected $table = 'customers';
|
||||
|
||||
public function employees()
|
||||
{
|
||||
return $this->hasMany(CustomerEmployees::class, 'customer_id', 'id');
|
||||
}
|
||||
|
||||
/* 模型事件:在删除客户记录之后执行 */
|
||||
public static function onAfterDelete($customer)
|
||||
{
|
||||
// 删除与该客户相关的员工记录
|
||||
$customer->employees()->delete();
|
||||
}
|
||||
|
||||
|
||||
public function getCompanyOfAccount(){
|
||||
return $this->hasMany(User::class,'company_id','id');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
94
app/common/model/Tickets.php
Normal file
94
app/common/model/Tickets.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
|
||||
class Tickets extends Model
|
||||
{
|
||||
protected $table = 'tickets';
|
||||
|
||||
# 自动写入时间戳
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
# 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
|
||||
# 定义字段类型
|
||||
protected $type = [
|
||||
'id' => 'integer',
|
||||
'company_id' => 'integer',
|
||||
'operator_id' => 'integer',
|
||||
'user_id' => 'integer',
|
||||
'website' => 'string',
|
||||
'datanum' => 'string',
|
||||
'progress' => 'integer',
|
||||
'status' => 'integer',
|
||||
'remark' => 'string',
|
||||
'lock_time' => 'integer',
|
||||
'create_time' => 'integer',
|
||||
'update_time' => 'integer',
|
||||
];
|
||||
|
||||
|
||||
/*
|
||||
时间戳获取器
|
||||
*/
|
||||
public function getCreateTimeAttr($value)
|
||||
{
|
||||
return date('Y-m-d H:i', $value);
|
||||
}
|
||||
|
||||
public function getUpdateTimeAttr($value)
|
||||
{
|
||||
return date('Y-m-d H:i', $value);
|
||||
}
|
||||
|
||||
public function getLockTimeAttr($value)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return '';
|
||||
}
|
||||
return date('Y-m-d H:i', $value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 关联:工单关联负责人
|
||||
*/
|
||||
public function ticketStaff()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||
}
|
||||
|
||||
public function ticketCompany()
|
||||
{
|
||||
return $this->belongsTo(Companys::class, 'company_id', 'id');
|
||||
}
|
||||
|
||||
public function ticketOperator()
|
||||
{
|
||||
return $this->belongsTo(CompanyOperators::class, 'operator_id', 'id');
|
||||
}
|
||||
|
||||
|
||||
// --- 定义虚拟属性 (获取关联表的值) ---
|
||||
|
||||
public function getUsernameAttr($value, $data)
|
||||
{
|
||||
return $this->ticketStaff->username ?? '';
|
||||
}
|
||||
|
||||
public function getCompanyNameAttr($value, $data)
|
||||
{
|
||||
return $this->ticketCompany->company_name ?? '';
|
||||
}
|
||||
|
||||
public function getOperatorNameAttr($value, $data)
|
||||
{
|
||||
return $this->ticketOperator->operator_name ?? '';
|
||||
}
|
||||
}
|
||||
16
app/common/model/User.php
Normal file
16
app/common/model/User.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
|
||||
class User extends Model
|
||||
{
|
||||
protected $table = 'users';
|
||||
|
||||
public function company(){
|
||||
return $this->belongsTo(Companys::class,'company_id','id');
|
||||
}
|
||||
|
||||
}
|
||||
42
app/common/service/AuthService.php
Normal file
42
app/common/service/AuthService.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\User;
|
||||
use think\facade\Session;
|
||||
|
||||
class AuthService
|
||||
{
|
||||
/**
|
||||
* 验证用户登录状态
|
||||
* @return array|false 返回用户信息数组或false
|
||||
*/
|
||||
public function login(string $username, string $password)
|
||||
{
|
||||
$user = User::with(['company'])
|
||||
->where('username', $username)
|
||||
->find();
|
||||
|
||||
|
||||
|
||||
if (!$user || !password_verify($password, $user['password'])) {
|
||||
throw new \Exception('用户名或密码错误');
|
||||
}
|
||||
|
||||
if ($user['status'] != 1) {
|
||||
throw new \Exception('账户已禁用');
|
||||
}
|
||||
|
||||
|
||||
$userInfo = [
|
||||
'company_name' => $user['company']['company_name'], // 所属公司名称
|
||||
'username' => $user['username'],
|
||||
'role' => $user['role'],
|
||||
];
|
||||
|
||||
Session::set('user_info', $user);
|
||||
|
||||
return $userInfo;
|
||||
|
||||
}
|
||||
}
|
||||
186
app/common/service/TicketService.php
Normal file
186
app/common/service/TicketService.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\Tickets;
|
||||
use app\common\model\CompanyOperators;
|
||||
use app\common\model\User;
|
||||
|
||||
use think\facade\Cache;
|
||||
|
||||
class TicketService
|
||||
{
|
||||
/**
|
||||
* 获取工单列表业务逻辑
|
||||
* @param array $params 外部传入的过滤参数
|
||||
*/
|
||||
|
||||
public function getTicketList(array $params)
|
||||
{
|
||||
|
||||
$query = Tickets::with(['ticketStaff', 'ticketCompany', 'ticketOperator']); // 查询构造器
|
||||
|
||||
// 状态筛选
|
||||
if ($params['status'] !== null) {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
// 运营人员筛选
|
||||
if (!empty($params['operator_name'])) {
|
||||
$query->where('operator_name', $params['operator_name']);
|
||||
}
|
||||
|
||||
// 负责人筛选
|
||||
if (!empty($params['username'])) {
|
||||
$query->where('username', $params['username']);
|
||||
}
|
||||
|
||||
// 关键词搜索
|
||||
if (!empty($params['searchKeyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('website', 'like', '%' . $params['searchKeyword'] . '%')
|
||||
->whereOr('operator_name', 'like', '%' . $params['searchKeyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
$order = strtolower($params['sortOrder']) === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
|
||||
// order -- 排序 , paginate -- 分页(查询当前页的数据,还会自动计算总记录数)
|
||||
$list = $query->order('create_time', $order)->paginate(
|
||||
$params['limit'],
|
||||
false,
|
||||
[
|
||||
'page' => $params['page'],
|
||||
'query' => $params // 保持分页链接的查询参数
|
||||
]
|
||||
);
|
||||
|
||||
$list->each(function ($item) {
|
||||
$item->hidden(['ticketStaff', 'ticketCompany', 'ticketOperator', 'company_id', 'operator_id', 'user_id']);
|
||||
$item->append(['username', 'company_name', 'operator_name']);
|
||||
|
||||
return $item;
|
||||
});
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新增工单
|
||||
*
|
||||
*/
|
||||
public function createTicket($data)
|
||||
{
|
||||
if (empty($data['website'])) {
|
||||
throw new \Exception('网站不能为空');
|
||||
}
|
||||
|
||||
$website = trim($data['website']);
|
||||
|
||||
// 并发锁
|
||||
$lockKey = 'create_ticket_lock_' . md5($website);
|
||||
|
||||
if (Cache::has($lockKey)) {
|
||||
throw new \Exception('当前该网址正在被创建工单中,请稍后重试');
|
||||
}
|
||||
|
||||
Cache::set($lockKey, 1, 5); // 锁定5秒
|
||||
|
||||
try {
|
||||
// 查找是否有未完成的同网站工单
|
||||
$unfinishedTicket = Tickets::where('website', $website)
|
||||
->whereIn('status', [0, 1])
|
||||
->find();
|
||||
|
||||
if ($unfinishedTicket) {
|
||||
Cache::delete($lockKey);
|
||||
throw new \Exception('已存在未完成的同网站工单,无法创建');
|
||||
}
|
||||
|
||||
// 当前无相同网站
|
||||
$ticketResult = Tickets::create($data);
|
||||
return $ticketResult;
|
||||
} catch (\Exception $e) {
|
||||
Cache::delete($lockKey);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 更新工单
|
||||
* @param $id 工单id
|
||||
* @param $data 外部传入的更新数据
|
||||
* @param $uid 当前登录用户id
|
||||
* @param $role 当前登录用户角色
|
||||
* @return array
|
||||
*/
|
||||
public function updateTicket($id, $data, $allowFields, $uid, $isSuper = false)
|
||||
{
|
||||
$ticket = Tickets::where('id', $id)->find();
|
||||
|
||||
if (!$ticket) {
|
||||
throw new \Exception('工单不存在');
|
||||
}
|
||||
|
||||
// 当不是管理员,进入判断
|
||||
if (!$isSuper) {
|
||||
if (!is_null($ticket->user_id) && $ticket->user_id != $uid) {
|
||||
throw new \Exception('没有权限修改该工单');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 提取 $allowFields 允许修改的字段
|
||||
$updateData = [];
|
||||
foreach ($allowFields as $field) {
|
||||
if (array_key_exists($field, $data)) {
|
||||
$updateData[$field] = $data[$field];
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有有效数据需要更新
|
||||
if (empty($updateData)) {
|
||||
throw new \Exception('没有合法的更新字段');
|
||||
}
|
||||
|
||||
|
||||
return $ticket->save($updateData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有运营人员名称 (下拉筛选用)-仅限后台使用
|
||||
*
|
||||
*/
|
||||
public function getAllOperators()
|
||||
{
|
||||
$operators = CompanyOperators::with('company')->select();
|
||||
|
||||
$operators->each(function ($item) {
|
||||
$item->hidden(['company_id', 'company', 'create_time', 'status']);
|
||||
|
||||
$item->append(['company_name']);
|
||||
return $item;
|
||||
});
|
||||
|
||||
return $operators;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取员工列表(下拉筛选用)
|
||||
*/
|
||||
public function getStaffList()
|
||||
{
|
||||
$map = [
|
||||
'role' => 'user',
|
||||
'status' => 1
|
||||
];
|
||||
|
||||
$staffs = User::where($map)->field('id, username', 'real_name')->select();
|
||||
return $staffs;
|
||||
}
|
||||
}
|
||||
17
app/event.php
Normal file
17
app/event.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// 事件定义文件
|
||||
return [
|
||||
'bind' => [
|
||||
],
|
||||
|
||||
'listen' => [
|
||||
'AppInit' => [],
|
||||
'HttpRun' => [],
|
||||
'HttpEnd' => [],
|
||||
'LogLevel' => [],
|
||||
'LogWrite' => [],
|
||||
],
|
||||
|
||||
'subscribe' => [
|
||||
],
|
||||
];
|
||||
2
app/index/common.php
Normal file
2
app/index/common.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// 这是系统自动生成的公共文件
|
||||
43
app/index/controller/Login.php
Normal file
43
app/index/controller/Login.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace app\index\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use app\common\service\AuthService;
|
||||
use think\facade\Session;
|
||||
|
||||
|
||||
// 已完成
|
||||
class Login extends BaseController
|
||||
{
|
||||
|
||||
/*
|
||||
处理登录请求(已完成)
|
||||
*/
|
||||
public function login(AuthService $authService)
|
||||
{
|
||||
$params = $this->request->only(['username', 'password'], 'post');
|
||||
|
||||
// 验证数据
|
||||
if (empty($params['username']) || empty($params['password'])) {
|
||||
return json(['code' => 400, 'message' => '用户名和密码不能为空']);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $authService->login($params['username'], $params['password']);
|
||||
} catch (\Exception $e) {
|
||||
return json(['code' => 400, 'message' => $e->getMessage(),'data' => []]);
|
||||
}
|
||||
|
||||
return json(['code' => 200, 'message' => '登录成功', 'data' => $result]);
|
||||
}
|
||||
|
||||
/*
|
||||
退出登录(已完成)
|
||||
*/
|
||||
protected function logout()
|
||||
{
|
||||
Session::clear();
|
||||
return json(['code' => 200, 'message' => '退出成功']);
|
||||
}
|
||||
}
|
||||
29
app/index/controller/Ticket.php
Normal file
29
app/index/controller/Ticket.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace app\index\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use app\common\service\TicketService;
|
||||
use think\facade\Session;
|
||||
|
||||
class Ticket extends BaseController
|
||||
{
|
||||
/**
|
||||
* 更新工单(前台调用)
|
||||
*/
|
||||
public function updateTicket(TicketService $ticketService, $id)
|
||||
{
|
||||
|
||||
$adminId = Session::get('id'); // 获取当前登录ID
|
||||
$data = $this->request->post();
|
||||
|
||||
$allowFields = ['datanum', 'progress', 'status', 'remark', 'lock_time'];
|
||||
|
||||
try {
|
||||
$result = $ticketService->updateTicket($id, $data, $allowFields, $adminId, false);
|
||||
return json(['code' => 200, 'msg' => '更新成功', 'data' => $result]);
|
||||
} catch (\Exception $e) {
|
||||
return json(['code' => 400, 'msg' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
5
app/index/event.php
Normal file
5
app/index/event.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
// 这是系统自动生成的event定义文件
|
||||
return [
|
||||
|
||||
];
|
||||
5
app/index/middleware.php
Normal file
5
app/index/middleware.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
// 这是系统自动生成的middleware定义文件
|
||||
return [
|
||||
|
||||
];
|
||||
6
app/index/route/app.php
Normal file
6
app/index/route/app.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
use think\facade\Route;
|
||||
|
||||
|
||||
Route::post('api/login', 'Login/login'); // 登录
|
||||
10
app/middleware.php
Normal file
10
app/middleware.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// 全局中间件定义文件
|
||||
return [
|
||||
// 全局请求缓存
|
||||
// \think\middleware\CheckRequestCache::class,
|
||||
// 多语言加载
|
||||
// \think\middleware\LoadLangPack::class,
|
||||
// Session初始化
|
||||
\think\middleware\SessionInit::class
|
||||
];
|
||||
23
app/middleware/CheckLogin.php
Normal file
23
app/middleware/CheckLogin.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\middleware;
|
||||
use think\facade\Session;
|
||||
class CheckLogin
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
if (!Session::has('user_info')) {
|
||||
return json(['code' => 401, 'message' => '未登录']);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
9
app/provider.php
Normal file
9
app/provider.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
use app\ExceptionHandle;
|
||||
use app\Request;
|
||||
|
||||
// 容器Provider定义文件
|
||||
return [
|
||||
'think\Request' => Request::class,
|
||||
'think\exception\Handle' => ExceptionHandle::class,
|
||||
];
|
||||
9
app/service.php
Normal file
9
app/service.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
use app\AppService;
|
||||
|
||||
// 系统服务定义文件
|
||||
// 服务在完成全局初始化之后执行
|
||||
return [
|
||||
AppService::class,
|
||||
];
|
||||
50
composer.json
Normal file
50
composer.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "topthink/think",
|
||||
"description": "the new thinkphp framework",
|
||||
"type": "project",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"thinkphp",
|
||||
"ORM"
|
||||
],
|
||||
"homepage": "https://www.thinkphp.cn/",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "liu21st",
|
||||
"email": "liu21st@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "yunwuxin",
|
||||
"email": "448901948@qq.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0.0",
|
||||
"topthink/framework": "^8.0",
|
||||
"topthink/think-orm": "^3.0|^4.0",
|
||||
"topthink/think-filesystem": "^2.0|^3.0",
|
||||
"topthink/think-multi-app": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"topthink/think-dumper": "^1.0",
|
||||
"topthink/think-trace": "^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"app\\": "app"
|
||||
},
|
||||
"psr-0": {
|
||||
"": "extend/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": "dist"
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"@php think service:discover",
|
||||
"@php think vendor:publish"
|
||||
]
|
||||
}
|
||||
}
|
||||
30
config/app.php
Normal file
30
config/app.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 应用的命名空间
|
||||
'app_namespace' => '',
|
||||
// 是否启用路由
|
||||
'with_route' => true,
|
||||
// 默认应用
|
||||
'default_app' => 'index',
|
||||
// 默认时区
|
||||
'default_timezone' => 'Asia/Shanghai',
|
||||
|
||||
// 应用映射(自动多应用模式有效)
|
||||
'app_map' => [],
|
||||
// 域名绑定(自动多应用模式有效)
|
||||
'domain_bind' => [],
|
||||
// 禁止URL访问的应用列表(自动多应用模式有效)
|
||||
'deny_app_list' => [],
|
||||
|
||||
// 异常页面的模板文件
|
||||
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
|
||||
|
||||
// 错误显示信息,非调试模式有效
|
||||
'error_message' => '页面错误!请稍后再试~',
|
||||
// 显示错误信息
|
||||
'show_error_msg' => false,
|
||||
];
|
||||
29
config/cache.php
Normal file
29
config/cache.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 缓存设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 默认缓存驱动
|
||||
'default' => 'file',
|
||||
|
||||
// 缓存连接方式配置
|
||||
'stores' => [
|
||||
'file' => [
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
'path' => '',
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
// 缓存标签前缀
|
||||
'tag_prefix' => 'tag:',
|
||||
// 序列化机制 例如 ['serialize', 'unserialize']
|
||||
'serialize' => [],
|
||||
],
|
||||
// 更多的缓存连接
|
||||
],
|
||||
];
|
||||
9
config/console.php
Normal file
9
config/console.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 控制台配置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 指令定义
|
||||
'commands' => [
|
||||
],
|
||||
];
|
||||
20
config/cookie.php
Normal file
20
config/cookie.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Cookie设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => false,
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => true,
|
||||
// samesite 设置,支持 'strict' 'lax'
|
||||
'samesite' => '',
|
||||
];
|
||||
63
config/database.php
Normal file
63
config/database.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
// 默认使用的数据库连接配置
|
||||
'default' => env('DB_DRIVER', 'mysql'),
|
||||
|
||||
// 自定义时间查询规则
|
||||
'time_query_rule' => [],
|
||||
|
||||
// 自动写入时间戳字段
|
||||
// true为自动识别类型 false关闭
|
||||
// 字符串则明确指定时间字段类型 支持 int timestamp datetime date
|
||||
'auto_timestamp' => true,
|
||||
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
|
||||
// 时间字段配置 配置格式:create_time,update_time
|
||||
'datetime_field' => '',
|
||||
|
||||
// 数据库连接配置信息
|
||||
'connections' => [
|
||||
'mysql' => [
|
||||
// 数据库类型
|
||||
'type' => env('DB_TYPE', 'mysql'),
|
||||
// 服务器地址
|
||||
'hostname' => env('DB_HOST', '127.0.0.1'),
|
||||
// 数据库名
|
||||
'database' => env('DB_NAME', ''),
|
||||
// 用户名
|
||||
'username' => env('DB_USER', 'root'),
|
||||
// 密码
|
||||
'password' => env('DB_PASS', ''),
|
||||
// 端口
|
||||
'hostport' => env('DB_PORT', '3306'),
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
// 数据库编码
|
||||
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||
// 数据库表前缀
|
||||
'prefix' => env('DB_PREFIX', ''),
|
||||
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 是否需要断线重连
|
||||
'break_reconnect' => false,
|
||||
// 监听SQL
|
||||
'trigger_sql' => env('APP_DEBUG', true),
|
||||
// 开启字段缓存
|
||||
'fields_cache' => false,
|
||||
],
|
||||
|
||||
// 更多的数据库配置信息
|
||||
],
|
||||
];
|
||||
24
config/filesystem.php
Normal file
24
config/filesystem.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
// 默认磁盘
|
||||
'default' => 'local',
|
||||
// 磁盘列表
|
||||
'disks' => [
|
||||
'local' => [
|
||||
'type' => 'local',
|
||||
'root' => app()->getRuntimePath() . 'storage',
|
||||
],
|
||||
'public' => [
|
||||
// 磁盘类型
|
||||
'type' => 'local',
|
||||
// 磁盘路径
|
||||
'root' => app()->getRootPath() . 'public/storage',
|
||||
// 磁盘路径对应的外部URL路径
|
||||
'url' => '/storage',
|
||||
// 可见性
|
||||
'visibility' => 'public',
|
||||
],
|
||||
// 更多的磁盘配置信息
|
||||
],
|
||||
];
|
||||
29
config/lang.php
Normal file
29
config/lang.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 多语言设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 默认语言
|
||||
'default_lang' => env('DEFAULT_LANG', 'zh-cn'),
|
||||
// 自动侦测浏览器语言
|
||||
'auto_detect_browser' => true,
|
||||
// 允许的语言列表
|
||||
'allow_lang_list' => [],
|
||||
// 多语言自动侦测变量名
|
||||
'detect_var' => 'lang',
|
||||
// 是否使用Cookie记录
|
||||
'use_cookie' => true,
|
||||
// 多语言cookie变量
|
||||
'cookie_var' => 'think_lang',
|
||||
// 多语言header变量
|
||||
'header_var' => 'think-lang',
|
||||
// 扩展语言包
|
||||
'extend_list' => [],
|
||||
// Accept-Language转义为对应语言包名称
|
||||
'accept_language' => [
|
||||
'zh-hans-cn' => 'zh-cn',
|
||||
],
|
||||
// 是否支持语言分组
|
||||
'allow_group' => false,
|
||||
];
|
||||
45
config/log.php
Normal file
45
config/log.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 日志设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 默认日志记录通道
|
||||
'default' => 'file',
|
||||
// 日志记录级别
|
||||
'level' => [],
|
||||
// 日志类型记录的通道 ['error'=>'email',...]
|
||||
'type_channel' => [],
|
||||
// 关闭全局日志写入
|
||||
'close' => false,
|
||||
// 全局日志处理 支持闭包
|
||||
'processor' => null,
|
||||
|
||||
// 日志通道列表
|
||||
'channels' => [
|
||||
'file' => [
|
||||
// 日志记录方式
|
||||
'type' => 'File',
|
||||
// 日志保存目录
|
||||
'path' => '',
|
||||
// 单文件日志写入
|
||||
'single' => false,
|
||||
// 独立日志级别
|
||||
'apart_level' => [],
|
||||
// 最大日志文件数量
|
||||
'max_files' => 0,
|
||||
// 使用JSON格式记录
|
||||
'json' => false,
|
||||
// 日志处理
|
||||
'processor' => null,
|
||||
// 关闭通道日志写入
|
||||
'close' => false,
|
||||
// 日志输出格式化
|
||||
'format' => '[%s][%s] %s',
|
||||
// 是否实时写入
|
||||
'realtime_write' => false,
|
||||
],
|
||||
// 其它日志通道配置
|
||||
],
|
||||
|
||||
];
|
||||
8
config/middleware.php
Normal file
8
config/middleware.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
// 中间件配置
|
||||
return [
|
||||
// 别名或分组
|
||||
'alias' => [],
|
||||
// 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
|
||||
'priority' => [],
|
||||
];
|
||||
55
config/route.php
Normal file
55
config/route.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 路由设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// 是否开启路由延迟解析
|
||||
'url_lazy_route' => false,
|
||||
// 是否强制使用路由
|
||||
'url_route_must' => false,
|
||||
// 是否区分大小写
|
||||
'url_case_sensitive' => false,
|
||||
// 自动扫描子目录分组
|
||||
'route_auto_group' => false,
|
||||
// 合并路由规则
|
||||
'route_rule_merge' => false,
|
||||
// 路由是否完全匹配
|
||||
'route_complete_match' => false,
|
||||
// 去除斜杠
|
||||
'remove_slash' => false,
|
||||
// 默认的路由变量规则
|
||||
'default_route_pattern' => '[\w\.]+',
|
||||
// URL伪静态后缀
|
||||
'url_html_suffix' => 'html',
|
||||
// 访问控制器层名称
|
||||
'controller_layer' => 'controller',
|
||||
// 空控制器名
|
||||
'empty_controller' => 'Error',
|
||||
// 是否使用控制器后缀
|
||||
'controller_suffix' => false,
|
||||
// 默认模块名(开启自动多模块有效)
|
||||
'default_module' => 'index',
|
||||
// 默认控制器名
|
||||
'default_controller' => 'Index',
|
||||
// 默认操作名
|
||||
'default_action' => 'index',
|
||||
// 操作方法后缀
|
||||
'action_suffix' => '',
|
||||
// 非路由变量是否使用普通参数方式(用于URL生成)
|
||||
'url_common_param' => true,
|
||||
// 操作方法的参数绑定方式 route get param
|
||||
'action_bind_param' => 'get',
|
||||
// 请求缓存规则 true为自动规则
|
||||
'request_cache_key' => true,
|
||||
// 请求缓存有效期
|
||||
'request_cache_expire' => null,
|
||||
// 全局请求缓存排除规则
|
||||
'request_cache_except' => [],
|
||||
// 请求缓存的Tag
|
||||
'request_cache_tag' => '',
|
||||
// API版本header变量
|
||||
'api_version' => 'Api-Version',
|
||||
];
|
||||
19
config/session.php
Normal file
19
config/session.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 会话设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// session name
|
||||
'name' => 'PHPSESSID',
|
||||
// SESSION_ID的提交变量,解决flash上传跨域
|
||||
'var_session_id' => '',
|
||||
// 驱动方式 支持file cache
|
||||
'type' => 'file',
|
||||
// 存储连接标识 当type使用cache的时候有效
|
||||
'store' => null,
|
||||
// 过期时间
|
||||
'expire' => 86400,
|
||||
// 前缀
|
||||
'prefix' => '',
|
||||
];
|
||||
10
config/trace.php
Normal file
10
config/trace.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Trace设置 开启调试模式后有效
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 内置Html和Console两种方式 支持扩展
|
||||
'type' => 'Html',
|
||||
// 读取的日志通道名
|
||||
'channel' => '',
|
||||
];
|
||||
25
config/view.php
Normal file
25
config/view.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模板设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 模板引擎类型使用Think
|
||||
'type' => 'Think',
|
||||
// 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
|
||||
'auto_rule' => 1,
|
||||
// 模板目录名
|
||||
'view_dir_name' => 'view',
|
||||
// 模板后缀
|
||||
'view_suffix' => 'html',
|
||||
// 模板文件名分隔符
|
||||
'view_depr' => DIRECTORY_SEPARATOR,
|
||||
// 模板引擎普通标签开始标记
|
||||
'tpl_begin' => '{',
|
||||
// 模板引擎普通标签结束标记
|
||||
'tpl_end' => '}',
|
||||
// 标签库标签开始标记
|
||||
'taglib_begin' => '{',
|
||||
// 标签库标签结束标记
|
||||
'taglib_end' => '}',
|
||||
];
|
||||
2
extend/.gitignore
vendored
Normal file
2
extend/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
0
public/.htaccess
Normal file
0
public/.htaccess
Normal file
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
25
public/index.php
Normal file
25
public/index.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2019 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use think\App;
|
||||
|
||||
// [ 应用入口文件 ]
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// 执行HTTP应用并响应
|
||||
$http = (new App())->http;
|
||||
|
||||
$response = $http->run();
|
||||
|
||||
$response->send();
|
||||
|
||||
$http->end($response);
|
||||
9
public/nginx.htaccess
Normal file
9
public/nginx.htaccess
Normal file
@@ -0,0 +1,9 @@
|
||||
location ~* (runtime|application)/{
|
||||
return 403;
|
||||
}
|
||||
|
||||
location / {
|
||||
if (!-e $request_filename){
|
||||
rewrite ^(.*)$ /index.php?s=$1 last; break;
|
||||
}
|
||||
}
|
||||
2
public/robots.txt
Normal file
2
public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
19
public/router.php
Normal file
19
public/router.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) {
|
||||
return false;
|
||||
} else {
|
||||
$_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php';
|
||||
|
||||
require __DIR__ . "/index.php";
|
||||
}
|
||||
2
public/static/.gitignore
vendored
Normal file
2
public/static/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
5
route/app.php
Normal file
5
route/app.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
use think\facade\Route;
|
||||
|
||||
|
||||
// Route::post('api/login', 'index/Login/login'); // 登录
|
||||
2
runtime/.gitignore
vendored
Normal file
2
runtime/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
11
think
Normal file
11
think
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use think\App;
|
||||
|
||||
// 命令行入口文件
|
||||
// 加载基础文件
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
// 应用初始化
|
||||
(new App())->console->run();
|
||||
1
view/README.md
Normal file
1
view/README.md
Normal file
@@ -0,0 +1 @@
|
||||
如果不使用模板,可以删除该目录
|
||||
Reference in New Issue
Block a user