Browse Source

新分支

huwhois 1 year ago
parent
commit
0469249fc6
100 changed files with 3106 additions and 3384 deletions
  1. 0 1
      .gitignore
  2. 4 4
      app/api/controller/Index.php
  3. 153 0
      app/command/FileConsole.php
  4. 1 1
      app/command/MakeController.php
  5. 1 1
      app/command/MakeModel.php
  6. 0 86
      app/common/command/FileConsole.php
  7. 0 21
      app/common/facade/ControllerUtils.php
  8. 0 21
      app/common/facade/ModelUtils.php
  9. 0 21
      app/common/facade/ValidateUtils.php
  10. 0 20
      app/common/facade/VueUtils.php
  11. 0 359
      app/common/service/FileService.php
  12. 0 0
      app/config/route.php
  13. 11 11
      app/config/view.php
  14. 9 9
      app/controller/Article.php
  15. 74 86
      app/controller/Base.php
  16. 72 76
      app/controller/Index.php
  17. 9 7
      app/controller/sys/Article.php
  18. 424 420
      app/controller/sys/Base.php
  19. 106 106
      app/controller/sys/Category.php
  20. 304 539
      app/controller/sys/FileManager.php
  21. 2 2
      app/controller/sys/GuestBook.php
  22. 6 6
      app/controller/sys/Index.php
  23. 47 42
      app/controller/sys/Login.php
  24. 2 2
      app/controller/sys/SysLog.php
  25. 2 2
      app/controller/sys/SysLogin.php
  26. 92 92
      app/controller/sys/SysMenu.php
  27. 4 4
      app/controller/sys/SysRole.php
  28. 3 3
      app/controller/sys/SysUser.php
  29. 2 2
      app/controller/sys/System.php
  30. 0 0
      app/controller/sys/common.php
  31. 0 0
      app/controller/sys/config/app.php
  32. 0 0
      app/controller/sys/config/view.php
  33. 0 0
      app/controller/sys/event.php
  34. 1 1
      app/controller/sys/listener/SysUserLog.php
  35. 0 0
      app/controller/sys/middleware.php
  36. 21 0
      app/facade/ControllerUtils.php
  37. 6 7
      app/facade/FileFacade.php
  38. 21 0
      app/facade/ModelFacade.php
  39. 6 6
      app/facade/StringFacade.php
  40. 21 0
      app/facade/ValidateFacade.php
  41. 20 0
      app/facade/VueFacade.php
  42. 0 13
      app/index/config/app.php
  43. 134 135
      app/middleware/Admin.php
  44. 2 2
      app/model/Article.php
  45. 27 27
      app/model/ArticleBrowerHistory.php
  46. 1 1
      app/model/ArticleDolikeLog.php
  47. 1 1
      app/model/ArticleTags.php
  48. 1 1
      app/model/Base.php
  49. 63 63
      app/model/Category.php
  50. 1 1
      app/model/FileManager.php
  51. 1 1
      app/model/GuestBook.php
  52. 1 1
      app/model/Module.php
  53. 1 1
      app/model/News.php
  54. 1 1
      app/model/Search.php
  55. 2 2
      app/model/SysLog.php
  56. 1 1
      app/model/SysLogin.php
  57. 2 2
      app/model/SysLoginFail.php
  58. 4 4
      app/model/SysMenu.php
  59. 1 1
      app/model/SysRole.php
  60. 4 4
      app/model/SysUser.php
  61. 1 1
      app/model/System.php
  62. 2 2
      app/model/Tag.php
  63. 3 3
      app/model/TagArticle.php
  64. 1 1
      app/model/Template.php
  65. 1 1
      app/model/TemplateType.php
  66. 173 0
      app/service/FileService.php
  67. 0 358
      app/sys/controller/Ueditor.php
  68. 90 90
      app/taglib/Tp.php
  69. 77 0
      app/utils/AliyunSmsUtils.php
  70. 74 0
      app/utils/CollectionUtils.php
  71. 82 82
      app/utils/ControllerUtils.php
  72. 2 2
      app/utils/FileUtils.php
  73. 155 155
      app/utils/ModelUtils.php
  74. 1 1
      app/utils/ParsedownUtils.php
  75. 1 1
      app/utils/ReUtils.php
  76. 73 0
      app/utils/StringUtils.php
  77. 115 0
      app/utils/ValidateUtils.php
  78. 120 0
      app/utils/ZipUtils.php
  79. 64 64
      app/utils/stubs/controller.stub
  80. 110 110
      app/utils/stubs/form.vue.stub
  81. 152 152
      app/utils/stubs/index.vue.stub
  82. 18 18
      app/utils/stubs/model.stub
  83. 21 21
      app/utils/stubs/validate.stub
  84. 0 1
      composer.json
  85. 0 48
      composer.lock
  86. 8 0
      config/app.php
  87. 3 3
      config/console.php
  88. 4 0
      config/view.php
  89. 1 0
      data/index.html
  90. 0 0
      public/static/css/index.css
  91. 31 1
      route/app.php
  92. 2 0
      vendor/.gitignore
  93. 0 0
      view/404.html
  94. 0 0
      view/article/archive.html
  95. 0 0
      view/article/article.bak.html
  96. 49 49
      view/article/index.html
  97. 0 0
      view/article/lists.bak.html
  98. 0 0
      view/article/read.html
  99. 0 0
      view/article/tag.html
  100. 0 0
      view/article/time.html

+ 0 - 1
.gitignore

@@ -1,6 +1,5 @@
 /.idea
 /.vscode
-/vendor
 *.log
 .env
 /public/static/plugins/ckeditor/ckeditor5/ckeditor.js.map

+ 4 - 4
app/api/controller/Index.php

@@ -6,10 +6,10 @@ namespace app\api\controller;
 use think\App;
 use think\exception\HttpException;
 
