314 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			314 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
<?php
 | 
						||
declare (strict_types=1);
 | 
						||
 | 
						||
namespace app\command;
 | 
						||
 | 
						||
use think\console\Command;
 | 
						||
use think\console\Input;
 | 
						||
use think\console\input\Option;
 | 
						||
use think\console\Output;
 | 
						||
use think\facade\Db;
 | 
						||
 | 
						||
class Generate extends Command
 | 
						||
{
 | 
						||
    protected string $controller;
 | 
						||
    protected string $name;
 | 
						||
    protected string $title;
 | 
						||
 | 
						||
    protected string $namespace;//控制器命名空间
 | 
						||
    protected string $viewDir;//view目录
 | 
						||
    protected string $jsFullDir;//js完整路径目录
 | 
						||
    protected string $jsDir;//js相对路径目录
 | 
						||
    protected string $controllerFullPath;//控制器完整路径
 | 
						||
    protected string $className;//控制器类名
 | 
						||
 | 
						||
    protected function configure()
 | 
						||
    {
 | 
						||
        // 指令配置
 | 
						||
        $this->setName('generate')
 | 
						||
            ->setDescription('生成后台基础crud')
 | 
						||
            ->addOption('title', 't', Option::VALUE_REQUIRED, '标题')
 | 
						||
            ->addOption('name', null, Option::VALUE_REQUIRED, '权限标识')
 | 
						||
            ->addOption('controller', null, Option::VALUE_REQUIRED, '控制器命名空间');
 | 
						||
    }
 | 
						||
 | 
						||
    protected function setInfo(string $controller, string $name, string $title)
 | 
						||
    {
 | 
						||
        $this->name       = $name;
 | 
						||
        $this->controller = $controller;
 | 
						||
        $this->title      = $title;
 | 
						||
 | 
						||
        $this->controllerFullPath = $this->getControllerPathName();
 | 
						||
        $this->viewDir            = $this->getViewDirName();
 | 
						||
        $this->jsFullDir          = $this->getJsFullDirName();
 | 
						||
        $this->jsDir              = $this->getJsDirName();
 | 
						||
 | 
						||
        $controllerPath  = explode('/', trim($controller, '/'));
 | 
						||
        $this->className = $controllerPath[count($controllerPath) - 1];
 | 
						||
 | 
						||
        $namespace       = 'app\\controller\\'.implode('\\', array_slice($controllerPath, 0, count($controllerPath) - 1));
 | 
						||
        $this->namespace = $namespace;
 | 
						||
    }
 | 
						||
 | 
						||
    protected function execute(Input $input, Output $output)
 | 
						||
    {
 | 
						||
        $title      = $input->getOption('title') ? trim($input->getOption('title')) : '';
 | 
						||
        $name       = $input->getOption('name') ? trim($input->getOption('name')) : '';
 | 
						||
        $controller = $input->getOption('controller') ? trim($input->getOption('controller')) : '';
 | 
						||
 | 
						||
        $this->setInfo($controller, $name, $title);
 | 
						||
        try {
 | 
						||
            $output->writeln('开始创建');
 | 
						||
            $output->writeln('1.菜单表生成数据...');
 | 
						||
            $dbRes = $this->createDb([
 | 
						||
                'title' => $title, 'name' => $name, 'controller' => $controller
 | 
						||
            ]);
 | 
						||
 | 
						||
            $successList = [];
 | 
						||
 | 
						||
            if ($dbRes) {
 | 
						||
                $output->info('菜单表数据生成成功!');
 | 
						||
                $successList[] = '菜单数据生成!';
 | 
						||
            } else {
 | 
						||
                $output->warning('菜单表数据生成失败');
 | 
						||
            }
 | 
						||
 | 
						||
            $output->writeln('2.生成控制器...');
 | 
						||
            if (is_file($this->controllerFullPath)) {
 | 
						||
                $output->error('控制器: '.$controller.' 已存在!');
 | 
						||
            }
 | 
						||
 | 
						||
            if (!is_dir(dirname($this->controllerFullPath))) {
 | 
						||
                mkdir(dirname($this->controllerFullPath), 0755, true);
 | 
						||
            }
 | 
						||
 | 
						||
            // 生成控制器
 | 
						||
            file_put_contents($this->controllerFullPath, $this->buildController());
 | 
						||
            $output->info($this->controllerFullPath.' 控制器生成成功!');
 | 
						||
            $successList[] = '创建文件:'.$this->controllerFullPath;
 | 
						||
 | 
						||
            $output->writeln('3.生成视图文件...');
 | 
						||
            if (!is_dir($this->viewDir)) {
 | 
						||
                mkdir($this->viewDir, 0755, true);
 | 
						||
            }
 | 
						||
 | 
						||
            foreach (['index', 'add', 'edit'] as $action) {
 | 
						||
                $actionHtml = sprintf('%s/%s.html', $this->viewDir, $action);
 | 
						||
 | 
						||
                if (is_file($actionHtml)) {
 | 
						||
                    $output->error($actionHtml.' 视图文件已存在!');
 | 
						||
                }
 | 
						||
 | 
						||
                file_put_contents($actionHtml, $this->buildView($action));
 | 
						||
                $output->info($actionHtml.' 文件创建成功');
 | 
						||
                $successList[] = '创建文件:'.$actionHtml;
 | 
						||
            }
 | 
						||
 | 
						||
            $output->info('视图文件生成成功!');
 | 
						||
 | 
						||
            $jsPath = sprintf('%s/%s.js', $this->jsFullDir, unCamelize($this->className, '_'));
 | 
						||
            $output->writeln('4.生成js文件...');
 | 
						||
            if (!is_dir($this->jsFullDir)) {
 | 
						||
                mkdir($this->jsFullDir, 0755, true);
 | 
						||
            }
 | 
						||
 | 
						||
            file_put_contents($jsPath, $this->buildJs());
 | 
						||
            $output->info($jsPath.' js文件创建成功!');
 | 
						||
            $successList[] = '创建文件:'.$jsPath;
 | 
						||
 | 
						||
            $output->newLine();
 | 
						||
            $output->writeln('信息汇总');
 | 
						||
            // 汇总信息
 | 
						||
            foreach ($successList as $success) {
 | 
						||
                $output->info($success);
 | 
						||
            }
 | 
						||
 | 
						||
            $output->newLine();
 | 
						||
            $output->info(sprintf('此时可访问路径查看是否创建成功 /%s/index', unCamelize($controller)));
 | 
						||
            $output->newLine();
 | 
						||
            $output->warning('请注意,控制器中 $noNeedRight 默认开启了所有权限,如需纳入权限控制,请删除并在角色中选择对应权限');
 | 
						||
 | 
						||
            // 指令输出
 | 
						||
            $output->info('创建完成');
 | 
						||
        } catch (\Exception $e) {
 | 
						||
            $output->error($e->getMessage());
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 构建控制器内容
 | 
						||
     *
 | 
						||
     * @return array|false|string|string[]
 | 
						||
     */
 | 
						||
    protected function buildController()
 | 
						||
    {
 | 
						||
        $controllerStubPath = __DIR__.DIRECTORY_SEPARATOR.'stubs/controller.stub';
 | 
						||
        $stub               = file_get_contents($controllerStubPath);
 | 
						||
 | 
						||
        return str_replace(['{%className%}', '{%namespace%}'], [
 | 
						||
            $this->className,
 | 
						||
            $this->namespace,
 | 
						||
        ], $stub);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 构建视图文件内容
 | 
						||
     *
 | 
						||
     * @param  string  $action
 | 
						||
     * @return array|false|string|string[]
 | 
						||
     */
 | 
						||
    protected function buildView(string $action)
 | 
						||
    {
 | 
						||
        $actionStubPath = __DIR__.DIRECTORY_SEPARATOR.'stubs/'.$action.'.stub';
 | 
						||
        $stub           = file_get_contents($actionStubPath);
 | 
						||
 | 
						||
        return str_replace(['{%path%}', '{%jsPath%}'], [
 | 
						||
            '/'.unCamelize($this->controller),
 | 
						||
            $this->jsDir.'/'.unCamelize($this->className, '_').'.js',
 | 
						||
        ], $stub);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 构建js文件内容
 | 
						||
     *
 | 
						||
     * @return false|string
 | 
						||
     */
 | 
						||
    protected function buildJs()
 | 
						||
    {
 | 
						||
        $actionStubPath = __DIR__.DIRECTORY_SEPARATOR.'stubs/js.stub';
 | 
						||
        return file_get_contents($actionStubPath);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取控制器完整路径
 | 
						||
     *
 | 
						||
     * @return string
 | 
						||
     */
 | 
						||
    protected function getControllerPathName(): string
 | 
						||
    {
 | 
						||
        return $this->app->getBasePath().'controller/'.ltrim(str_replace('\\', '/', $this->controller), '/').'.php';
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取对应view完整目录
 | 
						||
     *
 | 
						||
     * @return string
 | 
						||
     */
 | 
						||
    protected function getViewDirName(): string
 | 
						||
    {
 | 
						||
        return $this->app->getRootPath().'view/'.ltrim(unCamelize($this->controller, '_'), '/');
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取对应js完整目录
 | 
						||
     *
 | 
						||
     * @return string
 | 
						||
     */
 | 
						||
    protected function getJsFullDirName(): string
 | 
						||
    {
 | 
						||
        $dir = $this->app->getRootPath().'public/static/'.ltrim(unCamelize($this->controller, '_'), '/');
 | 
						||
        return str_replace('/manager/', '/manager/js/', $dir);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取对应js相对目录
 | 
						||
     *
 | 
						||
     * @return string
 | 
						||
     */
 | 
						||
    protected function getJsDirName(): string
 | 
						||
    {
 | 
						||
        return explode('/manager/', $this->jsFullDir)[1] ?? '';
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 自动添加菜单表数据
 | 
						||
     *
 | 
						||
     * @param  array  $data
 | 
						||
     * @return bool
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function createDb(array $data): bool
 | 
						||
    {
 | 
						||
        $menuTable = 'menu';
 | 
						||
        $now       = date('Y-m-d H:i:s');
 | 
						||
 | 
						||
        if (!isset($data['title']) || !isset($data['name']) || !isset($data['controller'])) {
 | 
						||
            throw new \Exception('参数错误 请添加:--title 标题 --name 权限标识,如aaa/bbb --controller 控制器 如manager/aaa/Bbb');
 | 
						||
        }
 | 
						||
 | 
						||
        if (empty($data['title']) || empty($data['name']) || empty($data['controller'])) {
 | 
						||
            throw new \Exception('参数错误 请添加:--title 标题 --name 权限标识,如aaa/bbb --controller 控制器 如manager/aaa/Bbb');
 | 
						||
        }
 | 
						||
 | 
						||
        // 检查权限标识是否已存在
 | 
						||
        $already = Db::name('menu')->where('name', $data['name'])->whereOr('title', $data['title'])->count();
 | 
						||
        if ($already) {
 | 
						||
            throw new \Exception('菜单名称或标识已存在');
 | 
						||
        }
 | 
						||
 | 
						||
        $href         = unCamelize($data['controller']);
 | 
						||
        $insertMaster = [
 | 
						||
            'pid'        => 0,
 | 
						||
            'title'      => $data['title'], //名称
 | 
						||
            'icon'       => $data['icon'] ?? 'fa-align-justify', //菜单图标
 | 
						||
            'name'       => $data['name'], //权限标识
 | 
						||
            'href'       => $href.'/index',//链接
 | 
						||
            'type'       => 'menu',
 | 
						||
            'is_show'    => 1,
 | 
						||
            'status'     => 1,
 | 
						||
            'remark'     => 'command generate',
 | 
						||
            'created_at' => $now,
 | 
						||
        ];
 | 
						||
 | 
						||
        $masterId = Db::name($menuTable)->insertGetId($insertMaster);
 | 
						||
 | 
						||
        $masterPath = sprintf(',0,%d,', $masterId);
 | 
						||
        Db::name($menuTable)->where('id', $masterId)->update([
 | 
						||
            'path' => $masterPath
 | 
						||
        ]);
 | 
						||
 | 
						||
        $insertName = trim($data['name'], '/');
 | 
						||
        $insertHref = '/'.trim($href, '/');
 | 
						||
 | 
						||
        $actionArr = $this->actionList();
 | 
						||
 | 
						||
        // 基于权限标识生成下级列表 默认index add del edit modify
 | 
						||
        $insertAll = [];
 | 
						||
        foreach (array_keys($actionArr) as $action) {
 | 
						||
            $insertAll[] = [
 | 
						||
                'pid'        => $masterId,
 | 
						||
                'title'      => $actionArr[$action]['title'], //名称
 | 
						||
                'icon'       => '', //菜单图标
 | 
						||
                'name'       => $insertName.':'.$action, //权限标识
 | 
						||
                'href'       => $insertHref.'/'.$action,//链接
 | 
						||
                'type'       => 'action',
 | 
						||
                'is_show'    => 1,
 | 
						||
                'status'     => 1,
 | 
						||
                'remark'     => 'command generate',
 | 
						||
                'path'       => $masterPath,//此时的path为负极path
 | 
						||
                'created_at' => $now,
 | 
						||
            ];
 | 
						||
        }
 | 
						||
 | 
						||
        // 插入自己菜单
 | 
						||
        Db::name($menuTable)->insertAll($insertAll);
 | 
						||
 | 
						||
        // 批量更新自己菜单path
 | 
						||
        Db::execute("update bee_$menuTable set `path`=concat(`path`, `id`, ',') where pid=$masterId");
 | 
						||
 | 
						||
        return true;
 | 
						||
    }
 | 
						||
 | 
						||
    protected function actionList(): array
 | 
						||
    {
 | 
						||
        return [
 | 
						||
            'index'  => ['title' => '查看'],
 | 
						||
            'add'    => ['title' => '添加'],
 | 
						||
            'edit'   => ['title' => '编辑'],
 | 
						||
            'del'    => ['title' => '删除'],
 | 
						||
            'modify' => ['title' => '属性设置'],
 | 
						||
            'sort'   => ['title' => '排序'],
 | 
						||
        ];
 | 
						||
    }
 | 
						||
}
 |