---
name: create-app
description: 快速创建 ThinkCMF 应用的脚手架工具。生成应用入口类、控制器、模型、验证器、服务层、数据迁移、导航配置等完整目录结构。创建前台/后台控制器时自动调用 create-theme-template 技能同步生成对应模板，API 控制器则不生成模板。当用户需要创建新应用、新模块、新功能模块时使用此技能。
---

# 快速创建 ThinkCMF 应用

## 工作流程

1. 收集应用需求（名称、功能、需要的组件）
2. 创建 `app/{应用名}/` 目录结构
3. 生成应用入口类 `{App}App.php`
4. 按需生成控制器、模型、验证器、服务层
5. 按需创建 `api/{应用名}/` API 目录
6. **后台控制器**：调用 `create-admin-menu` 技能生成 `@adminMenuRoot` 和 `@adminMenu` 菜单注解
7. **非 API 控制器**：调用 `create-theme-template` 技能同步生成对应模板文件

## 需求收集

| 参数 | 说明 | 示例 |
|------|------|------|
| 应用名 | 小写+下划线 | `brand`、`order`、`product` |
| 中文名 | 后台菜单显示 | `品牌管理`、`订单管理` |
| 功能描述 | 一句话描述 | `品牌的增删改查管理` |
| 需要后台管理 | 是否生成 Admin 控制器 | 是/否 |
| 需要前台页面 | 是否生成 Home 控制器 | 是/否 |
| 需要 API | 是否生成 api/ 下的控制器 | 是/否 |
| 数据表字段 | 主要字段列表 | `name, logo, status` |
| 是否使用服务层 | 是否生成 Service+Trait | 是/否（推荐是） |

## 目录结构

### 前台应用 `app/{应用名}/`

```
app/{应用名}/
├── {App}App.php              # 应用入口（必须）
├── controller/               # 控制器目录
│   ├── Admin{Entity}Controller.php   # 后台控制器
│   └── {Entity}Controller.php        # 前台控制器
├── model/
│   └── {Entity}Model.php     # 模型
├── validate/
│   └── {Entity}Validate.php  # 验证器
├── service/
│   ├── BaseService.php        # 服务基类
│   ├── {Entity}Service.php    # 业务服务
│   └── traits/                # Trait 目录
│       ├── CreateTrait.php
│       ├── DeleteTrait.php
│       ├── ListsTrait.php
│       ├── PageTrait.php
│       ├── ReadTrait.php
│       ├── UpdateTrait.php
│       └── ToggleStatusTrait.php
├── data/
│   └── migrations/            # 数据迁移
├── nav.php                    # 导航配置
├── url.php                    # URL 路由
├── hooks.php                  # 钩子定义
└── user_action.php            # 用户操作
```

### API 应用 `api/{应用名}/`

```
api/{应用名}/
├── controller/
│   └── IndexController.php    # API 控制器
├── model/                     # API 专用模型（可选）
├── validate/                  # API 专用验证（可选）
├── service/                   # 可复用 app 下的 service
└── route.php                  # API 路由配置
```

## 命名规则

| 元素 | 规则 | 示例 |
|------|------|------|
| 应用目录 | 小写+下划线 | `brand`、`order_item` |
| 应用入口类 | PascalCase + `App` | `BrandApp`、`OrderItemApp` |
| 控制器类 | PascalCase + `Controller` | `AdminBrandController` |
| 模型类 | PascalCase + `Model` | `BrandModel` |
| 验证器类 | PascalCase + `Validate` | `BrandValidate` |
| 服务类 | PascalCase + `Service` | `BrandService` |
| 数据表名 | 应用前缀+下划线 | `brand`、`order_item` |

## 模板代码

### 应用入口类 `{App}App.php`

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

/**
 * {中文名}应用
 */
class {App}App
{
    /**
     * 应用安装
     * @return bool
     */
    public function install(): bool
    {
        return true;
    }