-use app\common\model\Category;
-use app\common\model\Article;
-use app\common\model\ArticleTags;
-use app\common\model\ArticleDolikeLog;
+use app\model\Category;
+use app\model\Article;
+use app\model\ArticleTags;
+use app\model\ArticleDolikeLog;
 
 class Index
 {

+ 153 - 0
app/command/FileConsole.php

@@ -0,0 +1,153 @@
+<?php
+
+declare(strict_types=1);
+
+namespace app\command;
+
+use DirectoryIterator;
+use SplFileInfo;
+
+// 引入框架内置类
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Argument;
+use think\console\input\Option;
+use think\console\Output;
+use think\facade\Config;
+use think\File;
+
+use app\model\FileManager;
+
+class FileConsole extends Command
+{
+    protected function configure()
+    {
+        // 指令配置
+        $this->setName('fileconsole')
+            ->addArgument('name', Argument::OPTIONAL, "console name")
+            ->addOption('dir', null, Option::VALUE_REQUIRED, 'directory name')
+            ->addOption('savedir', null, Option::VALUE_REQUIRED, 'savedir name')
+            ->setDescription('the fileconsole command');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $name = trim($input->getArgument('name'));
+        $name = $name ?: 'thinkphp';
+
+        if ($input->hasOption('dir')) {
+            $dir = str_replace("\\", '/', app()->getRootPath() . $input->getOption('dir'));
+        } else {
+            $dir = str_replace("\\", '/', Config::get('filesystem.disks.public.root')) . '/';
+        }
+        if ($input->hasOption('savedir')) {
+            $savedir = str_replace("\\", '/', app()->getRootPath() . $input->getOption('savedir'));
+
+            // 指令输出
+            $output->writeln('fileconsole :' . $name . "--dir: " . $dir . '--savedir' . $savedir);
+
+            $this->$name($dir, $savedir);
+        } else {
+            // 指令输出
+            $output->writeln('fileconsole :' . $name . "--dir: " . $dir);
+    
+            $this->$name($dir);
+        }
+
+        $output->writeln("\n..ok");
+    }
+
+    public function thinkphp()
+    {
+        echo "hello thinkphp";
+    }
+
+    /**
+     * 建立文件管理目录索引(递归遍历目录)
+     */
+    public function scan($dir)
+    {
+        echo "test" . $dir;
+    }
+
+    /**
+     * 建立文件管理目录索引(递归遍历目录)
+     */
+    public function markwater($dir, $savepath = 'test/cpw', $watermark = "test/watermark2.png")
+    {
+        $source = str_replace("\\", '/', app()->getRootPath() . $watermark);
+
+        $savepath = str_replace("\\", '/', app()->getRootPath() . $savepath);
+
+        if (is_dir($dir)) {
+            $dirs = new DirectoryIterator($dir);
+
+            foreach ($dirs as $fileInfo) {
+                if ($fileInfo->isDot() || $fileInfo->getFilename() == '.gitignore') {
+                    continue;
+                }
+
+                $filename = $dirs->getPath() . '/' . $fileInfo->getFilename();
+                $savename = str_replace("\\", '/', $savepath . '/' . $fileInfo->getFilename());
+
+                echo $filename . "\n";
+                echo $savename . "\n";
+
+                $image = \think\Image::open($filename);
+
+                $image->water($source, \think\Image::WATER_NORTHWEST)->save($savename);
+
+                $image = null;
+            }
+        }
+    }
+
+    /**
+     * 重置图片文件大小
+     */
+    public function resize($dir, $savepath = 'test/resize', $xmax = 1000, $ymax = 1000)
+    {
+        $savepath = str_replace("\\", '/', app()->getRootPath() . $savepath);
+        
+        if (!file_exists($savepath)) {
+            mkdir($savepath, 0755);
+        }
+
+        if (is_dir($dir)) {
+            $dirs = new DirectoryIterator($dir);
+
+            foreach ($dirs as $fileInfo) {
+                if ($fileInfo->isDot() || $fileInfo->getFilename() == '.gitignore') {
+                    continue;
+                }
+
+                $filename = $dirs->getPath() . '/' . $fileInfo->getFilename();
+                $savename = str_replace("\\", '/', $savepath . '/' . $fileInfo->getFilename());
+
+                echo $filename . "\n";
+                echo $savename . "\n";
+
+                $image = \think\Image::open($filename);
+
+                $image->thumb($xmax, $ymax)->save($savename);
+
+                $image = null;
+            }
+        }
+    }
+
+    /**
+     * 清除无效目录索引
+     */
+    public function clear($dir = '')
+    {
+        $list = FileManager::select();
+        
+        foreach ($list as $value) {
+            $file = app()->getRootPath() . 'public/' . $value->filepath;
+            if (!is_file($file)) {
+                FileManager::destroy($value->fileid);
+            }
+        }
+    }
+}

+ 1 - 1
app/common/command/MakeController.php → app/command/MakeController.php

@@ -11,7 +11,7 @@ use think\console\input\Argument;
 use think\console\input\Option;
 use think\console\Command;
 
-use app\common\facade\ControllerUtils;
+use app\facade\ControllerUtils;
 
 class MakeController extends Command
 {

+ 1 - 1
app/common/command/MakeModel.php → app/command/MakeModel.php

@@ -11,7 +11,7 @@ use think\console\input\Argument;
 use think\console\input\Option;
 use think\console\Command;
 
-use app\common\facade\ModelUtils;
+use app\facade\ModelUtils;
 
 class MakeModel extends Command
 {

+ 0 - 86
app/common/command/FileConsole.php

@@ -1,86 +0,0 @@
-<?php
-declare (strict_types = 1);
-
-namespace app\common\command;
-
-use DirectoryIterator;
-use SplFileInfo;
-
-// 引入框架内置类
-use think\console\Command;
-use think\console\Input;
-use think\console\input\Argument;
-use think\console\input\Option;
-use think\console\Output;
-use think\facade\Config;
-use think\File;
-
-use app\common\model\FileManager;
-
-class FileConsole extends Command
-{
-    protected function configure()
-    {
-        // 指令配置
-        $this->setName('fileconsole')
-            ->addArgument('name', Argument::OPTIONAL, "console name")
-            ->addOption('dir', null, Option::VALUE_REQUIRED, 'directory name')
-            ->setDescription('the fileconsole command');
-    }
-
-    protected function execute(Input $input, Output $output)
-    {
-        $name = trim($input->getArgument('name'));
-      	$name = $name ?: 'thinkphp';
-
-		if ($input->hasOption('dir')) {
-        	$dir = str_replace("\\", '/', app()->getRootPath() . $input->getOption('dir'));
-        } else {
-        	$dir = str_replace("\\", '/', Config::get('filesystem.disks.public.root')) .'/';
-        }
-
-        // 指令输出
-        $output->writeln('fileconsole :' . $name . "--dir: " . $dir);
-        
-        $this->$name($dir);
-
-        $output->writeln('..ok');
-    }
-
-    /**
-     * 建立文件管理目录索引(递归遍历目录)
-     */
-    public function scan($dir)
-    {
-        if (is_file($dir)) {
-            $file = new File($dir);
-
-            FileManager::saveFileInfo($file);
-        } else {
-            $dirs = new DirectoryIterator($dir);
-            
-            foreach ($dirs as $fileInfo) {
-                if($fileInfo->isDot() || $fileInfo->getFilename() == '.gitignore') {
-                    continue;
-                }
-                
-                $this->scan($dirs->getPath() . '/' . $fileInfo->getFilename());
-            }
-        }
-    }
-
-    /**
-     * 清除无效目录索引
-     */
-    public function clear($dir = '')
-    {
-        $list = FileManager::select();
-        
-        foreach ($list as $value) {
-            $file = app()->getRootPath() . 'public/' . $value->filepath;
-            if (!is_file($file)) {
-                FileManager::destroy($value->fileid);
-            }
-        }
-    }
-}

+ 0 - 21
app/common/facade/ControllerUtils.php

@@ -1,21 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace app\common\facade;
-
-use think\Facade;
-
-/**
- * @see \app\common\utils\ControllerUtils
- * @package app\common\facade
- * @mixin \app\common\utils\ControllerUtils
- * @method static void makeModel()
- * @method static string codeModel()
- */
-class ControllerUtils extends Facade
-{
-    protected static function getFacadeClass()
-    {
-        return 'app\common\utils\ControllerUtils';
-    }
-}

+ 0 - 21
app/common/facade/ModelUtils.php

@@ -1,21 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace app\common\facade;
-
-use think\Facade;
-
-/**
- * @see \app\common\utils\ModelUtils
- * @package app\common\facade
- * @mixin \app\common\utils\ModelUtils
- * @method static void makeModel()
-* @method static string codeModel()
- */
-class ModelUtils extends Facade
-{
-    protected static function getFacadeClass()
-    {
-        return 'app\common\utils\ModelUtils';
-    }
-}

+ 0 - 21
app/common/facade/ValidateUtils.php

@@ -1,21 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace app\common\facade;
-
-use think\Facade;
-
-/**
- * @see \app\common\utils\ValidateUtils
- * @package app\common\facade
- * @mixin \app\common\utils\ValidateUtils
- * @method static void makeModel()
-* @method static string codeModel()
- */
-class ValidateUtils extends Facade
-{
-    protected static function getFacadeClass()
-    {
-        return 'app\common\utils\ValidateUtils';
-    }
-}

+ 0 - 20
app/common/facade/VueUtils.php

@@ -1,20 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace app\common\facade;
-
-use think\Facade;
-
-/**
- * @see \app\common\utils\VueUtils
- * @package app\common\facade
- * @mixin \app\common\utils\VueUtils
- * @method static string codeModel()
- */
-class VueUtils extends Facade
-{
-    protected static function getFacadeClass()
-    {
-        return 'app\common\utils\VueUtils';
-    }
-}

+ 0 - 359
app/common/service/FileService.php

@@ -1,359 +0,0 @@
-<<<<<<< HEAD
-<?php
-declare(strict_types=1);
-
-/**
- * 文件 service
- *
- * @version      0.0.1
- * @author      by huwhois
- * @time        2021/12/28
- */
-
-namespace app\common\service;
-
-use think\Image;
-use think\Exception;
-use think\File;
-use think\image\Exception as ImageException;
-use think\facade\Config;
-
-class FileService
-{
-    /**
-     * 图片添加水印
-     * @param File $file  要处理的文件
-     * @param int $type  水印类型 0 图片水印, 1 文字水印 
-     * @param string $waterimg  图片水印内容
-     * @param string $watertext  文字水印内容
-     * @param string $fonttype  水印文字类型
-     * @param int $fontsize  水印文字大小
-     * @param string $fontcolor  水印文字颜色
-     * @return Image  返回图片对象
-     */
-    public static function waterMark(File $file, int $type = 0, string $watermark = '', string $watertext = '', 
-        string $fonttype = '', int $fontsize = 0, string $fontcolor = '#ffffff30'): Image
-    {
-        $image = Image::open($file);
-
-        if ($type == 0) {
-            $watermark = $watermark ?: Config::get('filesystem.water.watermark');
-            $image->water($watermark);
-        } else {
-            $watetext = $watertext ?: Config::get('filesystem.water.watertext');
-            $fonttype = $fonttype ?: Config::get('filesystem.water.fonttype');
-            $fontsize = $fontsize ?: (int) Config::get('filesystem.water.fontsize');
-            $fontcolor = $fontcolor ?: (int) Config::get('filesystem.water.fontcolor');
-
-            $image->text($watetext, $fonttype, $fontsize, $fontcolor);
-        }
-
-        return $image;
-    }
-
-    /**
-     * 生成缩略图
-     * @param File $file  要处理的文件
-     * @param int $width 缩略图宽值, 默认 384px;
-     * @param int $height 缩略图高值, 默认 224px;
-     * @param int $type 缩略图裁剪方式, 默认值 1,固定尺寸缩放; 其他: 1,等比例缩放;2,缩放后填充;3,居中裁剪;4,左上角裁剪;5,右下角裁剪
-     * @param string $t_suffix  缩略图后缀
-     * @return Image  返回图片对象
-     */
-    public static function thumbnail(File $file, int $width = 384, int $height = 224, int $type = 1, string $t_suffix = "thumb")
-    {
-        $image = Image::open($file);
-
-        $ext = $file->getExtension();
-
-        $filename = $file->getFilename();
-
-        $thumbname = str_replace('.' . $ext, '', str_replace('\\', '/', $filename)) . $t_suffix . '.' . $ext;
-
-        $image->thumb($width, $height, $type)->save('./storage/' . $thumbname);
-
-        return $image;
-    }
-
-    /**
-     * 保存远程图片到本地
-     */
-    public function downloadUrlImg(string $url)
-    {
-        $ch = curl_init($url);
-        curl_setopt($ch, CURLOPT_HEADER, 0);
-        curl_setopt($ch, CURLOPT_NOBODY, 0); // 只取body头
-        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
-        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
-        curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
-        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- 
-        $package = curl_exec($ch);
-        $httpinfo = curl_getinfo($ch);
-        
-        curl_close($ch);
-
-        $imageAll = array_merge(array(
-            'imgBody' => $package
-        ), $httpinfo);
-        if ($httpinfo['download_content_length'] > 4 * 1024 * 1024) {
-            throw new Exception("文件太大", 1);
-        }
-
-        $type = null;
-
-        switch ($imageAll['content_type']) {
-            case 'image/gif':
-                $type = "gif";
-                break;
-            case 'image/webp':
-                $type = "webp";
-                break;
-            case 'image/jpeg':
-                $type = "jpg";
-                break;
-            case 'image/png':
-                $type = "png";
-                break;
-            default:
-                $type = null;
-                break;
-        }
-
-        // 腾讯公众号图片
-        if(strpos($url,'qpic.cn') !== false){
-            $urls = parse_url($url);
-        
-            if (isset($urls['query'])) {
-                $query_arr = [];
-                
-                parse_str($urls['query'], $query_arr);
-        
-                $type = isset($query_arr['wx_fmt']) ? $query_arr['wx_fmt'] : null;
-        
-                $type = $type == 'jpeg' ? 'jpg' : $type;
-            }
-        }
-
-        if (!$type) {
-            throw new Exception("不支持的文件后缀", 1);
-        }
-
-        $temp = app()->getRuntimePath() . 'temp';
-
-        if (!file_exists($temp)) {
-            mkdir($temp, 0755);
-        }
-
-        $tempname = $temp . '/php.' . $type;
-
-        file_put_contents($tempname, $imageAll["imgBody"]);
-
-        return new File($tempname);
-    }
-
-    /**
-     * 遍历获取目录下的指定类型的文件
-     * @param $path
-     * @param $allowFiles  png|jpg|jpeg|gif|bmp|webp
-     * @param array $files
-     * @return array
-     */
-    public static function getFiles($path, $allowFiles = 'png|jpg|jpeg|gif|bmp|webp', &$files = array())
-    {
-        if (!is_dir($path)) return null;
-        if (substr($path, strlen($path) - 1) != '/') $path .= '/';
-        $handle = opendir($path);
-        while (false !== ($file = readdir($handle))) {
-            if ($file != '.' && $file != '..') {
-                $path2 = $path . $file;
-                if (is_dir($path2)) {
-                    self::getFiles($path2, $allowFiles, $files);
-                } else {
-                    if (preg_match("/\.(" . $allowFiles . ")$/i", $file)) {
-                        $files[] = array(
-                            'url' => substr($path2, strlen(app()->getRootPath().'/public') - 1),
-                            'mtime' => filemtime($path2)
-                        );
-                    }
-                }
-            }
-        }
-        return $files;
-    }
-}
-=======
-<?php
-declare(strict_types=1);
-
-/**
- * 文件 service
- *
- * @version      0.0.1
- * @author      by huwhois
- * @time        2021/12/28
- */
-
-namespace app\common\service;
-
-use think\Image;
-use think\Exception;
-use think\File;
-use think\image\Exception as ImageException;
-use think\facade\Config;
-
-class FileService
-{
-    /**
-     * 图片添加水印
-     * @param File $file  要处理的文件
-     * @param int $type  水印类型 0 图片水印, 1 文字水印 
-     * @param string $waterimg  图片水印内容
-     * @param string $watertext  文字水印内容
-     * @param string $fonttype  水印文字类型
-     * @param int $fontsize  水印文字大小
-     * @param string $fontcolor  水印文字颜色
-     * @return Image  返回图片对象
-     */
-    public function waterMark(Image $image, int $type = 0, string $watermark = '', string $watertext = '', 
-        string $fonttype = '', int $fontsize = 0, string $fontcolor = '#ffffff30'): Image
-    {
-        if ($type == 0) {
-            $watermark = $watermark ?: Config::get('filesystem.water.watermark');
-            $image->water($watermark);
-        } else {
-            $watetext = $watertext ?: Config::get('filesystem.water.watertext');
-            $fonttype = $fonttype ?: Config::get('filesystem.water.fonttype');
-            $fontsize = $fontsize ?: (int) Config::get('filesystem.water.fontsize');
-            $fontcolor = $fontcolor ?: (int) Config::get('filesystem.water.fontcolor');
-
-            $image->text($watetext, $fonttype, $fontsize, $fontcolor);
-        }
-
-        return $image;
-    }
-
-    /**
-     * 生成缩略图
-     * @param Image $image  要处理的文件
-     * @param int $width 缩略图宽值, 默认 384px;
-     * @param int $height 缩略图高值, 默认 224px;
-     * @param int $type 缩略图裁剪方式, 默认值 1,固定尺寸缩放; 其他: 1,等比例缩放;2,缩放后填充;3,居中裁剪;4,左上角裁剪;5,右下角裁剪
-     * @param string $t_suffix  缩略图后缀
-     * @return Image  返回图片对象
-     */
-    public function thumbnail(Image $image, string $thumbname, int $width = 384, int $height = 224, int $type = 1)
-    {
-        $image->thumb($width, $height, $type)->save('./storage/' . $thumbname);
-
-        return $image;
-    }
-
-    /**
-     * 保存远程图片到本地
-     */
-    public function downloadUrlImg(string $url)
-    {
-        $ch = curl_init($url);
-        curl_setopt($ch, CURLOPT_HEADER, 0);
-        curl_setopt($ch, CURLOPT_NOBODY, 0); // 只取body头
-        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
-        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
-        curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
-        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- 
-        $package = curl_exec($ch);
-        $httpinfo = curl_getinfo($ch);
-        
-        curl_close($ch);
-
-        $imageAll = array_merge(array(
-            'imgBody' => $package
-        ), $httpinfo);
-        if ($httpinfo['download_content_length'] > 4 * 1024 * 1024) {
-            throw new Exception("文件太大", 1);
-        }
-
-        $type = null;
-
-        switch ($imageAll['content_type']) {
-            case 'image/gif':
-                $type = "gif";
-                break;
-            case 'image/webp':
-                $type = "webp";
-                break;
-            case 'image/jpeg':
-                $type = "jpg";
-                break;
-            case 'image/png':
-                $type = "png";
-                break;
-            default:
-                $type = null;
-                break;
-        }
-
-        // 腾讯公众号图片
-        if(strpos($url,'qpic.cn') !== false){
-            $urls = parse_url($url);
-        
-            if (isset($urls['query'])) {
-                $query_arr = [];
-                
-                parse_str($urls['query'], $query_arr);
-        
-                $type = isset($query_arr['wx_fmt']) ? $query_arr['wx_fmt'] : null;
-        
-                $type = $type == 'jpeg' ? 'jpg' : $type;
-            }
-        }
-
-        if (!$type) {
-            throw new Exception("不支持的文件后缀", 1);
-        }
-
-        $temp = app()->getRuntimePath() . 'temp';
-
-        if (!file_exists($temp)) {
-            mkdir($temp, 0755);
-        }
-
-        $tempname = $temp . '/php.' . $type;
-
-        file_put_contents($tempname, $imageAll["imgBody"]);
-
-        return new File($tempname);
-    }
-
-    /**
-     * 遍历获取目录下的指定类型的文件
-     * @param $path
-     * @param $allowFiles  png|jpg|jpeg|gif|bmp|webp
-     * @param array $files
-     * @return array
-     */
-    public function getFiles($path, $allowFiles = 'png|jpg|jpeg|gif|bmp|webp', &$files = array())
-    {
-        if (!is_dir($path)) return null;
-        if (substr($path, strlen($path) - 1) != '/') $path .= '/';
-        $handle = opendir($path);
-        while (false !== ($file = readdir($handle))) {
-            if ($file != '.' && $file != '..') {
-                $path2 = $path . $file;
-                if (is_dir($path2)) {
-                    self::getFiles($path2, $allowFiles, $files);
-                } else {
-                    if (preg_match("/\.(" . $allowFiles . ")$/i", $file)) {
-                        $files[] = array(
-                            'url' => substr($path2, strlen(app()->getRootPath().'/public') - 1),
-                            'mtime' => filemtime($path2)
-                        );
-                    }
-                }
-            }
-        }
-        return $files;
-    }
-}
->>>>>>> 78b76253c8ce5873016cf837373af5e30ac80c86

+ 0 - 0
app/index/config/route.php → app/config/route.php


+ 11 - 11
app/index/config/view.php → app/config/view.php

@@ -1,11 +1,11 @@
-<?php
-// +----------------------------------------------------------------------
-// | 模板设置
-// +----------------------------------------------------------------------
-
-return [
-    // 开启模板布局
-    'layout_on'    => true,
-    // 自定义标签库
-    'taglib_pre_load' => 'app\common\taglib\Tp',
-];
+<?php
+// +----------------------------------------------------------------------
+// | 模板设置
+// +----------------------------------------------------------------------
+
+return [
+    // 开启模板布局
+    'layout_on'    => true,
+    // 自定义标签库
+    'taglib_pre_load' => 'app\taglib\Tp',
+];

+ 9 - 9
app/index/controller/Article.php → app/controller/Article.php

@@ -8,20 +8,20 @@ declare(strict_types=1);
  * @version   0.0.6
  * +----------------------------------------------------------------------
  */
-namespace app\index\controller;
+namespace app\controller;
 
 // 引入框架内置类
 use think\facade\View;
 use think\exception\HttpException;
 
-use app\common\model\Category as CategoryModel;
-use app\common\model\Article as ArticleModel;
-use app\common\model\ArticleBrowerHistory;
-use app\common\model\ArticleTags as ArticleTagsModel;
-use app\common\model\ArticleDolikeLog;
-use app\common\model\Tag;
-use app\common\model\TagArticle;
-use app\common\utils\ParsedownUtils;
+use app\model\Category as CategoryModel;
+use app\model\Article as ArticleModel;
+use app\model\ArticleBrowerHistory;
+use app\model\ArticleTags as ArticleTagsModel;
+use app\model\ArticleDolikeLog;
+use app\model\Tag;
+use app\model\TagArticle;
+use app\utils\ParsedownUtils;
 
 /**
  * 文章管理  

+ 74 - 86
app/index/controller/Base.php → app/controller/Base.php

@@ -1,86 +1,74 @@
-<?php
-
-declare(strict_types=1);
-/**
- * @file   Index.php
- * @date   2019-02-27 14:49:36
- * @author huwhis<huuwhois>
- * @version   0.0.6
- */
-
-namespace app\index\controller;
-
-use think\facade\View;
-use think\facade\Config;
-use think\App;
-
-use app\common\model\Article;
-use app\common\model\Category;
-use think\facade\Env;
-
-abstract class Base
-{
-    /**
-     * Request实例
-     * @var \think\Request
-     */
-    protected $request;
-
-    /**
-     * 应用实例
-     * @var \think\App
-     */
-    protected $app;
-
-    /**
-     * seo
-     */
-    protected $seo = [];
-
-    /**
-     * makeHtmlFile
-     */
-    protected $html = false;
-
-    /**
-     * 构造方法
-     * @access public
-     * @param App $app 应用对象
-     */
-    public function __construct(App $app)
-    {
-        $this->app     = $app;
-        $this->request = $this->app->request;
-        $this->html    = Config::get('app.html', false);
-        // 控制器初始化
-        $this->initialize();
-    }
-
-    // 初始化
-    protected function initialize()
-    {
-        // SEO标题
-        $system = \app\common\model\System::find(1);
-        $this->seo = [
-            'title' => $system->title,
-            'key' => $system->key,
-            'des' => $system->des,
-        ];
-
-        View::assign('seo', $this->seo);
-
-        if (Env::get('app.app_env', false)) {
-            View::assign('bdtongji', $system->tongji);
-        } else {
-            View::assign('bdtongji', "");
-        }
-
-        // 栏目菜单(nav)
-        $categories = Category::getList(['is_nav'=>1]);
-        View::assign('categories', $categories);
-        
-        // 一般栏目
-        $cate_lists = Category::getList(['type'=>1]);
-        View::assign('cate_lists', $cate_lists);
-    }
-}
+<?php
+
+declare(strict_types=1);
+/**
+ * @file   Index.php
+ * @date   2019-02-27 14:49:36
+ * @author huwhis<huuwhois>
+ * @version   0.0.6
+ */
+
+namespace app\controller;
+
+use app\BaseController;
+use think\facade\View;
+use think\facade\Config;
+use think\App;
+
+use app\model\Article;
+use app\model\Category;
+use think\facade\Env;
+
+class Base extends BaseController
+{
+    /**
+     * seo
+     */
+    protected $seo = [];
+
+    /**
+     * makeHtmlFile
+     */
+    protected $html = false;
+
+    /**
+     * 构造方法
+     * @access public
+     * @param App $app 应用对象
+     */
+    public function __construct(App $app)
+    {
+        parent::__construct($app);
+        
+        // 控制器初始化
+        $this->initialize();
+    }
+
+    // 初始化
+    protected function initialize()
+    {
+        // SEO标题
+        $system = \app\model\System::find(1);
+        $this->seo = [
+            'title' => $system->title,
+            'key' => $system->key,
+            'des' => $system->des,
+        ];
+
+        View::assign('seo', $this->seo);
+
+        if (Env::get('app.app_env', false)=='dev') {
+            View::assign('bdtongji', "");
+        } else {
+            View::assign('bdtongji', $system->tongji);
+        }
+
+        // 栏目菜单(nav)
+        $categories = Category::getList(['is_nav'=>1]);
+        View::assign('categories', $categories);
+        
+        // 一般栏目
+        $cate_lists = Category::getList(['type'=>1]);
+        View::assign('cate_lists', $cate_lists);
+    }
+}

+ 72 - 76
app/index/controller/Index.php → app/controller/Index.php

@@ -1,76 +1,72 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @file   Index.php
- * @date   2019-02-27 14:49:36
- * @author huwhis<huuwhois>
- * @version   0.0.6
- */
-
-namespace app\index\controller;
-
-use think\facade\View;
-
-use app\index\controller\Base;
-use app\common\model\Article;
-use app\common\model\GuestBook;
-
-class Index extends Base
-{
-    public function index()
-    {
-        $html = View::fetch();
-
-        return $html;
-    }
-
-    /**
-     * 关于&留言
-     */
-    public function about()
-    {
-        $html = View::fetch();
-
-        return $html;
-    }
-
-    public function guestBook()
-    {
-        $list = GuestBook::order('id desc')->paginate();
-        View::assign('list', $list);
-
-        return View::fetch();
-    }
-
-    public function saveGuestBook()
-    {
-        $param = $this->request->param('', '', ['strip_tags', 'htmlspecialchars']);
-
-        if (empty($param['name']) or empty($param['contact'])) {
-            return json(['msg' => "请填写必填字段(姓名,电子邮件)", 'code' => 1]);
-        }
-
-        if (empty($param['content'])) {
-            return json(['msg' => "请留下内容", 'code' => 1]);
-        }
-
-        try {
-            $bgu = new GuestBook();
-            $bgu->save([
-                'content' => $param['content'],
-                'name' => $param['name'],
-                'contact' => $param['contact'],
-                'url' => $param['url'],
-                'time' => time(),
-            ]);
-            $bgu->datetime = date("Y-m-d", $bgu->time);
-            return json(['msg' => "保存成功", 'code' => 0, 'data' => $bgu]);
-        } catch (\Exception $e) {
-            $msg = $e->getMessage();
-
-            return json(['msg' => $msg, 'code' => 1]);
-        }
-    }
-}
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @file   Index.php
+ * @date   2019-02-27 14:49:36
+ * @author huwhis<huuwhois>
+ * @version   0.0.6
+ */
+
+namespace app\controller;
+
+use think\facade\View;
+
+use app\controller\Base;
+use app\model\Article;
+use app\model\GuestBook;
+
+class Index extends Base
+{
+    public function index()
+    {
+        return View::fetch();
+    }
+
+    /**
+     * 关于&留言
+     */
+    public function about()
+    {
+        return View::fetch();
+    }
+
+    public function guestBook()
+    {
+        $list = GuestBook::order('id desc')->paginate();
+        View::assign('list', $list);
+
+        return View::fetch();
+    }
+
+    public function saveGuestBook()
+    {
+        $param = $this->request->param('', '', ['strip_tags', 'htmlspecialchars']);
+
+        if (empty($param['name']) or empty($param['contact'])) {
+            return json(['msg' => "请填写必填字段(姓名,电子邮件)", 'code' => 1]);
+        }
+
+        if (empty($param['content'])) {
+            return json(['msg' => "请留下内容", 'code' => 1]);
+        }
+
+        try {
+            $bgu = new GuestBook();
+            $bgu->save([
+                'content' => $param['content'],
+                'name' => $param['name'],
+                'contact' => $param['contact'],
+                'url' => $param['url'],
+                'time' => time(),
+            ]);
+            $bgu->datetime = date("Y-m-d", $bgu->time);
+            return json(['msg' => "保存成功", 'code' => 0, 'data' => $bgu]);
+        } catch (\Exception $e) {
+            $msg = $e->getMessage();
+
+            return json(['msg' => $msg, 'code' => 1]);
+        }
+    }
+}

+ 9 - 7
app/sys/controller/Article.php → app/controller/sys/Article.php

@@ -9,20 +9,22 @@ declare(strict_types=1);
  * +----------------------------------------------------------------------
  */
 
-namespace app\sys\controller;
+namespace app\controller\sys;
 
 // 引入框架内置类
+
+use app\facade\FileFacade;
 use think\Exception;
 use think\facade\Db;
 use think\facade\Config;
 use think\facade\View;
 
 
-use app\common\model\Category as CategoryModel;
-use app\common\model\Article as ArticleModel;
-use app\common\facade\FileUtils;
-use app\common\utils\ReUtils;
-use app\common\model\FileManager as FileManagerModel;
+use app\model\Category as CategoryModel;
+use app\model\Article as ArticleModel;
+use app\facade\FileUtils;
+use app\utils\ReUtils;
+use app\model\FileManager as FileManagerModel;
 
 class Article extends Base
 {
@@ -117,7 +119,7 @@ class Article extends Base
         $img_arrays = array_unique($img_array[1]);
 
         foreach ($img_arrays as $value) {
-            $file = FileUtils::downloadUrlImg($value);
+            $file = FileFacade::downloadUrlImg($value);
 
             $savename = \think\facade\Filesystem::disk('public')->putFile('/', $file);
 

+ 424 - 420
app/sys/controller/Base.php → app/controller/sys/Base.php

@@ -1,420 +1,424 @@
-<?php
-
-/**
- * +----------------------------------------------------------------------
- * | 基础控制器
- * +----------------------------------------------------------------------
- * AUTHOR: huwhois
- * EMAIL: huwhois@163.com
- * DATETIME: 2020/03/08
- */
-
-declare(strict_types=1);
-
-namespace app\sys\controller;
-
-// 引入框架内置类
-use think\App;
-use think\exception\HttpResponseException;
-use think\exception\ValidateException;
-use think\facade\Config;
-use think\facade\Request;
-use think\facade\Session;
-use think\facade\View;
-use think\Response;
-use think\Validate;
-
-use app\common\model\SysMenu;
-
-/**
- * 控制器基础类
- */
-abstract class Base
-{
-    // use \liliuwei\think\Jump;
-    /**
-     * Request实例
-     * @var \think\Request
-     */
-    protected $request;
-
-    /**
-     * 应用实例
-     * @var \think\App
-     */
-    protected $app;
-
-    /**
-     * 是否批量验证
-     * @var bool
-     */
-    protected $batchValidate = false;
-
-    /**
-     * 控制器中间件
-     * @var array
-     */
-    protected $middleware = ['app\sys\middleware\Admin'];
-
-    // /**
-    //  * 分页数量
-    //  * @var int
-    //  */
-    // protected $pageSize = 0;
-
-    /**
-     * 系统设置
-     * @var array
-     */
-    protected $system = [];
-    /**
-     * 用户信息
-     */
-    protected $sysUser;
-    protected $modelName;
-
-
-    /**
-     * 构造方法
-     * @access public
-     * @param App $app 应用对象
-     */
-    public function __construct(App $app)
-    {
-        $this->app     = $app;
-        $this->request = $this->app->request;
-
-        // 控制器初始化
-        $this->initialize();
-    }
-
-    // 初始化
-    protected function initialize()
-    {   
-        // 左侧菜单
-        $rid = Session::get('adminuser.roleid');
-
-        $menus = $rid !=null ? SysMenu::getUserMenuList($rid) : [];
-
-        $controller =  strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::controller()));
-
-        $action = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::action()));
-
-        $route =  $controller . '/' . $action;
-        
-        $breadCrumb = SysMenu::getBreadCrumb($route);
-
-        // layer open
-        if (Request::has('_layer')) {
-            View::assign('layer', true);
-        } else {
-            View::assign('layer', false);
-        }
-
-        // // pjax
-        // if (Request::has('_pjax')) {
-        //     View::assign(['pjax' => true]);
-        // } else {
-        //     View::assign(['pjax' => false]);
-        // }
-
-        // 内容管理,获取栏目列表
-        // if (class_exists('\app\common\model\Cate')) {
-        //     $cates = \app\common\model\Cate::getList();
-        // }
-        // View::assign(['cates' => unlimitedForLayer($cates['data'] ?? [])]);
-
-        // index应用地址
-        // $domainBind = Config::get('app.domain_bind');
-        // if ($domainBind) {
-        //     $domainBindKey = array_search('index', $domainBind);
-        //     $domainBindKey = $domainBindKey == '*' ? 'www.' : ($domainBindKey ? $domainBindKey . '.' : '');
-        //     $indexUrl      = Request::scheme() . '://' . $domainBindKey . Request::rootDomain() . '/';
-        // }
-        // View::assign(['indexUrl' => $indexUrl ?? '/']);
-
-        // 查询系统设置
-        $system       = \app\common\model\System::find(1);
-        $this->system = $system;
-        View::assign([
-            'active_pid' => $breadCrumb['active_pid'],
-            'breadCrumb' => $breadCrumb['breadCrumb'],
-            'menus' => $menus,
-            'system' => $system,
-            'sys_version'    => Config::get('app.sys_version'),
-            'default_lang' => env('lang.default_lang', 'en')
-        ]);
-    }
-
-    /**
-     * 验证数据
-     * @access protected
-     * @param array        $data     数据
-     * @param string|array $validate 验证器名或者验证规则数组
-     * @param array        $message  提示信息
-     * @param bool         $batch    是否批量验证
-     * @return array|string|true
-     * @throws ValidateException
-     */
-    protected function validate(array $data, $validate, array $message = [], bool $batch = false)
-    {
-        if (is_array($validate)) {
-            $v = new Validate();
-            $v->rule($validate);
-        } else {
-            if (strpos($validate, '.')) {
-                // 支持场景
-                list($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);
-        }
-
-        $result = $v->failException(false)->check($data);
-        if (true !== $result) {
-            return $v->getError();
-        } else {
-            return $result;
-        }
-    }
-
-    /**
-     * 操作成功跳转的快捷方法
-     * @access protected
-     * @param  mixed $msg 提示信息
-     * @param  string $url 跳转的URL地址
-     * @param  mixed $data 返回的数据
-     * @param  integer $wait 跳转等待时间
-     * @param  array $header 发送的Header信息
-     * @return void
-     */
-    protected function success($msg = '', string $url = null, $data = '', int $wait = 3, array $header = [])
-    {
-        if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
-            $url = $_SERVER["HTTP_REFERER"];
-        } elseif ($url) {
-            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : (string)$this->app->route->buildUrl($url);
-        }
-
-        $result = [
-            'code' => 0,
-            'msg' => $msg,
-            'data' => $data,
-            'url' => $url,
-            'wait' => $wait,
-        ];
-
-        $type = $this->request->isJson() || $this->request->isAjax() ? 'json' : 'html';
-        // 把跳转模板的渲染下沉,这样在 response_send 行为里通过getData()获得的数据是一致性的格式
-        if ('html' == strtolower($type)) {
-            $type = 'view';
-            $response = Response::create($this->app->config->get('jump.dispatch_success_tmpl'), $type)->assign($result)->header($header);
-        } else {
-            $response = Response::create($result, $type)->header($header);
-        }
-
-        throw new HttpResponseException($response);
-    }
-
-    /**
-     * 操作错误跳转的快捷方法
-     * @access protected
-     * @param  mixed $msg 提示信息
-     * @param  string $url 跳转的URL地址
-     * @param  mixed $data 返回的数据
-     * @param  integer $wait 跳转等待时间
-     * @param  array $header 发送的Header信息
-     * @return void
-     */
-    protected function error($msg = '', string $url = null, $data = '', int $wait = 3, array $header = [])
-    {
-        if (is_null($url)) {
-            $url = $this->request->isAjax() ? '' : 'javascript:history.back(-1);';
-        } elseif ($url) {
-            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : (string)$this->app->route->buildUrl($url);
-        }
-
-        $result = [
-            'code' => 1,
-            'msg' => $msg,
-            'data' => $data,
-            'url' => $url,
-            'wait' => $wait,
-        ];
-
-        $type = $this->request->isJson() || $this->request->isAjax() ? 'json' : 'html';
-
-        if ('html' == strtolower($type)) {
-            $type = 'view';
-            $response = Response::create($this->app->config->get('jump.dispatch_error_tmpl'), $type)->assign($result)->header($header);
-        } else {
-            $response = Response::create($result, $type)->header($header);
-        }
-
-        throw new HttpResponseException($response);
-    }
-
-
-    // /**
-    //  * 返回封装后的API数据到客户端
-    //  * @param mixed   $data   要返回的数据
-    //  * @param integer $code   返回的code
-    //  * @param mixed   $msg    提示信息
-    //  * @param string  $type   返回数据格式
-    //  * @param array   $header 发送的Header信息
-    //  * @return Response
-    //  */
-    // protected function result($data, int $code = 0, $msg = '', string $type = '', array $header = []): Response
-    // {
-    //     $result = [
-    //         'code' => $code,
-    //         'msg'  => $msg,
-    //         'time' => time(),
-    //         'data' => $data,
-    //     ];
-
-    //     $type     = $type ?: 'json';
-    //     $response = Response::create($result, $type)->header($header);
-
-    //     throw new HttpResponseException($response);
-    // }
-
-    // // 列表
-    // public function index()
-    // {
-    //     // 获取主键
-    //     $pk = MakeBuilder::getPrimarykey($this->tableName);
-    //     // 获取列表数据
-    //     $columns = MakeBuilder::getListColumns($this->tableName);
-    //     // 获取搜索数据
-    //     $search = MakeBuilder::getListSearch($this->tableName);
-    //     // 获取当前模块信息
-    //     $model  = '\app\common\model\\' . $this->modelName;
-    //     $module = \app\common\model\Module::where('table_name', $this->tableName)->find();
-    //     // 搜索
-    //     if (Request::param('getList') == 1) {
-    //         $where         = MakeBuilder::getListWhere($this->tableName);
-    //         $orderByColumn = Request::param('orderByColumn') ?? $pk;
-    //         $isAsc         = Request::param('isAsc') ?? 'desc';
-    //         return $model::getList($where, $this->pageSize, [$orderByColumn => $isAsc]);
-    //     }
-    //     // 检测单页模式
-    //     $isSingle = MakeBuilder::checkSingle($this->modelName);
-    //     if ($isSingle) {
-    //         return $this->jump($isSingle);
-    //     }
-    //     // 获取新增地址
-    //     $addUlr = MakeBuilder::getAddUrl($this->tableName);
-    //     // 构建页面
-    //     return TableBuilder::getInstance()
-    //         ->setUniqueId($pk)                              // 设置主键
-    //         ->addColumns($columns)                          // 添加列表字段数据
-    //         ->setSearch($search)                            // 添加头部搜索
-    //         ->addColumn('right_button', '操作', 'btn')      // 启用右侧操作列
-    //         ->addRightButtons($module->right_button)        // 设置右侧操作列
-    //         ->addTopButtons($module->top_button)            // 设置顶部按钮组
-    //         ->setAddUrl($addUlr)                            // 设置新增地址
-    //         ->fetch();
-    // }
-
-    /**
-     * 新增 or 修改
-     * @param int $id  info id 
-     * @return mix 
-     */
-    public function save($id = 0)
-    {
-        if ($this->app->request->isPost()) {
-            $params = $this->app->request->param();
-
-            try {
-                $id = $params['id']; 
-                unset($params['id']);
-
-                if ($id != 0) {
-                    $this->modelName::update($params, ['id' => $id]);
-                } else {
-                    $this->modelName::create($params);
-                }
-            } catch (\Exception $e) {
-                $msg = $e->getMessage();
-
-                $this->error("错误提示:".$msg);
-            }
-            $this->success('操作成功', (String)url('index'));
-        } else {
-            if ($id != 0) {
-                $data = $this->modelName::find($id);
-            } else {
-                $data = null;
-            }
-            
-            View::assign('data', $data);
-
-            return View::fetch();
-        }
-    }
-
-    /**
-     * 删除
-     * @param int|array $id  info id
-     * @return array
-     */
-    public function delete($id)
-    {
-        if (Request::isPost()) {
-            $model = '\app\common\model\\' . $this->modelName;
-            if ($model ::destroy($id)) {
-                return ['code' => 0,'msg'=>'删除成功'];
-            } else {
-                return ['code' => 1,'msg'=>'删除失败'];
-            }
-        }
-    }
-
-    // 排序
-    public function sort()
-    {
-        if (Request::isPost()) {
-            $param  = Request::param();
-
-            $model = '\app\common\model\\' . $this->modelName;
-
-            return $model::sorts($param);
-        }
-    }
-
-    // 状态变更
-    public function status(int $id)
-    {
-        if (Request::isPost()) {
-            $model = '\app\common\model\\' . $this->modelName;
-            return $model::state($id);
-        }
-    }
-
-    // // 导出
-    // public function export()
-    // {
-    //     \app\common\model\Base::export($this->tableName, $this->modelName);
-    // }
-
-    // 获取当前登录用户信息
-    protected function getSysUser()
-    {
-        if (!$this->sysUser) {
-            $this->sysUser = \app\common\model\SysUser::where('userid', session('adminuser.userid'))->find();
-        }
-        return $this->sysUser;
-    }
-}
+<?php
+
+/**
+ * +----------------------------------------------------------------------
+ * | 基础控制器
+ * +----------------------------------------------------------------------
+ * AUTHOR: huwhois
+ * EMAIL: huwhois@163.com
+ * DATETIME: 2020/03/08
+ */
+
+declare(strict_types=1);
+
+namespace app\controller\sys;
+
+// 引入框架内置类
+use think\App;
+use think\exception\HttpResponseException;
+use think\exception\ValidateException;
+use think\facade\Config;
+use think\facade\Request;
+use think\facade\Session;
+use think\facade\View;
+use think\Response;
+use think\Validate;
+
+use app\model\SysMenu;
+
+/**
+ * 控制器基础类
+ */
+abstract class Base
+{
+    // use \liliuwei\think\Jump;
+    /**
+     * Request实例
+     * @var \think\Request
+     */
+    protected $request;
+
+    /**
+     * 应用实例
+     * @var \think\App
+     */
+    protected $app;
+
+    /**
+     * 是否批量验证
+     * @var bool
+     */
+    protected $batchValidate = false;
+
+    /**
+     * 控制器中间件
+     * @var array
+     */
+    protected $middleware = ['app\middleware\Admin'];
+
+    // /**
+    //  * 分页数量
+    //  * @var int
+    //  */
+    // protected $pageSize = 0;
+
+    /**
+     * 系统设置
+     * @var array
+     */
+    protected $system = [];
+    /**
+     * 用户信息
+     */
+    protected $sysUser;
+    protected $modelName;
+
+
+    /**
+     * 构造方法
+     * @access public
+     * @param App $app 应用对象
+     */
+    public function __construct(App $app)
+    {
+        $this->app     = $app;
+        $this->request = $this->app->request;
+
+        // 控制器初始化
+        $this->initialize();
+    }
+
+    // 初始化
+    protected function initialize()
+    {   
+        $eng = View::engine();
+
+        $eng->layout('sys/layout');
+        
+        // 左侧菜单
+        $rid = Session::get('adminuser.roleid');
+
+        $menus = $rid !=null ? SysMenu::getUserMenuList($rid) : [];
+
+        $controller =  strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::controller()));
+
+        $action = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::action()));
+
+        $route =  $controller . '/' . $action;
+        
+        $breadCrumb = SysMenu::getBreadCrumb($route);
+
+        // layer open
+        if (Request::has('_layer')) {
+            View::assign('layer', true);
+        } else {
+            View::assign('layer', false);
+        }
+
+        // // pjax
+        // if (Request::has('_pjax')) {
+        //     View::assign(['pjax' => true]);
+        // } else {
+        //     View::assign(['pjax' => false]);
+        // }
+
+        // 内容管理,获取栏目列表
+        // if (class_exists('\app\model\Cate')) {
+        //     $cates = \app\model\Cate::getList();
+        // }
+        // View::assign(['cates' => unlimitedForLayer($cates['data'] ?? [])]);
+
+        // index应用地址
+        // $domainBind = Config::get('app.domain_bind');
+        // if ($domainBind) {
+        //     $domainBindKey = array_search('index', $domainBind);
+        //     $domainBindKey = $domainBindKey == '*' ? 'www.' : ($domainBindKey ? $domainBindKey . '.' : '');
+        //     $indexUrl      = Request::scheme() . '://' . $domainBindKey . Request::rootDomain() . '/';
+        // }
+        // View::assign(['indexUrl' => $indexUrl ?? '/']);
+
+        // 查询系统设置
+        $system       = \app\model\System::find(1);
+        $this->system = $system;
+        View::assign([
+            'active_pid' => $breadCrumb['active_pid'],
+            'breadCrumb' => $breadCrumb['breadCrumb'],
+            'menus' => $menus,
+            'system' => $system,
+            'sys_version'    => Config::get('app.sys_version'),
+            'default_lang' => env('lang.default_lang', 'en')
+        ]);
+    }
+
+    /**
+     * 验证数据
+     * @access protected
+     * @param array        $data     数据
+     * @param string|array $validate 验证器名或者验证规则数组
+     * @param array        $message  提示信息
+     * @param bool         $batch    是否批量验证
+     * @return array|string|true
+     * @throws ValidateException
+     */
+    protected function validate(array $data, $validate, array $message = [], bool $batch = false)
+    {
+        if (is_array($validate)) {
+            $v = new Validate();
+            $v->rule($validate);
+        } else {
+            if (strpos($validate, '.')) {
+                // 支持场景
+                list($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);
+        }
+
+        $result = $v->failException(false)->check($data);
+        if (true !== $result) {
+            return $v->getError();
+        } else {
+            return $result;
+        }
+    }
+
+    /**
+     * 操作成功跳转的快捷方法
+     * @access protected
+     * @param  mixed $msg 提示信息
+     * @param  string $url 跳转的URL地址
+     * @param  mixed $data 返回的数据
+     * @param  integer $wait 跳转等待时间
+     * @param  array $header 发送的Header信息
+     * @return void
+     */
+    protected function success($msg = '', string $url = null, $data = '', int $wait = 3, array $header = [])
+    {
+        if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
+            $url = $_SERVER["HTTP_REFERER"];
+        } elseif ($url) {
+            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : (string)$this->app->route->buildUrl($url);
+        }
+
+        $result = [
+            'code' => 0,
+            'msg' => $msg,
+            'data' => $data,
+            'url' => $url,
+            'wait' => $wait,
+        ];
+
+        $type = $this->request->isJson() || $this->request->isAjax() ? 'json' : 'html';
+        // 把跳转模板的渲染下沉,这样在 response_send 行为里通过getData()获得的数据是一致性的格式
+        if ('html' == strtolower($type)) {
+            $type = 'view';
+            $response = Response::create($this->app->config->get('jump.dispatch_success_tmpl'), $type)->assign($result)->header($header);
+        } else {
+            $response = Response::create($result, $type)->header($header);
+        }
+
+        throw new HttpResponseException($response);
+    }
+
+    /**
+     * 操作错误跳转的快捷方法
+     * @access protected
+     * @param  mixed $msg 提示信息
+     * @param  string $url 跳转的URL地址
+     * @param  mixed $data 返回的数据
+     * @param  integer $wait 跳转等待时间
+     * @param  array $header 发送的Header信息
+     * @return void
+     */
+    protected function error($msg = '', string $url = null, $data = '', int $wait = 3, array $header = [])
+    {
+        if (is_null($url)) {
+            $url = $this->request->isAjax() ? '' : 'javascript:history.back(-1);';
+        } elseif ($url) {
+            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : (string)$this->app->route->buildUrl($url);
+        }
+
+        $result = [
+            'code' => 1,
+            'msg' => $msg,
+            'data' => $data,
+            'url' => $url,
+            'wait' => $wait,
+        ];
+
+        $type = $this->request->isJson() || $this->request->isAjax() ? 'json' : 'html';
+
+        if ('html' == strtolower($type)) {
+            $type = 'view';
+            $response = Response::create($this->app->config->get('jump.dispatch_error_tmpl'), $type)->assign($result)->header($header);
+        } else {
+            $response = Response::create($result, $type)->header($header);
+        }
+
+        throw new HttpResponseException($response);
+    }
+
+
+    // /**
+    //  * 返回封装后的API数据到客户端
+    //  * @param mixed   $data   要返回的数据
+    //  * @param integer $code   返回的code
+    //  * @param mixed   $msg    提示信息
+    //  * @param string  $type   返回数据格式
+    //  * @param array   $header 发送的Header信息
+    //  * @return Response
+    //  */
+    // protected function result($data, int $code = 0, $msg = '', string $type = '', array $header = []): Response
+    // {
+    //     $result = [
+    //         'code' => $code,
+    //         'msg'  => $msg,
+    //         'time' => time(),
+    //         'data' => $data,
+    //     ];
+
+    //     $type     = $type ?: 'json';
+    //     $response = Response::create($result, $type)->header($header);
+
+    //     throw new HttpResponseException($response);
+    // }
+
+    // // 列表
+    // public function index()
+    // {
+    //     // 获取主键
+    //     $pk = MakeBuilder::getPrimarykey($this->tableName);
+    //     // 获取列表数据
+    //     $columns = MakeBuilder::getListColumns($this->tableName);
+    //     // 获取搜索数据
+    //     $search = MakeBuilder::getListSearch($this->tableName);
+    //     // 获取当前模块信息
+    //     $model  = '\app\model\\' . $this->modelName;
+    //     $module = \app\model\Module::where('table_name', $this->tableName)->find();
+    //     // 搜索
+    //     if (Request::param('getList') == 1) {
+    //         $where         = MakeBuilder::getListWhere($this->tableName);
+    //         $orderByColumn = Request::param('orderByColumn') ?? $pk;
+    //         $isAsc         = Request::param('isAsc') ?? 'desc';
+    //         return $model::getList($where, $this->pageSize, [$orderByColumn => $isAsc]);
+    //     }
+    //     // 检测单页模式
+    //     $isSingle = MakeBuilder::checkSingle($this->modelName);
+    //     if ($isSingle) {
+    //         return $this->jump($isSingle);
+    //     }
+    //     // 获取新增地址
+    //     $addUlr = MakeBuilder::getAddUrl($this->tableName);
+    //     // 构建页面
+    //     return TableBuilder::getInstance()
+    //         ->setUniqueId($pk)                              // 设置主键
+    //         ->addColumns($columns)                          // 添加列表字段数据
+    //         ->setSearch($search)                            // 添加头部搜索
+    //         ->addColumn('right_button', '操作', 'btn')      // 启用右侧操作列
+    //         ->addRightButtons($module->right_button)        // 设置右侧操作列
+    //         ->addTopButtons($module->top_button)            // 设置顶部按钮组
+    //         ->setAddUrl($addUlr)                            // 设置新增地址
+    //         ->fetch();
+    // }
+
+    /**
+     * 新增 or 修改
+     * @param int $id  info id 
+     * @return mix 
+     */
+    public function save($id = 0)
+    {
+        if ($this->app->request->isPost()) {
+            $params = $this->app->request->param();
+
+            try {
+                $id = $params['id']; 
+                unset($params['id']);
+
+                if ($id != 0) {
+                    $this->modelName::update($params, ['id' => $id]);
+                } else {
+                    $this->modelName::create($params);
+                }
+            } catch (\Exception $e) {
+                $msg = $e->getMessage();
+
+                $this->error("错误提示:".$msg);
+            }
+            $this->success('操作成功', (String)url('index'));
+        } else {
+            if ($id != 0) {
+                $data = $this->modelName::find($id);
+            } else {
+                $data = null;
+            }
+            
+            View::assign('data', $data);
+
+            return View::fetch();
+        }
+    }
+
+    /**
+     * 删除
+     * @param int|array $id  info id
+     * @return array
+     */
+    public function delete($id)
+    {
+        if (Request::isPost()) {
+            $model = '\app\model\\' . $this->modelName;
+            if ($model ::destroy($id)) {
+                return ['code' => 0,'msg'=>'删除成功'];
+            } else {
+                return ['code' => 1,'msg'=>'删除失败'];
+            }
+        }
+    }
+
+    // 排序
+    public function sort()
+    {
+        if (Request::isPost()) {
+            $param  = Request::param();
+
+            $model = '\app\model\\' . $this->modelName;
+
+            return $model::sorts($param);
+        }
+    }
+
+    // 状态变更
+    public function status(int $id)
+    {
+        if (Request::isPost()) {
+            $model = '\app\model\\' . $this->modelName;
+            return $model::state($id);
+        }
+    }
+
+    // // 导出
+    // public function export()
+    // {
+    //     \app\model\Base::export($this->tableName, $this->modelName);
+    // }
+
+    // 获取当前登录用户信息
+    protected function getSysUser()
+    {
+        if (!$this->sysUser) {
+            $this->sysUser = \app\model\SysUser::where('userid', session('adminuser.userid'))->find();
+        }
+        return $this->sysUser;
+    }
+}

