---
name: create-admin-menu
description: 快速生成 ThinkCMF 后台菜单注解（@adminMenuRoot 和 @adminMenu）。根据控制器方法自动生成完整的菜单注解代码块，包含正确的 parent 层级关系、display/hasView 组合和权限节点。当用户需要添加后台菜单、生成菜单注解、配置后台菜单权限时使用此技能。
---

# 快速生成 ThinkCMF 后台菜单注解

## 注解类型

| 注解 | 级别 | 说明 |
|------|------|------|
| `@adminMenuRoot` | 类级 | 创建菜单根节点（虚拟操作），一个类可有多个 |
| `@adminMenu` | 方法级 | 为方法创建菜单项，每个方法只能有一个 |

## 需求收集

| 参数 | 说明 | 示例 |
|------|------|------|
| 应用名 | 小写，app/ 下的目录名 | `product`、`order` |
| 控制器名 | PascalCase | `AdminProduct`、`AdminBrand` |
| 菜单中文名 | 根菜单显示名 | `商品`、`订单` |
| 方法列表 | 需要注解的方法 | `index, add, create, edit, update, delete` |
| 父级菜单 | 菜单挂载位置 | 空（顶级）或 `product/AdminProduct/default` |
| 图标 | Font Awesome 图标名 | `shopping-cart`、`group`、`cog` |

## @adminMenuRoot 参数

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `name` | String | - | 菜单名称（必填） |
| `action` | String | - | 虚拟操作标识（必填），不对应实际方法 |
| `parent` | String | `''` | 父级，空字符串为顶级菜单 |
| `display` | Boolean | `true` | 是否在后台菜单显示 |
| `order` | Integer | `10000` | 排序，越小越靠前 |
| `icon` | String | `''` | Font Awesome 图标名 |
| `remark` | String | `''` | 备注 |

## @adminMenu 参数

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `name` | String | - | 菜单名称（必填） |
| `parent` | String | - | 父级（必填） |
| `display` | Boolean | `true` | 是否在后台菜单显示 |
| `hasView` | Boolean | `false` | 是否有前端页面 |
| `order` | Integer | `10000` | 排序 |
| `icon` | String | `''` | 图标 |
| `remark` | String | `''` | 备注 |
| `param` | String | `''` | 额外参数（预留） |

## parent 三种格式

| 格式 | 示例 | 场景 |
|------|------|------|
| 操作名（1段） | `'default'` 或 `'index'` | 引用同控制器内的操作 |
| 控制器/操作（2段） | `'AdminProduct/default'` | 引用同应用其他控制器 |
| 应用/控制器/操作（3段） | `'product/AdminProduct/default'` | 跨应用引用 |

## 方法与 display/hasView 映射表

| 方法 | display | hasView | type | 说明 |
|------|---------|---------|------|------|
| `index` | **true** | **true** | 1 | 列表页，显示在菜单中 |
| `add` | false | **true** | 1 | 添加页面 |
| `create` | false | false | 2 | 保存操作（POST） |
| `edit` | false | **true** | 1 | 编辑页面 |
| `update` | false | false | 2 | 更新操作（PUT） |
| `read` | false | **true** | 1 | 详情页面 |
| `delete` | false | false | 2 | 删除操作 |
| `listOrder` | false | false | 2 | 排序操作 |
| `toggleStatus` | false | false | 2 | 状态切换 |

**规则：只有 `index` 设置 `display=true`，其余方法均为 `false`。有前端页面的方法 `hasView=true`，纯操作 `hasView=false`。**

## 数据库 type 映射

| type | 来源 | 说明 |
|------|------|------|
| 0 | `@adminMenuRoot` | 菜单根节点，不可访问 |
| 1 | `@adminMenu` + `hasView=true` | 有界面菜单 |
| 2 | `@adminMenu` + `hasView=false` | 无界面操作（权限节点） |

## 模板

### 模式一：独立根菜单 + CRUD

用于主控制器（如应用的入口控制器），自带根菜单节点：

