mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-08 02:52:49 +08:00
feat: 发布智能体版
This commit is contained in:
106
extend/base/common/command/admin/menu/AdminMenuCreateBase.php
Normal file
106
extend/base/common/command/admin/menu/AdminMenuCreateBase.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
127
extend/base/common/command/admin/menu/AdminMenuExportBase.php
Normal file
127
extend/base/common/command/admin/menu/AdminMenuExportBase.php
Normal 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;
|
||||
}
|
||||
}
|
||||
132
extend/base/common/command/admin/menu/AdminMenuListBase.php
Normal file
132
extend/base/common/command/admin/menu/AdminMenuListBase.php
Normal 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));
|
||||
}
|
||||
}
|
||||
129
extend/base/common/command/admin/menu/AdminMenuUpdateBase.php
Normal file
129
extend/base/common/command/admin/menu/AdminMenuUpdateBase.php
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user