+ 106 - 106
app/sys/controller/Category.php → app/controller/sys/Category.php

@@ -1,106 +1,106 @@
-<?php
-declare(strict_types=1);
-/**
- * +----------------------------------------------------------------------
- * | 栏目控制制器
- * +----------------------------------------------------------------------
- */
-
-namespace app\sys\controller;
-
-// 引入框架内置类
-use think\facade\View;
-
-use app\common\model\Category as CategoryModel;
-
-class Category extends Base
-{
-    protected  $modelName = "Category";
-
-    public function index()
-    {
-        $list = CategoryModel::getList(['order'=>'id DESC']);
-
-        $list = list_tree($list, 'id', 'parent_id');
-
-        View::assign('list', $list);
-
-        View::assign('types', ['','一般','目录','单页','锚点','链接']);
-
-        return View::fetch();
-    }
-
-    /**
-     * 新增 or 修改
-     * @param int $id  info id 
-     * @return mix 
-     */
-    public function save($id = 0)
-    {
-        if ($id != 0) {
-            $data = CategoryModel::find($id);
-        } else {
-            $data = new CategoryModel();
-            $data->is_nav = 1;
-        }
-
-        View::assign('data', $data);
-
-        $list = list_tree(CategoryModel::select());
-
-        View::assign('list', $list);
-
-        return View::fetch();
-    }
-
-    public function doSave($id)
-    {
-        if ($this->app->request->isPost()) {
-            $params = $this->app->request->param();
-
-            if ($params['name'] == '') {
-                $this->error("名称不能为空");
-            }
-
-            try {
-                $id = $params['id'];
-                unset($params['id']);
-
-                if ($id != 0) {
-                    CategoryModel::update($params, ['id' => $id]);
-                } else {
-                    CategoryModel::create($params);
-                }
-            } catch (\Exception $e) {
-                $msg = $e->getMessage();
-
-                $this->error("错误提示:" . $msg);
-            }
-            $this->success('操作成功', (string)url('index'));
-        }
-    }
-
-    // 删除
-    public function delete($id)
-    {
-        if ($this->app->request->isPost()) {
-            if (CategoryModel::where('parent_id', $id)->value('id')) {
-                return ['code' => 0, 'msg' => '子栏目不为空, 若要删除请先清空子栏目'];
-            }
-
-            if (CategoryModel::destroy($id)) {
-                return ['code' => 0,'msg'=>'删除成功'];
-            } else {
-                return ['code' => 1,'msg'=>'删除失败'];
-            }
-        }
-    }
-
-    // 导航状态变更
-    public function navStatus(int $id)
-    {
-        if ($this->app->request->isPost()) {
-            return CategoryModel::navStaus($id);
-        }
-    }
-}
+<?php
+declare(strict_types=1);
+/**
+ * +----------------------------------------------------------------------
+ * | 栏目控制制器
+ * +----------------------------------------------------------------------
+ */
+
+namespace app\controller\sys;
+
+// 引入框架内置类
+use think\facade\View;
+
+use app\model\Category as CategoryModel;
+
+class Category extends Base
+{
+    protected  $modelName = "Category";
+
+    public function index()
+    {
+        $list = CategoryModel::getList(['order'=>'id DESC']);
+
+        $list = list_tree($list, 'id', 'parent_id');
+
+        View::assign('list', $list);
+
+        View::assign('types', ['','一般','目录','单页','锚点','链接']);
+
+        return View::fetch();
+    }
+
+    /**
+     * 新增 or 修改
+     * @param int $id  info id 
+     * @return mix 
+     */
+    public function save($id = 0)
+    {
+        if ($id != 0) {
+            $data = CategoryModel::find($id);
+        } else {
+            $data = new CategoryModel();
+            $data->is_nav = 1;
+        }
+
+        View::assign('data', $data);
+
+        $list = list_tree(CategoryModel::select());
+
+        View::assign('list', $list);
+
+        return View::fetch();
+    }
+
+    public function doSave($id)
+    {
+        if ($this->app->request->isPost()) {
+            $params = $this->app->request->param();
+
+            if ($params['name'] == '') {
+                $this->error("名称不能为空");
+            }
+
+            try {
+                $id = $params['id'];
+                unset($params['id']);
+
+                if ($id != 0) {
+                    CategoryModel::update($params, ['id' => $id]);
+                } else {
+                    CategoryModel::create($params);
+                }
+            } catch (\Exception $e) {
+                $msg = $e->getMessage();
+
+                $this->error("错误提示:" . $msg);
+            }
+            $this->success('操作成功', (string)url('index'));
+        }
+    }
+
+    // 删除
+    public function delete($id)
+    {
+        if ($this->app->request->isPost()) {
+            if (CategoryModel::where('parent_id', $id)->value('id')) {
+                return ['code' => 0, 'msg' => '子栏目不为空, 若要删除请先清空子栏目'];
+            }
+
+            if (CategoryModel::destroy($id)) {
+                return ['code' => 0,'msg'=>'删除成功'];
+            } else {
+                return ['code' => 1,'msg'=>'删除失败'];
+            }
+        }
+    }
+
+    // 导航状态变更
+    public function navStatus(int $id)
+    {
+        if ($this->app->request->isPost()) {
+            return CategoryModel::navStaus($id);
+        }
+    }
+}

+ 304 - 539
app/sys/controller/FileManager.php → app/controller/sys/FileManager.php

