This commit is contained in:
你的名字
2025-10-15 14:53:54 +08:00
commit ac0f12b21a
864 changed files with 200931 additions and 0 deletions

View File

@ -0,0 +1,247 @@
<?php
namespace app\admin\controller;
use app\admin\model\SystemUploadfile;
use app\admin\service\UploadService;
use app\common\controller\AdminController;
use app\common\service\MenuService;
use app\Request;
use Kaadon\Helper\GdImageHelper;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\db\Query;
use think\facade\Cache;
use think\file\UploadedFile;
use think\response\Json;
class Ajax extends AdminController
{
/**
* 初始化后台接口地址
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function initAdmin(): Json
{
$cacheData = Cache::get('initAdmin_' . $this->adminUid);
if (!empty($cacheData)) {
return json($cacheData);
}
$menuService = new MenuService($this->adminUid);
$data = [
'logoInfo' => [
'title' => sysConfig('site', 'logo_title'),
'image' => sysConfig('site', 'logo_image'),
'href' => __url('index/index'),
],
'homeInfo' => $menuService->getHomeInfo(),
'menuInfo' => $menuService->getMenuTree(),
];
Cache::tag('initAdmin')->set('initAdmin_' . $this->adminUid, $data);
return json($data);
}
/**
* 清理缓存接口
*/
public function clearCache(): void
{
Cache::clear();
$this->success('清理缓存成功');
}
/**
* 上传文件
* @param Request $request
* @return Json|null
* @throws \Kaadon\Helper\HelperException
*/
public function upload(Request $request): Json|null
{
$this->isDemo && $this->error('演示环境下不允许修改');
$this->checkPostRequest();
$type = $request->param('type', '');
$file = $request->file($type == 'editor' ? 'upload' : 'file');
if (config('filesystem.image.to_webp', true) && GdImageHelper::isSupportSuffix($file->extension())) {
(new GdImageHelper($file->getRealPath(), $file->extension()))->convertTo($file->getRealPath(),'webp');
$file = new UploadedFile($file->getRealPath(), date("YmdHis") . "_" . md5($file->getOriginalName()) . '.webp');
$file->setExtension('webp');
}
$data = [
'upload_type' => $request->post('upload_type'),
'file' => $file,
];
$uploadConfig = sysConfig('upload');
empty($data['upload_type']) && $data['upload_type'] = $uploadConfig['upload_type'];
$rule = [
'upload_type|指定上传类型有误' => "in:{$uploadConfig['upload_allow_type']}",
'file|文件' => "require|file|fileExt:{$uploadConfig['upload_allow_ext']},webp|fileSize:{$uploadConfig['upload_allow_size']}",
];
$this->validate($data, $rule);
$upload_type = $uploadConfig['upload_type'];
try {
$upload = UploadService::instance()->setConfig($uploadConfig)->$upload_type($data['file'], $type);
}catch (\Exception $e) {
$this->error($e->getMessage());
}
$code = $upload['code'] ?? 0;
if ($code == 0) {
$this->error($upload['data'] ?? '');
}else {
if ($type == 'editor') {
return json(
[
'error' => ['message' => '上传成功', 'number' => 201,],
'fileName' => '',
'uploaded' => 1,
'url' => $upload['data']['url'] ?? '',
]
);
}else {
$this->success('上传成功', $upload['data'] ?? '');
}
}
}
/**
* 获取上传文件列表
* @param Request $request
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getUploadFiles(Request $request): Json
{
$get = $request->get();
$page = !empty($get['page']) ? $get['page'] : 1;
$limit = !empty($get['limit']) ? $get['limit'] : 10;
$title = !empty($get['title']) ? $get['title'] : null;
$count = SystemUploadfile::where(function(Query $query) use ($title) {
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
})
->count();
$list = SystemUploadfile::where(function(Query $query) use ($title) {
!empty($title) && $query->where('original_name', 'like', "%{$title}%");
})
->page($page, $limit)
->order($this->sort)
->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
/**
* 百度编辑器上传
* @param Request $request
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws \Kaadon\Helper\HelperException
*/
public function uploadUEditor(Request $request): Json
{
$uploadConfig = sysConfig('upload');
$upload_allow_size = $uploadConfig['upload_allow_size'];
$_upload_allow_ext = explode(',', $uploadConfig['upload_allow_ext']);
$upload_allow_ext = [];
array_map(function($value) use (&$upload_allow_ext) {
$upload_allow_ext[] = '.' . $value;
}, $_upload_allow_ext);
$config = [
// 上传图片配置项
"imageActionName" => "image",
"imageFieldName" => "file",
"imageMaxSize" => $upload_allow_size,
"imageAllowFiles" => $upload_allow_ext,
"imageCompressEnable" => true,
"imageCompressBorder" => 5000,
"imageInsertAlign" => "none",
"imageUrlPrefix" => "",
// 列出图片
"imageManagerActionName" => "listImage",
"imageManagerListSize" => 20,
"imageManagerUrlPrefix" => "",
"imageManagerInsertAlign" => "none",
"imageManagerAllowFiles" => $upload_allow_ext,
// 上传 video
"videoActionName" => "video",
"videoFieldName" => "file",
"videoUrlPrefix" => "",
"videoMaxSize" => $upload_allow_size,
"videoAllowFiles" => $upload_allow_ext,
// 上传 附件
"fileActionName" => "attachment",
"fileFieldName" => "file",
"fileMaxSize" => $upload_allow_size,
"fileAllowFiles" => $upload_allow_ext,
];
$action = $request->param('action/s', '');
$file = $request->file('file');
$upload_type = $uploadConfig['upload_type'];
switch ($action) {
case 'image':
if (config('filesystem.image.to_webp', true) && GdImageHelper::isSupportSuffix($file->extension())) {
(new GdImageHelper($file->getRealPath(), $file->extension()))->convertTo($file->getRealPath(),'webp');
$file = new UploadedFile($file->getRealPath(), date("YmdHis") . "_" . md5($file->getOriginalName()) . '.webp');
$file->setExtension('webp');
}
case 'attachment':
case 'video':
if ($this->isDemo) return json(['state' => '演示环境下不允许修改']);
try {
$upload = UploadService::instance()->setConfig($uploadConfig)->$upload_type($file);
$code = $upload['code'] ?? 0;
if ($code == 0) {
return json(['state' => $upload['data'] ?? '上传错误信息']);
}else {
return json(['state' => 'SUCCESS', 'url' => $upload['data']['url'] ?? '']);
}
}catch (\Exception $e) {
$this->error($e->getMessage());
}
break;
case 'listImage':
$list = (new SystemUploadfile())->order($this->sort)->limit(100)->field('url')->select()->toArray();
$result = [
"state" => "SUCCESS",
"list" => $list,
"total" => 0,
"start" => 0,
];
return json($result);
default:
return json($config);
}
}
public function composerInfo(): Json
{
$lockFilePath = root_path() . '/composer.lock';
$list = [];
if (file_exists($lockFilePath)) {
$lockFileContent = file_get_contents($lockFilePath);
if ($lockFileContent !== false) {
$lockData = json_decode($lockFileContent, true);
if (!empty($lockData['packages'])) {
foreach ($lockData['packages'] as $package) {
$list[] = ['name' => $package['name'], 'version' => $package['version']];
}
}
}
}
$this->success('success', $list);
}
}