```php
<?php
namespace app\{应用名}\controller;

use cmf\controller\AdminBaseController;
use app\{应用名}\service\{Entity}Service;

/**
 * {中文名}管理
 * @adminMenuRoot(
 *     'name'   =>'{中文名}',
 *     'action' =>'default',
 *     'parent' =>'',
 *     'display'=> true,
 *     'order'  => 10000,
 *     'icon'   =>'{图标}',
 *     'remark' =>'{中文名}'
 * )
 */
class Admin{Entity}Controller extends AdminBaseController
{
    /**
     * {中文名}列表
     * @adminMenu(
     *     'name'   => '{中文名}列表',
     *     'parent' => 'default',
     *     'display'=> true,
     *     'hasView'=> true,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '{中文名}列表',
     *     'param'  => ''
     * )
     */
    public function index()
    {
        // ...
        return $this->fetch();
    }

    /**
     * 添加{中文名}
     * @adminMenu(
     *     'name'   => '添加{中文名}',
     *     'parent' => 'default',
     *     'display'=> false,
     *     'hasView'=> true,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '添加{中文名}',
     *     'param'  => ''
     * )
     */
    public function add()
    {
        return $this->fetch();
    }

    /**
     * 保存{中文名}
     * @adminMenu(
     *     'name'   => '保存{中文名}',
     *     'parent' => 'default',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '保存{中文名}',
     *     'param'  => ''
     * )
     */
    public function create(): void
    {
        // ...
    }

    /**
     * 编辑{中文名}
     * @adminMenu(
     *     'name'   => '编辑{中文名}',
     *     'parent' => 'default',
     *     'display'=> false,
     *     'hasView'=> true,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '编辑{中文名}',
     *     'param'  => ''
     * )
     */
    public function edit()
    {
        return $this->fetch();
    }

    /**
     * 更新{中文名}
     * @adminMenu(
     *     'name'   => '更新{中文名}',
     *     'parent' => 'default',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '更新{中文名}',
     *     'param'  => ''
     * )
     */
    public function update(): void
    {
        // ...
    }

    /**
     * {中文名}详情
     * @adminMenu(
     *     'name'   => '{中文名}详情',
     *     'parent' => 'default',
     *     'display'=> false,
     *     'hasView'=> true,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '{中文名}详情',
     *     'param'  => ''
     * )
     */
    public function read()
    {
        return $this->fetch();
    }

    /**
     * 删除{中文名}
     * @adminMenu(
     *     'name'   => '删除{中文名}',
     *     'parent' => 'default',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '删除{中文名}',
     *     'param'  => ''
     * )
     */
    public function delete(): void
    {
        // ...
    }

    /**
     * {中文名}排序
     * @adminMenu(
     *     'name'   => '{中文名}排序',
     *     'parent' => 'default',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '{中文名}排序',
     *     'param'  => ''
     * )
     */
    public function listOrder(): void
    {
        // ...
    }

    /**
     * {中文名}状态切换
     * @adminMenu(
     *     'name'   => '{中文名}状态切换',
     *     'parent' => 'default',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '{中文名}状态切换',
     *     'param'  => ''
     * )
     */
    public function toggleStatus(): void
    {
        // ...
    }
}
```

### 模式二：子菜单挂载到已有根菜单

用于同应用下的子模块控制器（如商品分类挂载到商品根菜单下）：

```php
/**
 * {子模块中文名}管理
 * 无 @adminMenuRoot，菜单挂载到已有根菜单
 */
class Admin{SubEntity}Controller extends AdminBaseController
{
    /**
     * {子模块中文名}列表
     * @adminMenu(
     *     'name'   => '{子模块中文名}',
     *     'parent' => '{应用名}/Admin{Entity}/default',
     *     'display'=> true,
     *     'hasView'=> true,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '{子模块中文名}列表',
     *     'param'  => ''
     * )
     */
    public function index()
    {
        return $this->fetch();
    }

    // 其余方法的 parent 也指向 '{应用名}/Admin{Entity}/default'
    // display/hasView 规则同模式一
}
```

### 模式三：多根菜单（同一控制器）

```php
/**
 * @adminMenuRoot(
 *     'name'   =>'用户管理',
 *     'action' =>'default',
 *     'parent' =>'',
 *     'display'=> true,
 *     'order'  => 10,
 *     'icon'   =>'group',
 *     'remark' =>'用户管理'
 * )
 *
 * @adminMenuRoot(
 *     'name'   =>'用户组',
 *     'action' =>'default1',
 *     'parent' =>'user/AdminIndex/default',
 *     'display'=> false,
 *     'order'  => 10000,
 *     'icon'   =>'',
 *     'remark' =>'用户组'
 * )
 */
class AdminIndexController extends AdminBaseController
{
    // action 值必须唯一：default, default1, default2...
}
```

## 单个方法注解生成

当只需要为现有控制器的某个方法添加注解时，直接生成注解块：

```php
/**
 * {方法描述}
 * @adminMenu(
 *     'name'   => '{菜单名}',
 *     'parent' => '{parent值}',
 *     'display'=> {true|false},
 *     'hasView'=> {true|false},
 *     'order'  => 10000,
 *     'icon'   => '',
 *     'remark' => '{菜单名}',
 *     'param'  => ''
 * )
 */
```

## 常用图标速查

| 图标名 | 适用场景 |
|--------|---------|
| `group` / `users` | 用户管理 |
| `shopping-cart` | 商品/订单 |
| `cog` / `cogs` | 系统设置 |
| `folder` | 分类/目录 |
| `file-text` | 内容/文章 |
| `link` | 友情链接 |
| `image` | 图片/幻灯片 |
| `bar-chart` | 统计/报表 |
| `truck` | 物流/发货 |
| `money` | 财务/支付 |

## 菜单导入

注解编写完成后，需在后台执行菜单导入：
- 后台路径：`后台 → 菜单管理 → 导入菜单`
- 系统自动扫描控制器注解并写入数据库

## 注意事项

1. `@adminMenuRoot` 的 `action` 是虚拟操作，**不需要对应实际方法**
2. 同一个类的多个 `@adminMenuRoot` 的 `action` 值必须**唯一**
3. 每个方法**只能有一个** `@adminMenu`
4. 所有注解必须写在 `/** ... */` 文档注释块中
5. `parent` 为空字符串 `''` 时创建顶级菜单
6. 隐藏的方法（`display=false`）仍作为**权限控制节点**