@@ -1,539 +1,304 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * upload文件管理
- *
- * @version      0.0.0
- * @author      by huwhois
- * @time        2017/11/27
- */
-
-namespace app\sys\controller;
-
-use Exception;
-use UnexpectedValueException;
-use DirectoryIterator;
-use think\facade\View;
-use think\facade\Config;
-use think\File;
-use think\Image;
-use think\exception\ValidateException;
-use think\file\UploadedFile;
-
-use app\common\service\FileService;
-use app\common\model\FileManager as FileManagerModel;
-use app\common\facade\FileUtils;
-
-class FileManager extends Base
-{
-    protected $modelName = 'FileManager';
-    protected $t_suffix = '_thumb';
-    protected $width = 400;  // 缩略图高度
-    protected $height = 300;
-    protected $storage_path = 'public/storage';
-    
-    public function index()
-    {
-        $param = $this->request->param();
-
-        $param['limit'] = isset($param['limit']) ? (int) $param['limit'] : Config::get('app.page_size');
-
-        $list = FileManagerModel::queryPage($param);
-
-        View::assign('list', $list);
-        
-        return View::fetch();
-    }
-
-    public function queryList()
-    {
-        $param = $this->request->param();
-
-        $list = FileManagerModel::queryList($param);
-
-        return json(['code'=>0, 'list'=>$list]);
-    }
-
-    /**
-     * 浏览文件
-     */
-    public function explorer()
-    {
-        $param = $this->request->param();
-
-        $activepath =  isset($param['activepath']) ? $param['activepath'] : '';
-
-        $realpath = $this->app->getRootPath() . $this->storage_path . $activepath;
-
-        try {
-            $dirhandle = new DirectoryIterator($realpath);
-
-            $dirs = $files = [];
-
-            foreach ($dirhandle as $fileInfo) {
-                if($fileInfo->isDot() || $fileInfo->getFilename() == '.gitignore') {
-                    continue;
-                } elseif ($fileInfo->isDir()) {
-                    $dirs[] = $fileInfo->getFilename();
-                } elseif ($fileInfo->isFile()) {
-                    $files[] = [
-                        'filename'  => $fileInfo->getFilename(),
-                        'extension' => strtolower($fileInfo->getExtension()),
-                        'size' => format_bytes($fileInfo->getSize()),
-                        'time' => $fileInfo->getCTime(),
-                    ];
-                }
-            }
-            
-            $counts = count($dirs) + count($files);
-
-            $activeurl = preg_replace("#[\/][^\/]*$#i", "", $activepath);
-            // halt($activeurl);
-            if ($this->request->isAjax()) {
-                return json([
-                    'code'      => 0,
-                    'dirs'      => $dirs,
-                    'files'     => $files,
-                    'counts'    => $counts,
-                    'activeurl' => $activeurl,
-                    'activepath'=> $activepath,
-                ]);
-            } else {
-                View::assign([
-                    'dirs'      => $dirs,
-                    'files'     => $files,
-                    'counts'    => $counts,
-                    'activeurl' => $activeurl,
-                    'activepath'=> $activepath,
-                ]);
-                
-                return View::fetch();
-            }
-            
-        } catch(UnexpectedValueException $uve) {
-            $this->error($uve->getMessage());
-        }
-    }
-
-    /**
-     * 附件上传
-     */
-    public function uploadFile()
-    {
-        $activepath = $this->request->has('activepath') ? $this->request->param('activepath') : '';
-
-        $files = $this->request->file('upload_file');
-
-        if ($files) {
-            try {
-                validate(
-                    [
-                        'file' => [
-                            // 限制文件大小(单位b),这里限制为10M
-                            'fileSize' => 10 * 1024 * 1024,
-                            // 限制文件后缀,多个后缀以英文逗号分割
-                            'fileExt'  => 'jpg,png,gif,jpeg,webp,jfif,pdf,doc,docx,xls,xlsx,ppt,pptx,txt'
-                        ]
-                    ],
-                    [
-                        'file.fileSize' => '文件太大',
-                        'file.fileExt' => '不支持的文件后缀',
-                    ]
-                )->check(['file' => $files]);
-
-                $savenames = [];
-
-                $uploadFiles = [];
-                
-                if (!is_array($files) && $files instanceof UploadedFile) {
-                    $uploadFiles[] = $files;
-                } else {
-                    $uploadFiles = $files;
-                }
-
-                $url = Config::get('filesystem.disks.public.url');
-
-                foreach ($uploadFiles as $file) {
-                    $fileinfo = new FileManagerModel();
-                    
-                    $fileinfo->title         = $file->getOriginalName();
-                    $fileinfo->filesize      = $file->getSize();
-                    $fileinfo->filetime      = $file->getCTime();
-                    $fileinfo->fileextension = $file->extension();
-                    $fileinfo->username      = $this->getSysUser()->username;
-                    $fileinfo->hash_md5      = $file->md5();
-
-                    if (empty($activepath)) {
-                        $savename = \think\facade\Filesystem::disk('public')->putFile('/', $file);
-                        
-                        $fileinfo->filepath = $url . '/' . $savename;
-                        $fileinfo->filename = basename($savename);  
-                    } else {
-                        $savename = $activepath . '/' . $file->hashName();
-                        $savepath = $this->app->getRootPath() . $this->storage_path . $savename;
-                        
-                        $file = $file->move($this->app->getRootPath() . $this->storage_path . $activepath, $savepath);
-
-                        $fileinfo->filepath = $url . $savename;
-                        $fileinfo->filename = $file->hashName();
-                    }
-
-                    $fileinfo->save();
-
-                    $savenames[] = $fileinfo->filepath;
-                }
-
-                return json(['code' => 0, 'msg'=>'上传成功', 'filename'=>$savenames]);
-            } catch (ValidateException $e) {
-                $this->error($e->getMessage());
-            }
-        } else {
-            $this->error('图片不能为空');
-        }
-    }
-
-    /**
-     * 修改文件title
-     */
-    public function updateFileTitle($id = 0, $filetitle = '')
-    {
-        $fileInfo = FileManagerModel::find($id);
-        if ($fileInfo == null) {
-            return json(['code'=>1, 'fileid='.$id.'不存在']);
-        }
-
-        $fileInfo->title = $filetitle;
-
-        if ($fileInfo->save()) {
-            return json(['code'=>0, 'msg'=>'success']);
-        } else {
-            return json(['code'=>1, 'msg'=>'failed']);
-        }
-    }
-
-    /**
-     * 删除
-     * @param int|array $id  info id
-     * @return array
-     */
-    public function delete($id)
-    {
-        if ($this->request->isPost()) {
-            $whereOp = '=';
-
-            if (is_array($id)) {
-                $whereOp = 'IN';
-            }
-
-            $list = FileManagerModel::where('fileid', $whereOp, $id)->select();
-
-            foreach ($list as $value) {
-                $file = $this->app->getRootPath() . 'public' . $value->filepath;
-                if (file_exists($file)) {
-                    unlink($file);
-                }
-            }
-  
-            if (FileManagerModel::destroy($id)) {
-                return ['code' => 0,'msg'=>'删除成功'];
-            } else {
-                return ['code' => 1,'msg'=>'删除失败'];
-            }
-        }
-    }
-
-    /**
-     * 删除空目录
-     */
-    public function deldir()
-    {
-        if ($this->request->isPost()) {
-            $dir = str_replace('/', DIRECTORY_SEPARATOR, $this->request->param('dir'));
-
-            $dir_name = $this->app->getRootPath() . $this->storage_path . DIRECTORY_SEPARATOR . $dir;
-
-            try {
-                rmdir($dir_name);
-                return ['code' => 0, 'msg' => 'success'];
-            } catch (Exception $e) {
-                return ['code' => 1, 'msg' => 'failed, 目录不为空'];
-            }
-        }
-    }
-
-    /**
-     * 删除文件
-     */
-    public function delfile()
-    {
-        if ($this->request->isPost()) {
-            $filename = str_replace('/', DIRECTORY_SEPARATOR, $this->request->param('filename'));
-
-            $filepath = $this->app->getRootPath() . $this->storage_path . DIRECTORY_SEPARATOR . $filename;
-
-            if (unlink($filepath)) {
-                return ['code' => 0, 'msg' => 'success'];
-            } else {
-                return ['code' => 1, 'msg' => 'failed'];
-            }
-        }
-    }
-
-    /**
-     * 图片上传(iframe 页面)
-     */
-    public function uploadimg(string $img_id = 'picture', $thumb = false, $width = 400, $height = 300,
-        $original = false, $infoid = 0, $cjid = 0)
-    {
-        View::assign([
-            'img_id'    => $img_id,
-            'thumb'     => $thumb,
-            'width'     => $width,
-            'height'    => $height,
-            'original'  => $original,
-            'infoid'    => $infoid,
-            'cjid'      => $cjid
-        ]);
-
-        return View::fetch();
-    }
-
-    /**
-     * 本地图片上传
-     * @file upload_file   上传的文件
-     * @param string  $img_id   图片ipnut text id 默认值 picture
-     * @param boolean $thumb    是否制作缩略图
-     * @param int $width        缩略图最大宽
-     * @param int $height       缩略图最大高
-     * @param int $id           信息ID
-     * @param int $cjid         信息临时ID
-     * @param bool $saveoriginal   生成缩略图后是否保存原图 默认保存 saveoriginal
-     */
-    public function uploadLocalImg(string $img_id = 'picture', $thumb = false, $width = 400, $height = 300,
-        $original = false, $id = 0, $cjid = 0)
-    {
-        if ($this->request->isPost()) {
-            $file = $this->request->file('upload_file');
-
-            if ($file) {
-                try {
-                    validate(
-                        [
-                            'file' => [
-                                // 限制文件大小(单位b),这里限制为4M
-                                'fileSize' => 4 * 1024 * 1024,
-                                // 限制文件后缀,多个后缀以英文逗号分割
-                                'fileExt'  => 'jpg,png,gif,jpeg,webp,jfif'
-                            ]
-                        ],
-                        [
-                            'file.fileSize' => '文件太大',
-                            'file.fileExt' => '不支持的文件后缀',
-                        ]
-                    )->check(['file' => $file]);
-
-                    $result = $this->dealUploadImg($file, $thumb, $width, $height, $original, $id, $cjid);
-
-                    return json([
-                        'code'    => 0,
-                        'img_id'  => $img_id,
-                        'picname' => $result['picname'],
-                        'thumb'   => $result['thumbname']
-                    ]);
-                } catch (ValidateException $e) {
-                    $this->error($e->getMessage());
-                } catch (Exception $e) {
-                    $this->error($e->getMessage());
-                }
-            } else {
-                $this->error('图片不能为空');
-            }
-        }
-    }
-
-    /**
-     * 网络图片上传
-     * @paran string url_file   网络图片地址
-     * @param string  $img_id   图片ipnut text id 默认值 picture
-     * @param boolean $water    是否添加水印
-     * @param boolean $thumb    是否制作缩略图
-     * @param int $width        缩略图最大宽
-     * @param int $height       缩略图最大高
-     * @param bool $overwrite   生成缩略图后是否保存原图
-     */
-    public function uploadUrlImg(string $img_id = 'picture', $thumb = false, $width = 400, $height = 300,
-        $original = false, $id = 0, $cjid = 0)
-    {
-        if ($this->request->isPost()) {
-            $urlImg = $this->request->param('url_file');
-
-            if ($urlImg) {
-                try {
-                    $file = FileUtils::downloadUrlImg($urlImg);
-                    
-                    $result = $this->dealUploadImg($file, $thumb, $width, $height, $original, $id, $cjid);
-
-                    // 删除临时文件
-                    @unlink($file->getRealPath());
-
-                    return json([
-                        'code'    => 0,
-                        'img_id'  => $img_id,
-                        'picname' => $result['picname'],
-                        'thumb'   => $result['thumbname']
-                    ]);
-                } catch (\think\exception\ValidateException $e) {
-                    $this->error($e->getMessage());
-                }
-            } else {
-                $this->error('图片地址不能为空');
-            }
-        }
-    }
-
-    /**
-     * 选择服务器图片
-     * @paran string online_file  服务器图片地址
-     * @param string  $img_id   图片ipnut text id 默认值 picture
-     */
-    public function uploadOnlineImg(string $img_id = 'picture')
-    {
-        if ($this->request->isPost()) {
-            $pathImg = $this->request->param('online_file');
-
-            if ($pathImg && file_exists($this->app->getRootPath() . "public" . $pathImg)) {
-                return json([
-                    'code'    => 0,
-                    'img_id'  => $img_id,
-                    'picname' => $pathImg,
-                    'thumb'   => ''
-                ]);
-            } else {
-                $this->error('图片地址不存在');
-            }
-        }
-    }
-
-    /**
-     * 判断(远程)文件是否为图片
-     */
-    // public function isImg()
-    // {
-    //     if ($this->request->isAjax()) {
-    //         $filename = $this->request->param('filename');
-
-    //         $res = \mylib\GetImageByurl::isImg($filename);
-    //         if (!$res) {
-    //             $this->error('该图片不合法');
-    //         } else {
-    //             return ['code'=>2,'msg'=>'图片地址可用'];
-    //         }
-    //     }
-    // }
-
-    /**
-     * ckeditor 富文本编辑器上传图片
-     */
-    public function ckeditorUploadImage()
-    {
-        if ($this->request->isPost()) {
-            $file = $this->request->file('upload');
-
-            if ($file) {
-                try {
-                    validate(
-                        [
-                            'file' => [
-                                // 限制文件大小(单位b),这里限制为4M
-                                'fileSize' => 4 * 1024 * 1024,
-                                // 限制文件后缀,多个后缀以英文逗号分割
-                                'fileExt'  => 'jpg,png,gif,jpeg,webp,jfif'
-                            ]
-                        ],
-                        [
-                            'file.fileSize' => '文件太大',
-                            'file.fileExt' => '不支持的文件后缀',
-                        ]
-                    )->check(['file' => $file]);
-
-                    $savename = \think\facade\Filesystem::disk('public')->putFile('/', $file);
-
-                    $savename = str_replace('\\', '/', $savename);
-                    $infoid   = (int) $this->request->param('infoid');
-                    $cjid     = (int) $this->request->param('cjid');
-                    $username = $this->getSysUser()->username;
-                    
-                    FileManagerModel::saveFileInfo($file, $savename, $file->getOriginalName(), $infoid, $cjid, $username);
-
-                    return json([
-                        'uploaded' => 1,
-                        'fileName' => basename($savename),
-                        'url' => Config::get('filesystem.disks.public.url') . '/' . $savename
-                    ]);
-                } catch (\think\exception\ValidateException $e) {
-                    $this->error($e->getMessage());
-                    return json([
-                        'uploaded' => 1,
-                        'error' =>  ['message' => $e->getMessage()]
-                    ]);
-                }
-            } else {
-                return json([
-                    'uploaded' => 1,
-                    'error' =>  ['message' => '图片不能为空']
-                ]);
-            }
-        }
-    }
-
-    /**
-     * 处理上传的图片
-     */
-    protected function dealUploadImg(UploadedFile $file, $thumb, $width, $height, $original, $id, $cjid): array
-    {
-        $urlpath = Config::get('filesystem.disks.public.url');
-
-        $username = $this->getSysUser()->username;
-
-        $savename =  str_replace('\\', '/', $file->hashName());
-
-        $originalName = $file->getOriginalName();
-
-        $thumbname = "";
-
-        if ($thumb == true) {
-            $image = Image::open($file);
-            
-            $image->thumb($width, $height, 1);
-
-            $ext = $file->extension();
-            
-            if ($original == true) {
-                \think\facade\Filesystem::disk('public')->putFileAs('/', $file, $savename);
-                
-                $thumbname = str_replace('.' . $ext, '',  $savename) . $this->t_suffix . '.' . $ext;
-
-                $savepath = str_replace('\\', '/', Config::get('filesystem.disks.public.root') . '/' . $thumbname);
-
-                $image->save($savepath);
-                
-                FileManagerModel::saveFileInfo($savepath, $thumbname, $originalName, $id, $cjid, $username);
-
-                $thumbname = $urlpath . '/' . $thumbname;
-            } else {
-                $image->save(Config::get('filesystem.disks.public.root') . '/' . $savename);
-            }
-        } else {
-            \think\facade\Filesystem::disk('public')->putFileAs('/', $file, $savename);
-        }
-
-        $fileinfo = FileManagerModel::saveFileInfo($file, $savename, $originalName, $id, $cjid, $username);
-        
-        return [
-            'picname'   => $fileinfo->filepath,
-            'thumbname' => $thumbname,
-        ];
-    }
-}
+<?php
+
+declare(strict_types=1);
+
+/**
+ * upload文件管理
+ *
+ * @version      0.0.0
+ * @author      by huwhois
+ * @time        2017/11/27
+ */
+
+namespace app\controller\sys;
+
+use Exception;
+use UnexpectedValueException;
+use DirectoryIterator;
+use think\facade\View;
+use think\facade\Config;
+use think\File;
+use think\Image;
+use think\exception\ValidateException;
+use think\file\UploadedFile;
+
+use app\common\service\FileService;
+use app\model\FileManager as FileManagerModel;
+use app\facade\FileFacade;
+
+class FileManager extends Base
+{
+    protected $modelName = 'FileManager';
+    protected $t_suffix = '_thumb';
+    protected $width = 400;  // 缩略图高度
+    protected $height = 300;
+    protected $storage_path = 'public/storage';
+    
+    public function index()
+    {
+        return "error";
+    }
+
+        /**
+     * ckeditor 富文本编辑器上传图片
+     */
+    public function ckeditorUploadImage()
+    {
+        if ($this->request->isPost()) {
+            $file = $this->request->file('upload');
+
+            if ($file) {
+                try {
+                    validate(
+                        [
+                            'file' => [
+                                // 限制文件大小(单位b),这里限制为4M
+                                'fileSize' => 4 * 1024 * 1024,
+                                // 限制文件后缀,多个后缀以英文逗号分割
+                                'fileExt'  => 'jpg,png,gif,jpeg,webp,jfif'
+                            ]
+                        ],
+                        [
+                            'file.fileSize' => '文件太大',
+                            'file.fileExt' => '不支持的文件后缀',
+                        ]
+                    )->check(['file' => $file]);
+
+                    $savename = \think\facade\Filesystem::disk('public')->putFile('/', $file);
+
+                    $savename = str_replace('\\', '/', $savename);
+                    $infoid   = (int) $this->request->param('infoid');
+                    $cjid     = (int) $this->request->param('cjid');
+                    $username = $this->getSysUser()->username;
+                    
+                    FileManagerModel::saveFileInfo($file, $savename, $file->getOriginalName(), $infoid, $cjid, $username);
+
+                    return json([
+                        'uploaded' => 1,
+                        'fileName' => basename($savename),
+                        'url' => Config::get('filesystem.disks.public.url') . '/' . $savename
+                    ]);
+                } catch (\think\exception\ValidateException $e) {
+                    $this->error($e->getMessage());
+                    return json([
+                        'uploaded' => 1,
+                        'error' =>  ['message' => $e->getMessage()]
+                    ]);
+                }
+            } else {
+                return json([
+                    'uploaded' => 1,
+                    'error' =>  ['message' => '图片不能为空']
+                ]);
+            }
+        }
+    }
+
+    /**
+     * 文件上传
+     */
+    public function uploadFile()
+    {
+        $files = $this->request->file('upload_file');
+
+        if ($files) {
+            try {
+                validate(
+                    [
+                        'file' => [
+                            // 限制文件大小(单位b),这里限制为10M
+                            'fileSize' => 10 * 1024 * 1024,
+                            // 限制文件后缀,多个后缀以英文逗号分割
+                            'fileExt'  => 'jpg,png,gif,jpeg,webp,jfif,pdf,doc,docx,xls,xlsx,ppt,pptx,txt'
+                        ]
+                    ],
+                    [
+                        'file.fileSize' => '文件太大',
+                        'file.fileExt' => '不支持的文件后缀',
+                    ]
+                )->check(['file' => $files]);
+
+                $savenames = [];
+
+                $uploadFiles = [];
+                
+                if (!is_array($files) && $files instanceof UploadedFile) {
+                    $uploadFiles[] = $files;
+                } else {
+                    $uploadFiles = $files;
+                }
+
+                $url = Config::get('filesystem.disks.public.url');
+
+                foreach ($uploadFiles as $file) {
+                    $fileinfo = new FileManagerModel();
+                    
+                    $fileinfo->title         = $file->getOriginalName();
+                    $fileinfo->filesize      = $file->getSize();
+                    $fileinfo->filetime      = $file->getCTime();
+                    $fileinfo->fileextension = $file->extension();
+                    $fileinfo->username      = $this->getSysUser()->username;
+                    $fileinfo->hash_md5      = $file->md5();
+                    
+                    $savename = \think\facade\Filesystem::disk('public')->putFile('/', $file);
+                    
+                    $fileinfo->filepath = $url . '/' . $savename;
+
+                    $fileinfo->save();
+
+                    $savenames[] = $fileinfo->filepath;
+                }
+
+                return json(['code' => 0, 'msg'=>'上传成功', 'filename'=>$savenames]);
+            } catch (ValidateException $e) {
+                $this->error($e->getMessage());
+            }
+        } else {
+            $this->error('图片不能为空');
+        }
+    }
+
+    /**
+     * 本地图片上传
+     * @file upload_file   上传的文件
+     * @param string  $img_id   图片ipnut text id 默认值 picture
+     * @param boolean $thumb    是否制作缩略图
+     * @param int $width        缩略图最大宽
+     * @param int $height       缩略图最大高
+     * @param int $id           信息ID
+     * @param int $cjid         信息临时ID
+     * @param bool $saveoriginal   生成缩略图后是否保存原图 默认保存 saveoriginal
+     */
+    public function uploadLocalImg(string $img_id = 'picture', $thumb = false, $width = 400, $height = 300,
+        $original = false, $id = 0, $cjid = 0)
+    {
+        if ($this->request->isPost()) {
+            $file = $this->request->file('upload_file');
+
+            if ($file) {
+                try {
+                    validate(
+                        [
+                            'file' => [
+                                // 限制文件大小(单位b),这里限制为4M
+                                'fileSize' => 4 * 1024 * 1024,
+                                // 限制文件后缀,多个后缀以英文逗号分割
+                                'fileExt'  => 'jpg,png,gif,jpeg,webp,jfif'
+                            ]
+                        ],
+                        [
+                            'file.fileSize' => '文件太大',
+                            'file.fileExt' => '不支持的文件后缀',
+                        ]
+                    )->check(['file' => $file]);
+
+                    $result = $this->dealUploadImg($file, $thumb, $width, $height, $original, $id, $cjid);
+
+                    return json([
+                        'code'    => 0,
+                        'img_id'  => $img_id,
+                        'picname' => $result['picname'],
+                        'thumb'   => $result['thumbname']
+                    ]);
+                } catch (ValidateException $e) {
+                    $this->error($e->getMessage());
+                } catch (Exception $e) {
+                    $this->error($e->getMessage());
+                }
+            } else {
+                $this->error('图片不能为空');
+            }
+        }
+    }
+
+    /**
+     * 网络图片上传
+     * @paran string url_file   网络图片地址
+     * @param string  $img_id   图片ipnut text id 默认值 picture
+     * @param boolean $water    是否添加水印
+     * @param boolean $thumb    是否制作缩略图
+     * @param int $width        缩略图最大宽
+     * @param int $height       缩略图最大高
+     * @param bool $overwrite   生成缩略图后是否保存原图
+     */
+    public function uploadUrlImg(string $img_id = 'picture', $thumb = false, $width = 400, $height = 300,
+        $original = false, $id = 0, $cjid = 0)
+    {
+        if ($this->request->isPost()) {
+            $urlImg = $this->request->param('url_file');
+
+            if ($urlImg) {
+                try {
+                    $file = FileFacade::downloadUrlImg($urlImg);
+                    
+                    $result = $this->dealUploadImg($file, $thumb, $width, $height, $original, $id, $cjid);
+
+                    // 删除临时文件
+                    @unlink($file->getRealPath());
+
+                    return json([
+                        'code'    => 0,
+                        'img_id'  => $img_id,
+                        'picname' => $result['picname'],
+                        'thumb'   => $result['thumbname']
+                    ]);
+                } catch (\think\exception\ValidateException $e) {
+                    $this->error($e->getMessage());
+                }
+            } else {
+                $this->error('图片地址不能为空');
+            }
+        }
+    }
+
+
+
+    /**
+     * 处理上传的图片
+     */
+    protected function dealUploadImg(UploadedFile $file, $thumb, $width, $height, $original, $id, $cjid): array
+    {
+        $urlpath = Config::get('filesystem.disks.public.url');
+
+        $username = $this->getSysUser()->username;
+
+        $savename =  str_replace('\\', '/', $file->hashName());
+
+        $originalName = $file->getOriginalName();
+
+        $thumbname = "";
+
+        if ($thumb == true) {
+            $image = Image::open($file);
+            
+            $image->thumb($width, $height, 1);
+
+            $ext = $file->extension();
+            
+            if ($original == true) {
+                \think\facade\Filesystem::disk('public')->putFileAs('/', $file, $savename);
+                
+                $thumbname = str_replace('.' . $ext, '',  $savename) . $this->t_suffix . '.' . $ext;
+
+                $savepath = str_replace('\\', '/', Config::get('filesystem.disks.public.root') . '/' . $thumbname);
+
+                $image->save($savepath);
+                
+                FileManagerModel::saveFileInfo($savepath, $thumbname, $originalName, $id, $cjid, $username);
+
+                $thumbname = $urlpath . '/' . $thumbname;
+            } else {
+                $image->save(Config::get('filesystem.disks.public.root') . '/' . $savename);
+            }
+        } else {
+            \think\facade\Filesystem::disk('public')->putFileAs('/', $file, $savename);
+        }
+
+        $fileinfo = FileManagerModel::saveFileInfo($file, $savename, $originalName, $id, $cjid, $username);
+        
+        return [
+            'picname'   => $fileinfo->filepath,
+            'thumbname' => $thumbname,
+        ];
+    }
+}

+ 2 - 2
app/sys/controller/GuestBook.php → app/controller/sys/GuestBook.php

@@ -1,9 +1,9 @@
 <?php
 
-namespace app\sys\controller;
+namespace app\controller\sys;
 
 use think\facade\View;
-use app\common\model\GuestBook as GuestBookModel;
+use app\model\GuestBook as GuestBookModel;
 
 class GuestBook extends Base
 {

+ 6 - 6
app/sys/controller/Index.php → app/controller/sys/Index.php

@@ -2,15 +2,15 @@
 
 declare(strict_types=1);
 
-namespace app\sys\controller;
+namespace app\controller\sys;
 
 use think\Exception;
 use think\facade\App;
 use think\facade\Db;
 use think\facade\Config;
 use think\facade\View;
-use app\common\model\SysMenu as SysMenuModel;
-use app\common\utils\ReUtils;
+use app\model\SysMenu as SysMenuModel;
+use app\utils\ReUtils;
 
 
 class Index  extends Base
@@ -33,9 +33,9 @@ class Index  extends Base
         ];
 
         // 快捷方式
-        $indexButton =  \app\common\model\SysMenu::getIndexButton();
+        $indexButton =  \app\model\SysMenu::getIndexButton();
 