View File

@ -0,0 +1,198 @@
<?php
namespace app\admin\controller;
use app\admin\model\MallOrder;
use app\admin\model\SystemAdmin;
use app\admin\model\SystemQuick;
use app\common\controller\AdminController;
use app\Request;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
class Index extends AdminController
{
/**
* 后台主页
* @param Request $request
* @return string
*/
public function index(Request $request): string
{
return $this->fetch('', ['admin' => $request->adminUserInfo,]);
}
/**
* 后台欢迎页
* @return string
* @throws Exception
*/
public function welcome(): string
{
$tpVersion = \think\facade\App::version();
$mysqlVersion = Db::query("select version() as version")[0]['version'] ?? '未知';
$phpVersion = phpversion();
$versions = compact('tpVersion', 'mysqlVersion', 'phpVersion');
$quick_list = SystemQuick::field('id,title,icon,href')
->where(['status' => 1])->order('sort', 'desc')->limit(50)->select()->toArray();
$quicks = array_chunk($quick_list, 8);
$this->assign(compact('quicks', 'versions'));
$data = [
'all_member'=>[
"title"=>"今日订单",
"data"=>(new MallOrder())->where([['create_time','>',strtotime(date('Y-m-d')." 06:00:00")]])->count(),
],
'login_member'=>[
"title"=>"今日金额",
"data"=> (new MallOrder())->where([['create_time','>',strtotime(date('Y-m-d')." 06:00:00")]])->sum('money'),
],
'recharge_member'=>[
"title"=>"今日已支付",
"data"=>(new MallOrder())->where([['create_time','>',strtotime(date('Y-m-d')." 06:00:00")],['status','=',2]])->count(),
],
'all_charge'=>[
"title"=>"今日已支付金额",
"data"=>(new MallOrder())->where([['create_time','>',strtotime(date('Y-m-d')." 06:00:00")],['status','=',2]])->sum('money'),
],
'day_charge'=>[
"title"=>"待处理订单",
"data"=>(new MallOrder())->where([['create_time','>',strtotime(date('Y-m-d')." 06:00:00")],['status','=',0]])->count(),
],
'recharge_number'=>[
"title"=>"总订单数",
"data"=>(new MallOrder())->count(),
],
];
$this->assign('data', $data);
return $this->fetch();
}
public function get_order()
{
$this->success('操作成功', [
'count'=>(new MallOrder())->where([['create_time','>',strtotime(date('Y-m-d')." 06:00:00")],['status','=',0]])->count(),
'rid'=>(new MallOrder())->where([['create_time','>',strtotime(date('Y-m-d')." 06:00:00")],['status','=',0]])
->order('id desc')->value('id')
]);
}
/**
* 修改管理员信息
* @param Request $request
* @return string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function editAdmin(Request $request): string
{
$id = $this->adminUid;
$row = (new SystemAdmin())
->withoutField('password')
->find($id);
empty($row) && $this->error('用户信息不存在');
if ($request->isPost()) {
$post = $request->post();
$this->isDemo && $this->error('演示环境下不允许修改');
$rule = [];
$this->validate($post, $rule);
try {
$login_type = $post['login_type'] ?? 1;
if ($login_type == 2) {
$ga_secret = (new SystemAdmin())->where('id', $id)->value('ga_secret');
if (empty($ga_secret)) $this->error('请先绑定谷歌验证器');
}
$save = $row->allowField(['head_img', 'phone', 'remark', 'update_time', 'login_type'])->save($post);
}catch (\PDOException $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
$notes = (new SystemAdmin())->notes;
$this->assign('notes', $notes);
return $this->fetch();
}
/**
* 修改密码
* @param Request $request
* @return string
*/
public function editPassword(Request $request): string
{
$id = $this->adminUid;
$row = (new SystemAdmin())
->withoutField('password')
->find($id);
if (!$row) {
$this->error('用户信息不存在');
}
if ($request->isPost()) {
$post = $request->post();
$this->isDemo && $this->error('演示环境下不允许修改');
$rule = [
'password|登录密码' => 'require',
'password_again|确认密码' => 'require',
];
$this->validate($post, $rule);
if ($post['password'] != $post['password_again']) {
$this->error('两次密码输入不一致');
}
try {
$save = $row->save([
'password' => password_hash($post['password'], PASSWORD_DEFAULT),
]);
}catch (Exception $e) {
$this->error('保存失败');
}
if ($save) {
$this->success('保存成功');
}else {
$this->error('保存失败');
}
}
$this->assign('row', $row);
return $this->fetch();
}
/**
* 设置谷歌验证码
* @param Request $request
* @return string
* @throws Exception
*/
public function set2fa(Request $request): string
{
$id = $this->adminUid;
$row = (new SystemAdmin())->withoutField('password')->find($id);
if (!$row) $this->error('用户信息不存在');
// You can see: https://gitee.com/wolf-code/authenticator
$ga = new \Wolfcode\Authenticator\google\PHPGangstaGoogleAuthenticator();
if (!$request->isAjax()) {
$old_secret = $row->ga_secret;
$secret = $ga->createSecret(32);
$ga_title = $this->isDemo ? 'EasyAdmin8演示环境' : '可自定义修改显示标题';
$dataUri = $ga->getQRCode($ga_title, $secret);
$this->assign(compact('row', 'dataUri', 'old_secret', 'secret'));
return $this->fetch();
}
$this->isDemo && $this->error('演示环境下不允许修改');
$post = $request->post();
$ga_secret = $post['ga_secret'] ?? '';
$ga_code = $post['ga_code'] ?? '';
if (empty($ga_code)) $this->error('请输入验证码');
if (!$ga->verifyCode($ga_secret, $ga_code)) $this->error('验证码错误');
$row->ga_secret = $ga_secret;
$row->login_type = 2;
$row->save();
$this->success('操作成功');
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace app\admin\controller;
use app\admin\model\SystemAdmin;
use app\common\controller\AdminController;
use app\common\utils\Helper;
use think\captcha\facade\Captcha;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use app\Request;
use think\Response;
use Wolfcode\RateLimiting\Attributes\RateLimitingMiddleware;
class Login extends AdminController
{
protected bool $ignoreLogin = true;
public function initialize(): void
{
parent::initialize();
$action = $this->request->action();
if (!empty($this->adminUid) && !in_array($action, ['out'])) {
$adminModuleName = config('admin.alias_name');
$this->success('已登录,无需再次登录', [], __url("@{$adminModuleName}"));
}
}
/**
* 用户登录
* @param Request $request
* @return string
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
#[RateLimitingMiddleware(key: [Helper::class, 'getIp'], seconds: 1, limit: 1, message: '请求过于频繁')]
public function index(Request $request): string
{
$captcha = env('EASYADMIN.CAPTCHA', 1);
if (!$request->isPost()) return $this->fetch('', compact('captcha'));
$post = $request->post();
$rule = [
'username|用户名' => 'require',
'password|密码' => 'require',
'keep_login|是否保持登录' => 'require',
];
$captcha == 1 && $rule['captcha|验证码'] = 'require|captcha';
$this->validate($post, $rule);
$admin = SystemAdmin::where(['username' => $post['username']])->find();
if (empty($admin)) {
$this->error('用户不存在');
}
if (!password_verify($post['password'], $admin->password)) {
$this->error('密码输入有误');
}
if ($admin->status == 0) {
$this->error('账号已被禁用');
}
if ($admin->login_type == 2) {
if (empty($post['ga_code'])) $this->error('请输入谷歌验证码', ['is_ga_code' => true]);
$ga = new \Wolfcode\Authenticator\google\PHPGangstaGoogleAuthenticator();
if (!$ga->verifyCode($admin->ga_secret, $post['ga_code'])) $this->error('谷歌验证码错误');;
}
$admin->login_num += 1;
$admin->save();
$admin = $admin->toArray();
unset($admin['password']);
$admin['expire_time'] = $post['keep_login'] == 1 ? 0 : time() + 7200;
session('admin', $admin);
$this->success('登录成功');
}
/**
* 用户退出
*/
public function out(): void
{
session('admin', null);
$this->success('退出登录成功');
}
/**
* 验证码
* @return Response
*/
public function captcha(): Response
{
return Captcha::instance()->create();
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace app\admin\controller\article;
use app\admin\service\annotation\NodeAnnotation;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\common\model\Articles;
use think\App;
#[ControllerAnnotation(title: '文章管理')]
class Article extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
self::$model = Articles::class;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace app\admin\controller\article;
use app\admin\service\annotation\NodeAnnotation;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\common\model\ArticleCates;
use think\App;
#[ControllerAnnotation(title: '文章分类管理')]
class Cate extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
self::$model = ArticleCates::class;
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace app\admin\controller\mall;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\MiddlewareAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\common\controller\AdminController;
use app\Request;
use think\App;
use think\response\Json;
#[ControllerAnnotation(title: '商城商品管理')]
class Blackip extends AdminController
{
#[NodeAnnotation(ignore: ['export'])] // 过滤不需要生成的权限节点 默认 CURD 中会自动生成部分节点 可以在此处过滤
protected array $ignoreNode;
public function __construct(App $app)
{
parent::__construct($app);
self::$model = new \app\admin\model\BlackIp();
}
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
if ($request->isAjax()) {
if (input('selectFields')) return $this->selectList();
list($page, $limit, $where) = $this->buildTableParams();
$count = self::$model::where($where)->count();
$list = self::$model::where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOGIN)]
public function no_check_login(Request $request): string
{
return '这里演示方法不需要经过登录验证';
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace app\admin\controller\mall;
use app\admin\model\MallCate;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use think\App;
#[ControllerAnnotation(title: '商品分类管理')]
class Cate extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
self::$model = MallCate::class;
}
}

View File

@ -0,0 +1,135 @@
<?php
namespace app\admin\controller\mall;
use app\admin\model\MallCate;
use app\admin\model\MallGoods;
use app\admin\service\annotation\MiddlewareAnnotation;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\App;
use think\response\Json;
use Wolfcode\Ai\Enum\AiType;
use Wolfcode\Ai\Service\AiChatService;
#[ControllerAnnotation(title: '商城商品管理')]
class Goods extends AdminController
{
#[NodeAnnotation(ignore: ['export'])] // 过滤不需要生成的权限节点 默认 CURD 中会自动生成部分节点 可以在此处过滤
protected array $ignoreNode;
public function __construct(App $app)
{
parent::__construct($app);
self::$model = new MallGoods();
$this->assign('cate', MallCate::column('title', 'id'));
}
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
if ($request->isAjax()) {
if (input('selectFields')) return $this->selectList();
list($page, $limit, $where) = $this->buildTableParams();
$count = self::$model::where($where)->count();
$list = self::$model::with(['cate'])->where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
#[NodeAnnotation(title: '入库', auth: true)]
public function stock(Request $request, $id): string
{
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
if ($request->isPost()) {
$post = $request->post();
$rule = [];
$this->validate($post, $rule);
try {
$post['total_stock'] = $row->total_stock + $post['stock'];
$post['stock'] = $row->stock + $post['stock'];
$save = $row->save($post);
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
return $this->fetch();
}
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOGIN)]
public function no_check_login(Request $request): string
{
return '这里演示方法不需要经过登录验证';
}
#[NodeAnnotation(title: 'AI优化', auth: true)]
public function aiOptimization(Request $request): void
{
$message = $request->post('message');
if (empty($message)) $this->error('请输入内容');
// 演示环境下 默认返回的内容
if ($this->isDemo) {
$content = <<<EOF
演示环境中 默认返回的内容
我来帮你优化这个标题,让它更有吸引力且更符合电商平台的搜索逻辑:
"商务男士高端定制马克杯 | 办公室精英必备 | 优质陶瓷防烫手柄"
这个优化后的标题:
1. 突出了目标用户群体(商务男士)
2. 强调了产品定位(高端定制)
3. 点明了使用场景(办公室)
4. 添加了材质和功能特点(优质陶瓷、防烫手柄)
5. 使用了吸引人的关键词(精英必备)
这样的标题不仅更具体,也更容易被搜索引擎识别,同时能精准触达目标客户群。您觉得这个版本如何?
EOF;
$choices = [['message' => [
'role' => 'assistant',
'content' => $content,
]]];
$this->success('success', compact('choices'));
}
try {
$result = AiChatService::instance()
// 当使用推理模型时,可能存在超时的情况,所以需要设置超时时间为 0
// ->setTimeLimit(0)
// 请替换为您需要的模型类型
->setAiType(AiType::QWEN)
// 如果需要指定模型的 API 地址,可自行设置
// ->setAiUrl('https://xxx.com')
// 请替换为您的模型
->setAiModel('qwen-plus')
// 请替换为您的 API KEY
->setAiKey('sk-1234567890')
// 此内容会作为系统提示,会影响到回答的内容 当前仅作为测试使用
->setSystemContent('你现在是一位资深的海外电商产品经理')
->chat($message);
$choices = $result['choices'];
}catch (\Throwable $exception) {
$choices = [['message' => [
'role' => 'assistant',
'content' => $exception->getMessage(),
]]];
}
$this->success('success', compact('choices'));
}
}

View File

@ -0,0 +1,120 @@
<?php
namespace app\admin\controller\mall;
use app\admin\model\MallOrder;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\MiddlewareAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\common\controller\AdminController;
use app\Request;
use think\App;
use think\facade\Db;
use think\response\Json;
use Wolfcode\Ai\Enum\AiType;
use Wolfcode\Ai\Service\AiChatService;
#[ControllerAnnotation(title: '商城商品管理')]
class Order extends AdminController
{
#[NodeAnnotation(ignore: ['export'])] // 过滤不需要生成的权限节点 默认 CURD 中会自动生成部分节点 可以在此处过滤
protected array $ignoreNode;
public function __construct(App $app)
{
parent::__construct($app);
self::$model = new MallOrder();
}
protected array $allowModifyFields = [
'status',
'sort',
'remark',
'is_delete',
'is_auth',
'title',
'url',
];
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
if ($request->isAjax()) {
if (input('selectFields')) return $this->selectList();
list($page, $limit, $where) = $this->buildTableParams();
$count = self::$model::where($where)->count();
$list = self::$model::where($where)->page($page, $limit)->order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
#[NodeAnnotation(title: '确认支付成功', auth: true)]
public function recharge(Request $request, $id): string
{
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
if ($request->isPost()) {
$post = $request->post();
try {
$post['status'] = 2;
$save = $row->save($post);
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('确认支付成功') : $this->error('保存失败');
}
}
#[NodeAnnotation(title: '编辑', auth: true)]
public function edit(Request $request, $id = 0): string
{
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
if ($request->isPost()) {
$post = $request->post();
$rule = [];
$this->validate($post, $rule);
try {
Db::transaction(function() use ($post, $row, &$save) {
$post['status'] = 1;
$save = $row->save($post);
});
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
return $this->fetch();
}
#[NodeAnnotation(title: 'IP拉黑', auth: true)]
public function blockip(Request $request, $id): string
{
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
if ($request->isPost()) {
try {
$save = (new \app\admin\model\BlackIp())->save([
'ip' => $row->ip,
]);
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('IP拉黑成功') : $this->error('保存失败');
}
}
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOGIN)]
public function no_check_login(Request $request): string
{
return '这里演示方法不需要经过登录验证';
}
}

View File

@ -0,0 +1,179 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemAdmin;
use app\admin\service\TriggerService;
use app\common\constants\AdminConstant;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\App;
use think\response\Json;
#[ControllerAnnotation(title: '管理员管理')]
class Admin extends AdminController
{
protected array $sort = [
'sort' => 'desc',
'id' => 'desc',
];
public function __construct(App $app)
{
parent::__construct($app);
self::$model = SystemAdmin::class;
$this->assign('auth_list', self::$model::getAuthList());
}
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
list($page, $limit, $where) = $this->buildTableParams();
$count = self::$model::where($where)->count();
$list = self::$model::withoutField('password')
->where($where)
->page($page, $limit)
->order($this->sort)
->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
#[NodeAnnotation(title: '添加', auth: true)]
public function add(Request $request): string
{
if ($request->isPost()) {
$post = $request->post();
$authIds = $request->post('auth_ids', []);
$post['auth_ids'] = implode(',', array_keys($authIds));
$rule = [];
$this->validate($post, $rule);
if (empty($post['password'])) $post['password'] = '123456';
$post['password'] = password_hash($post['password'],PASSWORD_DEFAULT);
try {
$save = self::$model::create($post);
}catch (\Exception $e) {
$this->error('保存失败' . $e->getMessage());
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
return $this->fetch();
}
#[NodeAnnotation(title: '编辑', auth: true)]
public function edit(Request $request, $id = 0): string
{
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
if ($request->isPost()) {
$post = $request->post();
$authIds = $request->post('auth_ids', []);
$post['auth_ids'] = implode(',', array_keys($authIds));
$rule = [];
$this->validate($post, $rule);
try {
$save = $row->save($post);
TriggerService::updateMenu($id);
}catch (\Exception $e) {
$this->error('保存失败' . $e->getMessage());
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
return $this->fetch();
}
#[NodeAnnotation(title: '设置密码', auth: true)]
public function password(Request $request, $id): string
{
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
if ($request->isAjax()) {
$post = $request->post();
$rule = [
'password|登录密码' => 'require',
'password_again|确认密码' => 'require',
];
$this->validate($post, $rule);
if ($post['password'] != $post['password_again']) {
$this->error('两次密码输入不一致');
}
try {
$save = $row->save([
'password' => password_hash($post['password'],PASSWORD_DEFAULT),
]);
}catch (\Exception $e) {
$this->error('保存失败');
}
$save ? $this->success('保存成功') : $this->error('保存失败');
}
$this->assign('row', $row);
return $this->fetch();
}
#[NodeAnnotation(title: '删除', auth: true)]
public function delete(Request $request): void
{
$this->checkPostRequest();
$id = $request->param('id');
$row = self::$model::whereIn('id', $id)->select();
$row->isEmpty() && $this->error('数据不存在');
$id == AdminConstant::SUPER_ADMIN_ID && $this->error('超级管理员不允许修改');
if (is_array($id)) {
if (in_array(AdminConstant::SUPER_ADMIN_ID, $id)) {
$this->error('超级管理员不允许修改');
}
}
try {
$save = $row->delete();
}catch (\Exception $e) {
$this->error('删除失败');
}
$save ? $this->success('删除成功') : $this->error('删除失败');
}
#[NodeAnnotation(title: '属性修改', auth: true)]
public function modify(Request $request): void
{
$this->checkPostRequest();
$post = $request->post();
$rule = [
'id|ID' => 'require',
'field|字段' => 'require',
'value|值' => 'require',
];
$this->validate($post, $rule);
if (!in_array($post['field'], $this->allowModifyFields)) {
$this->error('该字段不允许修改:' . $post['field']);
}
if ($post['id'] == AdminConstant::SUPER_ADMIN_ID && $post['field'] == 'status') {
$this->error('超级管理员状态不允许修改');
}
$row = self::$model::find($post['id']);
empty($row) && $this->error('数据不存在');
try {
$row->save([
$post['field'] => $post['value'],
]);
}catch (\Exception $e) {
$this->error($e->getMessage());
}
$this->success('保存成功');
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\App;
#[ControllerAnnotation(title: '角色权限管理', auth: true)]
class Auth extends AdminController
{
protected array $sort = [
'sort' => 'desc',
'id' => 'desc',
];
public function __construct(App $app)
{
parent::__construct($app);
self::$model = SystemAuth::class;
}
#[NodeAnnotation(title: '授权', auth: true)]
public function authorize(Request $request, $id): string
{
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
if ($request->isAjax()) {
$list = self::$model::getAuthorizeNodeListByAdminId($id);
$this->success('获取成功', $list);
}
$this->assign('row', $row);
return $this->fetch();
}
#[NodeAnnotation(title: '授权保存', auth: true)]
public function saveAuthorize(Request $request): void
{
$this->checkPostRequest();
$id = $request->post('id');
$node = $request->post('node', "[]");
$node = json_decode($node, true);
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
try {
$authNode = new SystemAuthNode();
$authNode->where('auth_id', $id)->delete();
if (!empty($node)) {
$saveAll = [];
foreach ($node as $vo) {
$saveAll[] = [
'auth_id' => $id,
'node_id' => $vo,
];
}
$authNode->saveAll($saveAll);
}
TriggerService::updateMenu();
}catch (\Exception $e) {
$this->error('保存失败');
}
$this->success('保存成功');
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemConfig;
use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\App;
use think\facade\Cache;
use think\response\Json;
#[ControllerAnnotation(title: '系统配置管理')]
class Config extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
self::$model = SystemConfig::class;
$this->assign('upload_types', config('admin.upload_types'));
$this->assign('editor_types', config('admin.editor_types'));
}
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
return $this->fetch();
}
#[NodeAnnotation(title: '保存', auth: true)]
public function save(Request $request): void
{
$this->checkPostRequest();
$post = $request->post();
$notAddFields = ['_token', 'file', 'group'];
try {
$group = $post['group'] ?? '';
if (empty($group)) $this->error('保存失败');
if ($group == 'upload') {
$upload_types = config('admin.upload_types');
// 兼容旧版本
self::$model::where('name', 'upload_allow_type')->update(['value' => implode(',', array_keys($upload_types))]);
}
foreach ($post as $key => $val) {
if (in_array($key, $notAddFields)) continue;
$config_key_data = self::$model::where('name', $key)->find();
if (!is_null($config_key_data)) {
$config_key_data->save(['value' => $val,]);
}else {
self::$model::create(
[
'name' => $key,
'value' => $val,
'group' => $group,
]);
}
if (Cache::has($key)) Cache::set($key, $val);
}
TriggerService::updateMenu();
TriggerService::updateSysConfig();
}catch (\Exception $e) {
$this->error('保存失败' . $e->getMessage());
}
$this->success('保存成功');
}
}

View File

@ -0,0 +1,155 @@
<?php
namespace app\admin\controller\system;
use app\admin\service\curd\BuildCurd;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use think\db\exception\PDOException;
use think\exception\FileException;
use think\facade\Console;
use think\facade\Db;
use think\helper\Str;
use think\response\Json;
#[ControllerAnnotation(title: 'CURD可视化管理')]
class CurdGenerate extends AdminController
{
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
return $this->fetch();
}
#[NodeAnnotation(title: '操作', auth: true)]
public function save(Request $request, string $type = ''): ?Json
{
if (!$request->isAjax()) $this->error();
switch ($type) {
case "search":
$tb_prefix = $request->param('tb_prefix/s', '');
$tb_name = $request->param('tb_name/s', '');
if (empty($tb_name)) $this->error('参数错误');
try {
$list = Db::query("SHOW FULL COLUMNS FROM {$tb_prefix}{$tb_name}");
$data = [];
foreach ($list as $value) {
$data[] = [
'name' => $value['Field'],
'type' => $value['Type'],
'key' => $value['Key'],
'extra' => $value['Extra'],
'null' => $value['Null'],
'desc' => $value['Comment'],
];
}
$this->success('查询成功', compact('data', 'list'));
}catch (PDOException $exception) {
$this->error($exception->getMessage());
}
break;
case "add":
$tb_prefix = $request->param('tb_prefix/s', '');
$tb_name = $request->param('tb_name/s', '');
if (empty($tb_name)) $this->error('参数错误');
$tb_fields = $request->param('tb_fields');
$force = $request->post('force/d', 0);
try {
$build = (new BuildCurd())->setTablePrefix($tb_prefix)->setTable($tb_name);
$build->setForce($force); // 强制覆盖
// 新增字段类型
if ($tb_fields) {
foreach ($tb_fields as $tk => $tf) {
if (empty($tf)) continue;
$tf = array_values($tf);
switch ($tk) {
case 'ignore':
$build->setIgnoreFields($tf, true);
break;
case 'select':
$build->setSelectFields($tf, true);
break;
case 'radio':
$build->setRadioFieldSuffix($tf, true);
break;
case 'checkbox':
$build->setCheckboxFieldSuffix($tf, true);
break;
case 'image':
$build->setImageFieldSuffix($tf, true);
break;
case 'images':
$build->setImagesFieldSuffix($tf, true);
break;
case 'date':
$build->setDateFieldSuffix($tf, true);
break;
case 'datetime':
$build->setDatetimeFieldSuffix($tf, true);
break;
case 'editor':
$build->setEditorFields($tf, true);
break;
default:
break;
}
}
}
$build = $build->render();
$fileList = $build->getFileList();
if (empty($fileList)) $this->error('这里什么都没有');
$result = $build->create();
$_file = $result[0] ?? '';
$link = '';
if (!empty($_file)) {
$_fileExp = explode(DIRECTORY_SEPARATOR, $_file);
$_fileExp_last = array_slice($_fileExp, -2);
$_fileExp_last_0 = $_fileExp_last[0] . '.';
if ($_fileExp_last[0] == 'controller') $_fileExp_last_0 = '';
$link = '/' . config('admin.alias_name') . '/' . $_fileExp_last_0 . Str::snake(explode('.php', end($_fileExp_last))[0] ?? '') . '/index';
}
$this->success('生成成功', compact('result', 'link'));
}catch (FileException $exception) {
return json(['code' => -1, 'msg' => $exception->getMessage()]);
}
break;
case "delete":
$tb_prefix = $request->param('tb_prefix/s', '');
$tb_name = $request->param('tb_name/s', '');
if (empty($tb_name)) $this->error('参数错误');
try {
$build = (new BuildCurd())->setTablePrefix($tb_prefix)->setTable($tb_name);
$build = $build->render();
$fileList = $build->getFileList();
if (empty($fileList)) $this->error('这里什么都没有');
$result = $build->delete();
$this->success('删除自动生成CURD文件成功', compact('result'));
}catch (FileException $exception) {
return json(['code' => -1, 'msg' => $exception->getMessage()]);
}
break;
case 'console':
$command = $request->post('command', '');
if (empty($command)) $this->error('请输入命令');
$commandExp = explode(' ', $command);
$commandExp = array_values(array_filter($commandExp));
try {
$output = Console::call('curd', [...$commandExp]);
}catch (\Throwable $exception) {
$this->error($exception->getMessage() . $exception->getLine());
}
if (empty($output)) $this->error('设置错误');
$this->success($output->fetch());
break;
default:
$this->error('参数错误');
break;
}
}
}

View File

@ -0,0 +1,138 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemLog;
use app\admin\service\annotation\MiddlewareAnnotation;
use app\admin\service\tool\CommonTool;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\Request;
use jianyan\excel\Excel;
use think\App;
use think\db\exception\DbException;
use think\db\exception\PDOException;
use think\facade\Db;
use think\response\Json;
#[ControllerAnnotation(title: '操作日志管理')]
class Log extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
self::$model = SystemLog::class;
}
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
$model = (new self::$model)->setSuffix("_$month")->with('admin')->where($where);
try {
$count = $model->count();
$list = $model->page($page, $limit)->order($this->sort)->select();
}catch (PDOException|DbException $exception) {
$count = 0;
$list = [];
}
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
#[NodeAnnotation(title: '导出', auth: true)]
public function export()
{
if (env('EASYADMIN.IS_DEMO', false)) {
$this->error('演示环境下不允许操作');
}
[$page, $limit, $where, $excludeFields] = $this->buildTableParams(['month']);
$month = !empty($excludeFields['month']) ? date('Ym', strtotime($excludeFields['month'])) : date('Ym');
$tableName = (new self::$model)->setSuffix("_$month")->getName();
$tableName = CommonTool::humpToLine(lcfirst($tableName));
$prefix = config('database.connections.mysql.prefix');
$dbList = Db::query("show full columns from {$prefix}{$tableName}");
$header = [];
foreach ($dbList as $vo) {
$comment = !empty($vo['Comment']) ? $vo['Comment'] : $vo['Field'];
if (!in_array($vo['Field'], $this->noExportFields)) {
$header[] = [$comment, $vo['Field']];
}
}
$model = (new self::$model)->setSuffix("_$month")->with('admin')->where($where);
try {
$list = $model
->limit(10000)
->order('id', 'desc')
->select()
->toArray();
foreach ($list as &$vo) {
$vo['content'] = json_encode($vo['content'], JSON_UNESCAPED_UNICODE);
$vo['response'] = json_encode($vo['response'], JSON_UNESCAPED_UNICODE);
}
exportExcel($header, $list, '操作日志');
}catch (\Throwable $exception) {
$this->error($exception->getMessage());
}
}
#[NodeAnnotation(title: '删除指定日志', auth: true)]
public function deleteMonthLog(Request $request)
{
if (!$request->isAjax()) {
return $this->fetch();
}
if ($this->isDemo) $this->error('演示环境下不允许操作');
$monthsAgo = $request->param('month/d', 0);
if ($monthsAgo < 1) $this->error('月份错误');
$currentDate = new \DateTime();
$currentDate->modify("-$monthsAgo months");
$dbPrefix = env('DB_PREFIX');
$dbLike = "{$dbPrefix}system_log_";
$tables = Db::query("SHOW TABLES LIKE '$dbLike%'");
$threshold = date('Ym', strtotime("-$monthsAgo month"));
$tableNames = [];
try {
foreach ($tables as $table) {
$tableName = current($table);
if (!preg_match("/^$dbLike\d{6}$/", $tableName)) continue;
$datePart = substr($tableName, -6);
$issetTable = Db::query("SHOW TABLES LIKE '$tableName'");
if (!$issetTable) continue;
if ($datePart - $threshold <= 0) {
Db::execute("DROP TABLE `$tableName`");
$tableNames[] = $tableName;
}
}
}catch (PDOException) {
}
if (empty($tableNames)) $this->error('没有需要删除的表');
$this->success('操作成功 - 共删除 ' . count($tableNames) . ' 张表<br/>' . implode('<br>', $tableNames));
}
#[MiddlewareAnnotation(ignore: MiddlewareAnnotation::IGNORE_LOG)]
#[NodeAnnotation(title: '框架日志', auth: true, ignore: NodeAnnotation::IGNORE_NODE)]
public function record(): Json|string
{
return (new \Wolfcode\PhpLogviewer\thinkphp\LogViewer())->fetch();
}
}

View File

@ -0,0 +1,191 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemMenu;
use app\admin\model\SystemNode;
use app\admin\service\TriggerService;
use app\common\constants\MenuConstant;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\common\controller\AdminController;
use app\Request;
use think\App;
use think\response\Json;
#[ControllerAnnotation(title: '菜单管理')]
class Menu extends AdminController
{
protected array $sort = [
'sort' => 'desc',
'id' => 'asc',
];
public function __construct(App $app)
{
parent::__construct($app);
self::$model = SystemMenu::class;
}
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
$count = self::$model::count();
$list = self::$model::order($this->sort)->select()->toArray();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
#[NodeAnnotation(title: '添加', auth: true)]
public function add(Request $request): string
{
$id = $request->param('id');
$homeId = self::$model::where(['pid' => MenuConstant::HOME_PID,])->value('id');
if ($id == $homeId) {
$this->error('首页不能添加子菜单');
}
if ($request->isPost()) {
$post = $request->post();
$rule = [
'pid|上级菜单' => 'require',
'title|菜单名称' => 'require',
'icon|菜单图标' => 'require',
];
$this->validate($post, $rule);
try {
$save = self::$model::create($post);
}catch (\Exception $e) {
$this->error('保存失败');
}
if ($save) {
TriggerService::updateMenu();
$this->success('保存成功');
}else {
$this->error('保存失败');
}
}
$pidMenuList = self::$model::getPidMenuList();
$this->assign('id', $id);
$this->assign('pidMenuList', $pidMenuList);
return $this->fetch();
}
#[NodeAnnotation(title: '编辑', auth: true)]
public function edit(Request $request, $id = 0): string
{
$row = self::$model::find($id);
empty($row) && $this->error('数据不存在');
if ($request->isPost()) {
$post = $request->post();
$rule = [
'pid|上级菜单' => 'require',
'title|菜单名称' => 'require',
'icon|菜单图标' => 'require',
];
$this->validate($post, $rule);
if ($row->pid == MenuConstant::HOME_PID) $post['pid'] = MenuConstant::HOME_PID;
try {
$save = $row->save($post);
}catch (\Exception $e) {
$this->error('保存失败');
}
if (!empty($save)) {
TriggerService::updateMenu();
$this->success('保存成功');
}else {
$this->error('保存失败');
}
}
$pidMenuList = self::$model::getPidMenuList();
$this->assign([
'id' => $id,
'pidMenuList' => $pidMenuList,
'row' => $row,
]);
return $this->fetch();
}
#[NodeAnnotation(title: '删除', auth: true)]
public function delete(Request $request): void
{
$this->checkPostRequest();
$id = $request->param('id');
$row = self::$model::whereIn('id', $id)->select();
empty($row) && $this->error('数据不存在');
try {
$save = $row->delete();
}catch (\Exception $e) {
$this->error('删除失败');
}
if ($save) {
TriggerService::updateMenu();
$this->success('删除成功');
}else {
$this->error('删除失败');
}
}
#[NodeAnnotation(title: '属性修改', auth: true)]
public function modify(Request $request): void
{
$this->checkPostRequest();
$post = $request->post();
$rule = [
'id|ID' => 'require',
'field|字段' => 'require',
'value|值' => 'require',
];
$this->validate($post, $rule);
$row = self::$model::find($post['id']);
if (!$row) {
$this->error('数据不存在');
}
if (!in_array($post['field'], $this->allowModifyFields)) {
$this->error('该字段不允许修改:' . $post['field']);
}
$homeId = self::$model::where([
'pid' => MenuConstant::HOME_PID,
])
->value('id');
if ($post['id'] == $homeId && $post['field'] == 'status') {
$this->error('首页状态不允许关闭');
}
try {
$row->save([
$post['field'] => $post['value'],
]);
}catch (\Exception $e) {
$this->error($e->getMessage());
}
TriggerService::updateMenu();
$this->success('保存成功');
}
#[NodeAnnotation(title: '添加菜单提示', auth: true)]
public function getMenuTips(): Json
{
$node = input('get.keywords');
$list = SystemNode::whereLike('node', "%{$node}%")
->field('node,title')
->limit(10)
->select()->toArray();
return json([
'code' => 0,
'content' => $list,
'type' => 'success',
]);
}
}

View File

@ -0,0 +1,125 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemMenu;
use app\admin\model\SystemNode;
use app\admin\service\TriggerService;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use app\admin\service\NodeService;
use app\Request;
use think\App;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
#[ControllerAnnotation(title: '系统节点管理')]
class Node extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
self::$model = SystemNode::class;
}
#[NodeAnnotation(title: '列表', auth: true)]
public function index(Request $request): Json|string
{
if ($request->isAjax()) {
if (input('selectFields')) {
return $this->selectList();
}
$count = self::$model::count();
$list = self::$model::getNodeTreeList();
$data = [
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
];
return json($data);
}
return $this->fetch();
}
#[NodeAnnotation(title: '系统节点更新', auth: true)]
public function refreshNode($force = 0): void
{
$this->checkPostRequest();
$nodeList = (new NodeService())->getNodeList();
empty($nodeList) && $this->error('暂无需要更新的系统节点');
try {
if ($force == 1) {
$updateNodeList = self::$model::whereIn('node', array_column($nodeList, 'node'))->select();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($updateNodeList as $vo) {
isset($formatNodeList[$vo['node']])
&& self::$model::where('id', $vo['id'])->update(
[
'title' => $formatNodeList[$vo['node']]['title'],
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
]
);
}
}
$existNodeList = self::$model::field('node,title,type,is_auth')->select();
foreach ($nodeList as $key => $vo) {
foreach ($existNodeList as $v) {
if ($vo['node'] == $v->node) {
unset($nodeList[$key]);
break;
}
}
}
if (!empty($nodeList)) {
(new self::$model)->saveAll($nodeList);
TriggerService::updateNode();
}
}catch (\Exception $e) {
$this->error('节点更新失败');
}
$this->success('节点更新成功');
}
#[NodeAnnotation(title: '清除失效节点', auth: true)]
public function clearNode(): void
{
$this->checkPostRequest();
$nodeList = (new NodeService())->getNodeList();
try {
$existNodeList = self::$model::field('id,node,title,type,is_auth')->select()->toArray();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($existNodeList as $vo) {
!isset($formatNodeList[$vo['node']]) && self::$model::where('id', $vo['id'])->delete();
}
TriggerService::updateNode();
}catch (\Exception $e) {
$this->error('节点更新失败');
}
$this->success('节点更新成功');
}
/**
* @throws \ReflectionException
* @throws \Doctrine\Common\Annotations\AnnotationException
*/
#[NodeAnnotation(title: '刷新菜单', auth: true)]
public function refreshMenu(): void
{
$this->checkPostRequest();
$nodeList = (new NodeService())->getNodeList();
empty($nodeList) && $this->error('暂无需要更新的系统节点');
try {
SystemMenu::refreshMenu($nodeList);
}catch (\Exception $e) {
$this->error($e->getMessage());
}
$this->success('菜单刷新成功');
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemQuick;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use think\App;
#[ControllerAnnotation(title: '快捷入口管理')]
class Quick extends AdminController
{
protected array $sort = [
'sort' => 'desc',
'id' => 'desc',
];
public function __construct(App $app)
{
parent::__construct($app);
self::$model = SystemQuick::class;
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace app\admin\controller\system;
use app\admin\model\SystemUploadfile;
use app\common\controller\AdminController;
use app\admin\service\annotation\ControllerAnnotation;
use app\admin\service\annotation\NodeAnnotation;
use think\App;
#[ControllerAnnotation(title: '上传文件管理')]
class Uploadfile extends AdminController
{
public function __construct(App $app)
{
parent::__construct($app);
self::$model = SystemUploadfile::class;
$this->assign('upload_types', config('admin.upload_types'));
}
}