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' => '排序'],
|
||
];
|
||
}
|
||
}
|