-        $menuList = \app\common\model\SysMenu::getMenuList();
+        $menuList = \app\model\SysMenu::getMenuList();
 
         View::assign([
             'config'        => $config,
@@ -103,7 +103,7 @@ class Index  extends Base
 
     //     foreach ($classess as $key => $class) {
     //         if ($class->islast == 1) {   // 列表模板, 其他的再说
-    //             $model = "\app\common\model\\" . $class->modelName;
+    //             $model = "\app\model\\" . $class->modelName;
     //             $path = $publicpath . $class->classpath;
     //             if (!file_exists($path)) {
     //                 mkdir($path, 0755, true);

+ 47 - 42
app/sys/controller/Login.php → app/controller/sys/Login.php

@@ -1,42 +1,47 @@
-<?php
-declare (strict_types = 1);
-/**
- * +----------------------------------------------------------------------
- * | 后台登录控制制器
- * +----------------------------------------------------------------------
- */
-namespace app\sys\controller;
-
-// 引入框架内置类
-use think\facade\Session;
-use think\facade\View;
-
-use app\common\model\SysUser;
-
-class Login
-{
-    // 登录页面
-    public function index()
-    {
-        // 已登录自动跳转
-        if (Session::has('adminuser')) {
-            return redirect((string)url('index/index'));
-        }
-        $restore_url = Session::has('restore') ? Session::get('restore'): (string)url('index/index');
-
-        View::assign('restore_url', $restore_url);
-
-        return View::fetch();
-    }
-
-    // 校验登录
-    public function checkLogin(){
-        return SysUser::checkLogin();
-    }
-
-    // 退出登录
-    public function logout(){
-        Session::delete('adminuser');
-        return redirect((string) url('login/index'));
-    }
-}
+<?php
+declare (strict_types = 1);
+/**
+ * +----------------------------------------------------------------------
+ * | 后台登录控制制器
+ * +----------------------------------------------------------------------
+ */
+namespace app\controller\sys;
+
+// 引入框架内置类
+use think\facade\View;
+use think\facade\Session;
+use think\facade\Request;
+use think\captcha\facade\Captcha;
+
+use app\utils\ReUtils;
+use app\model\SysUser;
+use app\model\SysLoginFail;
+use app\model\SysLoginNote;
+
+class Login
+{
+    // 登录页面
+    public function index()
+    {
+        // 已登录自动跳转
+        if (Session::has('adminuser')) {
+            return redirect((string)url('index/index'));
+        }
+        $restore_url = Session::has('restore') ? Session::get('restore'): (string)url('index/index');
+
+        View::assign('restore_url', $restore_url);
+
+        return View::fetch();
+    }
+
+    // 校验登录
+    public function checkLogin(){
+        return SysUser::checkLogin();
+    }
+
+    // 退出登录
+    public function logout(){
+        Session::delete('adminuser');
+        return redirect((string) url('login/index'));
+    }
+}

+ 2 - 2
app/sys/controller/SysLog.php → app/controller/sys/SysLog.php

@@ -5,12 +5,12 @@ declare (strict_types = 1);
  * | 管理员日志控制器
  * +----------------------------------------------------------------------
  */
-namespace app\sys\controller;
+namespace app\controller\sys;
 
 // 引入框架内置类
 use think\facade\View;
 
-use app\common\model\SysLog as SysLogModel;
+use app\model\SysLog as SysLogModel;
 
 class SysLog extends Base
 {

+ 2 - 2
app/sys/controller/SysLogin.php → app/controller/sys/SysLogin.php

@@ -5,12 +5,12 @@ declare (strict_types = 1);
  * | 管理员登录日志控制器
  * +----------------------------------------------------------------------
  */
-namespace app\sys\controller;
+namespace app\controller\sys;
 
 // 引入框架内置类
 use think\facade\View;
 
-use app\common\model\SysLogin as SysLoginModel;
+use app\model\SysLogin as SysLoginModel;
 
 class SysLogin extends Base
 {

+ 92 - 92
app/sys/controller/SysMenu.php → app/controller/sys/SysMenu.php

@@ -1,92 +1,92 @@
-<?php
-namespace app\sys\controller;
-
-// 引入框架内置类
-use think\facade\View;
-use think\facade\Request;
-
-use app\common\model\SysMenu as SysMenuModel;
-
-
-class SysMenu extends Base
-{
-    public function index()
-    {
-        $list = SysMenuModel::select();
-
-        View::assign('list', list_tree($list));
-
-        View::assign('type',  ['目录', '菜单', '按钮']);
-
-        return View::fetch();
-    }
-
-    public function save($id = 0)
-    {
-        if ($this->app->request->isPost()) {
-            $param = $this->app->request->param();
-            
-            if ($param['name'] == '') {
-                $this->error("目录名不能为空");
-            }
-
-            try {
-                if ($param['id'] != 0) {
-                    SysMenuModel::update([
-                        'pid' => $param['pid'],
-                        'name' => $param['name'],
-                        'url' => $param['url'] ?: null,
-                        'type' => $param['type'],
-                        'icon' => $param['icon']
-                    ], ['id'=>$param['id']]);
-                } else {
-                    SysMenuModel::create([
-                        'pid' => $param['pid'],
-                        'name' => $param['name'],
-                        'url' => $param['url'] ?: null,
-                        'type' => $param['type'],
-                        'icon' => $param['icon']
-                    ]);
-                }
-                // 删除菜单目录缓存
-            } catch (\Exception $e) {
-                $msg = $e->getMessage();
-
-                $this->error("错误提示:".$msg);
-            }
-            $this->success('操作成功', 'sys_menu/index');
-        } else {
-            if ($id != 0) {
-                $data = SysMenuModel::find($id);
-            } else {
-                $data = [
-                    'id' => 0,
-                    'pid' => 0,
-                    'name' => '',
-                    'url' => '',
-                    'type' => 0,
-                    'icon' =>''
-                ];
-            }
-            
-            View::assign('data', $data);
-
-            return View::fetch();
-        }
-    }
-
-    public function delete($id = null)
-    {
-        if ($this->app->request->isAjax()) {
-            if (SysMenuModel::where('pid', $id)->value('id')) {
-                return ['code'=>0, 'msg'=>'此权限子权限不为空, 若要删除请先清空子权限'];
-            }
-
-            if (SysMenuModel::destroy($id)) {
-                return ['code' => 1,'msg'=>"删除成功"];
-            } else {
-                return ['code' => 0,'msg'=>"删除失败"];
-            }
-        }
-    }
-}
+<?php
+namespace app\controller\sys;
+
+// 引入框架内置类
+use think\facade\View;
+use think\facade\Request;
+
+use app\model\SysMenu as SysMenuModel;
+
+
+class SysMenu extends Base
+{
+    public function index()
+    {
+        $list = SysMenuModel::select();
+
+        View::assign('list', list_tree($list));
+
+        View::assign('type',  ['目录', '菜单', '按钮']);
+
+        return View::fetch();
+    }
+
+    public function save($id = 0)
+    {
+        if ($this->app->request->isPost()) {
+            $param = $this->app->request->param();
+            
+            if ($param['name'] == '') {
+                $this->error("目录名不能为空");
+            }
+
+            try {
+                if ($param['id'] != 0) {
+                    SysMenuModel::update([
+                        'pid' => $param['pid'],
+                        'name' => $param['name'],
+                        'url' => $param['url'] ?: null,
+                        'type' => $param['type'],
+                        'icon' => $param['icon']
+                    ], ['id'=>$param['id']]);
+                } else {
+                    SysMenuModel::create([
+                        'pid' => $param['pid'],
+                        'name' => $param['name'],
+                        'url' => $param['url'] ?: null,
+                        'type' => $param['type'],
+                        'icon' => $param['icon']
+                    ]);
+                }
+                // 删除菜单目录缓存
+            } catch (\Exception $e) {
+                $msg = $e->getMessage();
+
+                $this->error("错误提示:".$msg);
+            }
+            $this->success('操作成功', 'sys_menu/index');
+        } else {
+            if ($id != 0) {
+                $data = SysMenuModel::find($id);
+            } else {
+                $data = [
+                    'id' => 0,
+                    'pid' => 0,
+                    'name' => '',
+                    'url' => '',
+                    'type' => 0,
+                    'icon' =>''
+                ];
+            }
+            
+            View::assign('data', $data);
+
+            return View::fetch();
+        }
+    }
+
+    public function delete($id = null)
+    {
+        if ($this->app->request->isAjax()) {
+            if (SysMenuModel::where('pid', $id)->value('id')) {
+                return ['code'=>0, 'msg'=>'此权限子权限不为空, 若要删除请先清空子权限'];
+            }
+
+            if (SysMenuModel::destroy($id)) {
+                return ['code' => 1,'msg'=>"删除成功"];
+            } else {
+                return ['code' => 0,'msg'=>"删除失败"];
+            }
+        }
+    }
+}

+ 4 - 4
app/sys/controller/SysRole.php → app/controller/sys/SysRole.php

@@ -1,11 +1,11 @@
 <?php
-namespace app\sys\controller;
+namespace app\controller\sys;
 
 use think\facade\View;
 
-use app\common\model\SysMenu;
-use app\common\model\SysUser;
-use app\common\model\SysRole as SysRoleModel;
+use app\model\SysMenu;
+use app\model\SysUser;
+use app\model\SysRole as SysRoleModel;
 use think\facade\Session;
 
 class SysRole extends Base

+ 3 - 3
app/sys/controller/SysUser.php → app/controller/sys/SysUser.php

@@ -5,14 +5,14 @@ declare (strict_types = 1);
  * | 后台登录控制制器
  * +----------------------------------------------------------------------
  */
-namespace app\sys\controller;
+namespace app\controller\sys;
 
 // 引入框架内置类
 use think\facade\View;
 use think\facade\Config;
 
-use app\common\model\SysUser as SysUserModel;
-use app\common\model\SysRole as SysRoleModel;
+use app\model\SysUser as SysUserModel;
+use app\model\SysRole as SysRoleModel;
 
 class SysUser extends Base
 {

+ 2 - 2
app/sys/controller/System.php → app/controller/sys/System.php

@@ -5,12 +5,12 @@ declare (strict_types = 1);
  * | 管理员日志控制器
  * +----------------------------------------------------------------------
  */
-namespace app\sys\controller;
+namespace app\controller\sys;
 
 // 引入框架内置类
 use think\facade\View;
 
-use app\common\model\System as SystemModel;
+use app\model\System as SystemModel;
 
 class System extends Base
 {

+ 0 - 0
app/sys/common.php → app/controller/sys/common.php


+ 0 - 0
app/sys/config/app.php → app/controller/sys/config/app.php


+ 0 - 0
app/sys/config/view.php → app/controller/sys/config/view.php


+ 0 - 0
app/sys/event.php → app/controller/sys/event.php


+ 1 - 1
app/sys/listener/SysUserLog.php → app/controller/sys/listener/SysUserLog.php

@@ -3,7 +3,7 @@ declare (strict_types = 1);
 
 namespace app\sys\listener;
 
-use app\common\model\SysLog;
+use app\model\SysLog;
 
 class SysUserLog
 {

+ 0 - 0
app/sys/middleware.php → app/controller/sys/middleware.php


+ 21 - 0
app/facade/ControllerUtils.php

@@ -0,0 +1,21 @@
+<?php
+declare(strict_types=1);
+
+namespace app\facade;
+
+use think\Facade;
+
+/**
+ * @see \app\utils\ControllerUtils
+ * @package app\facade
+ * @mixin \app\utils\ControllerUtils
+ * @method static void makeModel()
+ * @method static string codeModel()
+ */
+class ControllerFacade extends Facade
+{
+    protected static function getFacadeClass()
+    {
+        return 'app\utils\ControllerUtils';
+    }
+}

+ 6 - 7
app/common/facade/FileUtils.php → app/facade/FileFacade.php

@@ -1,23 +1,22 @@
-<<<<<<< HEAD
 <?php
 declare(strict_types=1);
 
-namespace app\common\facade;
+namespace app\facade;
 
 use think\Facade;
 
 /**
- * @see \app\common\utils\FileUtils
- * @package app\common\facade
- * @mixin \app\common\utils\FileUtils
+ * @see \app\utils\FileUtils
+ * @package app\facade
+ * @mixin \app\utils\FileUtils
  * @method static \think\Image waterMark()
  * @method static \think\Image thumbnail()
  * @method static \think\file\UploadedFile downloadUrlImg()
  */
-class FileUtils extends Facade
+class FileFacade extends Facade
 {
     protected static function getFacadeClass()
     {
-        return 'app\common\utils\FileUtils';
+        return 'app\utils\FileUtils';
     }
 }

+ 21 - 0
app/facade/ModelFacade.php

@@ -0,0 +1,21 @@
+<?php
+declare(strict_types=1);
+
+namespace app\facade;
+
+use think\Facade;
+
+/**
+ * @see \app\utils\ModelUtils
+ * @package app\facade
+ * @mixin \app\utils\ModelUtils
+ * @method static void makeModel()
+* @method static string codeModel()
+ */
+class ModelFacade extends Facade
+{
+    protected static function getFacadeClass()
+    {
+        return 'app\utils\ModelUtils';
+    }
+}

+ 6 - 6
app/common/facade/StringUtils.php → app/facade/StringFacade.php

@@ -1,14 +1,14 @@
 <?php
 declare(strict_types=1);
 
-namespace app\common\facade;
+namespace app\facade;
 
 use think\Facade;
 
 /**
- * @see \app\common\utils\StringUtils
- * @package app\common\facade
- * @mixin \app\common\utils\StringUtils
+ * @see \app\utils\StringUtils
+ * @package app\facade
+ * @mixin \app\utils\StringUtils
  * @method static bool startsWith(string $string, string $subString) 判断$string开头是否包含$subString
  * @method static bool endsWith(string $string, string $subString) 判断$string末尾是否包含$subString
  * @method static string camelizeFirstOn(string $string, $separator = '_') 下划线转驼峰(首字母大写)
@@ -16,7 +16,7 @@ use think\Facade;
  * @method static string uncamelize($camelCaps, $separator = '_') 驼峰命名转下划线命名
  * @method static string generate_stochastic_string(int $length = 16) 生成随机字符串
  */
-class StringUtils extends Facade
+class StringFacade extends Facade
 {   
     /**
     * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
@@ -25,6 +25,6 @@ class StringUtils extends Facade
     */
     protected static function getFacadeClass()
     {
-        return 'app\common\utils\StringUtils';
+        return 'app\utils\StringUtils';
     }
 }

+ 21 - 0
app/facade/ValidateFacade.php

@@ -0,0 +1,21 @@
+<?php
+declare(strict_types=1);
+
+namespace app\facade;
+
+use think\Facade;
+
+/**
+ * @see \app\utils\ValidateUtils
+ * @package app\facade
+ * @mixin \app\utils\ValidateUtils
+ * @method static void makeModel()
+* @method static string codeModel()
+ */
+class ValidateFacade extends Facade
+{
+    protected static function getFacadeClass()
+    {
+        return 'app\utils\ValidateUtils';
+    }
+}

+ 20 - 0
app/facade/VueFacade.php

@@ -0,0 +1,20 @@
+<?php
+declare(strict_types=1);
+
+namespace app\facade;
+
+use think\Facade;
+
+/**
+ * @see \app\utils\VueUtils
+ * @package app\facade
+ * @mixin \app\utils\VueUtils
+ * @method static string codeModel()
+ */
+class VueFacade extends Facade
+{
+    protected static function getFacadeClass()
+    {
+        return 'app\utils\VueUtils';
+    }
+}

+ 0 - 13
app/index/config/app.php

@@ -1,13 +0,0 @@
-<?php
-// +----------------------------------------------------------------------
-// | 应用设置
-// +----------------------------------------------------------------------
-
-return [
-    // 应用Trace
-    'app_trace'              => false,
-    // html 静态化
-    'html'             =>  env('www.html',false),
-    // 默认分页显示数量
-    'page_size'        => env('www.page_size', 20),
-];

+ 134 - 135
app/sys/middleware/Admin.php → app/middleware/Admin.php

@@ -1,135 +1,134 @@
-<?php
-
-/**
- * +----------------------------------------------------------------------
- * | 后台中间件
- * +----------------------------------------------------------------------
- */
-
-namespace app\sys\middleware;
-
-use think\facade\Config;
-use think\facade\Session;
-use think\Response;
-use think\exception\HttpResponseException;
-use think\facade\Request;
-use think\model\Collection;
-
-class Admin
-{
-    public function handle($request, \Closure $next)
-    {
-        // 获取当前用户
-        $admin_id = Session::get('adminuser.userid');
-
-        if (empty($admin_id)) {
-            return redirect((string)url('login/index'));
-        }
-
-        // 查找当前控制器和方法,控制器首字母大写,方法名首字母小写 如:Index/index
-        $route = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::controller())) . '/' . strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::action()));
-
-        // 权限认证
-        if (!$this->checkAuth($route, Session::get('adminuser.roleid'))) {
-            $this->error('您无此操作权限!');
-        }
-
-        // 进行操作日志的记录
-        $this->syslogRecord($route);
-
-        // 中间件handle方法的返回值必须是一个Response对象。
-        return $next($request);
-    }
-
-    protected function syslogRecord($route = '')
-    {
-        // 定义方法白名单(不记录日志)
-        $allow = [
-            
-        ];
-        
-        $action = Request::action();
-
-        if ($action != 'index' && !in_array($route, $allow)) {
-            \app\common\model\SysLog::record();
-        }
-    }
-
-    /**
-     * 检查权限
-     * @param  string|array  $route     需要验证的规则列表,支持逗号分隔的权限规则或索引数组
-     * @param  integer  $rid      认证用户角色ID
-     * @return boolean           通过验证返回true;失败返回false
-     */
-    public function checkAuth($route, $rid)
-    {
-        // 超级管理员不检查权限
-        if ($rid==1) {
-            return true;
-        }
-
-        $menus = \app\common\model\SysMenu::getUserMenuList($rid);
-
-        if (!Config::get('app.auth_on')) {
-            return true;
-        }
-
-        // 定义方法白名单
-        $allow = [
-            'index/index',      // 首页
-            'index/usedspace',      //  使用空间
-            'index/clearcache',      // 清除缓存
-            'file_manager/uploadimg',      // 图片上传
-        ];
-
-        // 查询所有不验证的方法并放入白名单
-        $menuOpen = \app\common\model\SysMenu::where('open', 1)->column('url');
-        
-        $allow = array_merge($allow, $menuOpen);
-
-        foreach ($menus as $value) {
-            if ($value->type == 0) {
-                continue;
-            }
-            $allow[] = $value->url;
-        }
-
-        $allow = array_unique($allow);
-
-        if (in_array($route, $allow)) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * 操作错误跳转的快捷方法 抽的 liliuwei Jump error 方法
-     * @access protected
-     * @param  mixed $msg 提示信息
-     * @return void
-     */
-    protected function error($msg = '')
-    {
-        $url = Request::isAjax() ? '' : 'javascript:history.back(-1);';
-
-        $result = [
-            'code' => 0,
-            'msg' => $msg,
-            'data' => '',
-            'url' => $url,
-            'wait' => 3,
-        ];
-
-        $type = Request::isJson() || Request::isAjax() ? 'json' : 'html';;
-
-        if ('html' == strtolower($type)) {
-            $type = 'view';
-            $dispatch_error_tmpl = app()->getRootPath().'/vendor/liliuwei/thinkphp-jump/src/tpl/dispatch_jump.tpl';
-            $response = Response::create($dispatch_error_tmpl, $type)->assign($result)->header([]);
-        } else {
-            $response = Response::create($result, $type)->header([]);
-        }
-
-        throw new HttpResponseException($response);
-    }
-}
+<?php
+
+/**
+ * +----------------------------------------------------------------------
+ * | 后台中间件
+ * +----------------------------------------------------------------------
+ */
+
+namespace app\middleware;
+
+use think\Response;
+use think\facade\Config;
+use think\facade\Session;
+use think\facade\Request;
+use think\exception\HttpResponseException;
+
+class Admin
+{
+    public function handle($request, \Closure $next)
+    {
+        // 获取当前用户
+        $admin_id = Session::get('adminuser.userid');
+
+        if (empty($admin_id)) {
+            return redirect((string)url('/sys/login/index'));
+        }
+
+        // 查找当前控制器和方法,控制器首字母大写,方法名首字母小写 如:Index/index
+        $route = str_replace("sys.", "", strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::controller()))) . '/' . strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::action()));
+
+        // 权限认证
+        if (!$this->checkAuth($route, Session::get('adminuser.roleid'))) {
+            $this->error('您无此操作权限!');
+        }
+
+        // 进行操作日志的记录
+        $this->syslogRecord($route);
+
+        // 中间件handle方法的返回值必须是一个Response对象。
+        return $next($request);
+    }
+
+    protected function syslogRecord($route = '')
+    {
+        // 定义方法白名单(不记录日志)
+        $allow = [
+            
+        ];
+        
+        $action = Request::action();
+
+        if ($action != 'index' && !in_array($route, $allow)) {
+            \app\model\SysLog::record();
+        }
+    }
+
+    /**
+     * 检查权限
+     * @param  string|array  $route     需要验证的规则列表,支持逗号分隔的权限规则或索引数组
+     * @param  integer  $rid      认证用户角色ID
+     * @return boolean           通过验证返回true;失败返回false
+     */
+    public function checkAuth($route, $rid)
+    {
+        // 超级管理员不检查权限
+        if ($rid==1) {
+            return true;
+        }
+
+        $menus = \app\model\SysMenu::getUserMenuList($rid);
+
+        if (!Config::get('app.auth_on')) {
+            return true;
+        }
+
+        // 定义方法白名单
+        $allow = [
+            'index/index',      // 首页
+            'index/usedspace',      //  使用空间
+            'index/clearcache',      // 清除缓存
+            'file_manager/uploadimg',      // 图片上传
+        ];
+
+        // 查询所有不验证的方法并放入白名单
+        $menuOpen = \app\model\SysMenu::where('open', 1)->column('url');
+        
+        $allow = array_merge($allow, $menuOpen);
+
+        foreach ($menus as $value) {
+            if ($value->type == 0) {
+                continue;
+            }
+            $allow[] = $value->url;
+        }
+
+        $allow = array_unique($allow);
+
+        if (in_array($route, $allow)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 操作错误跳转的快捷方法 抽的 liliuwei Jump error 方法
+     * @access protected
+     * @param  mixed $msg 提示信息
+     * @return void
+     */
+    protected function error($msg = '')
+    {
+        $url = Request::isAjax() ? '' : 'javascript:history.back(-1);';
+
+        $result = [
+            'code' => 0,
+            'msg' => $msg,
+            'data' => '',
+            'url' => $url,
+            'wait' => 3,
+        ];
+
+        $type = Request::isJson() || Request::isAjax() ? 'json' : 'html';;
+
+        if ('html' == strtolower($type)) {
+            $type = 'view';
+            $dispatch_error_tmpl = app()->getRootPath().'/vendor/liliuwei/thinkphp-jump/src/tpl/dispatch_jump.tpl';
+            $response = Response::create($dispatch_error_tmpl, $type)->assign($result)->header([]);
+        } else {
+            $response = Response::create($result, $type)->header([]);
+        }
+
+        throw new HttpResponseException($response);
+    }
+}

+ 2 - 2
app/common/model/Article.php → app/model/Article.php

@@ -2,11 +2,11 @@
 
 declare(strict_types=1);
 
-namespace app\common\model;
+namespace app\model;
 
 use think\exception\HttpException;
 
-use app\common\model\Base;
+use app\model\Base;
 use think\facade\Config;
 
 class Article extends Base

+ 27 - 27
app/common/model/ArticleBrowerHistory.php → app/model/ArticleBrowerHistory.php

@@ -1,27 +1,27 @@
-<?php
-declare (strict_types = 1);
-
-namespace app\common\model;
-
-use think\Model;
-
-/**
- * @mixin \think\Model
- */
-class ArticleBrowerHistory extends Model
-{
-    
-    protected $schema = [
-        "id" => "int",  // id
-        "ip" => "varchar",  // ip地址
-        "aid" => "int",  // 文章id
-        "create_time" => "int",  // 创建时间
-    ];
-
-    protected $autoWriteTimestamp = false;
-
-    public static function getByIpAid($ip, $aid)
-    {
-        return self::where('ip', $ip)->where('aid', $aid)->find();
-    }
-}
+<?php
+declare (strict_types = 1);
+
+namespace app\model;
+
+use think\Model;
+
+/**
+ * @mixin \think\Model
+ */
+class ArticleBrowerHistory extends Model
+{
+    
+    protected $schema = [
+        "id" => "int",  // id
+        "ip" => "varchar",  // ip地址
+        "aid" => "int",  // 文章id
+        "create_time" => "int",  // 创建时间
+    ];
+
+    protected $autoWriteTimestamp = false;
+
+    public static function getByIpAid($ip, $aid)
+    {
+        return self::where('ip', $ip)->where('aid', $aid)->find();
+    }
+}

+ 1 - 1
app/common/model/ArticleDolikeLog.php → app/model/ArticleDolikeLog.php

@@ -1,5 +1,5 @@
 <?php
-namespace app\common\model;
+namespace app\model;
 
 class ArticleDolikeLog extends \think\Model
 {

+ 1 - 1
app/common/model/ArticleTags.php → app/model/ArticleTags.php

@@ -1,5 +1,5 @@
 <?php
-namespace app\common\model;
+namespace app\model;
 
 class ArticleTags extends \think\Model
 {

+ 1 - 1
app/common/model/Base.php → app/model/Base.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace app\common\model;
+namespace app\model;
 
 use think\model;
 

+ 63 - 63
app/common/model/Category.php → app/model/Category.php

@@ -1,63 +1,63 @@
-<?php
-declare(strict_types=1);
-
-namespace app\common\model;
-
-/**
- * 栏目模型
- */
-class Category extends Base
-{
-    protected $schema = [
-        "id"          => "int",
-        "parent_id"   => "int",
-        "name"        => "varchar",
-        "url"         => "varchar",
-        "route"       => "varchar",
-        "tablename"   => "varchar",
-        "template"    => "varchar",
-        "type"        => "int",
-        "is_nav"      => "int",
-        "remark"       => "varchar",
-        "sort"        => "int",
-        'status'      => "varchar",
-        "title"       => "varchar",
-        "keywords"    => "varchar",
-        "description" => "varchar",
-        "is_blank"    => "int",
-        "create_time" => "int",
-        "update_time" => "int"
-    ];
-
-    // 获取列表
-    public static function getList(array $param = [])
-    {
-        $where = [];
-
-        if (isset($param['is_nav']) ) {
-            $where[] = ['is_nav', '=', (int) $param['is_nav']];
-        }
-
-        if (isset($param['type']) ) {
-            $where[] = ['type', '=', (int) $param['type']];
-        }
-
-        $order = isset($param['order']) ? (string) $param['order'] : "sort ASC,id DESC";
-
-        return self::where($where)->field("id,parent_id,name,url,route,tablename,template,type,is_nav,remark,sort,title,keywords,
-            description,is_blank,create_time,update_time")->order($order)->select();
-    }
-
-    // 导航状态修改 1,显示; 0,不显示
-    public static function navStaus(int $id)
-    {
-        try {
-            $info         = self::find($id);
-            $info->is_nav = 1 - $info['is_nav'];
-            $info->save();
-            return json(['code' => 0, 'msg' => '修改成功!', 'is_nav'=>$info->is_nav]);
-        } catch (\Exception $e) {
-            return json(['code' => 1, 'msg' => $e->getMessage()]);
-        }
-    }
-}
+<?php
+declare(strict_types=1);
+
+namespace app\model;
+
+/**
+ * 栏目模型
+ */
+class Category extends Base
+{
+    protected $schema = [
+        "id"          => "int",
+        "parent_id"   => "int",
+        "name"        => "varchar",
+        "url"         => "varchar",
+        "route"       => "varchar",
+        "tablename"   => "varchar",
+        "template"    => "varchar",
+        "type"        => "int",
+        "is_nav"      => "int",
+        "remark"       => "varchar",
+        "sort"        => "int",
+        'status'      => "varchar",
+        "title"       => "varchar",
+        "keywords"    => "varchar",
+        "description" => "varchar",
+        "is_blank"    => "int",
+        "create_time" => "int",
+        "update_time" => "int"
+    ];
+
+    // 获取列表
+    public static function getList(array $param = [])
+    {
+        $where = [];
+
+        if (isset($param['is_nav']) ) {
+            $where[] = ['is_nav', '=', (int) $param['is_nav']];
+        }
+
+        if (isset($param['type']) ) {
+            $where[] = ['type', '=', (int) $param['type']];
+        }
+
+        $order = isset($param['order']) ? (string) $param['order'] : "sort ASC,id DESC";
+
+        return self::where($where)->field("id,parent_id,name,url,route,tablename,template,type,is_nav,remark,sort,title,keywords,
+            description,is_blank,create_time,update_time")->order($order)->select();
+    }
+
+    // 导航状态修改 1,显示; 0,不显示
+    public static function navStaus(int $id)
+    {
+        try {
+            $info         = self::find($id);
+            $info->is_nav = 1 - $info['is_nav'];
+            $info->save();
+            return json(['code' => 0, 'msg' => '修改成功!', 'is_nav'=>$info->is_nav]);
+        } catch (\Exception $e) {
+            return json(['code' => 1, 'msg' => $e->getMessage()]);
+        }
+    }
+}

+ 1 - 1
app/common/model/FileManager.php → app/model/FileManager.php

@@ -1,7 +1,7 @@
 <?php
 declare(strict_types=1);
 
-namespace app\common\model;
+namespace app\model;
 
 use think\facade\Config;
 

+ 1 - 1
app/common/model/GuestBook.php → app/model/GuestBook.php

@@ -1,5 +1,5 @@
 <?php
-namespace app\common\model;
+namespace app\model;
 
 class GuestBook extends Base
 {

+ 1 - 1
app/common/model/Module.php → app/model/Module.php

@@ -1,5 +1,5 @@
 <?php
-namespace app\common\model;
+namespace app\model;
 
 class Module extends Base
 {

+ 1 - 1
app/common/model/News.php → app/model/News.php

@@ -1,5 +1,5 @@
 <?php
-namespace app\common\model;
+namespace app\model;
 
 class News extends \think\Model
 {

+ 1 - 1
app/common/model/Search.php → app/model/Search.php

@@ -1,5 +1,5 @@
 <?php
-namespace app\common\model;
+namespace app\model;
 
 class Enewssearch extends \think\Model
 {

+ 2 - 2
app/common/model/SysLog.php → app/model/SysLog.php

@@ -6,7 +6,7 @@
  */
 
 
-namespace app\common\model;
+namespace app\model;
 
 // 引入框架内置类
 use think\Model;
@@ -39,7 +39,7 @@ class SysLog extends Model
         // 标题处理
         $route = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::controller())) . '/' . strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', Request::action()));
         
-        $active =  \app\common\model\SysMenu::where('url', $route)->find();
+        $active =  \app\model\SysMenu::where('url', $route)->find();
 
         $title =  $active != null ? $active['name'] : "";
 

+ 1 - 1
app/common/model/SysLogin.php → app/model/SysLogin.php

@@ -4,7 +4,7 @@
  * | 管理员登录日志模型
  * +----------------------------------------------------------------------
  */
-namespace app\common\model;
+namespace app\model;
 
 // 引入框架内置类
 use think\Model;

+ 2 - 2
app/common/model/SysLoginFail.php → app/model/SysLoginFail.php

@@ -4,10 +4,10 @@
  * | 管理员登录日志模型
  * +----------------------------------------------------------------------
  */
-namespace app\common\model;
+namespace app\model;
 
 // 引入框架内置类
-use app\common\model\Base;
+use app\model\Base;
 
 class SysLoginFail extends Base
 {

+ 4 - 4
app/common/model/SysMenu.php → app/model/SysMenu.php

@@ -1,5 +1,5 @@
 <?php
-namespace app\common\model;
+namespace app\model;
 
 use think\Model;
 use think\facade\Db;
@@ -36,7 +36,7 @@ class SysMenu extends Model
      */
     public static function getBreadCrumb($route)
     {
-        $active =  \app\common\model\SysMenu::where('url', $route)->find();
+        $active =  \app\model\SysMenu::where('url', $route)->find();
 
         $active_pid = 0;
 
@@ -45,10 +45,10 @@ class SysMenu extends Model
         if ($active) {
             $active_pid = $active->pid;
 
-            $result = \app\common\model\SysMenu::find($active_pid);
+            $result = \app\model\SysMenu::find($active_pid);
             // 如果还有上级
             if ($result) {
-                $res = \app\common\model\SysMenu::find($result->pid);
+                $res = \app\model\SysMenu::find($result->pid);
                 // 如果还有上级
                 if ($res) {
                     $active_pid = $result->pid;

+ 1 - 1
app/common/model/SysRole.php → app/model/SysRole.php

@@ -1,5 +1,5 @@
 <?php
-namespace app\common\model;
+namespace app\model;
 
 use \think\Model;
 

+ 4 - 4
app/common/model/SysUser.php → app/model/SysUser.php

@@ -1,14 +1,14 @@
 <?php
 
-namespace app\common\model;
+namespace app\model;
 
 // 引入框架内置类
 use think\facade\Request;
 use think\facade\Session;
 
-use app\common\model\SysLoginFail;
-use app\common\model\SysLogin;
-use app\common\model\Base;
+use app\model\SysLoginFail;
+use app\model\SysLogin;
+use app\model\Base;
 
 class SysUser extends Base
 {

+ 1 - 1
app/common/model/System.php → app/model/System.php

@@ -4,7 +4,7 @@
  * | 管理员登录日志模型
  * +----------------------------------------------------------------------
  */
-namespace app\common\model;
+namespace app\model;
 
 // 引入框架内置类
 use think\Model;

+ 2 - 2
app/common/model/Tag.php → app/model/Tag.php

@@ -1,9 +1,9 @@
 <?php
 declare(strict_types=1);
 
-namespace app\common\model;
+namespace app\model;
 
-use app\common\model\Base;
+use app\model\Base;
 
 class Tag extends Base
 {

+ 3 - 3
app/common/model/TagArticle.php → app/model/TagArticle.php

@@ -1,13 +1,13 @@
 <?php
 declare(strict_types=1);
 
-namespace app\common\model;
+namespace app\model;
 
 use think\facade\Config;
 use think\facade\Db;
 
-use app\common\model\Base;
-use app\common\model\Article;
+use app\model\Base;
+use app\model\Article;
 
 class TagArticle extends Base
 {

+ 1 - 1
app/common/model/Template.php → app/model/Template.php

@@ -1,7 +1,7 @@
 <?php
 declare (strict_types = 1);
 
-namespace app\common\model;
+namespace app\model;
 
 class Template extends Base
 {

+ 1 - 1
app/common/model/TemplateType.php → app/model/TemplateType.php

@@ -1,7 +1,7 @@
 <?php
 declare (strict_types = 1);
 
-namespace app\common\model;
+namespace app\model;
 
 class TemplateType extends Base
 {

+ 173 - 0
app/service/FileService.php

@@ -0,0 +1,173 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * 文件 service
+ *
+ * @version      0.0.1
+ * @author      by huwhois
+ * @time        2021/12/28
+ */
+
+namespace app\common\service;
+
+use think\Image;
+use think\Exception;
+use think\File;
+use think\image\Exception as ImageException;
+use think\facade\Config;
+
+class FileService
+{
+    /**
+     * 图片添加水印
+     * @param File $file  要处理的文件
+     * @param int $type  水印类型 0 图片水印, 1 文字水印 
+     * @param string $waterimg  图片水印内容
+     * @param string $watertext  文字水印内容
+     * @param string $fonttype  水印文字类型
+     * @param int $fontsize  水印文字大小
+     * @param string $fontcolor  水印文字颜色
+     * @return Image  返回图片对象
+     */
+    public function waterMark(Image $image, int $type = 0, string $watermark = '', string $watertext = '', 
+        string $fonttype = '', int $fontsize = 0, string $fontcolor = '#ffffff30'): Image
+    {
+        if ($type == 0) {
+            $watermark = $watermark ?: Config::get('filesystem.water.watermark');
+            $image->water($watermark);
+        } else {
+            $watetext = $watertext ?: Config::get('filesystem.water.watertext');
+            $fonttype = $fonttype ?: Config::get('filesystem.water.fonttype');
+            $fontsize = $fontsize ?: (int) Config::get('filesystem.water.fontsize');
+            $fontcolor = $fontcolor ?: (int) Config::get('filesystem.water.fontcolor');
+
+            $image->text($watetext, $fonttype, $fontsize, $fontcolor);
+        }
+
+        return $image;
+    }
+
+    /**
+     * 生成缩略图
+     * @param Image $image  要处理的文件
+     * @param int $width 缩略图宽值, 默认 384px;
+     * @param int $height 缩略图高值, 默认 224px;
+     * @param int $type 缩略图裁剪方式, 默认值 1,固定尺寸缩放; 其他: 1,等比例缩放;2,缩放后填充;3,居中裁剪;4,左上角裁剪;5,右下角裁剪
+     * @param string $t_suffix  缩略图后缀
+     * @return Image  返回图片对象
+     */
+    public function thumbnail(Image $image, string $thumbname, int $width = 384, int $height = 224, int $type = 1)
+    {
+        $image->thumb($width, $height, $type)->save('./storage/' . $thumbname);
+
+        return $image;
+    }
+
+    /**
+     * 保存远程图片到本地
+     */
+    public function downloadUrlImg(string $url)
+    {
+        $ch = curl_init($url);
+        curl_setopt($ch, CURLOPT_HEADER, 0);
+        curl_setopt($ch, CURLOPT_NOBODY, 0); // 只取body头
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
+        curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ 
+        $package = curl_exec($ch);
+        $httpinfo = curl_getinfo($ch);
+        
+        curl_close($ch);
+
+        $imageAll = array_merge(array(
+            'imgBody' => $package
+        ), $httpinfo);
+        if ($httpinfo['download_content_length'] > 4 * 1024 * 1024) {
+            throw new Exception("文件太大", 1);
+        }
+
+        $type = null;
+
+        switch ($imageAll['content_type']) {
+            case 'image/gif':
+                $type = "gif";
+                break;
+            case 'image/webp':
+                $type = "webp";
+                break;
+            case 'image/jpeg':
+                $type = "jpg";
+                break;
+            case 'image/png':
+                $type = "png";
+                break;
+            default:
+                $type = null;
+                break;
+        }
+
+        // 腾讯公众号图片
+        if(strpos($url,'qpic.cn') !== false){
+            $urls = parse_url($url);
+        
+            if (isset($urls['query'])) {
+                $query_arr = [];
+                
+                parse_str($urls['query'], $query_arr);
+        
+                $type = isset($query_arr['wx_fmt']) ? $query_arr['wx_fmt'] : null;
+        
+                $type = $type == 'jpeg' ? 'jpg' : $type;
+            }
+        }
+
+        if (!$type) {
+            throw new Exception("不支持的文件后缀", 1);
+        }
+
+        $temp = app()->getRuntimePath() . 'temp';
+
+        if (!file_exists($temp)) {
+            mkdir($temp, 0755);
+        }
+
+        $tempname = $temp . '/php.' . $type;
+
+        file_put_contents($tempname, $imageAll["imgBody"]);
+
+        return new File($tempname);
+    }
+
+    /**
+     * 遍历获取目录下的指定类型的文件
+     * @param $path
+     * @param $allowFiles  png|jpg|jpeg|gif|bmp|webp
+     * @param array $files
+     * @return array
+     */
+    public function getFiles($path, $allowFiles = 'png|jpg|jpeg|gif|bmp|webp', &$files = array())
+    {
+        if (!is_dir($path)) return null;
+        if (substr($path, strlen($path) - 1) != '/') $path .= '/';
+        $handle = opendir($path);
+        while (false !== ($file = readdir($handle))) {
+            if ($file != '.' && $file != '..') {
+                $path2 = $path . $file;
+                if (is_dir($path2)) {
+                    self::getFiles($path2, $allowFiles, $files);
+                } else {
+                    if (preg_match("/\.(" . $allowFiles . ")$/i", $file)) {
+                        $files[] = array(
+                            'url' => substr($path2, strlen(app()->getRootPath().'/public') - 1),
+                            'mtime' => filemtime($path2)
+                        );
+                    }
+                }
+            }
+        }
+        return $files;
+    }
+}

+ 0 - 358
app/sys/controller/Ueditor.php

@@ -1,358 +0,0 @@
-<?php
-
-declare(strict_types=1);
-/**
- * +----------------------------------------------------------------------
- * | Ueditor编辑器后台控制器制器
- * +----------------------------------------------------------------------
- */
-
-namespace app\sys\controller;
-
-use think\App;
-use ueditor\Uploader;
-
-class Ueditor extends Base
-{
-    protected $config;
-
-    public function __construct(App $app)
-    {
-        parent::__construct($app);
-
-        $this->config = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents($this->app->getRootPath() . "/extend/ueditor/config.json")), true);
-    }
-
-    public function index()
-    {
-        return json($this->config);
-    }
-
-    public function config()
-    {
-        $result = json($this->config);
-
-        return $this->output($result);
-    }
-
-    public function uploadimage()
-    {
-        $result = $this->upload('uploadimage');
-
-        return $this->output($result);
-    }
-
-    public function uploadscrawl()
-    {
-        $result = $this->upload('uploadscrawl');
-
-        return $this->output($result);
-    }
-
-    public function uploadvideo()
-    {
-        $result = $this->upload('uploadvideo');
-
-        return $this->output($result);
-    }
-
-    public function uploadfile()
-    {
-        $result = $this->upload('uploadfile');
-
-        return $this->output($result);
-    }
-
-    public function listimage()
-    {
-        $result = $this->listfiles('listimage');
-
-        return $this->output($result);
-    }
-
-    public function listfile()
-    {
-        $result = $this->listimage('listfile');
-
-        return $this->output($result);
-    }
-
-    public function catchimage()
-    {
-        return $this->crawler();
-    }
-
-    /**
-     * 输出结果
-     */
-    public function output($result)
-    {
-        if (isset($_GET["callback"])) {
-            if (preg_match("/^[\w_]+$/", $_GET["callback"])) {
-                return htmlspecialchars($_GET["callback"]) . '(' . $result . ')';
-            } else {
-                return json(array(
-                    'state' => 'callback参数不合法'
-                ));
-            }
-        } else {
-            return $result;
-        }
-    }
-
-    /**
-     * 空操作
-     */
-    public function _empty()
-    {
-        return json([
-            'state' => '请求地址出错'
-        ]);
-    }
-
-    protected function upload($type = "")
-    {
-        $base64 = "upload";
-        switch ($type) {
-            case 'uploadimage':
-                $uploadconfig = [
-                    "pathFormat" => $this->config['imagePathFormat'],
-                    "maxSize" => $this->config['imageMaxSize'],
-                    "allowFiles" => $this->config['imageAllowFiles']
-                ];
-                $fieldName = $this->config['imageFieldName'];
-                break;
-            case 'uploadurlimage':
-                $uploadconfig = [
-                    "pathFormat" => $this->config['imagePathFormat'],
-                    "maxSize" => $this->config['imageMaxSize'],
-                    "allowFiles" => $this->config['imageAllowFiles']
-                ];
-                $fieldName = $this->config['imageFieldName'];
-                $base64 = "uploadurlimage";
-                break;
-            case 'uploadscrawl':
-                $uploadconfig = array(
-                    "pathFormat" => $this->config['scrawlPathFormat'],
-                    "maxSize" => $this->config['scrawlMaxSize'],
-                    "allowFiles" => $this->config['scrawlAllowFiles'],
-                    "oriName" => "scrawl.png"
-                );
-                $fieldName = $this->config['scrawlFieldName'];
-                $base64 = "base64";
-                break;
-            case 'uploadvideo':
-                $uploadconfig = array(
-                    "pathFormat" => $this->config['videoPathFormat'],
-                    "maxSize" => $this->config['videoMaxSize'],
-                    "allowFiles" => $this->config['videoAllowFiles']
-                );
-                $fieldName = $this->config['videoFieldName'];
-                break;
-            case 'uploadfile':
-            default:
-                $uploadconfig = array(
-                    "pathFormat" => $this->config['filePathFormat'],
-                    "maxSize" => $this->config['fileMaxSize'],
-                    "allowFiles" => $this->config['fileAllowFiles']
-                );
-                $fieldName = $this->config['fileFieldName'];
-                break;
-        }
-
-        /* 生成上传实例对象并完成上传 */
-        $up = new Uploader($fieldName, $uploadconfig, $base64);
-        /**
-         * 得到上传文件所对应的各个参数,数组结构
-         * array(
-         *     "state" => "",          //上传状态,上传成功时必须返回"SUCCESS"
-         *     "url" => "",            //返回的地址
-         *     "title" => "",          //新文件名
-         *     "original" => "",       //原始文件名
-         *     "type" => ""            //文件类型
-         *     "size" => "",           //文件大小
-         * )
-         */
-
-        /* 返回数据 */
-        return json($up->getFileInfo());
-    }
-
-    protected function listfiles($type = "")
-    {
-        /* 判断类型 */
-        switch ($type) {
-                /* 列出文件 */
-            case 'listfile':
-                $allowFiles = $this->config['fileManagerAllowFiles'];
-                $listSize = $this->config['fileManagerListSize'];
-                $path = $this->config['fileManagerListPath'];
-                break;
-                /* 列出图片 */
-            case 'listimage':
-            default:
-                $allowFiles = $this->config['imageManagerAllowFiles'];
-                $listSize = $this->config['imageManagerListSize'];
-                $path = $this->config['imageManagerListPath'];
-        }
-        $allowFiles = substr(str_replace(".", "|", join("", $allowFiles)), 1);
-
-        /* 获取参数 */
-        $size = isset($_GET['size']) ? htmlspecialchars($_GET['size']) : $listSize;
-        $start = isset($_GET['start']) ? htmlspecialchars($_GET['start']) : 0;
-        $end = $start + $size;
-
-        /* 获取文件列表 */
-        $path = $_SERVER['DOCUMENT_ROOT'] . (substr($path, 0, 1) == "/" ? "" : "/") . $path;
-        $files = getfiles($path, $allowFiles);
-        if (!count($files)) {
-            return json(array(
-                "state" => "no match file",
-                "list" => array(),
-                "start" => $start,
-                "total" => count($files)
-            ));
-        }
-
-        /* 获取指定范围的列表 */
-        $len = count($files);
-        for ($i = min($end, $len) - 1, $list = array(); $i < $len && $i >= 0 && $i >= $start; $i--) {
-            $list[] = $files[$i];
-        }
-        //倒序
-        //for ($i = $end, $list = array(); $i < $len && $i < $end; $i++){
-        //    $list[] = $files[$i];
-        //}
-
-        /* 返回数据 */
-        $result = json(array(
-            "state" => "SUCCESS",
-            "list" => $list,
-            "start" => $start,
-            "total" => count($files)
-        ));
-
-        return $result;
-    }
-
-    protected function crawler()
-    {
-        set_time_limit(0);
-        /* 上传配置 */
-        $config = array(
-            "pathFormat" => $this->config['catcherPathFormat'],
-            "maxSize" => $this->config['catcherMaxSize'],
-            "allowFiles" => $this->config['catcherAllowFiles'],
-            "oriName" => "remote.png"
-        );
-        $fieldName = $this->config['catcherFieldName'];
-
-        /* 抓取远程图片 */
-        $list = array();
-        if (isset($_POST[$fieldName])) {
-            $source = $_POST[$fieldName];
-        } else {
-            $source = $_GET[$fieldName];
-        }
-        foreach ($source as $imgUrl) {
-            $item = new Uploader($imgUrl, $config, "remote");
-            $info = $item->getFileInfo();
-            array_push($list, array(
-                "state" => $info["state"],
-                "url" => $info["url"],
-                "size" => $info["size"],
-                "title" => htmlspecialchars($info["title"]),
-                "original" => htmlspecialchars($info["original"]),
-                "source" => htmlspecialchars($imgUrl)
-            ));
-        }
-
-        /* 返回抓取数据 */
-        return json(array(
-            'state' => count($list) ? 'SUCCESS' : 'ERROR',
-            'list' => $list
-        ));
-    }
-
-    public function action($action = "")
-    {
-        switch ($action) {
-            case 'config':
-                $result =  json($this->config);
-                break;
-                /* 上传图片 */
-            case 'uploadimage':
-                /* 上传涂鸦 */
-            case 'uploadscrawl':
-                /* 上传视频 */
-            case 'uploadvideo':
-                /* 上传文件 */
-            case 'uploadfile':
-                $result = $this->upload();
-                break;
-
-                /* 列出图片 */
-            case 'listimage':
-                $result = $this->listfiles();
-                break;
-                /* 列出文件 */
-            case 'listfile':
-                $result = $this->listfiles();
-                break;
-
-                /* 抓取远程文件 */
-            case 'catchimage':
-                $result = $this->crawler();
-                break;
-
-            default:
-                $result = json(array(
-                    'state' => '请求地址出错'
-                ));
-                break;
-        }
-
-        /* 输出结果 */
-        if (isset($_GET["callback"])) {
-            if (preg_match("/^[\w_]+$/", $_GET["callback"])) {
-                return htmlspecialchars($_GET["callback"]) . '(' . $result . ')';
-            } else {
-                return json(array(
-                    'state' => 'callback参数不合法'
-                ));
-            }
-        } else {
-            return $result;
-        }
-    }
-
-    // /* 上传图片配置项 */
-    // "imageActionName": "uploadimage", /* 执行上传图片的action名称 */
-
-
-    // /* 涂鸦图片上传配置项 */
-    // "scrawlActionName": "uploadscrawl", /* 执行上传涂鸦的action名称 */
-
-
-    // /* 截图工具上传 */
-    // "snapscreenActionName": "uploadimage", /* 执行上传截图的action名称 */
-
-
-    // /* 抓取远程图片配置 */
-    // "catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
-
-
-    // /* 上传视频配置 */
-    // "videoActionName": "uploadvideo", /* 执行上传视频的action名称 */
-
-
-    // /* 上传文件配置 */
-    // "fileActionName": "uploadfile", /* controller里,执行上传视频的action名称 */
-
-
-    // /* 列出指定目录下的图片 */
-    // "imageManagerActionName": "listimage", /* 执行图片管理的action名称 */
-
-    // /* 列出指定目录下的文件 */
-    // "fileManagerActionName": "listfile", /* 执行文件管理的action名称 */
-}

+ 90 - 90
app/common/taglib/Tp.php → app/taglib/Tp.php

@@ -1,90 +1,90 @@
-<?php
-
-declare(strict_types=1);
-
-namespace app\common\taglib;
-
-use think\template\TagLib;
-
-/**
- * 标签扩展
- */
-class Tp extends TagLib
-{
-    /**
-     * 标签定义
-     *  attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次
-     * @var array
-     */
-    protected $tags = array(
-        'close'    => ['attr' => 'time,format', 'close' => 0],                          // 闭合标签,默认为不闭合
-        'open'     => ['attr' => 'name,type', 'close' => 1],
-        'nav'      => ['attr' => 'id,limit,name', 'close' => 1],                        // 通用导航信息
-        // 'cate'     => ['attr' => 'id,type,anchor', 'close' => 0],                    // 通用栏目信息
-        // 'position' => ['attr' => 'name', 'close' => 1],                              // 通用位置信息
-        // 'link'     => ['attr' => 'name', 'close' => 1],                              // 获取友情链接
-        // 'ad'       => ['attr' => 'name,id', 'close' => 1],                           // 获取广告信息
-        'listbycid'     => ['attr' => 'cid,name,limit', 'close' => 1],                  // 通用列表
-        'listtime'  => ['attr' => 'name,limit', 'close' => 1],                          // 时间归档
-    );
-
-    // 这是一个闭合标签的简单演示
-    public function tagClose($tag)
-    {
-        $format = empty($tag['format']) ? 'Y-m-d H:i:s' : $tag['format'];
-        $time   = empty($tag['time']) ? time() : $tag['time'];
-        $parse  = '<?php ';
-        $parse  .= 'echo date("' . $format . '",' . $time . ');';
-        $parse  .= ' ?>';
-        return $parse;
-    }
-
-    // 这是一个非闭合标签的简单演示
-    public function tagOpen($tag, $content)
-    {
-        $type  = empty($tag['type']) ? 0 : 1; // 这个type目的是为了区分类型,一般来源是数据库
-        $name  = $tag['name'];                // name是必填项,这里不做判断了
-        $parse = '<?php ';
-        $parse .= '$test_arr=[[1,3,5,7,9],[2,4,6,8,10]];'; // 这里是模拟数据
-        $parse .= '$__LIST__ = $test_arr[' . $type . '];';
-        $parse .= ' ?>';
-        $parse .= '{volist name="__LIST__" id="' . $name . '"}';
-        $parse .= $content;
-        $parse .= '{/volist}';
-        return $parse;
-    }
-
-    // 文章列表
-    public function tagListbycid($tag, $content)
-    {
-        $cid    = (int) $tag['cid'];                        // 不可以为空
-        $name   = (string) $tag['name'];                     // 不可为空
-        $order  =  isset($tag['order']) ? (string) $tag['order'] : 'sort ASC,id DESC';  // 可为空
-        $limit  = $tag['limit'] ? (int) $tag['limit'] :  10; // 多少条数据
-        
-        $parse = '<?php ';
-        $parse .= '$list = \app\common\model\Article::getListByCid(' . $cid . ', ' . $limit . ', "' . $order .'");';
-        $parse .= '?>';
-        $parse .= '{volist name="list" id="' . $name . '"}';
-        $parse .= $content;
-        $parse .= '{/volist}';
-        
-        return $parse;
-    }
-
-    // 
-    public function tagListtime($tag, $content)
-    {
-        $name   = (string) $tag['name'];                        // 不可为空
-        $limit  = $tag['limit'] ? (int) $tag['limit'] : 0;     // 多少条数据 0 不限制
-
-        $parse  = '<?php ';
-        $parse .= '$list = \app\common\model\Article::createTimeArchive(' . $limit . ');';
-        $parse .= '?>';
-        $parse .= '{volist name="list" id="' . $name . '"}';
-        $parse .= $content;
-        $parse .= '{/volist}';
-
-        return $parse;
-    }
-}
+<?php
+
+declare(strict_types=1);
+
+namespace app\taglib;
+
+use think\template\TagLib;
+
+/**
+ * 标签扩展
+ */
+class Tp extends TagLib
+{
+    /**
+     * 标签定义
+     *  attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次
+     * @var array
+     */
+    protected $tags = array(
+        'close'    => ['attr' => 'time,format', 'close' => 0],                          // 闭合标签,默认为不闭合
+        'open'     => ['attr' => 'name,type', 'close' => 1],
+        'nav'      => ['attr' => 'id,limit,name', 'close' => 1],                        // 通用导航信息
+        // 'cate'     => ['attr' => 'id,type,anchor', 'close' => 0],                    // 通用栏目信息
+        // 'position' => ['attr' => 'name', 'close' => 1],                              // 通用位置信息
+        // 'link'     => ['attr' => 'name', 'close' => 1],                              // 获取友情链接
+        // 'ad'       => ['attr' => 'name,id', 'close' => 1],                           // 获取广告信息
+        'listbycid'     => ['attr' => 'cid,name,limit', 'close' => 1],                  // 通用列表
+        'listtime'  => ['attr' => 'name,limit', 'close' => 1],                          // 时间归档
+    );
+
+    // 这是一个闭合标签的简单演示
+    public function tagClose($tag)
+    {
+        $format = empty($tag['format']) ? 'Y-m-d H:i:s' : $tag['format'];
+        $time   = empty($tag['time']) ? time() : $tag['time'];
+        $parse  = '<?php ';
+        $parse  .= 'echo date("' . $format . '",' . $time . ');';
+        $parse  .= ' ?>';
+        return $parse;
+    }
+
+    // 这是一个非闭合标签的简单演示
+    public function tagOpen($tag, $content)
+    {
+        $type  = empty($tag['type']) ? 0 : 1; // 这个type目的是为了区分类型,一般来源是数据库
+        $name  = $tag['name'];                // name是必填项,这里不做判断了
+        $parse = '<?php ';
+        $parse .= '$test_arr=[[1,3,5,7,9],[2,4,6,8,10]];'; // 这里是模拟数据
+        $parse .= '$__LIST__ = $test_arr[' . $type . '];';
+        $parse .= ' ?>';
+        $parse .= '{volist name="__LIST__" id="' . $name . '"}';
+        $parse .= $content;
+        $parse .= '{/volist}';
+        return $parse;
+    }
+
+    // 文章列表
+    public function tagListbycid($tag, $content)
+    {
+        $cid    = (int) $tag['cid'];                        // 不可以为空
+        $name   = (string) $tag['name'];                     // 不可为空
+        $order  =  isset($tag['order']) ? (string) $tag['order'] : 'sort ASC,id DESC';  // 可为空
+        $limit  = $tag['limit'] ? (int) $tag['limit'] :  10; // 多少条数据
+        
+        $parse = '<?php ';
+        $parse .= '$list = \app\model\Article::getListByCid(' . $cid . ', ' . $limit . ', "' . $order .'");';
+        $parse .= '?>';
+        $parse .= '{volist name="list" id="' . $name . '"}';
+        $parse .= $content;
+        $parse .= '{/volist}';
+        
+        return $parse;
+    }
+
+    // 
+    public function tagListtime($tag, $content)
+    {
+        $name   = (string) $tag['name'];                        // 不可为空
+        $limit  = $tag['limit'] ? (int) $tag['limit'] : 0;     // 多少条数据 0 不限制
+
+        $parse  = '<?php ';
+        $parse .= '$list = \app\model\Article::createTimeArchive(' . $limit . ');';
+        $parse .= '?>';
+        $parse .= '{volist name="list" id="' . $name . '"}';
+        $parse .= $content;
+        $parse .= '{/volist}';
+
+        return $parse;
+    }
+}

+ 77 - 0
app/utils/AliyunSmsUtils.php

@@ -0,0 +1,77 @@
+<?php
+
+// This file is auto-generated, don't edit it. Thanks.
+namespace app\utils;
+
+use think\facade\Env;
+
+use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
+use AlibabaCloud\Tea\Utils\Utils;
+
+use Darabonba\OpenApi\Models\Config;
+use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
+use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
+use app\model\SmsLog;
+
+class AliyunSmsUtils {
+
+    /**
+     * 使用AK&SK初始化账号Client
+     * @param string $accessKeyId
+     * @param string $accessKeySecret
+     * @return Dysmsapi Client
+     */
+    public static function createClient($accessKeyId, $accessKeySecret){
+        $config = new Config([
+            // 必填,您的 AccessKey ID
+            "accessKeyId" => $accessKeyId,
+            // 必填,您的 AccessKey Secret
+            "accessKeySecret" => $accessKeySecret
+        ]);
+        // 访问的域名
+        $config->endpoint = "dysmsapi.aliyuncs.com";
+        return new Dysmsapi($config);
+    }
+
+    /**
+     * 发送验证码
+     */
+    public static function sendSms($phone, $code)
+    {
+        $access_key_id = Env::get('aliyun.access_key_id');
+        # 必填,您的 AccessKey Secret
+        $access_key_secret = Env::get('aliyun.access_key_secret');
+        # 短信签名名称
+        $sign_name = Env::get('aliyun.sign_name');
+        # 短信模板CODE
+        $template_code = Env::get('aliyun.template_code');
+
+        $client = self::createClient($access_key_id, $access_key_secret);
+
+        $sendSmsRequest = new SendSmsRequest([
+            "signName" => $sign_name,
+            "templateCode" => $template_code,
+            "phoneNumbers" => $phone,
+            "templateParam" => "{\"code\":\"$code\"}"
+        ]);
+
+        $runtime = new RuntimeOptions([]);
+
+        $resp = $client->sendSmsWithOptions($sendSmsRequest, $runtime);
+
+        @SmsLog::create([
+            "phone" => $phone,  // 
+            "sign_name" => $sign_name,  // 签名
+            "template_code" => $template_code,  // 模板id
+            "template_param" => "{\"code\":\"$code\"}",  // 变量
+            "message" => $resp->body->message,  // 返回值信息
+            "request_id" => $resp->body->requestId,  // 请求id
+            "biz_id" => $resp->body->bizId,  // 回执id
+            "code" => $resp->body->code,  // 发送状态
+            "send_time" => date("Y-m-d H:i:s"),  // 发送时间
+        ]);
+
+        return $resp;
+    }
+}
+

+ 74 - 0
app/utils/CollectionUtils.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace app\utils;
+
+
+class CollectionUtils
+{
+    protected $_members = [];
+    protected $_itemHasType;    //标志是否指定元素的类型
+    protected $_itemType;       //集合中的元素类型
+
+    public function __construct($items = [], $itemHasType = false, $itemType = NULL)
+    {
+        $this->_itemHasType = $itemHasType;
+        $this->_itemType = $itemType;
+        $tmp = $this->getArrayableItems($items);
+        if ($this->_itemHasType) {
+            foreach ($tmp as $val) {
+                if ($val instanceof $this->_itemType) {
+                    $this->_members[] = $val;
+                }
+            }
+        } else {
+            $this->_members = $tmp;
+        }
+    }
+
+    public function addItem($obj)
+    {
+        if ($this->_itemHasType) {
+            if (!($obj instanceof $this->_itemType))
+                throw new \Exception("The added obj is not the type of \"$this->_itemType\"!");
+        }
+        if ($this->exists($obj)) {
+            throw new \Exception("Obj is already exists!");
+        } else {
+            $this->_members[] = $obj;
+        }
+    }
+
+    public function removeItem($obj)
+    {
+        if (false != ($key = array_search($obj, $this->_members))) {
+            unset($this->_members[$key]);
+        } else {
+            throw new \Exception("Obj is not exists!");
+        }
+    }
+
+    public function all()
+    {
+        return $this->_members;
+    }
+
+    public function length()
+    {
+        return sizeof($this->_members);
+    }
+
+    public function exists($obj)
+    {
+        return in_array($obj, $this->_members);
+    }
+
+    protected function getArrayableItems($items)
+    {
+        if (is_array($items)) {
+            return array_values(array_unique($items, SORT_REGULAR));
+        } elseif ($items instanceof self) {
+            return $items->all();
+        }
+        return (array) $items;
+    }
+}

+ 82 - 82
app/common/utils/ControllerUtils.php → app/utils/ControllerUtils.php

@@ -1,82 +1,82 @@
-<?php
-
-declare(strict_types=1);
-
-namespace app\common\utils;
-
-// 引入框架内置类
-use think\facade\Db;
-use think\facade\Config;
-
-/**
- * 模型 utils
- *
- * @version      0.0.1
- * @author      by huwhois
- * @time        2022/08/10
- */
-class ControllerUtils
-{
-    protected $namespace;
-    protected $class;
-
-    protected function getPathName(string $name): string
-    {
-        $name = substr($name, 4);
-
-        return app()->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
-    }
-
-    protected function getStub(): string
-    {
-        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'controller.stub';
-    }
-
-    /**
-     * 构建Class文件
-     * @return string
-     */
-    protected function buildClass()
-    {
-        $stub = file_get_contents($this->getStub());
-
-        return str_replace(['{%namespace%}', '{%className%}'], [
-            $this->namespace,
-            $this->class
-        ], $stub);
-    }
-
-    /**
-     * 生成 Model 文件
-     * @param  string $name 类目,包含命名空间
-     * @param string $connections 数据库配置, 默认 mysql
-     */
-    public function makeModel(string $name, string $connections = 'mysql')
-    {
-        $pathname = $this->getPathName($name);
-
-        if (is_file($pathname)) {
-            throw new \Exception("Model :' . $name . ' already exists!</error>", 1);
-        }
-
-        if (!is_dir(dirname($pathname))) {
-            mkdir(dirname($pathname), 0755, true);
-        }
-
-        file_put_contents($pathname, $this->codeModel($name, $connections));
-    }
-
-    /**
-     * 生成 Model 不生成文件
-     * @param  string $name 类目,包含命名空间
-     * @return string
-     */
-    public function codeModel(string $name)
-    {
-        $this->namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
-
-        $this->class = str_replace($this->namespace . '\\', '', $name);
-
-        return $this->buildClass();
-    }
-}
+<?php
+
+declare(strict_types=1);
+
+namespace app\utils;
+
+// 引入框架内置类
+use think\facade\Db;
+use think\facade\Config;
+
+/**
+ * 模型 utils
+ *
+ * @version      0.0.1
+ * @author      by huwhois
+ * @time        2022/08/10
+ */
+class ControllerUtils
+{
+    protected $namespace;
+    protected $class;
+
+    protected function getPathName(string $name): string
+    {
+        $name = substr($name, 4);
+
+        return app()->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
+    }
+
+    protected function getStub(): string
+    {
+        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'controller.stub';
+    }
+
+    /**
+     * 构建Class文件
+     * @return string
+     */
+    protected function buildClass()
+    {
+        $stub = file_get_contents($this->getStub());
+
+        return str_replace(['{%namespace%}', '{%className%}'], [
+            $this->namespace,
+            $this->class
+        ], $stub);
+    }
+
+    /**
+     * 生成 Model 文件
+     * @param  string $name 类目,包含命名空间
+     * @param string $connections 数据库配置, 默认 mysql
+     */
+    public function makeModel(string $name, string $connections = 'mysql')
+    {
+        $pathname = $this->getPathName($name);
+
+        if (is_file($pathname)) {
+            throw new \Exception("Model :' . $name . ' already exists!</error>", 1);
+        }
+
+        if (!is_dir(dirname($pathname))) {
+            mkdir(dirname($pathname), 0755, true);
+        }
+
+        file_put_contents($pathname, $this->codeModel($name, $connections));
+    }
+
+    /**
+     * 生成 Model 不生成文件
+     * @param  string $name 类目,包含命名空间
+     * @return string
+     */
+    public function codeModel(string $name)
+    {
+        $this->namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
+
+        $this->class = str_replace($this->namespace . '\\', '', $name);
+
+        return $this->buildClass();
+    }
+}

+ 2 - 2
app/common/utils/FileUtils.php → app/utils/FileUtils.php

@@ -10,7 +10,7 @@ declare(strict_types=1);
  * @time        20228/10
  */
 
-namespace app\common\utils;
+namespace app\utils;
 
 use think\Image;
 use think\Exception;
@@ -75,7 +75,7 @@ class FileUtils
     /**
      * 保存远程图片到本地
      */
-    public function downloadUrlImg(string $url)
+    public static function downloadUrlImg(string $url)
     {
         $ch = curl_init($url);
         curl_setopt($ch, CURLOPT_HEADER, 0);

+ 155 - 155
app/common/utils/ModelUtils.php → app/utils/ModelUtils.php

@@ -1,155 +1,155 @@
-<?php
-
-declare(strict_types=1);
-
-namespace app\common\utils;
-
-// 引入框架内置类
-use think\facade\Db;
-use think\facade\Config;
-
-/**
- * 模型 utils
- *
- * @version      0.0.1
- * @author      by huwhois
- * @time        2022/08/10
- */
-class ModelUtils
-{
-    protected $namespace;
-    protected $class;
-    protected $tableName;
-    protected $databaseName;
-
-    protected function getPathName(string $name): string
-    {
-        $name = substr($name, 4);
-
-        return app()->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
-    }
-
-    protected function getStub(): string
-    {
-        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'model.stub';
-    }
-
-    /**
-     * 获取表的主键
-     * @return string
-     */
-    protected function getPrimarykey()
-    {
-        $sql = "SELECT COLUMN_NAME AS pk FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = '" . $this->tableName . "' AND table_schema = '.$this->databaseName.' AND CONSTRAINT_NAME = 'PRIMARY'";
-
-        $res = Db::query($sql);
-
-        $pk = empty($res) ? '' : $res[0]['pk'];
-
-        return $pk;
-    }
-
-    /**
-     * 获取表的所有字段信息
-     * @return array
-     */
-    protected function getColumns(string $tableName = '', string $database = '')
-    {
-        $sql = "SELECT column_name,column_comment,data_type FROM information_schema.COLUMNS WHERE TABLE_NAME = '" . $this->tableName . "' AND table_schema = '" . $this->databaseName . "'";
-
-        // echo $sql . "\n";
-
-        $res = Db::query($sql);
-
-        $columns = empty($res) ? [] : $res;
-
-        return $columns;
-    }
-
-    /**
-     * 构建Class文件
-     * @return string
-     */
-    protected function buildClass()
-    {
-        $stub = file_get_contents($this->getStub());
-
-        $primarykey = "";
-
-        $pk = $this->getPrimarykey();
-
-        if ($pk != "" && $pk != "id") {
-            $primarykey = 'protected $pk = "' . $pk . '";';
-        }
-
-        $schemas = '';
-        $autoWriteTimestamp = '';
-        $create_time = false;
-        $update_time = false;
-
-        $columns = $this->getColumns();
-
-        foreach ($columns as $column) {
-            $schemas .= "\n" . '        "' . $column['column_name'] . '" => "' . $column['data_type'] . '",  // ' . $column['column_comment'];
-
-            if ($column['column_name'] == 'create_time') {
-                $create_time = true;
-            }
-
-            if ($column['column_name'] == 'update_time') {
-                $update_time = true;
-            }
-        }
-
-        if (!$create_time || !$update_time) {
-            $autoWriteTimestamp = 'protected $autoWriteTimestamp = false;';
-        }
-
-        return str_replace(['{%namespace%}', '{%className%}', '{%primarykey%}', '{%schemas%}', '{%autoWriteTimestamp%}'], [
-            $this->namespace,
-            $this->class,
-            $primarykey,
-            $schemas,
-            $autoWriteTimestamp
-        ], $stub);
-    }
-
-    /**
-     * 生成 Model 文件
-     * @param  string $name 类目,包含命名空间
-     * @param string $connections 数据库配置, 默认 mysql
-     */
-    public function makeModel(string $name, string $connections = 'mysql')
-    {
-        $pathname = $this->getPathName($name);
-
-        if (is_file($pathname)) {
-            throw new \Exception("Model :' . $name . ' already exists!</error>", 1);
-        }
-
-        if (!is_dir(dirname($pathname))) {
-            mkdir(dirname($pathname), 0755, true);
-        }
-
-        file_put_contents($pathname, $this->codeModel($name, $connections));
-    }
-
-    /**
-     * 生成 Model 不生成文件
-     * @param  string $name 类目,包含命名空间
-     * @param string $connections 数据库配置, 默认 mysql
-     * @return string
-     */
-    public function codeModel(string $name, string $connections = 'mysql')
-    {
-        $this->namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
-
-        $this->class = str_replace($this->namespace . '\\', '', $name);
-
-        $this->tableName = Config::get('database.connections.'.$connections.'.prefix') . strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $this->class));
-
-        $this->databaseName = Config::get('database.connections.'.$connections.'.database');
-
-        return $this->buildClass();
-    }
-}
+<?php
+
+declare(strict_types=1);
+
+namespace app\utils;
+
+// 引入框架内置类
+use think\facade\Db;
+use think\facade\Config;
+
+/**
+ * 模型 utils
+ *
+ * @version      0.0.1
+ * @author      by huwhois
+ * @time        2022/08/10
+ */
+class ModelUtils
+{
+    protected $namespace;
+    protected $class;
+    protected $tableName;
+    protected $databaseName;
+
+    protected function getPathName(string $name): string
+    {
+        $name = substr($name, 4);
+
+        return app()->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
+    }
+
+    protected function getStub(): string
+    {
+        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'model.stub';
+    }
+
+    /**
+     * 获取表的主键
+     * @return string
+     */
+    protected function getPrimarykey()
+    {
+        $sql = "SELECT COLUMN_NAME AS pk FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = '" . $this->tableName . "' AND table_schema = '.$this->databaseName.' AND CONSTRAINT_NAME = 'PRIMARY'";
+
+        $res = Db::query($sql);
+
+        $pk = empty($res) ? '' : $res[0]['pk'];
+
+        return $pk;
+    }
+
+    /**
+     * 获取表的所有字段信息
+     * @return array
+     */
+    protected function getColumns(string $tableName = '', string $database = '')
+    {
+        $sql = "SELECT column_name,column_comment,data_type FROM information_schema.COLUMNS WHERE TABLE_NAME = '" . $this->tableName . "' AND table_schema = '" . $this->databaseName . "'";
+
+        // echo $sql . "\n";
+
+        $res = Db::query($sql);
+
+        $columns = empty($res) ? [] : $res;
+
+        return $columns;
+    }
+
+    /**
+     * 构建Class文件
+     * @return string
+     */
+    protected function buildClass()
+    {
+        $stub = file_get_contents($this->getStub());
+
+        $primarykey = "";
+
+        $pk = $this->getPrimarykey();
+
+        if ($pk != "" && $pk != "id") {
+            $primarykey = 'protected $pk = "' . $pk . '";';
+        }
+
+        $schemas = '';
+        $autoWriteTimestamp = '';
+        $create_time = false;
+        $update_time = false;
+
+        $columns = $this->getColumns();
+
+        foreach ($columns as $column) {
+            $schemas .= "\n" . '        "' . $column['column_name'] . '" => "' . $column['data_type'] . '",  // ' . $column['column_comment'];
+
+            if ($column['column_name'] == 'create_time') {
+                $create_time = true;
+            }
+
+            if ($column['column_name'] == 'update_time') {
+                $update_time = true;
+            }
+        }
+
+        if (!$create_time || !$update_time) {
+            $autoWriteTimestamp = 'protected $autoWriteTimestamp = false;';
+        }
+
+        return str_replace(['{%namespace%}', '{%className%}', '{%primarykey%}', '{%schemas%}', '{%autoWriteTimestamp%}'], [
+            $this->namespace,
+            $this->class,
+            $primarykey,
+            $schemas,
+            $autoWriteTimestamp
+        ], $stub);
+    }
+
+    /**
+     * 生成 Model 文件
+     * @param  string $name 类目,包含命名空间
+     * @param string $connections 数据库配置, 默认 mysql
+     */
+    public function makeModel(string $name, string $connections = 'mysql')
+    {
+        $pathname = $this->getPathName($name);
+
+        if (is_file($pathname)) {
+            throw new \Exception("Model :' . $name . ' already exists!</error>", 1);
+        }
+
+        if (!is_dir(dirname($pathname))) {
+            mkdir(dirname($pathname), 0755, true);
+        }
+
+        file_put_contents($pathname, $this->codeModel($name, $connections));
+    }
+
+    /**
+     * 生成 Model 不生成文件
+     * @param  string $name 类目,包含命名空间
+     * @param string $connections 数据库配置, 默认 mysql
+     * @return string
+     */
+    public function codeModel(string $name, string $connections = 'mysql')
+    {
+        $this->namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
+
+        $this->class = str_replace($this->namespace . '\\', '', $name);
+
+        $this->tableName = Config::get('database.connections.'.$connections.'.prefix') . strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $this->class));
+
+        $this->databaseName = Config::get('database.connections.'.$connections.'.database');
+
+        return $this->buildClass();
+    }
+}

+ 1 - 1
app/common/utils/ParsedownUtils.php → app/utils/ParsedownUtils.php

@@ -2,7 +2,7 @@
 
 declare(strict_types=1);
 
-namespace app\common\utils;
+namespace app\utils;
 
 use \Parsedown;
 

+ 1 - 1
app/common/utils/ReUtils.php → app/utils/ReUtils.php

@@ -2,7 +2,7 @@
 
 declare(strict_types=1);
 
-namespace app\common\utils;
+namespace app\utils;
 
 use think\Response;
 use think\response\File;

+ 73 - 0
app/utils/StringUtils.php

@@ -0,0 +1,73 @@
+<?php
+
+declare(strict_types=1);
+
+namespace app\utils;
+
+
+/**
+ * 字符串工具类
+ */
+class StringUtils
+{
+    public function startsWith(string $string, string $subString): bool
+    {
+        return substr($string, 0, strlen($subString)) === $subString;
+        // 或者 strpos($s2, $s1) === 0
+    }
+
+    public function endsWith(string $string, string $subString): bool
+    {
+        return substr($string, strpos($string, $subString)) === $subString;
+    }
+
+    /**
+     * 下划线转驼峰(首字母大写)
+     * 思路:
+     * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
+     * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
+     * @param string $string 
+     * @param string $separator
+     * @return string 
+     */
+    public function camelizeFirstOn(string $string, $separator = '_')
+    {
+        $uncamelized_words = str_replace($separator, " ", strtolower($string));
+        return str_replace(" ", "", ucwords($uncamelized_words));
+    }
+
+    /**
+     * 下划线转驼峰(首字母小写)
+     * 思路:
+     * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
+     * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
+     * @param string $string 
+     * @param string $separator
+     * @return string 
+     */
+    public function camelize(string $string, $separator = '_')
+    {
+        $uncamelized_words = $separator . str_replace($separator, " ", strtolower($string));
+
+        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
+    }
+
+    /**
+     * 驼峰命名转下划线命名
+     * 思路:
+     * 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
+     */
+    public function uncamelize($camelCaps, $separator = '_')
+    {
+        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
+    }
+
+    /**
+     * 生成随机字符串
+     */
+    public function generateStochastic($length = 16)
+    {
+        $permitted_chars = '0123456789abcdefghijklmnopqrstuvwxyz';
+        return substr(str_shuffle($permitted_chars), 0, $length);
+    }
+}

+ 115 - 0
app/utils/ValidateUtils.php

@@ -0,0 +1,115 @@
+<?php
+
+declare(strict_types=1);
+
+namespace app\utils;
+
+// 引入框架内置类
+use think\facade\Db;
+use think\facade\Config;
+
+/**
+ * 验证 utils
+ *
+ * @version      0.0.1
+ * @author      by huwhois
+ * @time        20228/10
+ */
+class ValidateUtils
+{
+    protected $namespace;
+    protected $class;
+    protected $tableName;
+    protected $databaseName;
+
+    protected function getPathName(string $name): string
+    {
+        $name = substr($name, 4);
+
+        return app()->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
+    }
+
+    protected function getStub(): string
+    {
+        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'validate.stub';
+    }
+
+    /**
+     * 获取表的所有字段信息
+     * @return array
+     */
+    protected function getColumns()
+    {
+        $sql = "SELECT column_name,column_comment,data_type FROM information_schema.COLUMNS WHERE TABLE_NAME = '" . $this->tableName . "' AND table_schema = '" . $this->databaseName . "'";
+
+        // echo $sql . "\n";
+
+        $res = Db::query($sql);
+
+        $columns = empty($res) ? [] : $res;
+
+        return $columns;
+    }
+
+    /**
+     * 构建Class文件
+     * @return string
+     */
+    protected function buildClass()
+    {
+        $stub = file_get_contents($this->getStub());
+
+        $schemas = '';
+
+        $columns = $this->getColumns();
+
+        foreach ($columns as $column) {
+            $schemas .= "\n" . '        "' . $column['column_name'] . '" => "require",';
+        }
+
+        return str_replace(['{%namespace%}', '{%className%}', '{%schemas%}'], [
+            $this->namespace,
+            $this->class,
+            $schemas
+        ], $stub);
+    }
+
+    /**
+     * 生成 Model 文件
+     * @param  string $name 类目,包含命名空间
+     * @param string $connections 数据库配置, 默认 mysql
+     */
+    public function makeModel(string $name, string $connections = 'mysql')
+    {
+        $pathname = $this->getPathName($name);
+
+        if (is_file($pathname)) {
+            throw new \Exception("Valiate :' . $name . ' already exists!</error>", 1);
+        }
+
+        if (!is_dir(dirname($pathname))) {
+            mkdir(dirname($pathname), 0755, true);
+        }
+
+        file_put_contents($pathname, $this->codeModel($name, $connections));
+    }
+
+    /**
+     * 生成 Model 不生成文件
+     * @param  string $name 类目,包含命名空间
+     * @param string $connections 数据库配置, 默认 mysql
+     * @return string
+     */
+    public function codeModel(string $name, string $connections = 'mysql')
+    {
+        $this->namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
+
+        $this->class = str_replace($this->namespace . '\\', '', $name);
+
+        $this->tableName = Config::get('database.connections.'.$connections.'.prefix') . strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $this->class));
+
+        $this->databaseName = Config::get('database.connections.'.$connections.'.database');
+
+        return $this->buildClass();
+    }
+}

+ 120 - 0
app/utils/ZipUtils.php

@@ -0,0 +1,120 @@
+<?php
+
+declare(strict_types=1);
+
+namespace app\utils;
+
+use ZipArchive;
+
+class ZipUtils
+{
+    public function packZip($source, $dest)
+    {
+        //判断zip扩展是否加载或者文件目录是否存在
+        if (!extension_loaded('zip') || !file_exists($source)) {
+            return false;
+        }
+        //创建一个zip打包文件
+        $zip = new ZipArchive();
+
+        if (!$zip->open($dest, ZipArchive::CREATE)) {
+            return false;
+        }
+
+        $source = str_replace('\\', '/', realpath($source));
+        
+        if (is_dir($source) === true) {
+            //创建件一个目录迭代器
+            $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source));
+
+            foreach ($files as $file) {
+                $file = str_replace('\\', '/', $file);
+                //忽略当前目录和上级目录
+                if (in_array(substr($file, strrpos($file, '/') + 1), array('.', '..'))) {
+                    continue;
+                }
+                if (is_dir($file) === true) {
+                    //创建一个子目录
+                    $zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
+                } else if (is_file($file) === true) {
+                    //创建一个子文件
+                    $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
+                } else if (is_file($source) === true) {
+                    //创建文件根目录下的文件
+                    $zip->addFromString(basename($source), file_get_contents($source));
+                }
+            }
+            $zip->close();
+        }
+    }
+
+    protected function addFileToZip(string $path,  ZipArchive $zip)
+    {
+        $handler = opendir($path); //打开当前文件夹由$path指定。
+        while (($filename = readdir($handler)) !== false) {
+            if ($filename != "." && $filename != "..") { //文件夹文件名字为'.'和‘..’,不要对他们进行操作
+                if (is_dir($path . "/" . $filename)) {
+                    $this->addFileToZip($path . "/" . $filename, $zip);
+                } else {
+                    $zip->addFile($path . "/" . $filename);
+                }
+            }
+        }
+        @closedir($handler);
+    }
+
+
+    /**
+     * 删除临时路径
+     * @param $path
+     */
+    public function deleteDir($path)
+    {
+        if (is_dir($path)) {
+            //
+            $dirs = scandir($path);
+            foreach ($dirs as $dir) {
+                if ($dir != '.' | $dir != '..') {
+                    $sonDir = $path . '/' . $dir;
+                    if (is_dir($sonDir)) {
+                        $this->deleteDir($sonDir);
+                        @rmdir($sonDir);
+                    } else {
+                        @unlink($sonDir);
+                    }
+                }
+            }
+            @rmdir($path);
+        }
+    }
+
+    /**
+     * 文件下载
+     * @param $file
+     */
+    public function downLoad($file)
+    {
+        if (file_exists($file)) {
+            $openFile = fopen($file, 'r');
+            //返回文件类型
+            Header('Content-type: application/octet-iostream');
+            //返回文件的字节大小
+            Header('Accept-Range: bytes');
+            //返回文件大小
+            Header('Accept-Length: ' . $file);
+            //这里对客户端弹出的对话框,对应的文件名
+            Header('Content-disposition: filename=' . substr($file, strrpos($file, '/') + 1));
+            $buffer = 1024;
+            while (!feof($openFile)) {
+                $file_data = fread($openFile, $buffer);
+                echo $file_data;
+            }
+            fclose($file);
+
+            @unlink($file);
+        } else {
+
+            echo '下载文件不存在';
+        }
+    }
+}

+ 64 - 64
app/common/utils/stubs/controller.stub → app/utils/stubs/controller.stub

@@ -1,64 +1,64 @@
-<?php
-declare (strict_types = 1);
-
-namespace {%namespace%};
-
-use think\Request;
-
-class {%className%}
-{
-    /**
-     * 显示资源列表
-     *
-     * @return \think\Response
-     */
-    public function index()
-    {
-        //
-    }
-
-    /**
-     * 保存新建的资源
-     *
-     * @param  \think\Request  $request
-     * @return \think\Response
-     */
-    public function save(Request $request)
-    {
-        //
-    }
-
-    /**
-     * 显示指定的资源
-     *
-     * @param  int  $id
-     * @return \think\Response
-     */
-    public function read($id)
-    {
-        //
-    }
-
-    /**
-     * 保存更新的资源
-     *
-     * @param  \think\Request  $request
-     * @param  int  $id
-     * @return \think\Response
-     */
-    public function update(Request $request, $id)
-    {
-        //
-    }
-
-    /**
-     * 删除指定资源
-     *
-     * @param  int  $id
-     * @return \think\Response
-     */
-    public function delete($id)
-    {
-        //
-    }
-}
+<?php
+declare (strict_types = 1);
+
+namespace {%namespace%};
+
+use think\Request;
+
+class {%className%}
+{
+    /**
+     * 显示资源列表
+     *
+     * @return \think\Response
+     */
+    public function index()
+    {
+        //
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @param  \think\Request  $request
+     * @return \think\Response
+     */
+    public function save(Request $request)
+    {
+        //
+    }
+
+    /**
+     * 显示指定的资源
+     *
+     * @param  int  $id
+     * @return \think\Response
+     */
+    public function read($id)
+    {
+        //
+    }
+
+    /**
+     * 保存更新的资源
+     *
+     * @param  \think\Request  $request
+     * @param  int  $id
+     * @return \think\Response
+     */
+    public function update(Request $request, $id)
+    {
+        //
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param  int  $id
+     * @return \think\Response
+     */
+    public function delete($id)
+    {
+        //
+    }
+}

+ 110 - 110
app/common/utils/stubs/form.vue.stub → app/utils/stubs/form.vue.stub

@@ -1,110 +1,110 @@
-<template>
-  <el-dialog
-    :title="!dataForm.id ? '新增' : '修改'"
-    :close-on-click-modal="false"
-    :visible.sync="visible">
-    <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
-#foreach($column in $columns)
-#if($column.columnName != $pk.columnName)
-    <el-form-item label="${column.comments}" prop="${column.attrname}">
-      <el-input v-model="dataForm.${column.attrname}" placeholder="${column.comments}"></el-input>
-    </el-form-item>
-#end
-#end
-    </el-form>
-    <span slot="footer" class="dialog-footer">
-      <el-button @click="visible = false">取消</el-button>
-      <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
-    </span>
-  </el-dialog>
-</template>
-
-<script>
-  export default {
-    data () {
-      return {
-        visible: false,
-        dataForm: {
-#foreach($column in $columns)
-#if($column.columnName == $pk.columnName)
-          ${column.attrname}: 0,
-#else
-          ${column.attrname}: ''#if($velocityCount != $columns.size()),#end
-
-#end
-#end
-        },
-        dataRule: {
-#foreach($column in $columns)
-#if($column.columnName != $pk.columnName)
-          ${column.attrname}: [
-            { required: true, message: '${column.comments}不能为空', trigger: 'blur' }
-          ]#if($velocityCount != $columns.size()),#end
-
-#end
-#end
-        }
-      }
-    },
-    methods: {
-      init (id) {
-        this.dataForm.${pk.attrname} = id || 0
-        this.visible = true
-        this.$nextTick(() => {
-          this.$refs['dataForm'].resetFields()
-          if (this.dataForm.${pk.attrname}) {
-            this.$http({
-              url: #[[this.$http.adornUrl]]#(`/${moduleName}/${pathName}/info/#[[$]]#{this.dataForm.${pk.attrname}}`),
-              method: 'get',
-              #[[params: this.$http.adornParams()]]#
-            }).then(({data}) => {
-              if (data && data.code === 0) {
-#foreach($column in $columns)
-#if($column.columnName != $pk.columnName)
-                this.dataForm.${column.attrname} = data.${classname}.${column.attrname}
-#end
-#end
-              }
-            })
-          }
-        })
-      },
-      // 表单提交
-      dataFormSubmit () {
-        #[[this.$refs['dataForm'].validate((valid) => {]]#
-          if (valid) {
-            this.$http({
-              url: #[[this.$http.adornUrl]]#(`/${moduleName}/${pathName}/${!this.dataForm.${pk.attrname} ? 'save' : 'update'}`),
-              method: 'post',
-              #[[data: this.$http.adornData({]]#
-#foreach($column in $columns)
-#if($column.columnName == $pk.columnName)
-                '${column.attrname}': this.dataForm.${column.attrname} || undefined,
-#else
-                '${column.attrname}': this.dataForm.${column.attrname}#if($velocityCount != $columns.size()),#end
-
-#end
-#end
-              })
-            }).then(({data}) => {
-              if (data && data.code === 0) {
-                #[[this.$message({]]#
-                  message: '操作成功',
-                  type: 'success',
-                  duration: 1500,
-                  onClose: () => {
-                    this.visible = false
-                    #[[this.$emit('refreshDataList')]]#
-                  }
-                })
-              } else {
-                #[[this.$message.error(data.msg)]]#
-              }
-            })
-          }
-        })
-      }
-    }
-  }
-</script>
-
+<template>
+  <el-dialog
+    :title="!dataForm.id ? '新增' : '修改'"
+    :close-on-click-modal="false"
+    :visible.sync="visible">
+    <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
+#foreach($column in $columns)
+#if($column.columnName != $pk.columnName)
+    <el-form-item label="${column.comments}" prop="${column.attrname}">
+      <el-input v-model="dataForm.${column.attrname}" placeholder="${column.comments}"></el-input>
+    </el-form-item>
+#end
+#end
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="visible = false">取消</el-button>
+      <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+  export default {
+    data () {
+      return {
+        visible: false,
+        dataForm: {
+#foreach($column in $columns)
+#if($column.columnName == $pk.columnName)
+          ${column.attrname}: 0,
+#else
+          ${column.attrname}: ''#if($velocityCount != $columns.size()),#end
+
+#end
+#end
+        },
+        dataRule: {
+#foreach($column in $columns)
+#if($column.columnName != $pk.columnName)
+          ${column.attrname}: [
+            { required: true, message: '${column.comments}不能为空', trigger: 'blur' }
+          ]#if($velocityCount != $columns.size()),#end
+
+#end
+#end
+        }
+      }
+    },
+    methods: {
+      init (id) {
+        this.dataForm.${pk.attrname} = id || 0
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs['dataForm'].resetFields()
+          if (this.dataForm.${pk.attrname}) {
+            this.$http({
+              url: #[[this.$http.adornUrl]]#(`/${moduleName}/${pathName}/info/#[[$]]#{this.dataForm.${pk.attrname}}`),
+              method: 'get',
+              #[[params: this.$http.adornParams()]]#
+            }).then(({data}) => {
+              if (data && data.code === 0) {
+#foreach($column in $columns)
+#if($column.columnName != $pk.columnName)
+                this.dataForm.${column.attrname} = data.${classname}.${column.attrname}
+#end
+#end
+              }
+            })
+          }
+        })
+      },
+      // 表单提交
+      dataFormSubmit () {
+        #[[this.$refs['dataForm'].validate((valid) => {]]#
+          if (valid) {
+            this.$http({
+              url: #[[this.$http.adornUrl]]#(`/${moduleName}/${pathName}/${!this.dataForm.${pk.attrname} ? 'save' : 'update'}`),
+              method: 'post',
+              #[[data: this.$http.adornData({]]#
+#foreach($column in $columns)
+#if($column.columnName == $pk.columnName)
+                '${column.attrname}': this.dataForm.${column.attrname} || undefined,
+#else
+                '${column.attrname}': this.dataForm.${column.attrname}#if($velocityCount != $columns.size()),#end
+
+#end
+#end
+              })
+            }).then(({data}) => {
+              if (data && data.code === 0) {
+                #[[this.$message({]]#
+                  message: '操作成功',
+                  type: 'success',
+                  duration: 1500,
+                  onClose: () => {
+                    this.visible = false
+                    #[[this.$emit('refreshDataList')]]#
+                  }
+                })
+              } else {
+                #[[this.$message.error(data.msg)]]#
+              }
+            })
+          }
+        })
+      }
+    }
+  }
+</script>
+

