feat: 发布智能体版

This commit is contained in:
augushong
2026-03-26 20:22:34 +08:00
parent 7ee9e102a5
commit 8cc08bcb8c
138 changed files with 7964 additions and 660 deletions

View File

@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace base\common\command\admin;
use think\console\Command;
use app\common\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\App;
@@ -13,6 +13,8 @@ class ClearBase extends Command
{
protected function configure()
{
parent::configure();
// 指令配置
$this->setName('admin:clear')
->setDescription('删除开发临时生成目录');
@@ -20,31 +22,34 @@ class ClearBase extends Command
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->writeln('删除测试目录');
$dir = App::getRootPath() . '/runtime/source/';
$deleted = false;
$message = '';
$command_line = '';
$dir = App::getRootPath() . '/runtime/source/';
if (!is_dir($dir)) {
$output->writeln('删除成功');
return;
}
if (strpos(strtolower(PHP_OS), 'win') === 0) {
$command_line = implode(' ', ['rd', '/s', '/q', str_replace('/', '\\', $dir)]);
$deleted = true;
$message = '目录不存在,无需删除';
} else {
$command_line = implode(' ', ['rm', '-rf', $dir]);
if (strpos(strtolower(PHP_OS), 'win') === 0) {
$command_line = implode(' ', ['rd', '/s', '/q', str_replace('/', '\\', $dir)]);
} else {
$command_line = implode(' ', ['rm', '-rf', $dir]);
}
exec($command_line);
$deleted = !is_dir($dir);
$message = $deleted ? '删除成功' : '删除失败';
}
$output->info('删除目录:' . $command_line);
// 文本模式输出
$output->writeln('删除测试目录');
if ($command_line) {
$output->info('删除目录:' . $command_line);
$output->info('run command: ' . $command_line);
}
$output->info($message);
$output->info('run command: ' . $command_line);
exec($command_line);
$output->info('删除成功');
return $deleted ? 0 : 1;
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace base\common\command\admin;
use app\admin\service\AdminUpdateService;
use think\console\Command;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
@@ -17,11 +17,13 @@ class UpdateBase extends Command
protected function configure()
{
parent::configure();
// 指令配置
$this->setName('admin:update')
->addOption('reinstall', null, Option::VALUE_NONE, '重装版本')
->addOption('update-ulthon', null, Option::VALUE_NONE, '重装版本')
->setDescription('the admin:update command');
->addOption('update-ulthon', null, Option::VALUE_NONE, '更新 ulthon_admin')
->setDescription('更新系统代码');
}
protected function execute(Input $input, Output $output)
@@ -38,6 +40,7 @@ class UpdateBase extends Command
$update_service = new AdminUpdateService($repo);
$update_service->input = $input;
$update_service->output = $output;
$update_service->update();
}
}

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace base\common\command\admin;
use app\common\console\Command;
use app\common\tools\PathTools;
use think\App as ThinkApp;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
@@ -85,6 +85,8 @@ class VersionBase extends Command
protected function configure()
{
parent::configure();
// 指令配置
$this->setName('admin:version')
->addOption('generate-comment', null, Option::VALUE_NONE, '使用git命令生成说明文件')
@@ -96,6 +98,7 @@ class VersionBase extends Command
protected function execute(Input $input, Output $output)
{
// 文本模式输出
// 指令输出
if (!empty(static::PRODUCT_VERSION)) {
$output->info('当前版本号为:' . static::PRODUCT_VERSION);

View File

@@ -0,0 +1,106 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\menu;
use app\admin\model\SystemMenu;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
/**
* admin:menu:create command - 创建菜单
*/
class AdminMenuCreateBase extends Command
{
protected function configure()
{
parent::configure();
// 命令配置
$this->setName('admin:menu:create')
->addOption('title', null, Option::VALUE_REQUIRED, '菜单标题(必填)')
->addOption('path', null, Option::VALUE_OPTIONAL, '菜单路径', '')
->addOption('icon', null, Option::VALUE_OPTIONAL, '菜单图标', '')
->addOption('parent-id', null, Option::VALUE_OPTIONAL, '父菜单ID默认为0', 0)
->addOption('sort', null, Option::VALUE_OPTIONAL, '排序默认为100', 100)
->addOption('node', null, Option::VALUE_OPTIONAL, '权限节点', '')
->addOption('remark', null, Option::VALUE_OPTIONAL, '备注说明', '')
->setDescription('创建菜单');
}
protected function execute(Input $input, Output $output)
{
// 获取参数
$title = $input->getOption('title');
$path = $input->getOption('path');
$icon = $input->getOption('icon');
$parentId = $input->getOption('parent-id');
$sort = $input->getOption('sort');
$node = $input->getOption('node');
$remark = $input->getOption('remark');
// 验证必填参数
if (empty($title)) {
$output->error('菜单标题不能为空');
return false;
}
try {
// 准备菜单数据
$menuData = [
'title' => $title,
'path' => $path,
'icon' => $icon,
'parent_id' => (int)$parentId,
'sort' => (int)$sort,
'node' => $node,
'remark' => $remark,
];
// 实例化菜单服务(使用 app\admin\service\MenuService它继承自 base\common\service\MenuServiceBase
// 由于 MenuServiceBase 需要 adminId 参数,我们使用 0 表示命令行操作
$menuService = new \app\common\service\MenuService(0);
// 创建菜单
$menuId = $menuService->create($menuData);
// 获取创建的菜单详情
$menuModel = SystemMenu::find($menuId);
$menu = $menuModel ? $menuModel->toArray() : null;
if (empty($menu)) {
throw new \Exception('菜单创建成功,但无法获取菜单详情');
}
$outputData = [
'id' => (int)$menu['id'],
'title' => $menu['title'] ?? '',
'path' => $menu['href'] ?? '',
'icon' => $menu['icon'] ?? '',
'parent_id' => (int)($menu['pid'] ?? 0),
'sort' => (int)($menu['sort'] ?? 0),
'node' => $menu['auth_node'] ?? '',
];
// 输出结果
$output->info('菜单创建成功');
$output->info('菜单ID: ' . $outputData['id']);
$output->info('菜单标题: ' . $outputData['title']);
$output->info('菜单路径: ' . $outputData['path']);
$output->info('菜单图标: ' . $outputData['icon']);
$output->info('父菜单ID: ' . $outputData['parent_id']);
$output->info('排序: ' . $outputData['sort']);
if (!empty($outputData['node'])) {
$output->info('权限节点: ' . $outputData['node']);
}
} catch (\Throwable $e) {
$output->error('创建菜单失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\menu;
use app\admin\model\SystemMenu;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
/**
* admin:menu:delete command - 删除菜单
*/
class AdminMenuDeleteBase extends Command
{
protected function configure()
{
parent::configure();
// 指令配置
$this->setName('admin:menu:delete')
->addOption('id', null, Option::VALUE_REQUIRED, '菜单ID')
->setDescription('删除菜单');
}
protected function execute(Input $input, Output $output)
{
// 获取参数
$id = $input->getOption('id');
// 验证参数
if (empty($id)) {
$output->error('菜单ID不能为空');
return false;
}
try {
// 1. 验证菜单是否存在
$menu = SystemMenu::find($id);
if (empty($menu)) {
$output->error('菜单ID ' . $id . ' 不存在');
return false;
}
// 2. 检查是否有子菜单
$childCount = SystemMenu::where('pid', $id)
->where('delete_time', 0)
->count();
if ($childCount > 0) {
$output->error('菜单ID ' . $id . ' 存在 ' . $childCount . ' 个子菜单,请先删除子菜单');
return false;
}
// 3. 保存菜单信息用于输出
$menuInfo = [
'id' => (int)$menu->id,
'title' => $menu->title,
'path' => $menu->href ?? '',
'icon' => $menu->icon ?? '',
'parent_id' => (int)($menu->pid ?? 0),
'sort' => (int)($menu->sort ?? 0),
'node' => $menu->auth_node ?? '',
];
// 4. 执行删除(软删除)
$menu->delete();
// 5. 输出结果
$output->info('菜单删除成功');
$output->info('菜单ID: ' . $menuInfo['id']);
$output->info('菜单名称: ' . $menuInfo['title']);
$output->info('菜单路径: ' . $menuInfo['path']);
} catch (\Throwable $e) {
$output->error('删除菜单失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,127 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\menu;
use app\admin\model\SystemMenu;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
/**
* admin:menu:export command - 导出菜单
*/
class AdminMenuExportBase extends Command
{
protected function configure()
{
parent::configure();
// 指令配置
$this->setName('admin:menu:export')
->setDescription('导出菜单数据')
->addOption('format', null, Option::VALUE_OPTIONAL, '输出格式text/json', 'text')
->addOption('output', null, Option::VALUE_OPTIONAL, '输出文件路径(可选)');
}
protected function execute(Input $input, Output $output)
{
// 获取参数
$outputPath = $input->getOption('output');
try {
// 1. 查询所有菜单
$menus = SystemMenu::where('delete_time', 0)
->order(['sort' => 'desc', 'id' => 'asc'])
->select()
->hidden(['create_time', 'update_time', 'delete_time']);
// 2. 格式化菜单数据
$menuData = [];
foreach ($menus as $menu) {
$menuData[] = [
'id' => (int)$menu->id,
'pid' => (int)($menu->pid ?? 0),
'title' => $menu->title ?? '',
'href' => $menu->href ?? '',
'icon' => $menu->icon ?? '',
'sort' => (int)($menu->sort ?? 0),
'auth_node' => $menu->auth_node ?? '',
'status' => (int)($menu->status ?? 0),
'type' => (int)($menu->type ?? 0),
];
}
// JSON 模式输出
if ($input->getOption('format') === 'json') {
if (!empty($outputPath)) {
$jsonData = json_encode($menuData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
if ($jsonData === false) {
throw new \RuntimeException('JSON 编码失败');
}
$result = file_put_contents($outputPath, $jsonData);
if ($result === false) {
throw new \RuntimeException('无法写入文件: ' . $outputPath);
}
}
$json = json_encode([
'success' => true,
'data' => [
'menus' => $menuData,
'output' => !empty($outputPath) ? $outputPath : null,
],
'warnings' => [],
'metadata' => [
'count' => count($menuData),
'exported_at' => date('c'),
],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$output->writeln($json);
return true;
}
// 3. 如果指定了输出路径,写入文件
if (!empty($outputPath)) {
$jsonData = json_encode($menuData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
$result = file_put_contents($outputPath, $jsonData);
if ($result === false) {
$output->error('无法写入文件: ' . $outputPath);
return false;
}
$output->info('成功导出 ' . count($menuData) . ' 个菜单到文件: ' . $outputPath);
} else {
// 4. 输出结果到控制台
$output->info('成功导出 ' . count($menuData) . ' 个菜单');
// 以表格形式输出菜单数据
$output->writeln('菜单ID | 父菜单ID | 菜单标题 | 菜单路径 | 图标 | 排序 | 权限节点 | 状态 | 类型');
$output->writeln('--------|----------|----------|----------|------|------|----------|------|------');
foreach ($menuData as $menu) {
$output->writeln($menu['id'] . ' | ' .
$menu['pid'] . ' | ' .
$menu['title'] . ' | ' .
$menu['href'] . ' | ' .
$menu['icon'] . ' | ' .
$menu['sort'] . ' | ' .
$menu['auth_node'] . ' | ' .
$menu['status'] . ' | ' .
$menu['type']);
}
}
} catch (\Throwable $e) {
$output->error('导出菜单失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\menu;
use app\admin\model\SystemMenu;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminMenuListBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:menu:list')
->setDescription('列出所有菜单(树形结构)')
->addOption('format', null, Option::VALUE_OPTIONAL, '输出格式tree/table/json', 'tree')
->addOption('status', null, Option::VALUE_OPTIONAL, '筛选状态0=禁用1=启用all=全部)', 'all')
->addOption('pid', null, Option::VALUE_OPTIONAL, '指定父菜单ID默认从根菜单开始', null);
}
protected function execute(Input $input, Output $output)
{
$format = $input->getOption('format');
$statusFilter = $input->getOption('status');
$pidFilter = $input->getOption('pid');
try {
$query = SystemMenu::where('delete_time', 0);
if ($statusFilter !== 'all') {
$query->where('status', (int)$statusFilter);
}
$menus = $query->order(['sort' => 'desc', 'id' => 'asc'])
->select()
->toArray();
if (empty($menus)) {
$output->comment('没有找到菜单数据');
return true;
}
$menuTree = $this->buildTree($menus, $pidFilter ? (int)$pidFilter : 0);
switch ($format) {
case 'json':
$this->outputJson($output, $menuTree, count($menus));
break;
case 'table':
$this->outputTable($output, $menus);
break;
case 'tree':
default:
$this->outputTree($output, $menuTree);
break;
}
} catch (\Throwable $e) {
$output->error('获取菜单列表失败: ' . $e->getMessage());
return false;
}
return true;
}
protected function buildTree(array $menus, int $pid = 0): array
{
$tree = [];
foreach ($menus as $menu) {
if ((int)$menu['pid'] === $pid) {
$children = $this->buildTree($menus, (int)$menu['id']);
if (!empty($children)) {
$menu['children'] = $children;
}
$tree[] = $menu;
}
}
return $tree;
}
protected function outputTree(Output $output, array $tree, int $level = 0): void
{
$prefix = str_repeat(' ', $level);
$branch = $level > 0 ? '├─ ' : '';
foreach ($tree as $node) {
$status = $node['status'] ? '<info>●</info>' : '<comment>○</comment>';
$href = $node['href'] ?? '-';
$output->writeln("{$prefix}{$branch}{$status} [{$node['id']}] {$node['title']} <comment>({$href})</comment>");
if (!empty($node['children'])) {
$this->outputTree($output, $node['children'], $level + 1);
}
}
}
protected function outputTable(Output $output, array $menus): void
{
$output->writeln('ID | PID | 标题 | 路径 | 状态');
$output->writeln('---|-----|------|------|------');
foreach ($menus as $menu) {
$status = $menu['status'] ? '启用' : '禁用';
$output->writeln(sprintf(
'%d | %d | %s | %s | %s',
$menu['id'],
$menu['pid'],
$menu['title'],
$menu['href'] ?? '-',
$status
));
}
$output->writeln('');
$output->info('共 ' . count($menus) . ' 个菜单');
}
protected function outputJson(Output $output, array $tree, int $total): void
{
$data = [
'success' => true,
'data' => ['menus' => $tree],
'metadata' => ['total' => $total],
];
$output->writeln(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
}
}

View File

@@ -0,0 +1,129 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\menu;
use app\admin\model\SystemMenu;
use app\common\console\Command;
use app\common\service\MenuService;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
/**
* admin:menu:update command - 更新菜单
*/
class AdminMenuUpdateBase extends Command
{
protected function configure()
{
parent::configure();
// 指令配置
$this->setName('admin:menu:update')
->addOption('id', null, Option::VALUE_REQUIRED, '菜单ID必填')
->addOption('title', null, Option::VALUE_OPTIONAL, '菜单标题')
->addOption('path', null, Option::VALUE_OPTIONAL, '菜单路径')
->addOption('icon', null, Option::VALUE_OPTIONAL, '菜单图标')
->addOption('parent-id', null, Option::VALUE_OPTIONAL, '父级菜单ID')
->addOption('sort', null, Option::VALUE_OPTIONAL, '排序')
->setDescription('编辑菜单');
}
protected function execute(Input $input, Output $output)
{
// 获取参数
$id = (int)($input->getOption('id') ?? 0);
$title = $input->getOption('title');
$path = $input->getOption('path');
$icon = $input->getOption('icon');
$parentId = $input->getOption('parent-id');
$sort = $input->getOption('sort');
// 验证参数id 是必填的
if (empty($id)) {
$output->error('菜单ID不能为空');
return false;
}
try {
// 1. 验证菜单是否存在
$menu = SystemMenu::find($id);
if (empty($menu)) {
$output->writeln('<error>菜单ID ' . $id . ' 不存在</error>');
return false;
}
// 2. 准备更新数据
$updateData = [];
if ($title !== null) {
$updateData['title'] = $title;
}
if ($path !== null) {
$updateData['path'] = $path;
}
if ($icon !== null) {
$updateData['icon'] = $icon;
}
if ($parentId !== null) {
$updateData['parent_id'] = (int)$parentId;
}
if ($sort !== null) {
$updateData['sort'] = (int)$sort;
}
// 检查是否有需要更新的字段
if (empty($updateData)) {
$output->error('没有提供需要更新的字段');
return false;
}
// 3. 调用 MenuService 更新菜单
$menuService = new MenuService(0);
$success = $menuService->update($id, $updateData);
if (!$success) {
$output->writeln('<error>菜单更新失败</error>');
return false;
}
// 4. 重新查询菜单数据
$updatedMenu = SystemMenu::find($id);
if (empty($updatedMenu)) {
$output->writeln('<error>菜单更新后查询失败</error>');
return false;
}
$outputData = [
'id' => (int)$updatedMenu->id,
'title' => $updatedMenu->title ?? '',
'path' => $updatedMenu->href ?? '',
'icon' => $updatedMenu->icon ?? '',
'parent_id' => (int)($updatedMenu->pid ?? 0),
'sort' => (int)($updatedMenu->sort ?? 0),
'node' => $updatedMenu->auth_node ?? '',
];
// 5. 输出结果
$output->writeln('<info>菜单编辑成功</info>');
$output->writeln('<info>菜单ID: ' . $outputData['id'] . '</info>');
$output->writeln('<info>菜单标题: ' . $outputData['title'] . '</info>');
$output->writeln('<info>菜单路径: ' . $outputData['path'] . '</info>');
$output->writeln('<info>菜单图标: ' . $outputData['icon'] . '</info>');
$output->writeln('<info>父级菜单ID: ' . $outputData['parent_id'] . '</info>');
$output->writeln('<info>排序: ' . $outputData['sort'] . '</info>');
} catch (\Throwable $e) {
$output->error('编辑菜单失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\permission;
use app\common\console\Command;
use think\console\Input;
use think\console\Input\Option;
use think\console\Output;
use app\admin\service\NodeService;
/**
* admin:permission:nodes command - 查看权限节点
*/
class AdminPermissionNodesBase extends Command
{
/**
* 配置命令参数
*/
protected function configure()
{
parent::configure();
// 指令配置
$this->setName('admin:permission:nodes')
->setDescription('查看权限节点')
->addOption('level', null, Option::VALUE_OPTIONAL, '按级别过滤 (1=控制器, 2=方法)')
->addOption('module', null, Option::VALUE_OPTIONAL, '按模块过滤');
}
/**
* 执行命令
*
* @param Input $input
* @param Output $output
* @return int
* @throws \Doctrine\Common\Annotations\AnnotationException
* @throws \ReflectionException
*/
protected function execute(Input $input, Output $output)
{
try {
// 获取所有权限节点
$nodeService = new NodeService();
$nodeList = $nodeService->getNodelist();
// 过滤条件
$filterLevel = $input->getOption('level');
$filterModule = $input->getOption('module');
// 应用过滤
$filteredNodes = $nodeList;
if ($filterLevel !== null) {
$level = (int)$filterLevel;
$filteredNodes = array_filter($filteredNodes, function ($node) use ($level) {
return isset($node['type']) && $node['type'] === $level;
});
}
if ($filterModule !== null) {
$filteredNodes = array_filter($filteredNodes, function ($node) use ($filterModule) {
return isset($node['module']) && $node['module'] === $filterModule;
});
}
// 重新索引数组
$filteredNodes = array_values($filteredNodes);
// 输出表头
$output->info('权限节点列表');
$output->writeln('================================');
if (empty($filteredNodes)) {
$output->comment('没有找到符合条件的权限节点');
return 0;
}
// 输出权限节点信息
foreach ($filteredNodes as $node) {
$levelText = $node['type'] == 1 ? '控制器' : '方法';
$authText = isset($node['auth']) && $node['auth'] ? '是' : '否';
$output->info('节点: ' . ($node['node'] ?? ''));
$output->comment(' 标题: ' . ($node['title'] ?? ''));
$output->comment(' 级别: ' . $levelText . ' (' . ($node['type'] ?? 0) . ')');
$output->comment(' 模块: ' . ($node['module'] ?? ''));
$output->comment(' 需要授权: ' . $authText);
$output->writeln('--------------------------------');
}
$output->info('总计: ' . count($filteredNodes) . ' 个权限节点');
} catch (\Exception $e) {
$output->error('获取权限节点失败: ' . $e->getMessage());
return 1;
}
}
}

View File

@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\permission;
use app\admin\model\SystemAdmin;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\admin\service\NodeService;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
class AdminPermissionUserBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:permission:user')
->addOption('user-id', 'u', Option::VALUE_OPTIONAL, '用户ID', null)
->setDescription('查看用户权限');
}
protected function execute(Input $input, Output $output)
{
$userId = $input->getOption('user-id');
// 验证用户ID参数
if (empty($userId)) {
$output->error('缺少必要参数 --user-id');
return;
}
// 查询用户
$user = SystemAdmin::find($userId);
if (empty($user)) {
$output->error('用户不存在');
return;
}
// 查询用户角色
$roles = [];
$authIds = $user->auth_ids;
$authIdArray = [];
if (!empty($authIds)) {
$authIdArray = array_filter(explode(',', $authIds));
if (!empty($authIdArray)) {
$roles = SystemAuth::whereIn('id', $authIdArray)
->where('delete_time', 0)
->field('id,title')
->select()
->toArray();
}
}
// 查询用户权限节点
$nodes = [];
if (!empty($authIdArray)) {
$nodes = SystemAuthNode::whereIn('auth_id', $authIdArray)
->column('node');
}
// 输出结果
$output->info('用户权限信息');
$output->info('用户ID: ' . $user->id);
$output->info('用户名: ' . $user->username);
if (!empty($roles)) {
$output->info('角色列表:');
foreach ($roles as $role) {
$output->comment(' - ID: ' . $role['id'] . ', 标题: ' . $role['title']);
}
} else {
$output->comment('用户没有分配任何角色');
}
if (!empty($nodes)) {
$output->info('权限节点列表:');
foreach ($nodes as $node) {
$output->comment(' - ' . $node);
}
} else {
$output->comment('用户没有分配任何权限节点');
}
return;
}
}

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\role;
use app\admin\model\SystemAuth;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminRoleCreateBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:role:create')
->addOption('title', null, Option::VALUE_REQUIRED, '角色名称')
->addOption('remark', null, Option::VALUE_OPTIONAL, '角色备注')
->setDescription('创建角色');
}
protected function execute(Input $input, Output $output)
{
$title = $input->getOption('title');
$remark = $input->getOption('remark');
if (empty($title)) {
$output->error('角色名称不能为空');
return false;
}
try {
$auth = new SystemAuth();
$auth->title = $title;
$auth->remark = $remark ?? '';
$auth->sort = 0;
$auth->status = 1;
$auth->save();
$output->info('角色创建成功');
$output->info('角色ID: ' . $auth->id);
$output->info('角色名称: ' . $auth->title);
} catch (\Throwable $e) {
$output->error('创建角色失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\role;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\admin\model\SystemAdmin;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminRoleDeleteBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:role:delete')
->addOption('role-id', null, Option::VALUE_REQUIRED, '角色ID')
->setDescription('删除角色');
}
protected function execute(Input $input, Output $output)
{
$roleId = $input->getOption('role-id');
if (empty($roleId)) {
$output->error('角色ID不能为空');
return false;
}
try {
$auth = SystemAuth::find($roleId);
if (empty($auth)) {
$output->error('角色ID ' . $roleId . ' 不存在');
return false;
}
$checkUsers = SystemAdmin::where('auth_ids', 'like', '%' . $roleId . '%')
->where('delete_time', 0)
->count();
if ($checkUsers > 0) {
$output->error('角色ID ' . $roleId . ' 已分配给 ' . $checkUsers . ' 个用户,无法删除');
return false;
}
SystemAuthNode::where('auth_id', $roleId)->delete();
$auth->delete();
$output->info('角色删除成功');
$output->info('角色ID: ' . $roleId);
} catch (\Throwable $e) {
$output->error('删除角色失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\role;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminRoleInfoBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:role:info')
->addOption('role-id', null, Option::VALUE_REQUIRED, '角色ID')
->setDescription('查看角色详情');
}
protected function execute(Input $input, Output $output)
{
$roleId = $input->getOption('role-id');
if (empty($roleId)) {
$output->error('角色ID不能为空');
return false;
}
try {
$role = SystemAuth::find($roleId);
if (empty($role)) {
$output->error('角色ID ' . $roleId . ' 不存在');
return false;
}
$nodes = SystemAuthNode::where('auth_id', $roleId)
->column('node');
$output->info('角色详情');
$output->writeln('================================');
$output->info('角色ID: ' . $role->id);
$output->comment('角色名称: ' . $role->title);
$output->comment('状态: ' . ($role->status == 1 ? '启用' : '禁用'));
$output->comment('排序: ' . $role->sort);
if (!empty($role->remark)) {
$output->comment('备注: ' . $role->remark);
}
$output->writeln('--------------------------------');
$output->info('权限节点列表 (' . count($nodes) . ' 个):');
foreach ($nodes as $node) {
$output->comment(' - ' . $node);
}
} catch (\Throwable $e) {
$output->error('获取角色详情失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\role;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\common\console\Command;
use think\console\Input;
use think\console\Output;
class AdminRoleListBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:role:list')
->setDescription('查看角色列表');
}
protected function execute(Input $input, Output $output)
{
try {
$roles = SystemAuth::where('delete_time', 0)
->field('id,title,sort,status,remark')
->order('sort', 'asc')
->order('id', 'desc')
->select()
->toArray();
if (empty($roles)) {
$output->comment('没有找到任何角色');
return true;
}
$output->info('角色列表');
$output->writeln('================================');
foreach ($roles as $role) {
$nodeCount = SystemAuthNode::where('auth_id', $role['id'])->count();
$statusText = $role['status'] == 1 ? '启用' : '禁用';
$output->info('角色ID: ' . $role['id']);
$output->comment(' 角色名称: ' . $role['title']);
$output->comment(' 权限节点数: ' . $nodeCount);
$output->comment(' 状态: ' . $statusText);
$output->comment(' 排序: ' . $role['sort']);
if (!empty($role['remark'])) {
$output->comment(' 备注: ' . $role['remark']);
}
$output->writeln('--------------------------------');
}
$output->info('总计: ' . count($roles) . ' 个角色');
} catch (\Throwable $e) {
$output->error('获取角色列表失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,127 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\role;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\admin\service\NodeService;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminRolePermissionAssignBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:role:permission:assign')
->addOption('role-id', null, Option::VALUE_REQUIRED, '角色ID')
->addOption('nodes', null, Option::VALUE_REQUIRED, '权限节点列表(逗号分隔)')
->setDescription('给角色分配权限');
}
protected function execute(Input $input, Output $output)
{
$roleId = $input->getOption('role-id');
$nodesParam = $input->getOption('nodes');
if (empty($roleId)) {
$output->error('角色ID不能为空');
return false;
}
if (empty($nodesParam)) {
$output->error('权限节点不能为空');
return false;
}
try {
$auth = SystemAuth::find($roleId);
if (empty($auth)) {
$output->error('角色ID ' . $roleId . ' 不存在');
return false;
}
$nodes = $this->parseNodes($nodesParam);
if (empty($nodes)) {
$output->error('权限节点列表为空');
return false;
}
$validNodes = $this->validateNodes($nodes);
$invalidNodes = array_diff($nodes, $validNodes);
if (!empty($invalidNodes)) {
$invalidCount = count($invalidNodes);
$output->error("[错误] 发现 {$invalidCount} 个无效的权限节点:");
foreach (array_values($invalidNodes) as $node) {
$output->error(" - {$node}");
}
$output->writeln('');
}
if (empty($validNodes)) {
$output->error("有效权限节点数: 0");
$output->error("分配失败");
return false;
}
$existingNodes = SystemAuthNode::where('auth_id', $roleId)
->column('node');
$newNodes = array_diff($validNodes, $existingNodes);
if (empty($newNodes)) {
$output->info('所有权限节点已存在,无需重复分配');
return true;
}
$authNodes = [];
foreach ($newNodes as $node) {
$authNodes[] = [
'auth_id' => $roleId,
'node' => $node,
];
}
(new SystemAuthNode())->saveAll($authNodes);
$output->info('权限分配成功');
$output->info('角色ID: ' . $roleId);
$output->info('新增的权限节点: ' . implode(', ', $newNodes));
$output->info('该角色总权限节点数: ' . (count($existingNodes) + count($newNodes)));
} catch (\Throwable $e) {
$output->error('分配权限失败: ' . $e->getMessage());
return false;
}
return true;
}
protected function parseNodes(string $nodesParam): array
{
$nodes = explode(',', $nodesParam);
$nodes = array_map('trim', $nodes);
$nodes = array_filter($nodes);
return array_values($nodes);
}
protected function validateNodes(array $nodes): array
{
$nodeService = new NodeService();
$allNodes = $nodeService->getNodeParis();
$validNodes = [];
foreach ($nodes as $node) {
if (isset($allNodes[$node])) {
$validNodes[] = $node;
}
}
return $validNodes;
}
}

View File

@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\role;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminRolePermissionListBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:role:permission:list')
->addOption('role-id', null, Option::VALUE_REQUIRED, '角色ID')
->setDescription('查看角色权限');
}
protected function execute(Input $input, Output $output)
{
$roleId = $input->getOption('role-id');
if (empty($roleId)) {
$output->error('角色ID不能为空');
return false;
}
try {
$role = SystemAuth::find($roleId);
if (empty($role)) {
$output->error('角色ID ' . $roleId . ' 不存在');
return false;
}
$nodes = SystemAuthNode::where('auth_id', $roleId)
->column('node');
$output->info('角色权限列表');
$output->writeln('================================');
$output->info('角色ID: ' . $role->id);
$output->comment('角色名称: ' . $role->title);
$output->writeln('--------------------------------');
if (empty($nodes)) {
$output->comment('该角色没有分配任何权限节点');
} else {
$output->info('权限节点 (' . count($nodes) . ' 个):');
foreach ($nodes as $node) {
$output->comment(' - ' . $node);
}
}
} catch (\Throwable $e) {
$output->error('获取角色权限失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\role;
use app\admin\model\SystemAuth;
use app\admin\model\SystemAuthNode;
use app\admin\service\NodeService;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminRolePermissionRevokeBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:role:permission:revoke')
->addOption('role-id', null, Option::VALUE_REQUIRED, '角色ID')
->addOption('nodes', null, Option::VALUE_REQUIRED, '权限节点列表(逗号分隔)')
->setDescription('撤回角色权限');
}
protected function execute(Input $input, Output $output)
{
$roleId = $input->getOption('role-id');
$nodesParam = $input->getOption('nodes');
if (empty($roleId)) {
$output->error('角色ID不能为空');
return false;
}
if (empty($nodesParam)) {
$output->error('权限节点不能为空');
return false;
}
try {
$auth = SystemAuth::find($roleId);
if (empty($auth)) {
$output->error('角色ID ' . $roleId . ' 不存在');
return false;
}
$nodes = $this->parseNodes($nodesParam);
if (empty($nodes)) {
$output->error('权限节点列表为空');
return false;
}
$validNodes = $this->validateNodes($nodes);
$invalidNodes = array_diff($nodes, $validNodes);
if (!empty($invalidNodes)) {
$output->comment('警告: 以下权限节点无效: ' . implode(', ', array_values($invalidNodes)));
}
if (empty($validNodes)) {
$output->error('没有有效的权限节点');
return false;
}
$deletedCount = SystemAuthNode::where('auth_id', $roleId)
->where('node', 'in', $validNodes)
->delete();
if ($deletedCount == 0) {
$output->error('没有权限可以撤回(角色不包含指定的权限节点)');
return false;
}
$remainingCount = SystemAuthNode::where('auth_id', $roleId)->count();
$output->info('权限撤回成功');
$output->info('角色ID: ' . $roleId);
$output->info('撤回的权限节点: ' . implode(', ', $validNodes));
$output->info('该角色剩余权限节点数: ' . $remainingCount);
} catch (\Throwable $e) {
$output->error('撤回权限失败: ' . $e->getMessage());
return false;
}
return true;
}
protected function parseNodes(string $nodesParam): array
{
$nodes = explode(',', $nodesParam);
$nodes = array_map('trim', $nodes);
$nodes = array_filter($nodes);
return array_values($nodes);
}
protected function validateNodes(array $nodes): array
{
$nodeService = new NodeService();
$allNodes = $nodeService->getNodeParis();
$validNodes = [];
foreach ($nodes as $node) {
if (isset($allNodes[$node])) {
$validNodes[] = $node;
}
}
return $validNodes;
}
}

View File

@@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\user;
use app\admin\model\SystemAdmin;
use app\admin\model\SystemAuth;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminUserRoleAssignBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:user:role:assign')
->addOption('user-id', null, Option::VALUE_REQUIRED, '用户ID')
->addOption('role-ids', null, Option::VALUE_REQUIRED, '角色ID列表逗号分隔')
->setDescription('给用户分配角色');
}
protected function execute(Input $input, Output $output)
{
$userId = $input->getOption('user-id');
$roleIdsParam = $input->getOption('role-ids');
if (empty($userId)) {
$output->error('用户ID不能为空');
return false;
}
if (empty($roleIdsParam)) {
$output->error('角色ID不能为空');
return false;
}
try {
$admin = SystemAdmin::find($userId);
if (empty($admin)) {
$output->error('用户ID ' . $userId . ' 不存在');
return false;
}
$roleIds = $this->parseRoleIds($roleIdsParam);
if (empty($roleIds)) {
$output->error('角色ID列表为空');
return false;
}
$validRoleIds = $this->validateRoleIds($roleIds);
$invalidRoleIds = array_diff($roleIds, $validRoleIds);
if (!empty($invalidRoleIds)) {
$invalidCount = count($invalidRoleIds);
$output->error("[错误] 发现 {$invalidCount} 个无效的角色ID:");
foreach (array_values($invalidRoleIds) as $roleId) {
$output->error(" - {$roleId}");
}
$output->writeln('');
}
if (empty($validRoleIds)) {
$output->error("有效角色ID数: 0");
$output->error("分配失败");
return false;
}
$existingAuthIds = $admin->auth_ids;
$existingAuthIdArray = [];
if (!empty($existingAuthIds)) {
$existingAuthIdArray = array_filter(explode(',', $existingAuthIds));
}
$newRoleIds = array_diff($validRoleIds, $existingAuthIdArray);
if (empty($newRoleIds)) {
$output->info('所有角色已存在,无需重复分配');
return true;
}
$mergedRoleIds = array_merge($existingAuthIdArray, $newRoleIds);
$mergedRoleIds = array_values(array_unique($mergedRoleIds));
$admin->auth_ids = implode(',', $mergedRoleIds);
$admin->save();
$output->info('角色分配成功');
$output->info('用户ID: ' . $userId);
$output->info('新增的角色ID: ' . implode(', ', $newRoleIds));
$output->info('该用户总角色数: ' . count($mergedRoleIds));
$output->info('所有角色ID: ' . implode(', ', $mergedRoleIds));
} catch (\Throwable $e) {
$output->error('分配角色失败: ' . $e->getMessage());
return false;
}
return true;
}
protected function parseRoleIds(string $roleIdsParam): array
{
$roleIds = explode(',', $roleIdsParam);
$roleIds = array_map('trim', $roleIds);
$roleIds = array_filter($roleIds);
return array_values($roleIds);
}
protected function validateRoleIds(array $roleIds): array
{
$validRoleIds = SystemAuth::whereIn('id', $roleIds)
->where('delete_time', 0)
->column('id');
return $validRoleIds;
}
}

View File

@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\user;
use app\admin\model\SystemAdmin;
use app\admin\model\SystemAuth;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminUserRoleListBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:user:role:list')
->addOption('user-id', null, Option::VALUE_REQUIRED, '用户ID')
->setDescription('查看用户角色');
}
protected function execute(Input $input, Output $output)
{
$userId = $input->getOption('user-id');
if (empty($userId)) {
$output->error('用户ID不能为空');
return false;
}
try {
$user = SystemAdmin::find($userId);
if (empty($user)) {
$output->error('用户ID ' . $userId . ' 不存在');
return false;
}
$authIds = $user->auth_ids;
$authIdArray = [];
if (!empty($authIds)) {
$authIdArray = array_filter(explode(',', $authIds));
}
if (empty($authIdArray)) {
$output->info('用户角色列表');
$output->writeln('================================');
$output->info('用户ID: ' . $user->id);
$output->info('用户名: ' . $user->username);
$output->writeln('--------------------------------');
$output->comment('该用户没有分配任何角色');
return true;
}
$roles = SystemAuth::whereIn('id', $authIdArray)
->where('delete_time', 0)
->field('id,title,status,remark')
->select()
->toArray();
$output->info('用户角色列表');
$output->writeln('================================');
$output->info('用户ID: ' . $user->id);
$output->info('用户名: ' . $user->username);
$output->writeln('--------------------------------');
if (empty($roles)) {
$output->comment('没有找到有效的角色信息');
} else {
foreach ($roles as $role) {
$statusText = $role['status'] == 1 ? '启用' : '禁用';
$output->info('角色ID: ' . $role['id']);
$output->comment(' 角色名称: ' . $role['title']);
$output->comment(' 状态: ' . $statusText);
if (!empty($role['remark'])) {
$output->comment(' 备注: ' . $role['remark']);
}
$output->writeln('--------------------------------');
}
}
} catch (\Throwable $e) {
$output->error('获取用户角色失败: ' . $e->getMessage());
return false;
}
return true;
}
}

View File

@@ -0,0 +1,117 @@
<?php
declare(strict_types=1);
namespace base\common\command\admin\user;
use app\admin\model\SystemAdmin;
use app\admin\model\SystemAuth;
use app\common\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
class AdminUserRoleRevokeBase extends Command
{
protected function configure()
{
parent::configure();
$this->setName('admin:user:role:revoke')
->addOption('user-id', null, Option::VALUE_REQUIRED, '用户ID')
->addOption('role-ids', null, Option::VALUE_REQUIRED, '角色ID列表逗号分隔')
->setDescription('撤回用户角色');
}
protected function execute(Input $input, Output $output)
{
$userId = $input->getOption('user-id');
$roleIdsParam = $input->getOption('role-ids');
if (empty($userId)) {
$output->error('用户ID不能为空');
return false;
}
if (empty($roleIdsParam)) {
$output->error('角色ID不能为空');
return false;
}
try {
$admin = SystemAdmin::find($userId);
if (empty($admin)) {
$output->error('用户ID ' . $userId . ' 不存在');
return false;
}
$roleIds = $this->parseRoleIds($roleIdsParam);
if (empty($roleIds)) {
$output->error('角色ID列表为空');
return false;
}
$validRoleIds = $this->validateRoleIds($roleIds);
$invalidRoleIds = array_diff($roleIds, $validRoleIds);
if (!empty($invalidRoleIds)) {
$output->comment('警告: 以下角色ID无效: ' . implode(', ', array_values($invalidRoleIds)));
}
if (empty($validRoleIds)) {
$output->error('没有有效的角色ID');
return false;
}
$existingAuthIds = $admin->auth_ids;
if (empty($existingAuthIds)) {
$output->error('用户未分配任何角色,无法撤回');
return false;
}
$existingAuthIdArray = array_filter(explode(',', $existingAuthIds));
$revokedRoleIds = array_intersect($validRoleIds, $existingAuthIdArray);
if (empty($revokedRoleIds)) {
$output->error('没有角色可以撤回(用户不拥有指定的角色)');
return false;
}
$remainingRoleIds = array_diff($existingAuthIdArray, $revokedRoleIds);
$admin->auth_ids = empty($remainingRoleIds) ? '' : implode(',', $remainingRoleIds);
$admin->save();
$output->info('角色撤回成功');
$output->info('用户ID: ' . $userId);
$output->info('撤回的角色ID: ' . implode(', ', $revokedRoleIds));
$output->info('该用户剩余角色数: ' . count($remainingRoleIds));
if (!empty($remainingRoleIds)) {
$output->info('剩余角色ID: ' . implode(', ', $remainingRoleIds));
}
} catch (\Throwable $e) {
$output->error('撤回角色失败: ' . $e->getMessage());
return false;
}
return true;
}
protected function parseRoleIds(string $roleIdsParam): array
{
$roleIds = explode(',', $roleIdsParam);
$roleIds = array_map('trim', $roleIds);
$roleIds = array_filter($roleIds);
return array_values($roleIds);
}
protected function validateRoleIds(array $roleIds): array
{
$validRoleIds = SystemAuth::whereIn('id', $roleIds)
->where('delete_time', 0)
->column('id');
return $validRoleIds;
}
}