├── resource ├── language │ └── .keep ├── log.php ├── file_content.php ├── login.php ├── layouts │ ├── container.php │ ├── base.php │ └── left.php ├── home.php ├── home │ ├── terminal.php │ └── welcome.php ├── table │ ├── form.php │ └── lists.php ├── document.php └── app │ └── auto_reload.php ├── public ├── images │ ├── bg.png │ └── aiwrap.png ├── fonts │ ├── iconfont.eot │ ├── iconfont.ttf │ └── iconfont.woff ├── lib │ └── layui │ │ ├── font │ │ ├── iconfont.eot │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ │ ├── images │ │ └── face │ │ │ ├── 0.gif │ │ │ ├── 1.gif │ │ │ ├── 2.gif │ │ │ ├── 3.gif │ │ │ ├── 4.gif │ │ │ ├── 5.gif │ │ │ ├── 6.gif │ │ │ ├── 7.gif │ │ │ ├── 8.gif │ │ │ ├── 9.gif │ │ │ ├── 10.gif │ │ │ ├── 11.gif │ │ │ ├── 12.gif │ │ │ ├── 13.gif │ │ │ ├── 14.gif │ │ │ ├── 15.gif │ │ │ ├── 16.gif │ │ │ ├── 17.gif │ │ │ ├── 18.gif │ │ │ ├── 19.gif │ │ │ ├── 20.gif │ │ │ ├── 21.gif │ │ │ ├── 22.gif │ │ │ ├── 23.gif │ │ │ ├── 24.gif │ │ │ ├── 25.gif │ │ │ ├── 26.gif │ │ │ ├── 27.gif │ │ │ ├── 28.gif │ │ │ ├── 29.gif │ │ │ ├── 30.gif │ │ │ ├── 31.gif │ │ │ ├── 32.gif │ │ │ ├── 33.gif │ │ │ ├── 34.gif │ │ │ ├── 35.gif │ │ │ ├── 36.gif │ │ │ ├── 37.gif │ │ │ ├── 38.gif │ │ │ ├── 39.gif │ │ │ ├── 40.gif │ │ │ ├── 41.gif │ │ │ ├── 42.gif │ │ │ ├── 43.gif │ │ │ ├── 44.gif │ │ │ ├── 45.gif │ │ │ ├── 46.gif │ │ │ ├── 47.gif │ │ │ ├── 48.gif │ │ │ ├── 49.gif │ │ │ ├── 50.gif │ │ │ ├── 51.gif │ │ │ ├── 52.gif │ │ │ ├── 53.gif │ │ │ ├── 54.gif │ │ │ ├── 55.gif │ │ │ ├── 56.gif │ │ │ ├── 57.gif │ │ │ ├── 58.gif │ │ │ ├── 59.gif │ │ │ ├── 60.gif │ │ │ ├── 61.gif │ │ │ ├── 62.gif │ │ │ ├── 63.gif │ │ │ ├── 64.gif │ │ │ ├── 65.gif │ │ │ ├── 66.gif │ │ │ ├── 67.gif │ │ │ ├── 68.gif │ │ │ ├── 69.gif │ │ │ ├── 70.gif │ │ │ └── 71.gif │ │ ├── css │ │ └── modules │ │ │ ├── layer │ │ │ └── default │ │ │ │ ├── icon.png │ │ │ │ ├── icon-ext.png │ │ │ │ ├── loading-0.gif │ │ │ │ ├── loading-1.gif │ │ │ │ └── loading-2.gif │ │ │ └── code.css │ │ ├── lay │ │ └── modules │ │ │ ├── code.js │ │ │ ├── laytpl.js │ │ │ ├── flow.js │ │ │ ├── rate.js │ │ │ ├── tree.js │ │ │ ├── util.js │ │ │ ├── carousel.js │ │ │ ├── laypage.js │ │ │ ├── upload.js │ │ │ └── slider.js │ │ └── layui.js ├── css │ ├── theme2.css │ ├── theme1.css │ ├── theme3.css │ ├── theme4.css │ ├── font.css │ ├── theme5.css │ └── login.css └── terminal │ └── js │ └── jquery.mousewheel-min.js ├── exec ├── template │ ├── BaseClass │ ├── Command │ ├── Controller │ ├── Route │ ├── Crontab │ └── Middleware ├── Model │ ├── Logic │ │ ├── Postmen.php │ │ └── Directory.php │ ├── Data │ │ ├── ClassInfo.php │ │ ├── ControllerInfo.php │ │ ├── RouteInfo.php │ │ └── MiddlewareInfo.php │ └── Dao │ │ ├── AnnotationResource.php │ │ ├── ModelResource.php │ │ ├── ControllerResource.php │ │ ├── CrontabResource.php │ │ ├── ConsoleResource.php │ │ ├── MiddlewareResource.php │ │ └── RoutesResource.php ├── Controller │ ├── Crontab.php │ ├── Middleware.php │ ├── Console.php │ ├── Model.php │ ├── Postmen.php │ └── Controller.php ├── bootstrap.php └── Application.php ├── main.php ├── src ├── View │ ├── Logs.php │ ├── TerminalView.php │ ├── Login.php │ ├── Welcome.php │ ├── Button │ │ ├── ReloadButton.php │ │ ├── NewWindow.php │ │ └── NewWindowIcon.php │ ├── BaseButton.php │ ├── FileContent.php │ ├── Form.php │ ├── Document.php │ ├── Table.php │ ├── Form │ │ ├── TextareaForm.php │ │ ├── InputBlockForm.php │ │ ├── InputForm.php │ │ └── SelectForm.php │ ├── BaseView.php │ └── Home.php ├── Config │ └── user.config.php ├── Http │ ├── Msg.php │ ├── AdminServer.php │ ├── Controller │ │ ├── CrontabController.php │ │ ├── FilesController.php │ │ ├── HomeController.php │ │ ├── PublicController.php │ │ ├── MiddlewareController.php │ │ ├── ConsoleController.php │ │ ├── TerminalController.php │ │ ├── ModelController.php │ │ └── LogsController.php │ └── Middleware │ │ └── LoginMiddleware.php ├── Model │ ├── CallModel.php │ └── LoginModel.php ├── AutoLoader.php ├── Exec.php ├── Helper │ └── Functions.php └── Command │ └── AdminCommand.php ├── .gitignore ├── composer.json └── README.md /resource/language/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/images/bg.png -------------------------------------------------------------------------------- /public/images/aiwrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/images/aiwrap.png -------------------------------------------------------------------------------- /public/fonts/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/fonts/iconfont.eot -------------------------------------------------------------------------------- /public/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/fonts/iconfont.ttf -------------------------------------------------------------------------------- /public/fonts/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/fonts/iconfont.woff -------------------------------------------------------------------------------- /public/lib/layui/font/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/font/iconfont.eot -------------------------------------------------------------------------------- /public/lib/layui/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/font/iconfont.ttf -------------------------------------------------------------------------------- /public/lib/layui/images/face/0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/0.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/1.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/2.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/3.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/4.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/5.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/6.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/7.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/8.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/9.gif -------------------------------------------------------------------------------- /public/lib/layui/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/font/iconfont.woff -------------------------------------------------------------------------------- /public/lib/layui/images/face/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/10.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/11.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/12.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/13.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/14.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/15.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/16.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/17.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/18.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/19.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/20.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/21.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/22.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/23.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/24.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/25.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/26.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/27.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/27.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/28.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/29.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/30.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/31.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/32.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/33.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/34.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/35.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/36.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/37.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/38.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/39.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/40.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/40.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/41.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/41.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/42.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/42.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/43.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/43.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/44.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/44.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/45.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/45.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/46.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/46.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/47.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/47.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/48.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/48.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/49.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/49.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/50.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/51.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/51.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/52.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/53.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/53.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/54.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/54.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/55.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/55.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/56.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/56.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/57.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/57.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/58.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/58.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/59.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/59.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/60.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/60.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/61.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/61.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/62.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/62.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/63.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/63.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/64.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/64.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/65.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/65.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/66.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/66.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/67.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/67.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/68.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/68.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/69.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/69.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/70.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/70.gif -------------------------------------------------------------------------------- /public/lib/layui/images/face/71.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfang/swoft-admin/HEAD/public/lib/layui/images/face/71.gif -------------------------------------------------------------------------------- /exec/template/BaseClass: -------------------------------------------------------------------------------- 1 | run($argv); 9 | -------------------------------------------------------------------------------- /src/View/Logs.php: -------------------------------------------------------------------------------- 1 | 4 |
5 | layContent; ?>
6 | 
7 | -------------------------------------------------------------------------------- /src/View/Welcome.php: -------------------------------------------------------------------------------- 1 | [ 10 | // 账号=>密码 11 | 'admin' => password_hash("123456", PASSWORD_DEFAULT), 12 | ], 13 | ]; 14 | -------------------------------------------------------------------------------- /exec/Model/Data/RouteInfo.php: -------------------------------------------------------------------------------- 1 | withData([ 12 | 'title'=>"这是由Admin创建的路由", 13 | 'get'=>$request->get(), 14 | ]); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /resource/file_content.php: -------------------------------------------------------------------------------- 1 | 4 |
5 |
 6 | layContent; ?>
 7 | 
8 |
9 | 10 | 21 | -------------------------------------------------------------------------------- /exec/Controller/Crontab.php: -------------------------------------------------------------------------------- 1 | scan($dir); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/View/Button/ReloadButton.php: -------------------------------------------------------------------------------- 1 | 15 | 遍历代码 16 | 17 | button; 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /exec/Model/Data/MiddlewareInfo.php: -------------------------------------------------------------------------------- 1 | id = self::$zid; 15 | } 16 | 17 | public $id; 18 | /** @var string 标题 */ 19 | public $title; 20 | public $path; 21 | /** @var bool 全局 */ 22 | public $isGroup = false; 23 | /** @var bool bean */ 24 | public $bean = false; 25 | } 26 | -------------------------------------------------------------------------------- /src/View/BaseButton.php: -------------------------------------------------------------------------------- 1 | tableListFields = $fields; 20 | } 21 | 22 | /** 23 | * 输出html 24 | * @return string 25 | */ 26 | abstract public function toString(): string; 27 | } 28 | -------------------------------------------------------------------------------- /public/css/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'iconfont'; 3 | src: url('../fonts/iconfont.eot'); 4 | src: url('../fonts/iconfont.eot?#iefix') format('embedded-opentype'), 5 | url('../fonts/iconfont.woff') format('woff'), 6 | url('../fonts/iconfont.ttf') format('truetype'), 7 | url('../fonts/iconfont.svg#iconfont') format('svg'); 8 | } 9 | .iconfont{ 10 | font-family:"iconfont" !important; 11 | font-size:16px;font-style:normal; 12 | -webkit-font-smoothing: antialiased; 13 | -webkit-text-stroke-width: 0.2px; 14 | -moz-osx-font-smoothing: grayscale; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/View/FileContent.php: -------------------------------------------------------------------------------- 1 | layContent = $content; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /exec/template/Crontab: -------------------------------------------------------------------------------- 1 | title = $title; 21 | } 22 | 23 | public function addButton(BaseButton $button):BaseButton 24 | { 25 | $this->item[] = $button; 26 | return $button; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ctfang/swoft-admin", 3 | "type": "library", 4 | "keywords": [ 5 | "php", 6 | "swoole", 7 | "swoft", 8 | "webtool" 9 | ], 10 | "description": "swoft webtool component", 11 | "license": "Apache-2.0", 12 | "authors" : [ 13 | { 14 | "name": "ctfang", 15 | "email": "2206582181@qq.com" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=7.1", 20 | "swlib/saber": "*" 21 | }, 22 | "autoload": { 23 | "classmap": [ 24 | ], 25 | "psr-4": { 26 | "SwoftAdmin\\Tool\\": "src/", 27 | "SwoftAdmin\\Exec\\": "exec/" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/View/Document.php: -------------------------------------------------------------------------------- 1 | title = $title; 23 | } 24 | 25 | public function addButton(BaseButton $button):BaseButton 26 | { 27 | $this->item[] = $button; 28 | return $button; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /public/css/theme5.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background:#EEF5F9 !important; 3 | } 4 | .container{ 5 | background:linear-gradient(to left, #7b4397, #2196f3); 6 | } 7 | 8 | .left-nav{ 9 | background:#fff !important; 10 | } 11 | 12 | .left-nav a{ 13 | color:#686a76 !important; 14 | } 15 | .left-nav a.active{ 16 | background: linear-gradient(to left, #7c8ce4, #2196f3) !important; 17 | color: #fff !important; 18 | border-color: #7b4397 !important; 19 | } 20 | .left-nav a:hover{ 21 | background: linear-gradient(to left, #7c8ce4, #2196f3) !important; 22 | color: #fff !important; 23 | border-color: #7b4397 !important; 24 | } 25 | .container .logo a{ 26 | background: rgba(0,0,0,0) !important; 27 | } -------------------------------------------------------------------------------- /resource/login.php: -------------------------------------------------------------------------------- 1 | link('/css/login.css'); 6 | ?> 7 | 8 |
9 |
title;?>
10 |
11 | 12 |
13 | 14 |
15 | 16 |
17 | 18 |
19 |
20 |
21 | -------------------------------------------------------------------------------- /src/View/Table.php: -------------------------------------------------------------------------------- 1 | listButton[] = $baseButton; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Http/Msg.php: -------------------------------------------------------------------------------- 1 | 0, 20 | "msg" => "OK", 21 | "data" => $data, 22 | ]; 23 | } 24 | 25 | /** 26 | * @param string $msg 27 | * @param int $code 28 | * @return array 29 | */ 30 | public static function error(string $msg = "", int $code = 1): array 31 | { 32 | return [ 33 | "code" => $code, 34 | "msg" => $msg, 35 | "data" => [], 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Model/CallModel.php: -------------------------------------------------------------------------------- 1 | handel = end($arr); 21 | } 22 | 23 | public function __call($name, $arguments) 24 | { 25 | $rule = $this->handel."@".$name; 26 | $callArr[] = $rule; 27 | if ($arguments){ 28 | foreach ($arguments as $name=>$argument){ 29 | $callArr[] = $argument; 30 | } 31 | } 32 | 33 | return call_user_func_array([Exec::class,"run"],$callArr); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /exec/Model/Dao/AnnotationResource.php: -------------------------------------------------------------------------------- 1 | 0){ 29 | $title = $str; 30 | break; 31 | } 32 | } 33 | if( strlen($title)<1 || $title{0}=="@" ){ 34 | return ""; 35 | } 36 | return $title; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /exec/template/Middleware: -------------------------------------------------------------------------------- 1 | handle($request); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Http/AdminServer.php: -------------------------------------------------------------------------------- 1 | title = $title; 18 | $this->field = $field; 19 | $this->placeholder = $placeholder; 20 | } 21 | 22 | public function toString(): string 23 | { 24 | $str = << 26 | 29 |
30 | 31 |
32 | 33 | str; 34 | return $str; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/View/Button/NewWindow.php: -------------------------------------------------------------------------------- 1 | url = admin_url($url, false); 24 | $this->name = $name; 25 | $this->icon = $icon; 26 | } 27 | 28 | public function toString(): string 29 | { 30 | $str = << 35 | button; 36 | return $str; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /public/lib/layui/css/modules/code.css: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none} -------------------------------------------------------------------------------- /src/View/Button/NewWindowIcon.php: -------------------------------------------------------------------------------- 1 | url = admin_url($url, false); 24 | $this->name = $name; 25 | $this->icon = $icon; 26 | } 27 | 28 | public function toString(): string 29 | { 30 | $str = << 34 | button; 35 | return $str; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resource/layouts/container.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 5 |
6 | 7 |
8 | 24 |
25 | 26 | -------------------------------------------------------------------------------- /exec/bootstrap.php: -------------------------------------------------------------------------------- 1 | /g,">").replace(/'/g,"'").replace(/"/g,""")),c.html('
  1. '+o.replace(/[\r\t\n]+/g,"
  2. ")+"
"),c.find(">.layui-code-h3")[0]||c.prepend('

'+(c.attr("lay-title")||e.title||"code")+(e.about?'layui.code':"")+"

");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss"); -------------------------------------------------------------------------------- /exec/Controller/Middleware.php: -------------------------------------------------------------------------------- 1 | scan($dir); 21 | } 22 | 23 | /** 24 | * 新增一个中间件 25 | * @param $name 26 | * @param $title 27 | */ 28 | public function addMiddleware($name,$title = "无标题") 29 | { 30 | $data = Application::getDirs('App\\Http\\Middleware'); 31 | $dir = key($data); 32 | 33 | $className = $name."Middleware"; 34 | $path = $dir.$className.".php"; 35 | if (file_exists($path)){ 36 | return; 37 | } 38 | $template = file_get_contents(Application::getTemplate("Middleware")); 39 | $template = str_replace(["{title}","{name}"],[$title,$name],$template); 40 | 41 | file_put_contents($path,$template); 42 | return; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/AutoLoader.php: -------------------------------------------------------------------------------- 1 | dir path 26 | * ] 27 | */ 28 | public function getPrefixDirs(): array 29 | { 30 | return [ 31 | __NAMESPACE__ => __DIR__, 32 | ]; 33 | } 34 | 35 | /** 36 | * Metadata information for the component. 37 | * 38 | * Quick config: 39 | * 40 | * ```php 41 | * $jsonFile = \dirname(__DIR__) . '/composer.json'; 42 | * 43 | * return ComposerJSON::open($jsonFile)->getMetadata(); 44 | * ``` 45 | * 46 | * @return array 47 | * @see ComponentInterface::getMetadata() 48 | */ 49 | public function metadata(): array 50 | { 51 | $jsonFile = dirname(__DIR__) . '/composer.json'; 52 | 53 | return ComposerJSON::open($jsonFile)->getMetadata(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Http/Controller/CrontabController.php: -------------------------------------------------------------------------------- 1 | title = "定时任务"; 31 | 32 | $view->listHeader[] = new ReloadButton(); 33 | $view->listTitle["id"] = "ID"; 34 | $view->listTitle["handel"] = "处理"; 35 | $view->listTitle["cron"] = "设置"; 36 | 37 | $view->listData = Exec::bean(Crontab::class)->getTasks(); 38 | 39 | return $view->toString(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Exec.php: -------------------------------------------------------------------------------- 1 | include('layouts/container',['username'=>$data->username]) ?> 7 | include('layouts/left', ['menu'=>$data->getLeftMenu()]) ?> 8 | 9 | 10 |
11 |
12 |
    13 |
  • 14 | 我的桌面 15 |
  • 16 |
17 |
18 |
19 |
关闭当前
20 |
关闭其它
21 |
关闭全部
22 |
23 |
24 |
25 |
26 | 27 |
28 |
29 |
30 |
31 |
32 |
33 | 34 | -------------------------------------------------------------------------------- /resource/layouts/base.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Swoft-WebTool 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | {_CONTENT_} 30 | 31 | 32 | -------------------------------------------------------------------------------- /exec/Controller/Console.php: -------------------------------------------------------------------------------- 1 | scan($dir); 28 | } 29 | 30 | /** 31 | * 新增命令 32 | * @param $name 33 | * @param $des 34 | * @param $pre 35 | * @CommandMapping(name="cmd/add") 36 | */ 37 | public function add($name, $des, $pre) 38 | { 39 | $namespace = "App\\Console\\Command\\"; 40 | $data = Application::getDirs($namespace); 41 | $dir = key($data); 42 | 43 | $className = $name."Command"; 44 | $path = $dir.$className.".php"; 45 | if (file_exists($path)){ 46 | return; 47 | } 48 | 49 | $template = file_get_contents(Application::getTemplate("Command")); 50 | $template = str_replace(["{name}","{des}","{pre}"],[$name,$des,$pre],$template); 51 | file_put_contents($path,$template); 52 | return; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Helper/Functions.php: -------------------------------------------------------------------------------- 1 | setViewsPath($viewPath); 49 | $response = Context::get()->getResponse(); 50 | $content = $renderer->render($viewPath.$template, $data, $layout); 51 | 52 | return $response 53 | ->withContent($content) 54 | ->withHeader('Content-Type', 'text/html'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/View/Form/InputBlockForm.php: -------------------------------------------------------------------------------- 1 | name = $name; 17 | $this->inputs = $inputs; 18 | } 19 | 20 | public function toString(): string 21 | { 22 | $inputs = ''; 23 | foreach ($this->inputs as $input){ 24 | $inputs .= ""; 25 | } 26 | 27 | $str = << 29 | 32 | 33 | 34 | 35 | 38 | 43 | 44 | 45 |
36 | 37 | 39 |
40 | {$inputs} 41 |
42 |
46 | 47 | str; 48 | return $str; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Http/Controller/FilesController.php: -------------------------------------------------------------------------------- 1 | get("path"); 29 | $namespace = str_replace('..','',$namespace); 30 | 31 | $arr = explode('App\\', $namespace); 32 | 33 | if ( count($arr)==2 ){ 34 | $file = end($arr); 35 | $path = alias('@app/'.$file.'.php'); 36 | }else{ 37 | unset($arr[0]); 38 | $file = implode('/',$arr); 39 | $path = alias('@app/'.$file.'.php'); 40 | } 41 | 42 | $path = str_replace(['\\'],['/'],$path); 43 | 44 | $view = new FileContent(); 45 | $view->title = "显示控制器内容"; 46 | $view->layContent = file_get_contents($path); 47 | // 防止空行被装修器删除 48 | $view->layContent = str_replace(PHP_EOL.PHP_EOL,PHP_EOL." ".PHP_EOL,$view->layContent); 49 | return $view->toString(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /exec/Model/Dao/ModelResource.php: -------------------------------------------------------------------------------- 1 | scanClass() as $className) { 19 | try{ 20 | $info = []; 21 | // Annotation reader 22 | $reflectionClass = new \ReflectionClass($className); 23 | 24 | // Fix ignore abstract 25 | if ($reflectionClass->isAbstract()) { 26 | continue; 27 | } 28 | 29 | $info['title'] = $this->getTitle($reflectionClass->getDocComment()); 30 | $info['path'] = $className; 31 | $info['key'] = $className; 32 | $info['bean'] = "否"; 33 | 34 | // Annotation reader 35 | $reader = new AnnotationReader(); 36 | 37 | $classAnnotations = $reader->getClassAnnotations($reflectionClass); 38 | // 类注解遍历 39 | foreach ($classAnnotations as $classAnnotation) { 40 | if ($classAnnotation instanceof Bean) { 41 | $info['bean'] = "是"; 42 | } 43 | } 44 | $list[] = $info; 45 | }catch (\Throwable $exception){ 46 | continue; 47 | } 48 | } 49 | 50 | return $list; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /exec/Model/Dao/ControllerResource.php: -------------------------------------------------------------------------------- 1 | scanClass() as $className) { 26 | 27 | // Annotation reader 28 | $reflectionClass = new \ReflectionClass($className); 29 | 30 | // Fix ignore abstract 31 | if ($reflectionClass->isAbstract()) { 32 | continue; 33 | } 34 | 35 | // Annotation reader 36 | $reader = new AnnotationReader(); 37 | $classAnnotations = $reader->getClassAnnotations($reflectionClass); 38 | // 类注解遍历 39 | foreach ($classAnnotations as $classAnnotation) { 40 | if ($classAnnotation instanceof Controller) { 41 | $con = new ControllerInfo(); 42 | $con->title = $this->getTitle($reflectionClass->getDocComment()); 43 | $con->path = $className; 44 | $con->prefix = $classAnnotation->getPrefix(); 45 | $list[] = (array)$con; 46 | } 47 | } 48 | } 49 | return $list; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/View/Form/InputForm.php: -------------------------------------------------------------------------------- 1 | field = $field; 29 | $this->name = $name; 30 | $this->type = $type; 31 | $this->placeholder = $placeholder; 32 | $this->verify = $verify; 33 | } 34 | 35 | public function setValue($data) 36 | { 37 | $this->value = " value=\"{$data}\""; 38 | return $this; 39 | } 40 | 41 | public function toString(): string 42 | { 43 | $verify = $this->verify?"*":""; 44 | $str = << 46 | 49 |
50 | value}> 52 |
53 | 54 | str; 55 | return $str; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /exec/Model/Logic/Directory.php: -------------------------------------------------------------------------------- 1 | dirBindNameSpace[$directory] = $nameSpace; 20 | } 21 | 22 | /** 23 | * 遍历目录下所有类 24 | * 25 | * @return \Generator 26 | */ 27 | public function scanClass() 28 | { 29 | $arr = []; 30 | foreach ($this->dirBindNameSpace as $directory => $nameSpace) { 31 | foreach ($this->scanNameSpace($directory,$nameSpace) as $class) { 32 | $arr[] = $class; 33 | } 34 | } 35 | return $arr; 36 | } 37 | 38 | /** 39 | * 遍历命名空间 40 | * 41 | * @param $directory 42 | * @param $nameSpace 43 | * @return \Generator 44 | */ 45 | private function scanNameSpace($directory,$nameSpace) 46 | { 47 | if ($dh = opendir($directory)) { 48 | while (($file = readdir($dh)) !== false) { 49 | if (in_array($file, ['.', '..'])) { 50 | continue; 51 | } elseif (is_dir($directory . DIRECTORY_SEPARATOR . $file)) { 52 | foreach ($this->scanNameSpace($directory . DIRECTORY_SEPARATOR . $file,$nameSpace.$file."\\") as $arrValue){ 53 | yield $arrValue; 54 | } 55 | } elseif (substr($file, -4) == '.php') { 56 | yield $nameSpace.pathinfo($file,PATHINFO_FILENAME); 57 | } 58 | } 59 | closedir($dh); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /public/lib/layui/lay/modules/laytpl.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var c="Laytpl Error:";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)}); -------------------------------------------------------------------------------- /src/View/Form/SelectForm.php: -------------------------------------------------------------------------------- 1 | field = $field; 23 | $this->label = $label; 24 | } 25 | 26 | /** 27 | * @param string $title 28 | * @param $value 29 | * @param int $default 30 | */ 31 | public function addOption(string $title,$value,$default = 0) 32 | { 33 | $this->options[$value] = ['title'=>$title,'default'=>$default]; 34 | } 35 | 36 | /** 37 | * 输出html 38 | * @return string 39 | */ 40 | public function toString(): string 41 | { 42 | $select = ""; 43 | foreach ($this->options as $value=>$arr){ 44 | 45 | if (!$arr['default']){ 46 | $default = ""; 47 | }else{ 48 | $default = "selected"; 49 | } 50 | $select .= ""; 51 | } 52 | 53 | return << 55 | 58 |
59 | 62 |
63 | 64 | str; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /public/lib/layui/lay/modules/flow.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="加载更多",h=l('");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;su)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)}); -------------------------------------------------------------------------------- /exec/Controller/Model.php: -------------------------------------------------------------------------------- 1 | scan($dir); 17 | } 18 | 19 | public function data() 20 | { 21 | $dir = Application::getDirectory('App\\Model\\Data'); 22 | return (new ModelResource())->scan($dir); 23 | } 24 | 25 | public function logic() 26 | { 27 | $dir = Application::getDirectory('App\\Model\\Logic'); 28 | return (new ModelResource())->scan($dir); 29 | } 30 | 31 | /** 32 | * 新增类文件 33 | * @param $namespace 34 | * @param $name 35 | * @param string $title 36 | * @param $suffix 37 | */ 38 | public function addClass($namespace,$name,string $title = '' ,string $suffix = '') 39 | { 40 | $namespace = str_replace('/','\\',$namespace); 41 | $data = Application::getDirs($namespace); 42 | $dir = key($data); 43 | 44 | $className = $name.$suffix; 45 | $path = $dir.$className.".php"; 46 | if (file_exists($path)){ 47 | return; 48 | } 49 | if ($suffix && file_exists(Application::getTemplate($suffix))){ 50 | $template = file_get_contents(Application::getTemplate($suffix)); 51 | }else{ 52 | $template = file_get_contents(Application::getTemplate('BaseClass')); 53 | } 54 | 55 | $endStr = substr($namespace,-1); 56 | if ($endStr=="\\"){ 57 | $namespace = substr($namespace,0,-1); 58 | } 59 | $template = str_replace(["{title}","{name}","{namespace}","{suffix}","{date}"],[$title,$name,$namespace,$suffix,date("ymdhis")],$template); 60 | file_put_contents($path,$template); 61 | return; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /resource/home/terminal.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Terminal 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /resource/table/form.php: -------------------------------------------------------------------------------- 1 | 5 |
6 | item as $item) { 7 | echo $item->toString(); 8 | } ?> 9 |
10 | 11 |
12 |
13 | 61 | -------------------------------------------------------------------------------- /src/View/BaseView.php: -------------------------------------------------------------------------------- 1 | viewLink[] = ""; 29 | }else{ 30 | $this->viewLink[] = ""; 31 | } 32 | } 33 | 34 | /** 35 | * js脚本地址 36 | * @param string $src 37 | */ 38 | public function script(string $src) 39 | { 40 | if ( strpos($src,'http')===false ){ 41 | $src = admin_src(false).$src; 42 | $this->viewScript[] = ""; 43 | }else{ 44 | $this->viewScript[] = ""; 45 | } 46 | } 47 | 48 | public function toString() 49 | { 50 | $viewPath = dirname(dirname(__DIR__))."/resource/"; 51 | /** 52 | * @var Renderer $renderer 53 | * @var Response $response 54 | */ 55 | $renderer = Swoft::getSingleton('view'); 56 | $renderer->setViewsPath($viewPath); 57 | $response = Context::get()->getResponse(); 58 | 59 | $data['data'] = $this; 60 | 61 | $output = $renderer->fetch($viewPath.$this->view, $data); 62 | 63 | $data['viewLink'] = $this->viewLink; 64 | $data['viewScript'] = $this->viewScript; 65 | $content = $renderer->renderContent($output, $data, $this->layout); 66 | 67 | 68 | return $response 69 | ->withContent($content) 70 | ->withHeader('Content-Type', 'text/html'); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /exec/Model/Dao/CrontabResource.php: -------------------------------------------------------------------------------- 1 | scanClass() as $className) { 18 | $info = []; 19 | // Annotation reader 20 | $reflectionClass = new \ReflectionClass($className); 21 | 22 | // Fix ignore abstract 23 | if ($reflectionClass->isAbstract()) { 24 | continue; 25 | } 26 | 27 | // Annotation reader 28 | $reader = new AnnotationReader(); 29 | 30 | $classAnnotations = $reader->getClassAnnotations($reflectionClass); 31 | // 类注解遍历 32 | foreach ($classAnnotations as $classAnnotation) { 33 | if ($classAnnotation instanceof Scheduled) { 34 | // 函数遍历 35 | $reflectionMethods = $reflectionClass->getMethods(); 36 | foreach ($reflectionMethods as $reflectionMethod) { 37 | $methodName = $reflectionMethod->getName(); 38 | $methodAnnotations = $reader->getMethodAnnotations($reflectionMethod); 39 | 40 | if (!empty($methodAnnotations)) { 41 | foreach ($methodAnnotations as $annotation){ 42 | if ($annotation instanceof Cron){ 43 | $info['handel'] = $reflectionClass->getName().'@'.$methodName; 44 | $info['key'] = $reflectionClass->getName().'@'.$methodName; 45 | $info['cron'] = $annotation->getValue(); 46 | 47 | $list[] = $info; 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | 56 | return $list; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swoft-admin 2 | swoft的web开发辅助工具 3 | 4 | ## 安装 5 | 6 | ~~~~ 7 | composer require ctfang/swoft-admin 8 | ~~~~ 9 | 10 | 下载主干 composer require ctfang/swoft-admin dev-master 11 | 12 | ## 配置 13 | 在 `app/bean.php` 新增 14 | ~~~~ 15 | 'adminServer' => [ 16 | 'class' => AdminServer::class, 17 | 'port' => 18366, 18 | 'on' => [ 19 | SwooleEvent::REQUEST => bean(RequestListener::class), 20 | ], 21 | /* @see HttpServer::$setting 静态文件配置 */ 22 | 'setting' => [ 23 | 'enable_static_handler' => true, 24 | 'document_root' => __DIR__."/../vendor/ctfang/swoft-admin/public/", 25 | ] 26 | ], 27 | ~~~~ 28 | 29 | ## 修改 .env 配置 30 | 31 | 默认 `ADMIN_WEB = http://127.0.0.1/public/` 32 | ~~~~ 33 | # 设置ip访问限制 (默认不限制) 34 | ADMIN_ALLOW="*.*.*.*" 35 | # 打开登录开关 (默认登录后才能访问) 36 | ADMIN_ENABLE_LOGIN=1 37 | # 配置静态文件地址 38 | ADMIN_WEB="http://127.0.0.1:18366/" 39 | ~~~~ 40 | 41 | ## 启动 42 | ~~~~ 43 | php bin/swoft admin:start 44 | ~~~~ 45 | 46 | 如果需要在 `http:start` 也能访问,需要设置 `.env` 47 | 48 | ````php 49 | ADMIN_ENABLE=1 50 | ```` 51 | 52 | ## 访问,默认账号密码 `username = admin ; password = 123456` 53 | 54 | http://your.com/__admin/login 55 | 56 | ## 修改密码 57 | 58 | 复制文件 `vendor/ctfang/swoft-admin/src/Config/user.config.php` 到 `@config/__admin.php@config/__admin.php` 59 | 60 | 61 | ## 计划 62 | 63 | - [x] [控制器展示&创建](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller/RouteController.php) 64 | - [x] [中间件展示&创建](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller/RouteController.php) 65 | - [x] [路由导出postmen](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller/RouteController.php) 66 | - [x] [Model目录展示&创建](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller) 67 | - [x] [定时器展示](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller) 68 | - [x] [命令展示&创建](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller) 69 | - [x] [Web Terminal](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller) 70 | - [x] [控制器代码查看](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller) 71 | - [x] [Logs查看](https://github.com/ctfang/swoft-admin/blob/master/src/Http/Controller) 72 | - [ ] 第三方登录模拟 73 | - [x] 启动&关闭http 74 | - [x] 界面创建路由(空函数) 75 | - [ ] 配置查看 76 | - [ ] 进程信息 77 | -------------------------------------------------------------------------------- /exec/Model/Dao/ConsoleResource.php: -------------------------------------------------------------------------------- 1 | scanClass() as $className) { 23 | $info = []; 24 | // Annotation reader 25 | $reflectionClass = new \ReflectionClass($className); 26 | 27 | // Fix ignore abstract 28 | if ($reflectionClass->isAbstract()) { 29 | continue; 30 | } 31 | 32 | // Annotation reader 33 | $reader = new AnnotationReader(); 34 | 35 | $classAnnotations = $reader->getClassAnnotations($reflectionClass); 36 | // 类注解遍历 37 | foreach ($classAnnotations as $classAnnotation) { 38 | if ($classAnnotation instanceof Command) { 39 | // 函数遍历 40 | $reflectionMethods = $reflectionClass->getMethods(); 41 | foreach ($reflectionMethods as $reflectionMethod) { 42 | $methodName = $reflectionMethod->getName(); 43 | $methodAnnotations = $reader->getMethodAnnotations($reflectionMethod); 44 | 45 | if (!empty($methodAnnotations)) { 46 | foreach ($methodAnnotations as $annotation){ 47 | if ($annotation instanceof CommandMapping){ 48 | $info['handel'] = $reflectionClass->getName().'@'.$methodName; 49 | $info['key'] = $reflectionClass->getName().'@'.$methodName; 50 | $info['des'] = $annotation->getDesc(); 51 | $info['name'] = $classAnnotation->getName().":".$annotation->getName(); 52 | 53 | $list[] = $info; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | 62 | return $list; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Http/Controller/HomeController.php: -------------------------------------------------------------------------------- 1 | date = date("Y-m-d H:i:s"); 29 | } 30 | 31 | /** 32 | * 首页 33 | * @RequestMapping("/__admin/home") 34 | * @param Request $request 35 | * @return Home 36 | */ 37 | public function home(Request $request) 38 | { 39 | $view = new Home(); 40 | $token = bean(LoginModel::class)->getRequestToken($request); 41 | $arr = explode('.', $token); 42 | $view->username = $arr[1] ?? "admin"; 43 | return $view->toString(); 44 | } 45 | 46 | /** 47 | * 启动页 48 | * @RequestMapping("/__admin/welcome") 49 | * @param Request $request 50 | * @return Welcome 51 | */ 52 | public function welcome(Request $request) 53 | { 54 | $view = new Welcome(); 55 | 56 | $root = dirname(\Swoft::getAlias("@app")); 57 | $size = round(disk_free_space($root) / 1073741824 * 100) / 100 .' GB'; 58 | 59 | $view->system[] = ['key' => '启动时间', 'value' => $this->date]; 60 | $view->system[] = ['key' => '启动用户', 'value' => get_current_user()]; 61 | $view->system[] = ['key' => '监听端口', 'value' => $request->getServerParams()['server_port']]; 62 | $view->system[] = ['key' => '操作系统', 'value' => \PHP_OS]; 63 | $view->system[] = ['key' => 'PHP版本', 'value' => \PHP_VERSION]; 64 | $view->system[] = ['key' => 'Swoole版本', 'value' => \SWOOLE_VERSION]; 65 | $view->system[] = ['key' => 'Swoft 版本', 'value' => \Swoft::VERSION]; 66 | $view->system[] = ['key' => 'ROOT目录', 'value' => dirname($root)]; 67 | $view->system[] = ['key' => 'ROOT可用', 'value' => $size]; 68 | 69 | foreach (\get_loaded_extensions() as $extension) { 70 | $view->ext[] = ['key' => $extension]; 71 | } 72 | 73 | return $view->toString(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /public/lib/layui/lay/modules/rate.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var a=layui.jquery,i={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,a){return layui.onevent.call(this,n,e,a)}},l=function(){var e=this,a=e.config;return{setvalue:function(a){e.setvalue.call(e,a)},config:a}},n="rate",t="layui-rate",o="layui-icon-rate",s="layui-icon-rate-solid",u="layui-icon-rate-half",r="layui-icon-rate-solid layui-icon-rate-half",c="layui-icon-rate-solid layui-icon-rate",f="layui-icon-rate layui-icon-rate-half",v=function(e){var l=this;l.index=++i.index,l.config=a.extend({},l.config,i.config,e),l.render()};v.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:""},v.prototype.render=function(){var e=this,i=e.config,l=i.theme?'style="color: '+i.theme+';"':"";i.elem=a(i.elem),parseInt(i.value)!==i.value&&(i.half||(i.value=Math.ceil(i.value)-i.value<.5?Math.ceil(i.value):Math.floor(i.value)));for(var n='
    ",u=1;u<=i.length;u++){var r='
  • ";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+'
  • ":n+=r}n+="
"+(i.text?''+i.value+"星":"")+"";var c=i.elem,f=c.next("."+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next("span"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass("layui-inline"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find("i").width();l.children("li").each(function(e){var t=e+1,v=a(this);v.on("click",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next("span").text(i.value+"星"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on("mousemove",function(e){if(l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+t+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children("i").addClass(u).removeClass(s)}}),v.on("mouseleave",function(){l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+Math.floor(i.value)+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)}); -------------------------------------------------------------------------------- /resource/layouts/left.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 52 | 53 | 54 | 55 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /exec/Model/Dao/MiddlewareResource.php: -------------------------------------------------------------------------------- 1 | scanClass() as $className) { 27 | try{ 28 | // Annotation reader 29 | $reflectionClass = new \ReflectionClass($className); 30 | 31 | // Fix ignore abstract 32 | if ($reflectionClass->isAbstract()) { 33 | continue; 34 | } 35 | 36 | $this->list[$className] = new MiddlewareInfo(); 37 | $this->set($className)->title = $this->getTitle($reflectionClass->getDocComment()); 38 | $this->set($className)->path = $className; 39 | 40 | // Annotation reader 41 | $reader = new AnnotationReader(); 42 | 43 | $classAnnotations = $reader->getClassAnnotations($reflectionClass); 44 | // 类注解遍历 45 | foreach ($classAnnotations as $classAnnotation) { 46 | if ($classAnnotation instanceof Bean) { 47 | $this->set($className)->bean = true; 48 | } 49 | } 50 | $this->set($className)->isGroup = $this->isGroup($className); 51 | }catch (\Throwable $exception){ 52 | continue; 53 | } 54 | } 55 | 56 | return $this->list; 57 | } 58 | 59 | /** 60 | * @param $className 61 | * @return MiddlewareInfo 62 | */ 63 | public function set($className):MiddlewareInfo 64 | { 65 | return $this->list[$className]; 66 | } 67 | 68 | /** 69 | * 全局中间件 70 | * @param $className 71 | * @return bool 72 | */ 73 | public function isGroup($className):bool 74 | { 75 | $beanPath = getRootPath()."/app/bean.php"; 76 | $bean = include $beanPath; 77 | $middlewares = $bean["httpDispatcher"]["middlewares"]??[]; 78 | 79 | foreach ($middlewares as $str){ 80 | if( $className ==$str ){ 81 | return true; 82 | } 83 | } 84 | return false; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /public/css/login.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xuebingsi 3 | * @Date: 2019-04-01 13:37:17 4 | * @Last Modified by: zhibinm 5 | * @Last Modified time: 2019-04-01 13:37:19 6 | */ 7 | .login-bg{ 8 | /*background: #eeeeee url() 0 0 no-repeat;*/ 9 | background:url(../images/bg.png) no-repeat center; 10 | background-size: cover; 11 | overflow: hidden; 12 | } 13 | .login{ 14 | margin: 120px auto 0 auto; 15 | min-height: 420px; 16 | max-width: 420px; 17 | padding: 40px; 18 | background-color: #ffffff; 19 | margin-left: auto; 20 | margin-right: auto; 21 | border-radius: 4px; 22 | /* overflow-x: hidden; */ 23 | box-sizing: border-box; 24 | } 25 | .login a.logo{ 26 | display: block; 27 | height: 58px; 28 | width: 167px; 29 | margin: 0 auto 30px auto; 30 | background-size: 167px 42px; 31 | } 32 | .login .message { 33 | margin: 10px 0 0 -58px; 34 | padding: 18px 10px 18px 60px; 35 | background: #189F92; 36 | position: relative; 37 | color: #fff; 38 | font-size: 16px; 39 | } 40 | .login #darkbannerwrap { 41 | background: url(../images/aiwrap.png); 42 | width: 18px; 43 | height: 10px; 44 | margin: 0 0 20px -58px; 45 | position: relative; 46 | } 47 | 48 | .login input[type=text], 49 | .login input[type=file], 50 | .login input[type=password], 51 | .login input[type=email], select { 52 | border: 1px solid #DCDEE0; 53 | vertical-align: middle; 54 | border-radius: 3px; 55 | height: 50px; 56 | padding: 0px 16px; 57 | font-size: 14px; 58 | color: #555555; 59 | outline:none; 60 | width:100%; 61 | box-sizing: border-box; 62 | } 63 | .login input[type=text]:focus, 64 | .login input[type=file]:focus, 65 | .login input[type=password]:focus, 66 | .login input[type=email]:focus, select:focus { 67 | border: 1px solid #27A9E3; 68 | } 69 | .login input[type=submit], 70 | .login input[type=button]{ 71 | display: inline-block; 72 | vertical-align: middle; 73 | padding: 12px 24px; 74 | margin: 0px; 75 | font-size: 18px; 76 | line-height: 24px; 77 | text-align: center; 78 | white-space: nowrap; 79 | vertical-align: middle; 80 | cursor: pointer; 81 | color: #ffffff; 82 | background-color: #189F92; 83 | border-radius: 3px; 84 | border: none; 85 | -webkit-appearance: none; 86 | outline:none; 87 | width:100%; 88 | } 89 | .login hr { 90 | background: #fff url() 0 0 no-repeat; 91 | } 92 | .login hr.hr15 { 93 | height: 15px; 94 | border: none; 95 | margin: 0px; 96 | padding: 0px; 97 | width: 100%; 98 | } 99 | .login hr.hr20 { 100 | height: 20px; 101 | border: none; 102 | margin: 0px; 103 | padding: 0px; 104 | width: 100%; 105 | } -------------------------------------------------------------------------------- /src/Http/Middleware/LoginMiddleware.php: -------------------------------------------------------------------------------- 1 | getResponse()->withContent("admin 未开启")->withStatus(404); 47 | } 48 | // 检查是否限制IP 49 | $allow = env("ADMIN_ALLOW","*.*.*.*"); 50 | if ( $allow!=="*.*.*.*" ){ 51 | $remoteAddr = $request->getHeader('x-real-ip'); 52 | $accept = true; 53 | $allowARR = explode('.',$allow); 54 | foreach ($remoteAddr as $str){ 55 | $strArr = explode('.',$str); 56 | foreach ($allowARR as $key=>$item){ 57 | if ( $item!="*" && $strArr[$key]!=$item ){ 58 | $accept = false; 59 | break 2; 60 | } 61 | } 62 | } 63 | if (!$accept){ 64 | return context()->getResponse()->withContent("限制IP访问")->withStatus(404); 65 | } 66 | } 67 | 68 | // 检查是否需登录 69 | if (env('ADMIN_ENABLE_LOGIN', true)) { 70 | $token = $this->login->getRequestToken($request); 71 | 72 | if (!$token || !$this->login->verifyToken($token)) { 73 | $path = $request->getUri()->getPath(); 74 | if ($path != admin_url("login", false)) { 75 | return context()->getResponse()->redirect(admin_url("login", false)); 76 | } 77 | } 78 | } 79 | 80 | return $handler->handle($request); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Http/Controller/PublicController.php: -------------------------------------------------------------------------------- 1 | redirect('/__admin/login'); 42 | } 43 | return $response->redirect('/__admin/home'); 44 | } 45 | 46 | /** 47 | * show login 48 | * @RequestMapping("login",method={RequestMethod::GET}) 49 | * @param Request $request 50 | * @return Response|Login 51 | */ 52 | public function login(Request $request, Response $response) 53 | { 54 | $view = new Login(); 55 | $view->url = 'login'; 56 | 57 | return $view->toString(); 58 | } 59 | 60 | /** 61 | * login 62 | * @RequestMapping("login",method={RequestMethod::POST}) 63 | * @param Request $request 64 | * @param Response $response 65 | * @return Response 66 | */ 67 | public function loginPost(Request $request, Response $response) 68 | { 69 | $username = $request->post("username"); 70 | $password = $request->post("password"); 71 | 72 | if ($this->login->login($username, $password)) { 73 | $token = $this->login->getToken($username); 74 | return $response->withCookie($this->login->tokenKey, $token)->redirect('/__admin/home?'.$this->login->tokenKey."=".$token); 75 | } 76 | 77 | return $response->redirect('login'); 78 | } 79 | 80 | /** 81 | * 退出登录 82 | * @RequestMapping("logout") 83 | * @param Request $request 84 | * @param Response $response 85 | * @return \Swoft\Http\Message\Concern\CookiesTrait|Response 86 | */ 87 | public function logout(Request $request, Response $response) 88 | { 89 | return $response->withCookie($this->login->tokenKey,'')->redirect('/__admin/login'); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /public/lib/layui/lay/modules/tree.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var o=layui.$,a=layui.hint(),i="layui-tree-enter",r=function(e){this.options=e},t={arrow:["",""],checkbox:["",""],radio:["",""],branch:["",""],leaf:""};r.prototype.init=function(e){var o=this;e.addClass("layui-box layui-tree"),o.options.skin&&e.addClass("layui-tree-skin-"+o.options.skin),o.tree(e),o.on(e)},r.prototype.tree=function(e,a){var i=this,r=i.options,n=a||r.nodes;layui.each(n,function(a,n){var l=n.children&&n.children.length>0,c=o('
    '),s=o(["
  • ",function(){return l?''+(n.spread?t.arrow[1]:t.arrow[0])+"":""}(),function(){return r.check?''+("checkbox"===r.check?t.checkbox[0]:"radio"===r.check?t.radio[0]:"")+"":""}(),function(){return'"+(''+(l?n.spread?t.branch[1]:t.branch[0]:t.leaf)+"")+(""+(n.name||"未命名")+"")}(),"
  • "].join(""));l&&(s.append(c),i.tree(c,n.children)),e.append(s),"function"==typeof r.click&&i.click(s,n),i.spread(s,n),r.drag&&i.drag(s,n)})},r.prototype.click=function(e,o){var a=this,i=a.options;e.children("a").on("click",function(e){layui.stope(e),i.click(o)})},r.prototype.spread=function(e,o){var a=this,i=(a.options,e.children(".layui-tree-spread")),r=e.children("ul"),n=e.children("a"),l=function(){e.data("spread")?(e.data("spread",null),r.removeClass("layui-show"),i.html(t.arrow[0]),n.find(".layui-icon").html(t.branch[0])):(e.data("spread",!0),r.addClass("layui-show"),i.html(t.arrow[1]),n.find(".layui-icon").html(t.branch[1]))};r[0]&&(i.on("click",l),n.on("dblclick",l))},r.prototype.on=function(e){var a=this,r=a.options,t="layui-tree-drag";e.find("i").on("selectstart",function(e){return!1}),r.drag&&o(document).on("mousemove",function(e){var i=a.move;if(i.from){var r=(i.to,o('
    '));e.preventDefault(),o("."+t)[0]||o("body").append(r);var n=o("."+t)[0]?o("."+t):r;n.addClass("layui-show").html(i.from.elem.children("a").html()),n.css({left:e.pageX+10,top:e.pageY+10})}}).on("mouseup",function(){var e=a.move;e.from&&(e.from.elem.children("a").removeClass(i),e.to&&e.to.elem.children("a").removeClass(i),a.move={},o("."+t).remove())})},r.prototype.move={},r.prototype.drag=function(e,a){var r=this,t=(r.options,e.children("a")),n=function(){var t=o(this),n=r.move;n.from&&(n.to={item:a,elem:e},t.addClass(i))};t.on("mousedown",function(){var o=r.move;o.from={item:a,elem:e}}),t.on("mouseenter",n).on("mousemove",n).on("mouseleave",function(){var e=o(this),a=r.move;a.from&&(delete a.to,e.removeClass(i))})},e("tree",function(e){var i=new r(e=e||{}),t=o(e.elem);return t[0]?void i.init(t):a.error("layui.tree 没有找到"+e.elem+"元素")})}); -------------------------------------------------------------------------------- /resource/document.php: -------------------------------------------------------------------------------- 1 | 6 |
    7 |
    8 |
    9 | 10 |
    11 | 简要描述: 12 |
    13 | route['title']??""; ?> 14 |
    15 |
    16 | 17 |
    18 |
    19 |
    20 |
    21 |
    22 |
    23 | 请求地址 24 |
    25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
    地址请求方式
    route['path']??""; ?>route['method'])?implode(' | ',$data->route['method']):""; ?>
    44 |
    45 |
    46 |
    47 |
    48 |
    49 | 50 |
    51 |
    52 |
    53 | 54 |
    55 | 请求参数 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | route["params"]??[] as $field=>$item){ ?> 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
    字段名类型默认值必选备注
    83 |
    84 | 85 | 86 |
    87 | -------------------------------------------------------------------------------- /src/Model/LoginModel.php: -------------------------------------------------------------------------------- 1 | config = (array) $config; 29 | } 30 | 31 | public function getRequestToken(ServerRequestInterface $request) 32 | { 33 | $cookie = $request->getCookieParams(); 34 | $token = $cookie[$this->tokenKey] ?? ""; 35 | if (!$token) { 36 | $token = $request->get($this->tokenKey); 37 | } 38 | 39 | return $token; 40 | } 41 | 42 | /** 43 | * 获取配置 44 | * @return array 45 | */ 46 | public function getConfig(): array 47 | { 48 | return $this->config; 49 | } 50 | 51 | /** 52 | * 检查登录 53 | * @param $username 54 | * @param $password 55 | * @return bool 56 | */ 57 | public function login($username, $password): bool 58 | { 59 | $config = $this->getConfig(); 60 | $users = $config["users"] ?? []; 61 | if (!isset($users[$username])) { 62 | return false; 63 | } 64 | if (!password_verify($password, $users[$username])) { 65 | return false; 66 | } 67 | return true; 68 | } 69 | 70 | /** 71 | * 登录成功生成token 72 | * @param $username 73 | * @return string 74 | */ 75 | public function getToken($username): string 76 | { 77 | return $this->getSign($username, time()); 78 | } 79 | 80 | /** 81 | * 检查是否有效 82 | * @param $str 83 | * @return bool 84 | */ 85 | public function verifyToken($str): bool 86 | { 87 | $arr = explode('.', $str); 88 | if (count($arr) != 3) { 89 | return false; 90 | } 91 | $username = $arr[1]; 92 | $time = $arr[0]; 93 | 94 | if ($time < (time() - 3600 * 8)) { 95 | return false; 96 | } 97 | $str2 = $this->getSign($username, $time); 98 | $eq = ($str == $str2); 99 | return $eq; 100 | } 101 | 102 | private function getSign($username, $time) 103 | { 104 | $config = $this->getConfig(); 105 | $users = $config["users"] ?? []; 106 | if (!isset($users[$username])) { 107 | return ""; 108 | } 109 | $password = $users[$username]; 110 | $str = $time.".".$username; 111 | return $str.".".md5($str.$password); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/View/Home.php: -------------------------------------------------------------------------------- 1 | $icon, 'url' => $url]; 29 | } 30 | 31 | /** 32 | * 获取菜单 33 | * @return array 34 | */ 35 | public function getLeftMenu() 36 | { 37 | $menu = $this->leftMenu; 38 | 39 | foreach (self::$merMenu as $group => $arr) { 40 | foreach ($arr as $name => $con) { 41 | $con['name'] = $name; 42 | if ($group) { 43 | $menu[$group]['ul'][] = $con; 44 | } else { 45 | $menu[$name] = $con; 46 | } 47 | } 48 | } 49 | return $menu; 50 | } 51 | 52 | /** 53 | * @var array 基础菜单 54 | */ 55 | public $leftMenu = [ 56 | "Http" => [ 57 | 'name' => 'Http', 58 | 'icon' => '', 59 | 'ul' => [ 60 | ['name' => '路由列表', 'icon' => '', 'url' => 'control/routes'], 61 | ['name' => '控制器', 'icon' => '', 'url' => 'control/list'], 62 | ['name' => '中间件', 'icon' => '', 'url' => 'mid/list'], 63 | ], 64 | ], 65 | "Model" => [ 66 | 'name' => 'Model', 67 | 'icon' => '', 68 | 'ul' => [ 69 | ['name' => 'Dao', 'icon' => '', 'url' => 'model/dao'], 70 | ['name' => 'Data', 'icon' => '', 'url' => 'model/data'], 71 | ['name' => 'logic', 'icon' => '', 'url' => 'model/logic'], 72 | ], 73 | ], 74 | "Console" => [ 75 | 'name' => 'Console', 76 | 'icon' => '', 77 | 'ul' => [ 78 | ['name' => 'Command', 'icon' => '', 'url' => 'console/command'], 79 | ], 80 | ], 81 | "Crontab" => [ 82 | 'name' => 'Crontab', 83 | 'icon' => '', 84 | 'ul' => [ 85 | ['name' => 'Crontab', 'icon' => '', 'url' => 'crontab/lists'], 86 | ], 87 | ], 88 | "Logs" => [ 89 | 'name' => 'Logs', 90 | 'icon' => '', 91 | 'ul' => [ 92 | ['name' => 'Logs', 'icon' => '', 'url' => 'logs/logs'], 93 | ['name' => 'Runtime', 'icon' => '', 'url' => 'logs/runtime'], 94 | ], 95 | ], 96 | ]; 97 | } 98 | -------------------------------------------------------------------------------- /src/Http/Controller/MiddlewareController.php: -------------------------------------------------------------------------------- 1 | getMiddleware(); 37 | 38 | $view = new Table(); 39 | $view->title = "中间件列表"; 40 | $view->listTitle['id'] = "ID"; 41 | $view->listTitle['title'] = "标题"; 42 | $view->listTitle['path'] = "Path"; 43 | $view->listTitle['isGroup'] = "全局"; 44 | $view->listTitle['bean'] = "Bean"; 45 | 46 | $arr = []; 47 | foreach ($list as $item){ 48 | $arr[] = (array)$item; 49 | } 50 | $view->listData = $arr; 51 | 52 | $view->listHeader[] = new ReloadButton(); 53 | $view->listHeader[] = new NewWindow('mid/create','创建中间件'); 54 | 55 | $button = new NewWindowIcon('file/show', '文件内容'); 56 | $button->mix = "true"; 57 | $button->addField(['path'=>'path']); 58 | $view->addListButton($button); 59 | 60 | return $view->toString(); 61 | } 62 | 63 | /** 64 | * 创建中间件显示界面 65 | * @RequestMapping(route="create",method={RequestMethod::GET}) 66 | * @return \Swoft\Http\Message\Response 67 | * @throws \Throwable 68 | */ 69 | public function create() 70 | { 71 | $view = new Form(); 72 | $view->title = '创建中间件'; 73 | $view->action = 'mid/add'; 74 | 75 | $view->item[] = new Form\InputForm('classTitle','标题'); 76 | $view->item[] = new Form\InputForm('className','类名',"类名,自带Middleware"); 77 | 78 | return $view->toString(); 79 | } 80 | 81 | /** 82 | * 创建中间件 83 | * @RequestMapping(route="add") 84 | */ 85 | public function createPost() 86 | { 87 | $className = Context::get()->getRequest()->post("className"); 88 | $classTitle = Context::get()->getRequest()->post("classTitle"); 89 | if (!$className) { 90 | return Msg::error("失败"); 91 | } 92 | 93 | Exec::bean(Middleware::class)->addMiddleware($className,$classTitle); 94 | 95 | return Msg::success(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /resource/app/auto_reload.php: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 首页 4 | title ?? ""; ?> 5 | 6 | 9 | 10 | 11 |
    12 | 13 |
    14 |
    15 |
    16 | 17 |
    18 | 20 |
    21 |
    22 |
    23 | 24 |
    25 | 27 |
    28 |
    29 |
    30 | 31 |
    32 | 34 |
    35 |
    36 |
    37 | 38 |
    39 | 41 |
    42 |
    43 |
    44 |
    45 | 46 | 47 |
    48 |
    49 |
    50 | 51 |
    52 | 78 | -------------------------------------------------------------------------------- /public/lib/layui/lay/modules/util.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(t){"use strict";var e=layui.$,i={fixbar:function(t){var i,a,n="layui-fixbar",r="layui-fixbar-top",o=e(document),l=e("body");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?"":t.bar1,t.bar2=t.bar2===!0?"":t.bar2,t.bgcolor=t.bgcolor?"background-color:"+t.bgcolor:"";var c=[t.bar1,t.bar2,""],g=e(['
      ',t.bar1?'
    • '+c[0]+"
    • ":"",t.bar2?'
    • '+c[1]+"
    • ":"",'
    • '+c[2]+"
    • ","
    "].join("")),s=g.find("."+r),u=function(){var e=o.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e("."+n)[0]||("object"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find("li").on("click",function(){var i=e(this),a=i.attr("lay-type");"top"===a&&e("html,body").animate({scrollTop:0},200),t.click&&t.click.call(this,a)}),o.on("scroll",function(){clearTimeout(a),a=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var a=this,n="function"==typeof e,r=new Date(t).getTime(),o=new Date(!e||n?(new Date).getTime():e).getTime(),l=r-o,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];n&&(i=e);var g=setTimeout(function(){a.countdown(t,o+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,a=[[],[]],n=(new Date).getTime()-new Date(t).getTime();return n>6912e5?(n=new Date(t),a[0][0]=i.digit(n.getFullYear(),4),a[0][1]=i.digit(n.getMonth()+1),a[0][2]=i.digit(n.getDate()),e||(a[1][0]=i.digit(n.getHours()),a[1][1]=i.digit(n.getMinutes()),a[1][2]=i.digit(n.getSeconds())),a[0].join("-")+" "+a[1].join(":")):n>=864e5?(n/1e3/60/60/24|0)+"天前":n>=36e5?(n/1e3/60/60|0)+"小时前":n>=12e4?(n/1e3/60|0)+"分钟前":n<0?"未来":"刚刚"},digit:function(t,e){var i="";t=String(t),e=e||2;for(var a=t.length;a/g,">").replace(/'/g,"'").replace(/"/g,""")}};!function(t,e,i){"$:nomunge";function a(){n=e[l](function(){r.each(function(){var e=t(this),i=e.width(),a=e.height(),n=t.data(this,g);(i!==n.w||a!==n.h)&&e.trigger(c,[n.w=i,n.h=a])}),a()},o[s])}var n,r=t([]),o=t.resize=t.extend(t.resize,{}),l="setTimeout",c="resize",g=c+"-special-event",s="delay",u="throttleWindow";o[s]=250,o[u]=!0,t.event.special[c]={setup:function(){if(!o[u]&&this[l])return!1;var e=t(this);r=r.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===r.length&&a()},teardown:function(){if(!o[u]&&this[l])return!1;var e=t(this);r=r.not(e),e.removeData(g),r.length||clearTimeout(n)},add:function(e){function a(e,a,r){var o=t(this),l=t.data(this,g)||{};l.w=a!==i?a:o.width(),l.h=r!==i?r:o.height(),n.apply(this,arguments)}if(!o[u]&&this[l])return!1;var n;return t.isFunction(e)?(n=e,a):(n=e.handler,void(e.handler=a))}}}(e,window),t("util",i)}); -------------------------------------------------------------------------------- /src/Http/Controller/ConsoleController.php: -------------------------------------------------------------------------------- 1 | command(); 36 | 37 | $listView = new Table(); 38 | $listView->title = "命令应用"; 39 | $listView->listTitle = [ 40 | "name" => '命令', 41 | "des" => '说明', 42 | "handel" => '处理', 43 | ]; 44 | $listView->listHeader[] = new ReloadButton(); 45 | $listView->listHeader[] = new NewWindow('console/addClassShow', '新增命令'); 46 | 47 | $listView->listData = is_array($list) ? $list : []; 48 | $button = new NewWindowIcon("console/run","运行",""); 49 | $button->addField(['name'=>'run']); 50 | $listView->listButton[] = $button; 51 | 52 | return $listView->toString(); 53 | } 54 | 55 | 56 | /** 57 | * 新增命令 58 | * @RequestMapping("addClassShow") 59 | * @param Request $request 60 | * @return \Swoft\Http\Message\Response 61 | * @throws \Throwable 62 | */ 63 | public function addDaoShow(Request $request) 64 | { 65 | $view = new Form(); 66 | $view->title = "新增命令类"; 67 | $view->item[] = new Form\InputForm('des','说明'); 68 | $view->item[] = new Form\InputForm('className','类名'); 69 | $view->item[] = new Form\InputForm('pre','命令前缀'); 70 | $view->action = "console/addClass"; 71 | 72 | return $view->toString(); 73 | } 74 | 75 | 76 | /** 77 | * 新增类文件 78 | * @param Request $request 79 | * @RequestMapping("addClass") 80 | * @return array 81 | */ 82 | public function addClass(Request $request) 83 | { 84 | $name = $request->post('className', ''); 85 | $des = $request->post('des', ''); 86 | $pre = $request->post("pre", ''); 87 | 88 | Exec::bean(Console::class)->add($name, $des, $pre); 89 | return Msg::success(); 90 | } 91 | 92 | /** 93 | * 执行命令行 94 | * @param Request $request 95 | * @RequestMapping("run") 96 | * @return string 97 | */ 98 | public function runCmd(Request $request) 99 | { 100 | $cmd = $request->get("run", ''); 101 | $cmd = "php bin/swoft ".$cmd; 102 | $root = alias("@app"); 103 | $root = dirname($root); 104 | 105 | $command = "cd {$root};".$cmd; 106 | Log::info($command); 107 | exec($command, $arr); 108 | 109 | return implode("
    ", $arr); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Http/Controller/TerminalController.php: -------------------------------------------------------------------------------- 1 | toString(); 33 | } 34 | 35 | /** 36 | * 运行命令 37 | * @RequestMapping("run",method={RequestMethod::POST}) 38 | * @param Request $request 39 | * @return string 40 | */ 41 | public function runCmd(Request $request) 42 | { 43 | $cmd = $request->post("run"); 44 | 45 | if (!$cmd) { 46 | return "\n"; 47 | } 48 | 49 | $str = $this->run($cmd); 50 | $str = str_replace("]", "\]", $str); 51 | return "[[;darkgreen;]{$str}]"; 52 | } 53 | 54 | /** 55 | * buttonEvent运行命令 56 | * @RequestMapping("button/run",method={RequestMethod::POST}) 57 | * @param Request $request 58 | * @return string 59 | */ 60 | public function buttonEvent(Request $request) 61 | { 62 | $cmd = $request->post("run"); 63 | 64 | if (!$cmd) { 65 | return "\n"; 66 | } 67 | 68 | switch ($cmd) { 69 | case "restart": 70 | return $this->button_restart(); 71 | break; 72 | case "stopAdmin": 73 | $this->run("php bin/swoft admin:stop&"); 74 | if (AdminServer::$enable===1){ 75 | bean('adminServer')->stop(); 76 | return "[[;red;]已经发生异步处理]"; 77 | }else{ 78 | AdminServer::$enable = 0; 79 | return "[[;darkgreen;]已经禁用admin]"; 80 | } 81 | break; 82 | default: 83 | $str = $this->run($cmd); 84 | $str = str_replace("]", "\]", $str); 85 | return "[[;darkgreen;]{$str}]"; 86 | } 87 | } 88 | 89 | private function button_restart() 90 | { 91 | if (AdminServer::$enable===1){ 92 | // 由admin启动的,可以隔离启动 93 | $str = $this->run("php bin/swoft http:restart"); 94 | $str = str_replace("]", "\]", $str); 95 | return "[[;darkgreen;]{$str}]"; 96 | }else{ 97 | // http:start 内部启动admin 98 | $str = $this->run("php bin/swoft http:restart&"); 99 | return "[[;red;]已经发生异步处理]"; 100 | } 101 | } 102 | 103 | private function run($cmd):string 104 | { 105 | $root = alias("@app"); 106 | $root = dirname($root); 107 | 108 | $command = "cd {$root};".$cmd; 109 | Log::info($command); 110 | exec($command, $arr); 111 | 112 | return implode("\n", $arr); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /exec/Model/Dao/RoutesResource.php: -------------------------------------------------------------------------------- 1 | scanClass() as $className) { 28 | try { 29 | // Annotation reader 30 | $reflectionClass = new \ReflectionClass($className); 31 | 32 | // Fix ignore abstract 33 | if ($reflectionClass->isAbstract()) { 34 | continue; 35 | } 36 | 37 | // Annotation reader 38 | $reader = new AnnotationReader(); 39 | $className = $reflectionClass->getName(); 40 | 41 | $classAnnotations = $reader->getClassAnnotations($reflectionClass); 42 | // 类注解遍历 43 | foreach ($classAnnotations as $classAnnotation) { 44 | if ($classAnnotation instanceof Controller) { 45 | // 函数遍历 46 | $reflectionMethods = $reflectionClass->getMethods(); 47 | foreach ($reflectionMethods as $reflectionMethod) { 48 | $methodName = $reflectionMethod->getName(); 49 | $methodAnnotations = $reader->getMethodAnnotations($reflectionMethod); 50 | 51 | if (!empty($methodAnnotations)) { 52 | $oneClassAnnotation['methods'][$methodName]['annotation'] = $methodAnnotations; 53 | $oneClassAnnotation['methods'][$methodName]['reflection'] = $reflectionMethod; 54 | $routeInfo = new RouteInfo(); 55 | $routeInfo->title = $this->getTitle($reflectionMethod->getDocComment()); 56 | $routeInfo->controller = $className; 57 | $routeInfo->action = $reflectionMethod->getName(); 58 | 59 | foreach ($methodAnnotations as $annotation) { 60 | if ($annotation instanceof RequestMapping) { 61 | $routeInfo->path = $classAnnotation->getPrefix() ? 62 | $classAnnotation->getPrefix()."/".$annotation->getRoute() : $annotation->getRoute(); 63 | $routeInfo->method = $annotation->getMethod(); 64 | } elseif ($annotation instanceof Validate) { 65 | $routeInfo->validator = $annotation; 66 | } 67 | } 68 | 69 | $routes[] = (array) $routeInfo; 70 | } 71 | } 72 | } 73 | } 74 | } catch (\Throwable $exception) { 75 | continue; 76 | } 77 | } 78 | 79 | return $routes; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /public/lib/layui/lay/modules/carousel.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['",'"].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['
      ',function(){var i=[];return layui.each(e.elemItem,function(e){i.push("")}),i.join("")}(),"
    "].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-(t.height()/2)),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):a 5 |
    6 | 7 | 首页 8 | title; ?> 9 | 10 | 13 | 14 | 15 |
    16 |
    17 |
    18 |
    19 |
    20 | listHeader) { 21 | echo "
    "; ?> 22 | listHeader as $button) { 23 | echo $button->toString(); 24 | } ?> 25 | "; 26 | } ?> 27 |
    28 | 29 | 30 | 31 | listTitle as $name) { ?> 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | listData as $key => $info) { ?> 40 | 41 | listTitle as $name => $title) { ?> 42 | 56 | 57 | 71 | 72 | 73 | 74 |
    操作
    58 | listButton as $button) { 60 | $arr = []; 61 | $url = $button->url; 62 | foreach ($button->tableListFields as $field => $param) { 63 | $field = is_numeric($field) ? $param : $field; 64 | $arr[] = $param."=".urlencode($info[$field] ?? ""); 65 | } 66 | $button->url = $button->url."?".implode('&', $arr); 67 | echo $button->toString(); 68 | $button->url = $url; 69 | } ?> 70 |
    75 |
    76 |
    77 |
    78 |
    79 |
    80 | -------------------------------------------------------------------------------- /public/lib/layui/lay/modules/laypage.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"上一页",a.next="next"in a?a.next:"下一页";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?''+a.prev+"":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push(''+(a.first||1)+"");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r2&&e.push('');r<=u;r++)r===a.curr?e.push('"+r+""):e.push(''+r+"");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1…'),0!==t&&e.push(''+(a.last||a.pages)+"")),e.join("")}(),next:function(){return a.next?''+a.next+"":""}(),count:'共 '+a.count+" 条",limit:function(){var e=['"}(),refresh:['','',""].join(""),skip:function(){return['到第','','页',""].join("")}()};return['
    ',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"
    "].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;oi.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)}); -------------------------------------------------------------------------------- /exec/Application.php: -------------------------------------------------------------------------------- 1 | loader = $loader; 25 | 26 | $controlNamespace = "SwoftAdmin\\Exec\\Controller"; 27 | $dir = new Directory(); 28 | foreach ($this->getDir($controlNamespace) as $scanDir => $namespace) { 29 | $dir->setScanDirectory($scanDir, $namespace); 30 | } 31 | 32 | foreach ($dir->scanClass() as $className) { 33 | // Annotation reader 34 | $reflectionClass = new \ReflectionClass($className); 35 | 36 | // Fix ignore abstract 37 | if ($reflectionClass->isAbstract()) { 38 | return; 39 | } 40 | $arr = explode('\\',$className); 41 | $handel = end($arr); 42 | 43 | $cmd = new $className(); 44 | // Annotation reader 45 | $reader = new AnnotationReader(); 46 | $reflectionMethods = $reflectionClass->getMethods(); 47 | foreach ($reflectionMethods as $reflectionMethod) { 48 | $methodAnnotations = $reader->getMethodAnnotations($reflectionMethod); 49 | $this->addRoute($handel."@".$reflectionMethod->getName(),[$cmd,$reflectionMethod->getName()]); 50 | if (!empty($methodAnnotations)) { 51 | foreach ($methodAnnotations as $annotation) { 52 | if ($annotation instanceof CommandMapping) { 53 | $this->addRoute($annotation->getName(),[$cmd,$reflectionMethod->getName()]); 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | self::$myself = $this; 61 | } 62 | 63 | /** 64 | * @param string $name 65 | * @param callable $fun 66 | */ 67 | public function addRoute(string $name, $fun) 68 | { 69 | $this->routes[$name] = $fun; 70 | } 71 | 72 | /** 73 | * 运行命令 74 | * @param array $argv 75 | */ 76 | public function run(array $argv) 77 | { 78 | if (isset($argv[1]) && isset($this->routes[$argv[1]])) { 79 | $route = $argv[1]; 80 | $call = $this->routes[$route]; 81 | 82 | $class = $call[0]; 83 | $class = new $class(); 84 | $action = $call[1]; 85 | 86 | $params = []; 87 | foreach ($argv as $key => $item) { 88 | $key > 1 and $params[] = $item; 89 | } 90 | 91 | $data = call_user_func_array([$class, $action], $params); 92 | 93 | echo serialize($data); 94 | return; 95 | } 96 | } 97 | 98 | /** 99 | * 获取目录 100 | * @param $namespace 101 | * @return array 102 | */ 103 | public function getDir($namespace): array 104 | { 105 | $psr = $this->loader->getPrefixesPsr4(); 106 | $arr = explode("\\", $namespace); 107 | foreach ($arr as $name) { 108 | $base = isset($base) ? $base.$name."\\" : $name."\\"; 109 | if (isset($psr[$base])) { 110 | $temp = explode($base, $namespace); 111 | $find = end($temp); 112 | $find = str_replace("\\", "/", $find); 113 | break; 114 | } 115 | } 116 | 117 | if (!isset($find) || !isset($psr[$base])) { 118 | return []; 119 | } 120 | $data = []; 121 | foreach ($psr[$base] as $dir) { 122 | $dir = realpath($dir); 123 | $is = $dir."/".$find."/"; 124 | if (is_dir($is)) { 125 | $data[$is] = $namespace."\\"; 126 | } 127 | } 128 | 129 | return $data; 130 | } 131 | 132 | /** 133 | * 获取目录对象 134 | * @param $namespace 135 | * @return Directory 136 | */ 137 | public static function getDirectory($namespace):Directory 138 | { 139 | $dirList = self::$myself->getDir($namespace); 140 | 141 | $dir = new Directory(); 142 | foreach ($dirList as $scanDir=>$namespace){ 143 | $dir->setScanDirectory($scanDir, $namespace); 144 | } 145 | return $dir; 146 | } 147 | 148 | 149 | /** 150 | * 获取目录对象 151 | * @param $namespace 152 | * @return array 153 | */ 154 | public static function getDirs($namespace) 155 | { 156 | return self::$myself->getDir($namespace); 157 | } 158 | 159 | public static function getTemplate(string $name):string 160 | { 161 | return __DIR__."/template/".$name; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/Http/Controller/ModelController.php: -------------------------------------------------------------------------------- 1 | dao(); 35 | 36 | $view = new Table(); 37 | $view->title = "Dao"; 38 | $view->listTitle = [ 39 | "title" => '标题', 40 | "path" => '类名', 41 | "bean" => '拥有Bean', 42 | ]; 43 | $view->listHeader[] = new ReloadButton(); 44 | $view->listHeader[] = new NewWindow('model/addClassShow','新增Dao'); 45 | 46 | $view->listData = is_array($list) ? $list : []; 47 | 48 | $button = new NewWindowIcon('file/show', '文件内容'); 49 | $button->mix = "true"; 50 | $button->addField(['path'=>'path']); 51 | $view->addListButton($button); 52 | 53 | return $view->toString(); 54 | } 55 | 56 | /** 57 | * 新增Dao 58 | * @RequestMapping("addClassShow") 59 | * @param Request $request 60 | * @return \Swoft\Http\Message\Response 61 | * @throws \Throwable 62 | */ 63 | public function addDaoShow(Request $request) 64 | { 65 | $title = $request->get('title', "add Dao"); 66 | $namespace = $request->get('namespace', "App/Model/Dao/"); 67 | $suffix = $request->get('suffix', "Dao"); 68 | 69 | $addView = new Form(); 70 | $addView->title = $title; 71 | $addView->item[] = new Form\InputForm('title',"标题",'注释第一行说明'); 72 | $addView->item[] = new Form\InputForm('className',"类名","自动加 {$suffix} 后缀"); 73 | $addView->item[] = (new Form\InputForm('namespace','命名空间'))->setValue($namespace); 74 | $addView->item[] = (new Form\InputForm('suffix','后缀'))->setValue($suffix); 75 | 76 | $addView->action = 'model/addClass'; 77 | return $addView->toString(); 78 | } 79 | 80 | /** 81 | * Data目录 82 | * @RequestMapping("data") 83 | */ 84 | public function data() 85 | { 86 | $list = Exec::bean(Model::class)->data(); 87 | 88 | $view = new Table(); 89 | $view->title = "Data目录"; 90 | $view->listTitle = [ 91 | "title" => '标题', 92 | "path" => '类名', 93 | "bean" => '拥有Bean', 94 | ]; 95 | $view->listHeader[] = new ReloadButton(); 96 | $view->listHeader[] = new NewWindow('model/addClassShow?title=Data&namespace=App/Model/Data/&suffix=Data','新增Data'); 97 | 98 | $view->listData = is_array($list) ? $list : []; 99 | 100 | $button = new NewWindowIcon('file/show', '文件内容'); 101 | $button->mix = "true"; 102 | $button->addField(['path'=>'path']); 103 | $view->addListButton($button); 104 | 105 | return $view->toString(); 106 | } 107 | 108 | /** 109 | * Logic目录 110 | * @RequestMapping("logic") 111 | */ 112 | public function logic() 113 | { 114 | $list = Exec::bean(Model::class)->logic(); 115 | 116 | $view = new Table(); 117 | $view->title = "Logic目录"; 118 | $view->listTitle = [ 119 | "title" => '标题', 120 | "path" => '类名', 121 | "bean" => '拥有Bean', 122 | ]; 123 | $view->listHeader[] = new ReloadButton(); 124 | $view->listHeader[] = new NewWindow('model/addClassShow?title=Logic&namespace=App/Model/Logic/&suffix=Logic','新增Logic'); 125 | 126 | $view->listData = is_array($list) ? $list : []; 127 | 128 | $button = new NewWindowIcon('file/show', '文件内容'); 129 | $button->mix = "true"; 130 | $button->addField(['path'=>'path']); 131 | $view->addListButton($button); 132 | 133 | return $view->toString(); 134 | } 135 | 136 | /** 137 | * 新增类文件 138 | * @param Request $request 139 | * @RequestMapping("addClass") 140 | * @return array 141 | */ 142 | public function addClass(Request $request) 143 | { 144 | $namespace = $request->post('namespace',''); 145 | $name = $request->post('className',''); 146 | $title = $request->post('title',''); 147 | $suffix = $request->post("suffix",''); 148 | 149 | Exec::bean(Model::class)->addClass($namespace, $name, $title, $suffix); 150 | return Msg::success(); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /resource/home/welcome.php: -------------------------------------------------------------------------------- 1 | script("terminal/js/jquery-1.7.1.min.js"); 6 | $data->script("terminal/js/jquery.mousewheel-min.js"); 7 | $data->script("terminal/js/jquery.terminal.min.js"); 8 | $data->script("https://unpkg.com/js-polyfills/keyboard.js"); 9 | $data->link("terminal/css/jquery.terminal.min.css"); 10 | ?> 11 |
    12 |
    13 |
    14 | 15 |
    16 |
    Terminal
    17 |
    18 | 19 |
    20 |
    21 | 22 |
    23 |
    常用功能
    24 |
    25 | 26 | 27 | 28 | 29 | 30 |
    31 |
    32 |
    33 | 34 |
    35 |
    36 |
    系统信息
    37 |
    38 | 39 | 40 | system as $datum) { ?> 41 | 42 | 43 | 44 | 45 | 46 | 47 |
    48 |
    49 |
    50 |
    51 |
    扩展信息
    52 |
    53 | ext as $datum) { ?> 54 | 55 | 56 |
    57 |
    58 |
    59 |
    60 |
    61 | 128 | -------------------------------------------------------------------------------- /exec/Controller/Postmen.php: -------------------------------------------------------------------------------- 1 | reader = new AnnotationReader(); 25 | 26 | $postmen = []; 27 | 28 | foreach ($loader->scanClass() as $className) { 29 | 30 | // Annotation reader 31 | $reflectionClass = new \ReflectionClass($className); 32 | 33 | // Fix ignore abstract 34 | if ($reflectionClass->isAbstract()) { 35 | continue; 36 | } 37 | $postmen['info'] = $this->getInfo(); 38 | $classAnnotations = $this->reader->getClassAnnotations($reflectionClass); 39 | // 类注解遍历 40 | foreach ($classAnnotations as $classAnnotation) { 41 | if ($classAnnotation instanceof Controller) { 42 | $postmen['item'][] = $this->getControllerItem($reflectionClass, $classAnnotation); 43 | } 44 | } 45 | } 46 | 47 | return $postmen; 48 | } 49 | 50 | protected function getInfo() 51 | { 52 | return [ 53 | "_postman_id" => uniqid(), 54 | "name" => "swoft-admin", 55 | "schema" => "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 56 | ]; 57 | } 58 | 59 | protected function getControllerItem(\ReflectionClass $reflectionClass, Controller $classAnnotation) 60 | { 61 | $itemList = []; 62 | $itemList['name'] = $this->getTitle($reflectionClass->getDocComment()); 63 | $itemList['item'] = []; 64 | 65 | 66 | $contr = new ReflectionRoute(); 67 | 68 | $reflectionMethods = $reflectionClass->getMethods(); 69 | foreach ($reflectionMethods as $reflectionMethod) { 70 | $action = []; 71 | $action['name'] = $this->getTitle($reflectionMethod->getDocComment()); 72 | $action['event'] = $this->getTestEvent(); 73 | 74 | $prefix = $classAnnotation->getPrefix(); 75 | $url = []; 76 | $methodAnnotations = $this->reader->getMethodAnnotations($reflectionMethod); 77 | if (!empty($methodAnnotations)) { 78 | foreach ($methodAnnotations as $annotation) { 79 | $url = []; 80 | $body = []; 81 | if ($annotation instanceof RequestMapping) { 82 | $path = $prefix ? $prefix."/".$annotation->getRoute() : $annotation->getRoute(); 83 | $url['raw'] = "{{url}}".$path; 84 | $url['host'] = ["{{url}}"]; 85 | $url['path'] = explode('/', $path); 86 | $methods = $annotation->getMethod(); 87 | $method = "GET"; 88 | if ($methods) { 89 | $method = reset($methods); 90 | } 91 | $routesInfo = $contr->getParameters($reflectionClass, $reflectionMethod); 92 | 93 | $body['mode'] = "formdata"; 94 | foreach ($routesInfo['params'] ?? [] as $item) { 95 | $tem = [ 96 | "key" => $item['key'], 97 | "value" => $item['default'], 98 | "description" => $item['title'], 99 | "type" => "text" 100 | ]; 101 | $body['formdata'][] = $tem; 102 | } 103 | } 104 | } 105 | 106 | if ($url) { 107 | $action["request"]["url"] = $url; 108 | $action["request"]["body"] = $body; 109 | $action["request"]["method"] = $method; 110 | $itemList['item'][] = $action; 111 | } 112 | } 113 | } 114 | return $itemList; 115 | } 116 | 117 | /** 118 | * 是否生成自动测试 119 | * @return array 120 | */ 121 | protected function getTestEvent() 122 | { 123 | return [ 124 | [ 125 | "listen" => "test", 126 | "script" => [ 127 | "exec" => [ 128 | "var data = JSON.parse(responseBody)", 129 | "if(data.code == '0'){", 130 | " tests[\"this code is 0\"] = true", 131 | "}else{", 132 | " tests[\"hhas error code \"] = false", 133 | "}" 134 | ], 135 | ], 136 | "type" => "text/javascript" 137 | ], 138 | ]; 139 | } 140 | 141 | /** 142 | * 第一行注释 143 | * @param $doc 144 | * @return string 145 | */ 146 | protected function getTitle($doc): string 147 | { 148 | $title = ""; 149 | 150 | $arr = explode(PHP_EOL, $doc); 151 | 152 | foreach ($arr as $str) { 153 | $str = str_replace(["/", "*"], "", $str); 154 | $str = trim($str); 155 | 156 | if (strlen($str) > 0) { 157 | $title = $str; 158 | break; 159 | } 160 | } 161 | if ($title && $title{0} == "@") { 162 | return ""; 163 | } 164 | return $title; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/Http/Controller/LogsController.php: -------------------------------------------------------------------------------- 1 | title = "运行缓存目录"; 37 | $view->listTitle = [ 38 | "id" => 'ID', 39 | "path" => 'File', 40 | "size" => 'Size', 41 | ]; 42 | 43 | $view->listData = $this->getFiles("@runtime/"); 44 | 45 | $button = new NewWindowIcon('logs/runtimeFile', '文件内容'); 46 | $button->mix = "true"; 47 | $button->addField(['path' => 'path']); 48 | $view->addListButton($button); 49 | 50 | $button = new NewWindowIcon('logs/runtimeDown', '文件下载', ''); 51 | $button->addField(['path' => 'path']); 52 | $view->addListButton($button); 53 | 54 | return $view->toString(); 55 | } 56 | 57 | /** 58 | * 获取目录下文件列表 59 | * @param $path 60 | * @return array 61 | */ 62 | private function getFiles($path) 63 | { 64 | $root = alias($path); 65 | $list = scandir($root); 66 | $arr = []; 67 | foreach ($list as $key => $item) { 68 | if (in_array($item, ['', '.', '..']) || is_dir($root.$item)) { 69 | continue; 70 | } 71 | $arr[] = [ 72 | 'path' => $path.$item, 73 | 'size' => filesize($root.$item), 74 | ]; 75 | } 76 | return $arr; 77 | } 78 | 79 | /** 80 | * 日记文件 81 | * @RequestMapping("logs") 82 | */ 83 | public function logs() 84 | { 85 | $view = new Table(); 86 | $view->title = "运行缓存目录"; 87 | $view->listTitle = [ 88 | "id" => 'ID', 89 | "path" => 'File', 90 | "size" => 'Size', 91 | ]; 92 | 93 | $view->listData = $this->getFiles("@runtime/logs/"); 94 | 95 | $button = new NewWindowIcon('logs/runtimeFile', "日志内容,倒序300行,如果多于300行,需要另行下载"); 96 | $button->mix = "true"; 97 | $button->addField(['path' => 'path']); 98 | $view->addListButton($button); 99 | 100 | $button = new NewWindowIcon('logs/runtimeDown', '文件下载', ''); 101 | $button->addField(['path' => 'path']); 102 | $view->addListButton($button); 103 | 104 | return $view->toString(); 105 | } 106 | 107 | 108 | /** 109 | * 查看文件 110 | * @RequestMapping("runtimeFile") 111 | * @param Request $request 112 | * @return FileContent 113 | */ 114 | public function runtimeFile(Request $request) 115 | { 116 | $path = $request->get("path"); 117 | $path = $this->getPath($path); 118 | 119 | $view = new Logs(); 120 | $view->title = "显示控制器内容"; 121 | $view->layContent = $this->getLastLines($path, 300); 122 | return $view->toString(); 123 | } 124 | 125 | /** 126 | * 过滤不安全的路径 127 | * @param $path 128 | * @return string 129 | */ 130 | private function getPath($path) 131 | { 132 | $path = str_replace('..', '', $path); 133 | if ( $path{0}!="@" ){ 134 | Log::error("不能使用非 @ 开头路径"); 135 | CLog::error("不能使用非 @ 开头路径"); 136 | return ""; 137 | } 138 | return alias($path); 139 | } 140 | 141 | /** 142 | * 下载日记文件 143 | * @RequestMapping("runtimeDown") 144 | * @param Request $request 145 | * @param Response $response 146 | * @return Response 147 | */ 148 | public function runtimeDown(Request $request, Response $response) 149 | { 150 | $path = $request->get("path"); 151 | $path = $this->getPath($path); 152 | $fileName = pathinfo($path,PATHINFO_BASENAME); 153 | 154 | $response->getCoResponse()->header('Content-Disposition',"attachment; filename={$fileName}"); 155 | 156 | return $response->file($path, "application/octet-stream"); 157 | } 158 | 159 | /** 160 | * 读取文件尾数行数 161 | * @param $file 162 | * @param int $line 163 | * @return string 164 | */ 165 | public function getLastLines($file, $line = 1) 166 | { 167 | if (!$fp = fopen($file, 'r')) { 168 | Log::error("不能打开文件{$file}"); 169 | CLog::error("不能打开文件{$file}"); 170 | return "不能打开文件{$file}"; 171 | } 172 | $pos = -2; 173 | $eof = ""; 174 | $str = ""; 175 | $head = false; 176 | while ($line > 0) { 177 | while ($eof != "\n") { 178 | if (!fseek($fp, $pos, SEEK_END)) { 179 | $eof = fgetc($fp); 180 | $pos--; 181 | } else { 182 | fseek($fp, 0, SEEK_SET); 183 | $head = true; 184 | break; 185 | } 186 | } 187 | $str .= fgets($fp); 188 | if ($head) { 189 | break; 190 | } 191 | $eof = ""; 192 | $line--; 193 | } 194 | return $str; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /exec/Controller/Controller.php: -------------------------------------------------------------------------------- 1 | getParameters($reflectionClass,$reflectionClass->getMethod($action)); 37 | } 38 | 39 | /** 40 | * 获取所有路由信息 41 | * @return array 42 | * @throws \Doctrine\Common\Annotations\AnnotationException 43 | * @throws \ReflectionException 44 | * @CommandMapping(name="routes") 45 | */ 46 | public function getRoutes() 47 | { 48 | $dir = Application::getDirectory('App\\Http\\Controller'); 49 | return (new RoutesResource())->scanRoutes($dir); 50 | } 51 | 52 | /** 53 | * 获取控制器列表 54 | */ 55 | public function getControllers() 56 | { 57 | $dir = Application::getDirectory('App\\Http\\Controller'); 58 | return (new ControllerResource())->scanController($dir); 59 | } 60 | 61 | /** 62 | * 创建控制器 63 | * @param $name 64 | * @param $title 65 | * @param $mids 66 | */ 67 | public function addControllers($name, $title = "无标题", ...$mids) 68 | { 69 | $data = Application::getDirs('App\\Http\\Controller'); 70 | $dir = key($data); 71 | 72 | $className = $name."Controller"; 73 | $path = $dir.$className.".php"; 74 | if (file_exists($path)) { 75 | return; 76 | } 77 | $template = file_get_contents(Application::getTemplate("Controller")); 78 | 79 | $strMids = ""; 80 | $use = ""; 81 | if (is_array($mids) && $mids) { 82 | $use .= "\nuse Swoft\\Http\\Server\\Annotation\\Mapping\\Middlewares;"; 83 | $use .= "\nuse Swoft\\Http\\Server\\Annotation\\Mapping\\Middleware;"; 84 | foreach ($mids as $mid) { 85 | $mid = urldecode($mid); 86 | $arrT = explode("\\", $mid); 87 | $midName = end($arrT); 88 | $use .= "\nuse {$mid};"; 89 | $strMids = $strMids." * @Middleware(".$midName."::class),\n"; 90 | } 91 | } 92 | if ($strMids) { 93 | $strMids = "\n * @Middlewares({\n".$strMids." * })"; 94 | } 95 | 96 | $template = str_replace(["{title}", "{name}", "{Middlewares}", "{use}"], [$title, $name, $strMids, $use], 97 | $template); 98 | 99 | file_put_contents($path, $template); 100 | return; 101 | } 102 | 103 | /** 104 | * 生成路由函数 105 | * @param string $con 106 | * @param string $route 107 | * @param string $function 108 | * @param string $title 109 | * @param string $method 110 | * @return bool|string 111 | * @throws \ReflectionException 112 | */ 113 | public function addRoute($con, $route, $function, $title = "无注释", $method = "GET") 114 | { 115 | // 格式检查 116 | $con = urldecode($con); 117 | 118 | $reflector = new \ReflectionClass($con); 119 | $filePath = $reflector->getFileName(); 120 | $content = file_get_contents($filePath); 121 | $content = trim($content); 122 | $strLen = strlen($content); 123 | $endStr = $content{$strLen - 1}; 124 | 125 | if ($endStr != "}") { 126 | return "不是以 } 结束的类文件"; 127 | } 128 | 129 | if (strlen($function) <= 2 || !preg_match('/^[_0-9a-z]{2,30}$/i', $function)) { 130 | return "函数名不合法"; 131 | } 132 | 133 | foreach ($reflector->getMethods() as $reflectionMethod) { 134 | if ($reflectionMethod->getName() == $function) { 135 | return "函数名已存在"; 136 | } 137 | } 138 | 139 | $firstStr = substr($content, 0, -1); 140 | $backups = getRootPath().'/runtime/admin/backups/'; 141 | if (!is_dir($backups)) { 142 | if (!mkdir($backups, 0755, true)) { 143 | return false; 144 | } 145 | } 146 | copy($filePath, $backups.'/'.time().'.php'); 147 | $newFunc = file_get_contents(__DIR__.'/../template/Route'); 148 | 149 | /** 150 | * 补全命名空间引用 151 | * 必须有 use Swoft\Http\Server\Annotation\Mapping\Controller; 152 | */ 153 | $needController = "use Swoft\Http\Server\Annotation\Mapping\Controller;"; 154 | if (strpos($firstStr, $needController) === false) { 155 | return false; 156 | } 157 | 158 | $useArr = [ 159 | "use Swoft\\Http\\Message\\Request;", 160 | "use Swoft\\Http\\Message\\Response;", 161 | "use Swoft\\Http\\Server\\Annotation\\Mapping\\RequestMapping;", 162 | "use Swoft\\Http\\Server\\Annotation\\Mapping\\RequestMethod;", 163 | ]; 164 | foreach ($useArr as $use) { 165 | if (strpos($firstStr, $use) === false) { 166 | $firstStr = str_replace([$needController], [$needController."\n".$use], $firstStr); 167 | } 168 | } 169 | 170 | $newFunc = str_replace(["{title}", "{route}", "{function}", "{method}"], [$title, $route, $function, $method], 171 | $newFunc); 172 | 173 | file_put_contents($filePath, $firstStr.$newFunc); 174 | return true; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/Command/AdminCommand.php: -------------------------------------------------------------------------------- 1 | createServer(); 52 | 53 | // Check if it has started 54 | if ($server->isRunning()) { 55 | $masterPid = $server->getPid(); 56 | output()->writeln("The HTTP server have been running!(PID: {$masterPid})"); 57 | return; 58 | } 59 | 60 | // Startup settings 61 | $this->configStartOption($server); 62 | 63 | $settings = $server->getSetting(); 64 | // Setting 65 | $workerNum = $settings['worker_num']; 66 | 67 | // Server startup parameters 68 | $mainHost = $server->getHost(); 69 | $mainPort = $server->getPort(); 70 | $modeName = $server->getModeName(); 71 | $typeName = $server->getTypeName(); 72 | 73 | // Http 74 | $panel = [ 75 | 'HTTP' => [ 76 | 'listen' => $mainHost . ':' . $mainPort, 77 | 'type' => $typeName, 78 | 'mode' => $modeName, 79 | 'worker' => $workerNum, 80 | ], 81 | ]; 82 | 83 | // Port Listeners 84 | $panel = $this->appendPortsToPanel($server, $panel); 85 | 86 | Show::panel($panel); 87 | 88 | output()->writeln('HTTP server start success !'); 89 | 90 | // Start the server 91 | $server->start(); 92 | } 93 | 94 | /** 95 | * Reload worker processes 96 | * 97 | * @CommandMapping(usage="{fullCommand} [-t]") 98 | * @CommandOption("t", desc="Only to reload task processes, default to reload worker and task") 99 | * 100 | * @throws ReflectionException 101 | * @throws ContainerException 102 | */ 103 | public function reload(): void 104 | { 105 | $server = $this->createServer(); 106 | $script = input()->getScriptFile(); 107 | 108 | // Check if it has started 109 | if (!$server->isRunning()) { 110 | output()->writeln('The HTTP server is not running! cannot reload'); 111 | return; 112 | } 113 | 114 | output()->writef('Server %s is reloading', $script); 115 | 116 | if ($reloadTask = input()->hasOpt('t')) { 117 | Show::notice('Will only reload task worker'); 118 | } 119 | 120 | if (!$server->reload($reloadTask)) { 121 | Show::error('The swoole server worker process reload fail!'); 122 | return; 123 | } 124 | 125 | output()->writef('HTTP server %s reload success', $script); 126 | } 127 | 128 | /** 129 | * Stop the currently running server 130 | * 131 | * @CommandMapping() 132 | * 133 | * @throws ReflectionException 134 | * @throws ContainerException 135 | */ 136 | public function stop(): void 137 | { 138 | $server = $this->createServer(); 139 | 140 | // Check if it has started 141 | if (!$server->isRunning()) { 142 | output()->writeln('The HTTP server is not running! cannot stop.'); 143 | return; 144 | } 145 | 146 | // Do stopping. 147 | $server->stop(); 148 | } 149 | 150 | /** 151 | * Restart the http server 152 | * 153 | * @CommandMapping(usage="{fullCommand} [-d|--daemon]",) 154 | * @CommandOption("daemon", short="d", desc="Run server on the background") 155 | * 156 | * @throws ReflectionException 157 | * @throws ContainerException 158 | * @example 159 | * {fullCommand} 160 | * {fullCommand} -d 161 | */ 162 | public function restart(): void 163 | { 164 | $server = $this->createServer(); 165 | 166 | // Check if it has started 167 | if ($server->isRunning()) { 168 | $success = $server->stop(); 169 | 170 | if (!$success) { 171 | output()->error('Stop the old server failed!'); 172 | return; 173 | } 174 | } 175 | 176 | output()->writef('Server HTTP restart success !'); 177 | $server->startWithDaemonize(); 178 | } 179 | 180 | /** 181 | * @return Server 182 | * @throws ReflectionException 183 | * @throws ContainerException 184 | */ 185 | private function createServer(): Server 186 | { 187 | $script = input()->getScriptFile(); 188 | $command = $this->getFullCommand(); 189 | 190 | /** @var Server $server */ 191 | $server = bean('adminServer'); 192 | $server->setScriptFile(Swoft::app()->getPath($script)); 193 | $server->setFullCommand($command); 194 | 195 | return $server; 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /public/lib/layui/layui.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;!function(e){"use strict";var t=document,o={modules:{},status:{},timeout:10,event:{}},n=function(){this.v="2.4.5"},r=function(){var e=t.currentScript?t.currentScript.src:function(){for(var e,o=t.scripts,n=o.length-1,r=n;r>0;r--)if("interactive"===o[r].readyState){e=o[r].src;break}return e||o[n].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),i=function(t){e.console&&console.error&&console.error("Layui hint: "+t)},a="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),u={layer:"modules/layer",laydate:"modules/laydate",laypage:"modules/laypage",laytpl:"modules/laytpl",layim:"modules/layim",layedit:"modules/layedit",form:"modules/form",upload:"modules/upload",tree:"modules/tree",table:"modules/table",element:"modules/element",rate:"modules/rate",colorpicker:"modules/colorpicker",slider:"modules/slider",carousel:"modules/carousel",flow:"modules/flow",util:"modules/util",code:"modules/code",jquery:"modules/jquery",mobile:"modules/mobile","layui.all":"../layui.all"};n.prototype.cache=o,n.prototype.define=function(e,t){var n=this,r="function"==typeof e,i=function(){var e=function(e,t){layui[e]=t,o.status[e]=!0};return"function"==typeof t&&t(function(n,r){e(n,r),o.callback[n]=function(){t(e)}}),this};return r&&(t=e,e=[]),layui["layui.all"]||!layui["layui.all"]&&layui["layui.mobile"]?i.call(n):(n.use(e,i),n)},n.prototype.use=function(e,n,l){function s(e,t){var n="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[f]=t,d.removeChild(v),function r(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void(o.status[f]?c():setTimeout(r,4))}())}function c(){l.push(layui[f]),e.length>1?y.use(e.slice(1),n,l):"function"==typeof n&&n.apply(layui,l)}var y=this,p=o.dir=o.dir?o.dir:r,d=t.getElementsByTagName("head")[0];e="string"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(y.each(e,function(t,o){"jquery"===o&&e.splice(t,1)}),layui.jquery=layui.$=jQuery);var f=e[0],m=0;if(l=l||[],o.host=o.host||(p.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===e.length||layui["layui.all"]&&u[f]||!layui["layui.all"]&&layui["layui.mobile"]&&u[f])return c(),y;if(o.modules[f])!function g(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void("string"==typeof o.modules[f]&&o.status[f]?c():setTimeout(g,4))}();else{var v=t.createElement("script"),h=(u[f]?p+"lay/":/^\{\/\}/.test(y.modules[f])?"":o.base||"")+(y.modules[f]||f)+".js";h=h.replace(/^\{\/\}/,""),v.async=!0,v.charset="utf-8",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||"";return e?"?v="+e:""}(),d.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf("[native code")<0||a?v.addEventListener("load",function(e){s(e,h)},!1):v.attachEvent("onreadystatechange",function(e){s(e,h)}),o.modules[f]=h}return y},n.prototype.getStyle=function(t,o){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](o)},n.prototype.link=function(e,n,r){var a=this,u=t.createElement("link"),l=t.getElementsByTagName("head")[0];"string"==typeof n&&(r=n);var s=(r||e).replace(/\.|\//g,""),c=u.id="layuicss-"+s,y=0;return u.rel="stylesheet",u.href=e+(o.debug?"?v="+(new Date).getTime():""),u.media="all",t.getElementById(c)||l.appendChild(u),"function"!=typeof n?a:(function p(){return++y>1e3*o.timeout/100?i(e+" timeout"):void(1989===parseInt(a.getStyle(t.getElementById(c),"width"))?function(){n()}():setTimeout(p,100))}(),a)},o.callback={},n.prototype.factory=function(e){if(layui[e])return"function"==typeof o.callback[e]?o.callback[e]:null},n.prototype.addcss=function(e,t,n){return layui.link(o.dir+"css/"+e,t,n)},n.prototype.img=function(e,t,o){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,"function"==typeof t&&t(n)},void(n.onerror=function(e){n.onerror=null,"function"==typeof o&&o(e)}))},n.prototype.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},n.prototype.modules=function(){var e={};for(var t in u)e[t]=u[t];return e}(),n.prototype.extend=function(e){var t=this;e=e||{};for(var o in e)t[o]||t.modules[o]?i("模块名 "+o+" 已被占用"):t.modules[o]=e[o];return t},n.prototype.router=function(e){var t=this,e=e||location.hash,o={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(e)?(e=e.replace(/^#\//,""),o.href="/"+e,e=e.replace(/([^#])(#.*$)/,"$1").split("/")||[],t.each(e,function(e,t){/^\w+=/.test(t)?function(){t=t.split("="),o.search[t[0]]=t[1]}():o.path.push(t)}),o):o},n.prototype.data=function(t,o,n){if(t=t||"layui",n=n||localStorage,e.JSON&&e.JSON.parse){if(null===o)return delete n[t];o="object"==typeof o?o:{key:o};try{var r=JSON.parse(n[t])}catch(i){var r={}}return"value"in o&&(r[o.key]=o.value),o.remove&&delete r[o.key],n[t]=JSON.stringify(r),o.key?r[o.key]:r}},n.prototype.sessionData=function(e,t){return this.data(e,t,sessionStorage)},n.prototype.device=function(t){var o=navigator.userAgent.toLowerCase(),n=function(e){var t=new RegExp(e+"/([^\\s\\_\\-]+)");return e=(o.match(t)||[])[1],e||!1},r={os:function(){return/windows/.test(o)?"windows":/linux/.test(o)?"linux":/iphone|ipod|ipad|ios/.test(o)?"ios":/mac/.test(o)?"mac":void 0}(),ie:function(){return!!(e.ActiveXObject||"ActiveXObject"in e)&&((o.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:n("micromessenger")};return t&&!r[t]&&(r[t]=n(t)),r.android=/android/.test(o),r.ios="ios"===r.os,r},n.prototype.hint=function(){return{error:i}},n.prototype.each=function(e,t){var o,n=this;if("function"!=typeof t)return n;if(e=e||[],e.constructor===Object){for(o in e)if(t.call(e[o],o,e[o]))break}else for(o=0;oi?1:r"].join("")),o=t.elem.next();(o.hasClass(u)||o.hasClass(c))&&o.remove(),a.ie&&a.ie<10&&t.elem.wrap('
    '),e.isFile()?(e.elemFile=t.elem,t.field=t.elem[0].name):t.elem.after(n),a.ie&&a.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,t=e.config,n=i(''),a=i(['
    ',"
    "].join(""));i("#"+f)[0]||i("body").append(n),t.elem.next().hasClass(c)||(e.elemFile.wrap(a),t.elem.next("."+c).append(function(){var e=[];return layui.each(t.data,function(i,t){t="function"==typeof t?t():t,e.push('')}),e.join("")}()))},p.prototype.msg=function(e){return t.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},p.prototype.preview=function(e){var i=this;window.FileReader&&layui.each(i.chooseFiles,function(i,t){var n=new FileReader;n.readAsDataURL(t),n.onload=function(){e&&e(i,t,this.result)}})},p.prototype.upload=function(e,t){var n,o=this,l=o.config,r=o.elemFile[0],u=function(){var t=0,n=0,a=e||o.files||o.chooseFiles||r.files,u=function(){l.multiple&&t+n===o.fileLength&&"function"==typeof l.allDone&&l.allDone({total:o.fileLength,successful:t,aborted:n})};layui.each(a,function(e,a){var r=new FormData;r.append(l.field,a),layui.each(l.data,function(e,i){i="function"==typeof i?i():i,r.append(e,i)}),i.ajax({url:l.url,type:"post",data:r,contentType:!1,processData:!1,dataType:"json",headers:l.headers||{},success:function(i){t++,d(e,i),u()},error:function(){n++,o.msg("请求上传接口出现异常"),m(e),u()}})})},c=function(){var e=i("#"+f);o.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var i,t=e.contents().find("body");try{i=t.text()}catch(n){o.msg("获取上传后的响应信息出现异常"),clearInterval(p.timer),m()}i&&(clearInterval(p.timer),t.html(""),d(0,i))},30)},d=function(e,i){if(o.elemFile.next("."+s).remove(),r.value="","object"!=typeof i)try{i=JSON.parse(i)}catch(t){return i={},o.msg("请对上传接口返回有效JSON")}"function"==typeof l.done&&l.done(i,e||0,function(e){o.upload(e)})},m=function(e){l.auto&&(r.value=""),"function"==typeof l.error&&l.error(e||0,function(e){o.upload(e)})},h=l.exts,v=function(){var i=[];return layui.each(e||o.chooseFiles,function(e,t){i.push(t.name)}),i}(),g={preview:function(e){o.preview(e)},upload:function(e,i){var t={};t[e]=i,o.upload(t)},pushFile:function(){return o.files=o.files||{},layui.each(o.chooseFiles,function(e,i){o.files[e]=i}),o.files},resetFile:function(e,i,t){var n=new File([i],t);o.files=o.files||{},o.files[e]=n}},y=function(){if("choose"!==t&&!l.auto||(l.choose&&l.choose(g),"choose"!==t))return l.before&&l.before(g),a.ie?a.ie>9?u():c():void u()};if(v=0===v.length?r.value.match(/[^\/\\]+\..+/g)||[]||"":v,0!==v.length){switch(l.accept){case"file":if(h&&!RegExp("\\w\\.("+h+")$","i").test(escape(v)))return o.msg("选择的文件中包含不支持的格式"),r.value="";break;case"video":if(!RegExp("\\w\\.("+(h||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(v)))return o.msg("选择的视频中包含不支持的格式"),r.value="";break;case"audio":if(!RegExp("\\w\\.("+(h||"mp3|wav|mid")+")$","i").test(escape(v)))return o.msg("选择的音频中包含不支持的格式"),r.value="";break;default:if(layui.each(v,function(e,i){RegExp("\\w\\.("+(h||"jpg|png|gif|bmp|jpeg$")+")","i").test(escape(i))||(n=!0)}),n)return o.msg("选择的图片中包含不支持的格式"),r.value=""}if(o.fileLength=function(){var i=0,t=e||o.files||o.chooseFiles||r.files;return layui.each(t,function(){i++}),i}(),l.number&&o.fileLength>l.number)return o.msg("同时最多只能上传的数量为:"+l.number);if(l.size>0&&!(a.ie&&a.ie<10)){var F;if(layui.each(o.chooseFiles,function(e,i){if(i.size>1024*l.size){var t=l.size/1024;t=t>=1?t.toFixed(2)+"MB":l.size+"KB",r.value="",F=t}}),F)return o.msg("文件不能超过"+F)}y()}},p.prototype.events=function(){var e=this,t=e.config,o=function(i){e.chooseFiles={},layui.each(i,function(i,t){var n=(new Date).getTime();e.chooseFiles[n+"-"+i]=t})},l=function(i,n){var a=e.elemFile,o=i.length>1?i.length+"个文件":(i[0]||{}).name||a[0].value.match(/[^\/\\]+\..+/g)||[]||"";a.next().hasClass(s)&&a.next().remove(),e.upload(null,"choose"),e.isFile()||t.choose||a.after(''+o+"")};t.elem.off("upload.start").on("upload.start",function(){var a=i(this),o=a.attr("lay-data");if(o)try{o=new Function("return "+o)(),e.config=i.extend({},t,o)}catch(l){n.error("Upload element property lay-data configuration item has a syntax error: "+o)}e.config.item=a,e.elemFile[0].click()}),a.ie&&a.ie<10||t.elem.off("upload.over").on("upload.over",function(){var e=i(this);e.attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){var e=i(this);e.removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(n,a){var r=i(this),u=a.originalEvent.dataTransfer.files||[];r.removeAttr("lay-over"),o(u),t.auto?e.upload(u):l(u)}),e.elemFile.off("upload.change").on("upload.change",function(){var i=this.files||[];o(i),t.auto?e.upload():l(i)}),t.bindAction.off("upload.action").on("upload.action",function(){e.upload()}),t.elem.data("haveEvents")||(e.elemFile.on("change",function(){i(this).trigger("upload.change")}),t.elem.on("click",function(){e.isFile()||i(this).trigger("upload.start")}),t.drag&&t.elem.on("dragover",function(e){e.preventDefault(),i(this).trigger("upload.over")}).on("dragleave",function(e){i(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),i(this).trigger("upload.drop",e)}),t.bindAction.on("click",function(){i(this).trigger("upload.action")}),t.elem.data("haveEvents",!0))},o.render=function(e){var i=new p(e);return l.call(i)},e(r,o)}); -------------------------------------------------------------------------------- /public/lib/layui/lay/modules/slider.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var i=layui.jquery,t={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var t=this;return t.config=i.extend({},t.config,e),t},on:function(e,i){return layui.onevent.call(this,n,e,i)}},a=function(){var e=this,i=e.config;return{setValue:function(i,t){return e.slide("set",i,t||0)},config:i}},n="slider",l="layui-disabled",s="layui-slider",r="layui-slider-bar",o="layui-slider-wrap",u="layui-slider-wrap-btn",d="layui-slider-tips",v="layui-slider-input",c="layui-slider-input-txt",m="layui-slider-input-btn",p="layui-slider-hover",f=function(e){var a=this;a.index=++t.index,a.config=i.extend({},a.config,t.config,e),a.render()};f.prototype.config={type:"default",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,input:!1,range:!1,height:200,disabled:!1,theme:"#009688"},f.prototype.render=function(){var e=this,t=e.config;if(t.step<1&&(t.step=1),t.maxt.min?a:t.min,t.value[1]=n>t.min?n:t.min,t.value[0]=t.value[0]>t.max?t.max:t.value[0],t.value[1]=t.value[1]>t.max?t.max:t.value[1];var r=Math.floor((t.value[0]-t.min)/(t.max-t.min)*100),v=Math.floor((t.value[1]-t.min)/(t.max-t.min)*100),m=v-r+"%";r+="%",v+="%"}else{"object"==typeof t.value&&(t.value=Math.min.apply(null,t.value)),t.valuet.max&&(t.value=t.max);var m=Math.floor((t.value-t.min)/(t.max-t.min)*100)+"%"}var p=t.disabled?"#c2c2c2":t.theme,f='
    '+(t.tips?'
    ':"")+'
    '+(t.range?'
    ':"")+"
    ",h=i(t.elem),y=h.next("."+s);if(y[0]&&y.remove(),e.elemTemp=i(f),t.range?(e.elemTemp.find("."+o).eq(0).data("value",t.value[0]),e.elemTemp.find("."+o).eq(1).data("value",t.value[1])):e.elemTemp.find("."+o).data("value",t.value),h.html(e.elemTemp),"vertical"===t.type&&e.elemTemp.height(t.height+"px"),t.showstep){for(var g=(t.max-t.min)/t.step,b="",x=1;x
    ')}e.elemTemp.append(b)}if(t.input&&!t.range){var w=i('
    ');h.css("position","relative"),h.append(w),h.find("."+c).children("input").val(t.value),"vertical"===t.type?w.css({left:0,top:-48}):e.elemTemp.css("margin-right",w.outerWidth()+15)}t.disabled?(e.elemTemp.addClass(l),e.elemTemp.find("."+u).addClass(l)):e.slide(),e.elemTemp.find("."+u).on("mouseover",function(){var a="vertical"===t.type?t.height:e.elemTemp[0].offsetWidth,n=e.elemTemp.find("."+o),l="vertical"===t.type?a-i(this).parent()[0].offsetTop-n.height():i(this).parent()[0].offsetLeft,s=l/a*100,r=i(this).parent().data("value"),u=t.setTips?t.setTips(r):r;e.elemTemp.find("."+d).html(u),"vertical"===t.type?e.elemTemp.find("."+d).css({bottom:s+"%","margin-bottom":"20px",display:"inline-block"}):e.elemTemp.find("."+d).css({left:s+"%",display:"inline-block"})}).on("mouseout",function(){e.elemTemp.find("."+d).css("display","none")})},f.prototype.slide=function(e,t,a){var n=this,l=n.config,s=n.elemTemp,f=function(){return"vertical"===l.type?l.height:s[0].offsetWidth},h=s.find("."+o),y=s.next("."+v),g=y.children("."+c).children("input").val(),b=100/((l.max-l.min)/Math.ceil(l.step)),x=function(e,i){e=Math.ceil(e)*b>100?Math.ceil(e)*b:Math.round(e)*b,e=e>100?100:e,h.eq(i).css("vertical"===l.type?"bottom":"left",e+"%");var t=T(h[0].offsetLeft),a=l.range?T(h[1].offsetLeft):0;"vertical"===l.type?(s.find("."+d).css({bottom:e+"%","margin-bottom":"20px"}),t=T(f()-h[0].offsetTop-h.height()),a=l.range?T(f()-h[1].offsetTop-h.height()):0):s.find("."+d).css("left",e+"%"),t=t>100?100:t,a=a>100?100:a;var n=Math.min(t,a),o=Math.abs(t-a);"vertical"===l.type?s.find("."+r).css({height:o+"%",bottom:n+"%"}):s.find("."+r).css({width:o+"%",left:n+"%"});var u=l.min+Math.round((l.max-l.min)*e/100);if(g=u,y.children("."+c).children("input").val(g),h.eq(i).data("value",u),u=l.setTips?l.setTips(u):u,s.find("."+d).html(u),l.range){var v=[h.eq(0).data("value"),h.eq(1).data("value")];v[0]>v[1]&&v.reverse()}l.change&&l.change(l.range?v:u)},T=function(e){var i=e/f()*100/b,t=Math.round(i)*b;return e==f()&&(t=Math.ceil(i)*b),t},w=i(['
    f()&&(r=f());var o=r/f()*100/b;x(o,e),t.addClass(p),s.find("."+d).show(),i.preventDefault()},o=function(){t.removeClass(p),s.find("."+d).hide()};M(r,o)})}),s.on("click",function(e){var t=i("."+u);if(!t.is(event.target)&&0===t.has(event.target).length&&t.length){var a,n="vertical"===l.type?f()-e.clientY+i(this).offset().top:e.clientX-i(this).offset().left;n<0&&(n=0),n>f()&&(n=f());var s=n/f()*100/b;a=l.range?"vertical"===l.type?Math.abs(n-parseInt(i(h[0]).css("bottom")))>Math.abs(n-parseInt(i(h[1]).css("bottom")))?1:0:Math.abs(n-h[0].offsetLeft)>Math.abs(n-h[1].offsetLeft)?1:0:0,x(s,a),e.preventDefault()}}),y.hover(function(){var e=i(this);e.children("."+m).fadeIn("fast")},function(){var e=i(this);e.children("."+m).fadeOut("fast")}),y.children("."+m).children("i").each(function(e){i(this).on("click",function(){g=1==e?g-l.stepl.max?l.max:Number(g)+l.step;var i=(g-l.min)/(l.max-l.min)*100/b;x(i,0)})});var q=function(){var e=this.value;e=isNaN(e)?0:e,e=el.max?l.max:e,this.value=e;var i=(e-l.min)/(l.max-l.min)*100/b;x(i,0)};y.children("."+c).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),q.call(this))}).on("change",q)},f.prototype.events=function(){var e=this;e.config},t.render=function(e){var i=new f(e);return a.call(i)},e(n,t)}); --------------------------------------------------------------------------------