+ 152 - 152
app/common/utils/stubs/index.vue.stub → app/utils/stubs/index.vue.stub

@@ -1,152 +1,152 @@
-<template>
-  <div class="app-container">
-    <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
-      <el-form-item>
-        <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
-      </el-form-item>
-      <el-form-item>
-        <el-button @click="getDataList()">查询</el-button>
-        <el-button v-if="isAuth('{%moduleName%}:{%className%}:save')" type="primary" @click="addOrUpdateHandle()">新增</el-button>
-        <el-button v-if="isAuth('{%moduleName%}:{%className%}:delete')" type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button>
-      </el-form-item>
-    </el-form>
-    <el-table
-      :data="dataList"
-      border
-      v-loading="dataListLoading"
-      @selection-change="selectionChangeHandle"
-      style="width: 100%;">
-      <el-table-column
-        type="selection"
-        header-align="center"
-        align="center"
-        width="50">
-      </el-table-column>
-        {%schemas%}
-      <el-table-column
-        fixed="right"
-        header-align="center"
-        align="center"
-        width="150"
-        label="操作">
-        <template slot-scope="scope">
-          <el-button type="text" size="small" @click="addOrUpdateHandle(scope.row.{%primarykey%})">修改</el-button>
-          <el-button type="text" size="small" @click="deleteHandle(scope.row.{%primarykey%})">删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    <el-pagination
-      @size-change="sizeChangeHandle"
-      @current-change="currentChangeHandle"
-      :current-page="pageIndex"
-      :page-sizes="[10, 20, 50, 100]"
-      :page-size="pageSize"
-      :total="totalPage"
-      layout="total, sizes, prev, pager, next, jumper">
-    </el-pagination>
-    <!-- 弹窗, 新增 / 修改 -->
-    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
-  </div>
-</template>
-
-<script>
-  import AddOrUpdate from './{%className%}-add-or-update'
-  export default {
-    data () {
-      return {
-        dataForm: {
-          key: ''
-        },
-        dataList: [],
-        pageIndex: 1,
-        pageSize: 10,
-        totalPage: 0,
-        dataListLoading: false,
-        dataListSelections: [],
-        addOrUpdateVisible: false
-      }
-    },
-    components: {
-      AddOrUpdate
-    },
-    activated () {
-      this.getDataList()
-    },
-    methods: {
-      // 获取数据列表
-      getDataList () {
-        this.dataListLoading = true
-        this.$http({
-          url: this.$http.adornUrl('/{%moduleName%}/{%className%}/index'),
-          method: 'get',
-          params: this.$http.adornParams({
-            'page': this.pageIndex,
-            'limit': this.pageSize,
-            'key': this.dataForm.key
-          })
-        }).then(({res}) => {
-          if (res && res.code === 0) {
-            this.dataList = res.data.data
-            this.totalPage = res.data.total
-          } else {
-            this.dataList = []
-            this.totalPage = 0
-          }
-          this.dataListLoading = false
-        })
-      },
-      // 每页数
-      sizeChangeHandle (val) {
-        this.pageSize = val
-        this.pageIndex = 1
-        this.getDataList()
-      },
-      // 当前页
-      currentChangeHandle (val) {
-        this.pageIndex = val
-        this.getDataList()
-      },
-      // 多选
-      selectionChangeHandle (val) {
-        this.dataListSelections = val
-      },
-      // 新增 / 修改
-      addOrUpdateHandle (id) {
-        this.addOrUpdateVisible = true
-        this.$nextTick(() => {
-          this.$refs.addOrUpdate.init(id)
-        })
-      },
-      // 删除
-      deleteHandle (id) {
-        var ids = id ? [id] : this.dataListSelections.map(item => {
-          return item.{%primarykey%}
-        })
-        this.$confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
-          confirmButtonText: '确定',
-          cancelButtonText: '取消',
-          type: 'warning'
-        }).then(() => {
-          this.$http({
-            url: this.$http.adornUrl('/{%moduleName%}/{%className%}/delete'),
-            method: 'post',
-            data: this.$http.adornData(ids, false)
-          }).then(({data}) => {
-            if (data && data.code === 0) {
-              this.$message({
-                message: '操作成功',
-                type: 'success',
-                duration: 1500,
-                onClose: () => {
-                  this.getDataList()
-                }
-              })
-            } else {
-              this.$message.error(data.msg)
-            }
-          })
-        }).catch(() => {})
-      }
-    }
-  }
-</script>
+<template>
+  <div class="app-container">
+    <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
+      <el-form-item>
+        <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="getDataList()">查询</el-button>
+        <el-button v-if="isAuth('{%moduleName%}:{%className%}:save')" type="primary" @click="addOrUpdateHandle()">新增</el-button>
+        <el-button v-if="isAuth('{%moduleName%}:{%className%}:delete')" type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+      :data="dataList"
+      border
+      v-loading="dataListLoading"
+      @selection-change="selectionChangeHandle"
+      style="width: 100%;">
+      <el-table-column
+        type="selection"
+        header-align="center"
+        align="center"
+        width="50">
+      </el-table-column>
+        {%schemas%}
+      <el-table-column
+        fixed="right"
+        header-align="center"
+        align="center"
+        width="150"
+        label="操作">
+        <template slot-scope="scope">
+          <el-button type="text" size="small" @click="addOrUpdateHandle(scope.row.{%primarykey%})">修改</el-button>
+          <el-button type="text" size="small" @click="deleteHandle(scope.row.{%primarykey%})">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      @size-change="sizeChangeHandle"
+      @current-change="currentChangeHandle"
+      :current-page="pageIndex"
+      :page-sizes="[10, 20, 50, 100]"
+      :page-size="pageSize"
+      :total="totalPage"
+      layout="total, sizes, prev, pager, next, jumper">
+    </el-pagination>
+    <!-- 弹窗, 新增 / 修改 -->
+    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
+  </div>
+</template>
+
+<script>
+  import AddOrUpdate from './{%className%}-add-or-update'
+  export default {
+    data () {
+      return {
+        dataForm: {
+          key: ''
+        },
+        dataList: [],
+        pageIndex: 1,
+        pageSize: 10,
+        totalPage: 0,
+        dataListLoading: false,
+        dataListSelections: [],
+        addOrUpdateVisible: false
+      }
+    },
+    components: {
+      AddOrUpdate
+    },
+    activated () {
+      this.getDataList()
+    },
+    methods: {
+      // 获取数据列表
+      getDataList () {
+        this.dataListLoading = true
+        this.$http({
+          url: this.$http.adornUrl('/{%moduleName%}/{%className%}/index'),
+          method: 'get',
+          params: this.$http.adornParams({
+            'page': this.pageIndex,
+            'limit': this.pageSize,
+            'key': this.dataForm.key
+          })
+        }).then(({res}) => {
+          if (res && res.code === 0) {
+            this.dataList = res.data.data
+            this.totalPage = res.data.total
+          } else {
+            this.dataList = []
+            this.totalPage = 0
+          }
+          this.dataListLoading = false
+        })
+      },
+      // 每页数
+      sizeChangeHandle (val) {
+        this.pageSize = val
+        this.pageIndex = 1
+        this.getDataList()
+      },
+      // 当前页
+      currentChangeHandle (val) {
+        this.pageIndex = val
+        this.getDataList()
+      },
+      // 多选
+      selectionChangeHandle (val) {
+        this.dataListSelections = val
+      },
+      // 新增 / 修改
+      addOrUpdateHandle (id) {
+        this.addOrUpdateVisible = true
+        this.$nextTick(() => {
+          this.$refs.addOrUpdate.init(id)
+        })
+      },
+      // 删除
+      deleteHandle (id) {
+        var ids = id ? [id] : this.dataListSelections.map(item => {
+          return item.{%primarykey%}
+        })
+        this.$confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          this.$http({
+            url: this.$http.adornUrl('/{%moduleName%}/{%className%}/delete'),
+            method: 'post',
+            data: this.$http.adornData(ids, false)
+          }).then(({data}) => {
+            if (data && data.code === 0) {
+              this.$message({
+                message: '操作成功',
+                type: 'success',
+                duration: 1500,
+                onClose: () => {
+                  this.getDataList()
+                }
+              })
+            } else {
+              this.$message.error(data.msg)
+            }
+          })
+        }).catch(() => {})
+      }
+    }
+  }
+</script>