    /**
     * 应用卸载
     * @return bool
     */
    public function uninstall(): bool
    {
        return true;
    }
}
```

### 后台控制器 `Admin{Entity}Controller.php`

```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' => '{中文名}列表'
     * )
     */
    public function index()
    {
        $validateResult = $this->validate($this->request->param(), '{Entity}.index');
        if ($validateResult !== true) {
            $this->error($validateResult);
        }
        $service = new {Entity}Service();
        $data = $service->page($this->request->param());
        $this->assign('data', $data);
        return $this->fetch();
    }

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

    /**
     * 保存{中文名}
     * @adminMenu(
     *     'name'   => '保存{中文名}',
     *     'parent' => 'index',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '保存{中文名}'
     * )
     */
    public function create(): void
    {
        $validateResult = $this->validate($this->request->param(), '{Entity}.create');
        if ($validateResult !== true) {
            $this->error($validateResult);
        }
        $service = new {Entity}Service();
        $service->create($this->request->param());
        $this->success('添加成功!');
    }

    /**
     * 编辑{中文名}
     * @adminMenu(
     *     'name'   => '编辑{中文名}',
     *     'parent' => 'index',
     *     'display'=> false,
     *     'hasView'=> true,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '编辑{中文名}'
     * )
     */
    public function edit()
    {
        $id = $this->request->param('id', 0, 'intval');
        $service = new {Entity}Service();
        $data = $service->read($id);
        $this->assign('data', $data);
        return $this->fetch();
    }

    /**
     * 更新{中文名}
     * @adminMenu(
     *     'name'   => '更新{中文名}',
     *     'parent' => 'index',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '更新{中文名}'
     * )
     */
    public function update(): void
    {
        $validateResult = $this->validate($this->request->param(), '{Entity}.update');
        if ($validateResult !== true) {
            $this->error($validateResult);
        }
        $service = new {Entity}Service();
        $service->update($this->request->param());
        $this->success('更新成功!');
    }

    /**
     * 删除{中文名}
     * @adminMenu(
     *     'name'   => '删除{中文名}',
     *     'parent' => 'index',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '删除{中文名}'
     * )
     */
    public function delete(): void
    {
        $validateResult = $this->validate($this->request->param(), '{Entity}.delete');
        if ($validateResult !== true) {
            $this->error($validateResult);
        }
        $service = new {Entity}Service();
        $service->delete($this->request->param('id'));
        $this->success('删除成功!');
    }

    /**
     * 排序
     * @adminMenu(
     *     'name'   => '{中文名}排序',
     *     'parent' => 'index',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '{中文名}排序'
     * )
     */
    public function listOrder(): void
    {
        $service = new {Entity}Service();
        $service->listOrder($this->request->param('list_orders'));
        $this->success('排序成功!');
    }

    /**
     * 切换状态
     * @adminMenu(
     *     'name'   => '{中文名}状态切换',
     *     'parent' => 'index',
     *     'display'=> false,
     *     'hasView'=> false,
     *     'order'  => 10000,
     *     'icon'   => '',
     *     'remark' => '{中文名}状态切换'
     * )
     */
    public function toggleStatus(): void
    {
        $service = new {Entity}Service();
        $service->toggleStatus($this->request->param());
        $this->success('操作成功!');
    }
}
```

### 前台控制器 `{Entity}Controller.php`

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

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

/**
 * {中文名}前台控制器
 */
class {Entity}Controller extends HomeBaseController
{
    /**
     * {中文名}列表页
     */
    public function index()
    {
        $service = new {Entity}Service();
        $data = $service->page([
            'where' => [['status', '=', 1]]
        ]);
        $this->assign('data', $data);
        return $this->fetch();
    }

    /**
     * {中文名}详情页
     */
    public function read()
    {
        $id = $this->request->param('id', 0, 'intval');
        $service = new {Entity}Service();
        $data = $service->read($id);
        $this->assign('data', $data);
        return $this->fetch();
    }
}
```

### API 控制器 `api/{应用名}/controller/IndexController.php`

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

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

/**
 * @OA\Tag(
 *     name="{应用名}",
 *     description="{中文名}"
 * )
 */
class IndexController extends RestBaseController
{
    /**
     * {中文名}列表
     * @OA\Get(
     *     tags={"{应用名}"},
     *     path="/{应用名}/index",
     *     description="{中文名}列表",
     *     @OA\Response(response="200", description="success")
     * )
     */
    public function index(): void
    {
        $data = (new {Entity}Service())->page([
            'where' => [['status', '=', 1]]
        ]);
        $this->success('请求成功!', $data);
    }

    /**
     * {中文名}详情
     * @OA\Get(
     *     tags={"{应用名}"},
     *     path="/{应用名}/read/{id}",
     *     description="{中文名}详情",
     *     @OA\Parameter(name="id", in="path", required=true),
     *     @OA\Response(response="200", description="success")
     * )
     */
    public function read($id): void
    {
        $data = (new {Entity}Service())->read(intval($id));
        $this->success('请求成功!', $data);
    }
}
```

### API 路由 `api/{应用名}/route.php`

```php
<?php
use think\facade\Route;