+ 18 - 18
app/common/utils/stubs/model.stub → app/utils/stubs/model.stub

@@ -1,18 +1,18 @@
-<?php
-declare (strict_types = 1);
-
-namespace {%namespace%};
-
-use think\Model;
-
-/**
- * @mixin \think\Model
- */
-class {%className%} extends Model
-{
-    {%primarykey%}
-    protected $schema = [{%schemas%}
-    ];
-
-    {%autoWriteTimestamp%}    
-}
+<?php
+declare (strict_types = 1);
+
+namespace {%namespace%};
+
+use think\Model;
+
+/**
+ * @mixin \think\Model
+ */
+class {%className%} extends Model
+{
+    {%primarykey%}
+    protected $schema = [{%schemas%}
+    ];
+
+    {%autoWriteTimestamp%}    
+}

+ 21 - 21
app/common/utils/stubs/validate.stub → app/utils/stubs/validate.stub

@@ -1,21 +1,21 @@
-<?php
-declare (strict_types = 1);
-
-namespace {%namespace%};
-
-use think\Validate;
-
-/**
- * @mixin \think\Validate
- */
-class {%className%} extends Validate
-{
-    /**
-     * 定义验证规则
-     * 格式:'字段名' =>  ['规则1','规则2'...]
-     *
-     * @var array
-     */
-    protected $rule = [{%schemas%}
-    ];   
-}
+<?php
+declare (strict_types = 1);
+
+namespace {%namespace%};
+
+use think\Validate;
+
+/**
+ * @mixin \think\Validate
+ */
+class {%className%} extends Validate
+{
+    /**
+     * 定义验证规则
+     * 格式:'字段名' =>  ['规则1','规则2'...]
+     *
+     * @var array
+     */
+    protected $rule = [{%schemas%}
+    ];   
+}

+ 0 - 1
composer.json

@@ -23,7 +23,6 @@
         "php": ">=7.1.0",
         "topthink/framework": "^6.0.0",
         "topthink/think-orm": "^2.0",
-        "topthink/think-multi-app": "^1.0",
         "liliuwei/thinkphp-jump": "^1.5",
         "topthink/think-image": "^1.0",
         "erusev/parsedown": "^1.8.0-beta-7"

+ 0 - 48
composer.lock

@@ -722,54 +722,6 @@
             },
             "time": "2016-09-29T06:05:43+00:00"
         },
-        {
-            "name": "topthink/think-multi-app",
-            "version": "v1.0.14",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/top-think/think-multi-app.git",
-                "reference": "ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/top-think/think-multi-app/zipball/ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3",
-                "reference": "ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.1.0",
-                "topthink/framework": "^6.0.0"
-            },
-            "type": "library",
-            "extra": {
-                "think": {
-                    "services": [
-                        "think\\app\\Service"
-                    ]
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "think\\app\\": "src"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "Apache-2.0"
-            ],
-            "authors": [
-                {
-                    "name": "liu21st",
-                    "email": "liu21st@gmail.com"
-                }
-            ],
-            "description": "thinkphp6 multi app support",
-            "support": {
-                "issues": "https://github.com/top-think/think-multi-app/issues",
-                "source": "https://github.com/top-think/think-multi-app/tree/master"
-            },
-            "time": "2020-07-12T13:50:37+00:00"
-        },
         {
             "name": "topthink/think-orm",
             "version": "v2.0.53",

+ 8 - 0
config/app.php

@@ -39,4 +39,12 @@ return [
     'error_message'    => '页面错误!请稍后再试~',
     // 显示错误信息
     'show_error_msg'   => false,
+    // 默认分页显示数量
+    'page_size'             => 20,
+    // 版本信息
+    'sys_version'          => '0.1',
+    // 默认密码
+    'default_password' => 'qwe123',
+    // 是否开启权限认证
+    'auth_on'               => true,
 ];

+ 3 - 3
config/console.php

@@ -5,8 +5,8 @@
 return [
     // 指令定义
     'commands' => [
-        'fileconsole' => 'app\common\command\FileConsole',
-        'makemodel' => 'app\common\command\MakeModel',
-        'makecontroller' => 'app\common\command\MakeController',
+        'fileconsole' => 'app\command\FileConsole',
+        'makemodel' => 'app\command\MakeModel',
+        'makecontroller' => 'app\command\MakeController',
     ],
 ];

+ 4 - 0
config/view.php

@@ -22,4 +22,8 @@ return [
     'taglib_begin'  => '{',
     // 标签库标签结束标记
     'taglib_end'    => '}',
+    // 自定义标签库
+    'taglib_pre_load' => 'app\taglib\Tp',
+    // 开启模板布局
+    'layout_on'    => true,
 ];

+ 1 - 0
data/index.html

@@ -0,0 +1 @@
+test

+ 0 - 0
public/static/index/css/index.css → public/static/css/index.css


+ 31 - 1
app/index/route/app.php → route/app.php

@@ -9,8 +9,9 @@
 // | Author: liu21st <liu21st@gmail.com>
 // +----------------------------------------------------------------------
 use think\facade\Route;
-use app\common\model\Category;
+use app\model\Category;
 use think\facade\Template;
+use app\model\SysMenu;
 
 Route::pattern([
     'name' => '\w+',
@@ -33,6 +34,7 @@ Route::get('/tags/:name', 'index/article/tag');
 Route::get('/tag/:name', 'index/article/tag');
 Route::get('/all-<page?>', 'index/article/index')->append(['cid' => 0]);
 Route::post('/dolike', 'index/article/dolike');
+Route::get('/detail/<id>-<name>', 'index/article/read');
 Route::get('/:year/<month>-<day>/:id', 'index/article/read');
 Route::get('/:year/<month>-<page?>', 'index/article/archive');
 
@@ -41,3 +43,31 @@ $list = Category::getList();
 foreach ($list as $key => $value) {
     Route::get($value->url . '-<page?>', $value->route)->append(['cid' => $value->id]);
 }
+
+Route::get('sys/index', 'sys.index/index');
+Route::post('sys/index/usedspace', 'sys.index/usedspace');
+Route::post('sys/index/clearcache', 'sys.index/clearcache');
+Route::post('sys/index/countArticle', 'sys.index/countArticle');
+Route::post('sys/index/countIndustry', 'sys.index/countIndustry');
+Route::post('sys/index/countGuestBook', 'sys.index/countGuestBook');
+Route::post('sys/index/saveIndexButton', 'sys.index/saveIndexButton');
+Route::get('sys/login/index', 'sys.login/index');
+Route::post('sys/login/dologin', 'sys.login/dologin');
+Route::get('sys/login/logout', 'sys.login/logout');
+Route::get('sys/verify', 'sys.login/verify');
+Route::post('sys/file_manager/uploadImage', 'sys.file_manager/uploadImage');
+Route::post('sys/file_manager/uploadMoive', 'sys.file_manager/uploadMoive');
+Route::post('sys/file_manager/ckeditorUploadImage', 'sys.file_manager/ckeditorUploadImage');
+Route::post('sys/file_manager/uploadUrlImg', 'sys.file_manager/uploadUrlImg');
+
+Route::group('sys', function () {
+    $menuList = SysMenu::where('type', '<>', '0')->field('id, pid, name, url, icon')->select();
+    foreach ($menuList as $menu) {
+        $menuUrl = $menu->url;
+        $router = 'sys.' . $menuUrl;
+        Route::rule($menuUrl, $router);
+    }
+});
+
+Route::get('sys', 'sys.index/index');
+

+ 2 - 0
vendor/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 0 - 0
view/index/404.html → view/404.html


+ 0 - 0
view/index/article/archive.html → view/article/archive.html


+ 0 - 0
view/index/article/article.bak.html → view/article/article.bak.html


+ 49 - 49
view/index/article/index.html → view/article/index.html

@@ -1,50 +1,50 @@
-<div class="box">
-  <div class="place">
-    <a href="/all.html" class="{$cid==0 ? 'current_category': ''}">All</a>
-    {foreach $cate_lists as $value}
-    <a href="{$value.url}" class="{$cid==$value.id ? 'current_category': ''}">{$value.name}</a>
-    {/foreach}
-  </div>
-  <div class="blank"></div>
-  <div class="blogs">
-    {foreach $list as $val}
-    <div class="bloglist">
-      <h2><a href="/{$val.create_time|date='Y/m-d'}/{$val.id}.html" title="{$val.title}">{$val.title}</a></h2>
-      <div class="bloginfo">
-        <ul>
-          <li class="author"><a href="{$val.category_url}.html"> {$val.category_name} </a></li>
-          <li class="timer">{$val.create_time}</li>
-          <li class="view">{$val.hits} 已阅读</li>
-          <li class="like">{$val.likes}</li>
-        </ul>
-      </div>
-      <p>{$val.summary}</p>
-    </div>
-    {/foreach}
-    {lt name="list|count" value="$limit"}
-    <p style="text-align: center;">全都给你了, 没有更多啦(╥╯^╰╥).</p>
-    {/lt}
-    <div class="pagelist">
-      <a title="Total record">共&nbsp;<b>{$lastPage}</b>&nbsp;页</a>&nbsp;&nbsp;&nbsp;
-      {neq name="page" value="1"}
-      <a href="{$baseUrl}">首页</a>
-      <a href="{$baseUrl}-{$page - 1}">上一页</a>&nbsp;
-      {/neq}
-      <b>{$page}</b>&nbsp;
-      {if ( $lastPage != 0) && ( $lastPage != $page) }
-      <a href="{$baseUrl}-{$page + 1}">下一页</a>&nbsp;
-      <a href="{$baseUrl}-{$lastPage}">尾页</a>
-      {/if}
-      <input type="number" min="1" max="{$lastPage}" name="topage">
-      <a href="javascript:goto()">转到</a>
-    </div>
-  </div>
-  {include file="aside"}
-</div>
-
-<script>
-  function goto() {
-    var page = $("input[name='topage']").val();
-    window.location.href = "{$baseUrl}-" + page;
-  }
+<div class="box">
+  <div class="place">
+    <a href="/all.html" class="{$cid==0 ? 'current_category': ''}">All</a>
+    {foreach $cate_lists as $value}
+    <a href="{$value.url}" class="{$cid==$value.id ? 'current_category': ''}">{$value.name}</a>
+    {/foreach}
+  </div>
+  <div class="blank"></div>
+  <div class="blogs">
+    {foreach $list as $val}
+    <div class="bloglist">
+      <h2><a href="/{$val.create_time|date='Y/m-d'}/{$val.id}.html" title="{$val.title}">{$val.title}</a></h2>
+      <div class="bloginfo">
+        <ul>
+          <li class="author"><a href="{$val.category_url}.html"> {$val.category_name} </a></li>
+          <li class="timer">{$val.create_time}</li>
+          <li class="view">{$val.hits} 已阅读</li>
+          <li class="like">{$val.likes}</li>
+        </ul>
+      </div>
+      <p>{$val.summary}</p>
+    </div>
+    {/foreach}
+    {lt name="list|count" value="$limit"}
+    <p style="text-align: center;">全都给你了, 没有更多啦(╥╯^╰╥).</p>
+    {/lt}
+    <div class="pagelist">
+      <a title="Total record">共&nbsp;<b>{$lastPage}</b>&nbsp;页</a>&nbsp;&nbsp;&nbsp;
+      {neq name="page" value="1"}
+      <a href="{$baseUrl}">首页</a>
+      <a href="{$baseUrl}-{$page - 1}">上一页</a>&nbsp;
+      {/neq}
+      <b>{$page}</b>&nbsp;
+      {if ( $lastPage != 0) && ( $lastPage != $page) }
+      <a href="{$baseUrl}-{$page + 1}">下一页</a>&nbsp;
+      <a href="{$baseUrl}-{$lastPage}">尾页</a>
+      {/if}
+      <input type="number" min="1" max="{$lastPage}" name="topage">
+      <a href="javascript:goto()">转到</a>
+    </div>
+  </div>
+  {include file="aside"}
+</div>
+
+<script>
+  function goto() {
+    var page = $("input[name='topage']").val();
+    window.location.href = "{$baseUrl}-" + page;
+  }
 </script>

+ 0 - 0
view/index/article/lists.bak.html → view/article/lists.bak.html


+ 0 - 0
view/index/article/read.html → view/article/read.html


+ 0 - 0
view/index/article/tag.html → view/article/tag.html


+ 0 - 0
view/index/article/time.html → view/article/time.html


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