Route::get('{应用名}/index$', '{应用名}/Index/index');
Route::get('{应用名}/read/:id$', '{应用名}/Index/read');
```

### 模型 `{Entity}Model.php`

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

use think\Model;

/**
 * {中文名}模型
 */
class {Entity}Model extends Model
{
    /**
     * 数据表名（不含前缀）
     */
    protected $name = '{表名}';
}
```

### 验证器 `{Entity}Validate.php`

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

use think\Validate;

/**
 * {中文名}验证器
 */
class {Entity}Validate extends Validate
{
    protected $rule = [
        'id' => ['require'],
    ];

    protected $message = [];

    protected $scene = [
        'delete' => ['id'],
        'update' => ['id'],
        'read'   => ['id'],
    ];

    /**
     * 列表场景
     */
    protected function sceneIndex()
    {
        return $this->only(['id'])->remove('id', true);
    }

    /**
     * 创建场景
     */
    protected function sceneCreate()
    {
        return $this->only(['id'])->remove('id', true);
    }
}
```

### 服务基类 `BaseService.php`

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

/**
 * 服务基类
 */
class BaseService
{
    protected object $app;
    protected string $modelClassName;

    public function __construct()
    {
        $this->app = app();
        $this->initialize();
    }

    /**
     * 初始化
     */
    protected function initialize(): void
    {
    }
}
```

### 业务服务 `{Entity}Service.php`

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

use app\{应用名}\model\{Entity}Model;

/**
 * {中文名}服务
 */
class {Entity}Service extends BaseService
{
    protected function initialize(): void
    {
        parent::initialize();
        $this->modelClassName = {Entity}Model::class;
    }

    use \app\{应用名}\service\traits\CreateTrait;
    use \app\{应用名}\service\traits\DeleteTrait;
    use \app\{应用名}\service\traits\ListsTrait;
    use \app\{应用名}\service\traits\PageTrait;
    use \app\{应用名}\service\traits\ReadTrait;
    use \app\{应用名}\service\traits\UpdateTrait;
    use \app\{应用名}\service\traits\ToggleStatusTrait;
}
```

### 服务 Trait 模板

详见 [traits.md](traits.md)

### 配置文件模板

**nav.php**：
```php
<?php
return [];
```

**url.php**：
```php
<?php
return [];
```

**hooks.php**：
```php
<?php
return [];
```

**user_action.php**：
```php
<?php
return [];
```

## 技能联动规则

**核心规则：**
1. **后台控制器**：调用 `create-admin-menu` 技能生成 `@adminMenuRoot`（类级）和 `@adminMenu`（方法级）注解，确保菜单层级、display/hasView 组合正确
2. **非 API 控制器**：调用 `create-theme-template` 技能生成对应视图模板
3. **API 控制器**：不生成模板，不生成菜单注解

| 控制器类型 | 需要生成模板 | 模板位置 |
|-----------|------------|---------|
| `Admin{Entity}Controller` | **是** | `public/themes/admin_default/{应用名}/admin_{entity}/` |
| `{Entity}Controller`（前台） | **是** | `public/themes/default/{应用名}/` |
| API `IndexController` | **否** | 无视图 |

### 后台控制器模板映射

| 方法 | 模板类型 | 调用 create-theme-template 参数 |
|------|---------|-------------------------------|
| `index()` | 列表页 | 类型=admin_list |
| `add()` | 添加页 | 类型=admin_add |
| `edit()` | 编辑页 | 类型=admin_edit |

### 前台控制器模板映射

| 方法 | 模板类型 | 调用 create-theme-template 参数 |
|------|---------|-------------------------------|
| `index()` | 前台页面 | 类型=front_page |
| `read()` | 前台页面 | 类型=front_page |

## 完成检查清单

- [ ] `{App}App.php` 应用入口类已创建
- [ ] 命名空间正确：`app\{应用名}\...`
- [ ] 后台控制器继承 `AdminBaseController`，含 `@adminMenuRoot` 和 `@adminMenu` 注解（参考 `create-admin-menu` 技能）
- [ ] 前台控制器继承 `HomeBaseController`
- [ ] API 控制器继承 `RestBaseController`，含 `@OA` 注解
- [ ] 模型 `$name` 属性正确设置表名
- [ ] 验证器包含 `scene` 定义
- [ ] 服务层使用 Trait 组合
- [ ] 配置文件（nav/url/hooks/user_action）已创建
- [ ] **非 API 控制器已同步生成对应主题模板**
- [ ] API 路由 `route.php` 已配置
