477 lines
12 KiB
Markdown
477 lines
12 KiB
Markdown
---
|
||
name: cross-fullstack-admin-crud-feature
|
||
description: Full-stack development workflow for Madong Admin CRUD features. Covers requirement analysis, existing implementation verification, backend migration/model/DAO/service/validate/schema/controller, frontend API/page/schema, menu permissions, migration execution, validation, and skill auto-evolution.
|
||
globs:
|
||
- "backend/app/**/*.php"
|
||
- "backend/resource/database/migrations/**/*.php"
|
||
- "backend/resource/data/menu/**/*.php"
|
||
- "frontend/admin/src/api/**/*.ts"
|
||
- "frontend/admin/src/views/**/*.vue"
|
||
- "frontend/admin/src/views/**/*.tsx"
|
||
- ".windsurf/skills/**/*.md"
|
||
---
|
||
|
||
# Madong Admin 全栈 CRUD 功能开发流程
|
||
|
||
用于开发类似“应用授权”这类后台管理功能,覆盖数据库、后端、前端、菜单权限、迁移执行与校验。
|
||
|
||
## 适用场景
|
||
|
||
- 在 Admin 后台新增一个业务管理页面。
|
||
- 需要新增数据库表、后端 CRUD、前端列表/表单/API。
|
||
- 需要菜单入口和按钮权限。
|
||
- 需要参考现有模块目录结构,例如 `/tools/delegation`、`/setting/notice`。
|
||
- 需要自动生成字段或自定义操作,例如 Access Key / Secret Key 自动生成、重置密钥。
|
||
|
||
## 总原则
|
||
|
||
1. 先核对项目真实实现,再使用 skill 或模板。
|
||
2. 以现有项目代码为准,skill 与项目不一致时先更新 skill。
|
||
3. 优先复用官方现有组件和基类。
|
||
4. 不直接照搬 Laravel Artisan 命令,当前项目使用 Webman/Madong 命令体系。
|
||
5. 数据库迁移执行前必须先 dry-run,确认会执行哪些迁移。
|
||
6. 前后端路径、权限码、菜单码必须保持一致。
|
||
|
||
## 开发前检查
|
||
|
||
### 1. 确认参考模块
|
||
|
||
优先读取用户指定的参考模块。
|
||
|
||
常见参考:
|
||
|
||
- `frontend/admin/src/views/setting/notice`
|
||
- `frontend/admin/src/views/tools/delegation`
|
||
- `frontend/admin/src/api/tools/delegation`
|
||
- `backend/app/adminapi/controller/notice/NoticeController.php`
|
||
- `backend/app/adminapi/controller/plugin/PluginMadongAuthController.php`
|
||
|
||
### 2. 确认真实项目规范
|
||
|
||
至少核对以下内容:
|
||
|
||
- 后端控制器是否继承 `app\adminapi\controller\Crud`。
|
||
- 模型是否继承 `core\base\BaseModel`。
|
||
- DAO 是否继承 `core\base\BaseDao`。
|
||
- Service 是否继承 `core\base\BaseService`。
|
||
- Validate 是否继承 `core\base\BaseValidate`。
|
||
- 前端 CRUD 是否使用 `useCrud`、`CrudSchema`、`BasicCrud`。
|
||
- 前端 API 是否使用 `BaseService` 和 `@/utils/http`。
|
||
- 表单组件名是否存在于 `frontend/admin/src/components/form/components`。
|
||
- 菜单数据是否维护在 `backend/resource/data/menu/admin.php`。
|
||
|
||
## 后端开发流程
|
||
|
||
### 1. 数据库迁移
|
||
|
||
路径:
|
||
|
||
```text
|
||
backend/resource/database/migrations/{timestamp}_create_{table}_table.php
|
||
```
|
||
|
||
当前项目雪花 ID 主键写法:
|
||
|
||
```php
|
||
$table->bigInteger('id')->primary()->comment('主键');
|
||
```
|
||
|
||
不要使用 Laravel 默认的:
|
||
|
||
```php
|
||
$table->id();
|
||
```
|
||
|
||
字段设计要求:
|
||
|
||
- 主键使用雪花 ID。
|
||
- 按需增加唯一索引、普通索引。
|
||
- 状态字段常用 `enabled`,默认 `1`。
|
||
- 时间字段按项目迁移写法使用 `timestamps()` 或项目已有封装。
|
||
- 如果模型使用软删除,迁移需包含软删除字段。
|
||
|
||
### 2. Model
|
||
|
||
路径:
|
||
|
||
```text
|
||
backend/app/model/{module}/{Model}.php
|
||
```
|
||
|
||
要求:
|
||
|
||
- 继承 `core\base\BaseModel`。
|
||
- 设置 `$table`。
|
||
- 设置 `$fillable`。
|
||
- 设置 `$casts`。
|
||
- 如项目同类模型使用软删除,则保持一致。
|
||
|
||
### 3. DAO
|
||
|
||
路径:
|
||
|
||
```text
|
||
backend/app/dao/{module}/{Model}Dao.php
|
||
```
|
||
|
||
要求:
|
||
|
||
- 继承 `core\base\BaseDao`。
|
||
- `setModel()` 返回模型类。
|
||
- 如需关键字搜索,按项目已有 DAO 实现 `getKeywordFields()`。
|
||
|
||
### 4. Service
|
||
|
||
路径:
|
||
|
||
```text
|
||
backend/app/service/admin/{module}/{Model}Service.php
|
||
```
|
||
|
||
要求:
|
||
|
||
- 继承 `core\base\BaseService`。
|
||
- 构造函数注入 DAO。
|
||
- 自定义业务逻辑放在 Service。
|
||
- 自动生成字段在 `save()` / `create()` 入口处理。
|
||
- 自定义操作单独暴露方法,例如 `resetSecret()`。
|
||
|
||
应用授权类功能示例:
|
||
|
||
- 新增时自动生成 `access_key`。
|
||
- 新增时自动生成 `secret_key`。
|
||
- 重置时只更新 `secret_key`。
|
||
- 密钥生成应使用安全随机源,例如 `random_bytes()`。
|
||
|
||
### 5. Validate
|
||
|
||
路径:
|
||
|
||
```text
|
||
backend/app/adminapi/validate/{module}/{Model}Validate.php
|
||
```
|
||
|
||
要求:
|
||
|
||
- 继承 `core\base\BaseValidate`。
|
||
- 定义 `$rule`、`$message`、`$scene`。
|
||
- `store` 场景不要求 `id`。
|
||
- `update` 场景要求 `id`。
|
||
- 自动生成字段不要暴露为必填输入。
|
||
|
||
### 6. Request / Response Schema
|
||
|
||
请求路径:
|
||
|
||
```text
|
||
backend/app/adminapi/schema/request/{module}/{Model}FormRequest.php
|
||
backend/app/adminapi/schema/request/{module}/{Model}QueryRequest.php
|
||
```
|
||
|
||
响应路径:
|
||
|
||
```text
|
||
backend/app/adminapi/schema/response/{module}/{Model}Response.php
|
||
```
|
||
|
||
要求:
|
||
|
||
- FormRequest 继承项目实际存在的表单基类。
|
||
- QueryRequest 使用项目实际存在的 `BaseQueryRequest`。
|
||
- 不要引用不存在的 `PageRequest`。
|
||
- OpenAPI 属性需与控制器 `x: [SchemaConstants::X_SCHEMA_REQUEST => ...]` 对应。
|
||
|
||
### 7. Controller
|
||
|
||
路径:
|
||
|
||
```text
|
||
backend/app/adminapi/controller/{module}/{Model}Controller.php
|
||
```
|
||
|
||
要求:
|
||
|
||
- 继承 `Crud`。
|
||
- 构造函数注入 Service 和 Validate。
|
||
- 标准接口调用 `parent::index()`、`parent::show()`、`parent::store()`、`parent::update()`、`parent::destroy()`。
|
||
- 路由通过 OpenAPI Attribute 标注。
|
||
- 权限码与前端和菜单保持一致。
|
||
|
||
推荐路由格式:
|
||
|
||
```text
|
||
GET /{module}/{resource}
|
||
GET /{module}/{resource}/{id}
|
||
POST /{module}/{resource}
|
||
PUT /{module}/{resource}/{id}
|
||
DELETE /{module}/{resource}/{id}
|
||
POST /{module}/{resource}/{id}/{custom-action}
|
||
```
|
||
|
||
应用授权示例:
|
||
|
||
```text
|
||
/plugin/application-auth
|
||
/plugin/application-auth/{id}
|
||
/plugin/application-auth/{id}/reset-secret
|
||
```
|
||
|
||
## 前端开发流程
|
||
|
||
### 1. API
|
||
|
||
路径参考用户指定目录结构。
|
||
|
||
例如参考 `/tools/delegation` 时:
|
||
|
||
```text
|
||
frontend/admin/src/api/tools/{feature}/index.ts
|
||
frontend/admin/src/api/tools/{feature}/types.ts
|
||
```
|
||
|
||
要求:
|
||
|
||
- 使用 `BaseService`。
|
||
- 使用 `@/utils/http`。
|
||
- 基础路径与后端路由一致。
|
||
- 自定义接口单独封装方法。
|
||
|
||
示例:
|
||
|
||
```ts
|
||
const baseUrl = '/plugin/application-auth'
|
||
```
|
||
|
||
### 2. 页面
|
||
|
||
路径参考用户指定目录结构。
|
||
|
||
例如参考 `/tools/delegation` 时:
|
||
|
||
```text
|
||
frontend/admin/src/views/tools/{feature}/index.vue
|
||
frontend/admin/src/views/tools/{feature}/schemas/index.tsx
|
||
```
|
||
|
||
要求:
|
||
|
||
- 使用 `useCrud` 和 `BasicCrud`。
|
||
- CRUD 配置写在 `schemas/index.tsx`。
|
||
- 不要使用项目未注册的表单组件。
|
||
- 当前项目日期时间选择使用 `DatePicker` + `componentProps.type = 'datetime'`。
|
||
- 当前项目 `CrudSchema` 列类型不支持 `type: 'operate'`,操作列由 `BasicCrud` 根据 `tableActions` / `dropDownActions` 自动生成。
|
||
|
||
### 3. 列表字段
|
||
|
||
按照用户需求定义:
|
||
|
||
- 序号:`type: 'index'`
|
||
- 名称:普通列
|
||
- Access Key:建议列表遮罩显示
|
||
- Secret Key:建议列表遮罩显示
|
||
- 失效时间:使用 `formatDateTime`
|
||
- 状态:使用 `ApiDict`
|
||
- 描述:`showOverflowTooltip`
|
||
- 创建时间:优先使用后端格式化字段,或 `formatDateTime(created_at)`
|
||
- 操作:通过 CRUD 操作配置生成
|
||
|
||
### 4. 表单字段
|
||
|
||
自动生成字段不要出现在新增表单中。
|
||
|
||
应用授权示例:
|
||
|
||
- `name`:必填
|
||
- `expired_at`:可选
|
||
- `enabled`:必填,默认 `1`
|
||
- `description`:可选
|
||
- `access_key`:后端自动生成,不手填
|
||
- `secret_key`:后端自动生成,不手填
|
||
|
||
### 5. 自定义操作
|
||
|
||
例如重置 Secret Key:
|
||
|
||
- 前端按钮放在 `dropDownActions` 或项目实际支持的操作配置中。
|
||
- 按钮增加 `auth`。
|
||
- 操作前使用 `ElMessageBox.confirm` 二次确认。
|
||
- 成功后提示新密钥并刷新列表。
|
||
|
||
## 菜单与权限
|
||
|
||
菜单数据路径:
|
||
|
||
```text
|
||
backend/resource/data/menu/admin.php
|
||
```
|
||
|
||
页面菜单示例字段:
|
||
|
||
```php
|
||
"title" => "应用授权",
|
||
"code" => "plugin:application-auth:list",
|
||
"type" => 2,
|
||
"path" => "/tools/application-auth",
|
||
"component" => "/tools/application-auth/index",
|
||
"methods" => "GET",
|
||
```
|
||
|
||
按钮权限建议补齐:
|
||
|
||
```text
|
||
plugin:application-auth:create
|
||
plugin:application-auth:delete
|
||
plugin:application-auth:update
|
||
plugin:application-auth:read
|
||
plugin:application-auth:reset-secret
|
||
```
|
||
|
||
按钮节点:
|
||
|
||
- `type` 使用 `3`。
|
||
- `is_show` 使用 `0`。
|
||
- `path`、`component`、`icon` 通常为 `null`。
|
||
- `methods` 与接口方法保持一致。
|
||
|
||
## 迁移执行流程
|
||
|
||
当前项目没有 Laravel `artisan` 文件,不使用:
|
||
|
||
```bash
|
||
php artisan migrate
|
||
php artisan migrate:status
|
||
```
|
||
|
||
当前项目使用:
|
||
|
||
```bash
|
||
php webman madong-migrate status
|
||
php webman madong-migrate up --dry-run
|
||
php webman madong-migrate up
|
||
```
|
||
|
||
### 执行前必须 dry-run
|
||
|
||
```bash
|
||
php webman madong-migrate up --dry-run
|
||
```
|
||
|
||
确认输出中将执行的迁移文件。
|
||
|
||
注意:
|
||
|
||
- `madong-migrate up` 会执行所有未执行迁移。
|
||
- 当前命令不支持 Laravel 的 `--path=` 单文件迁移参数。
|
||
- 如果只允许迁移单个文件,不要直接执行 `madong-migrate up`。
|
||
|
||
### 事务异常注意事项
|
||
|
||
如果执行迁移时出现:
|
||
|
||
```text
|
||
There is no active transaction
|
||
```
|
||
|
||
常见原因:
|
||
|
||
- MySQL DDL 会隐式提交事务。
|
||
- 迁移命令将多个 DDL 包在事务中,可能导致事务管理器提交时发现事务已结束。
|
||
|
||
处理流程:
|
||
|
||
1. 先不要重复执行迁移。
|
||
2. 检查数据表是否已经创建成功。
|
||
3. 执行 `php webman madong-migrate status` 查看迁移日志状态。
|
||
4. 如果表已创建但日志未写入,需要谨慎补齐迁移日志或修复迁移命令事务逻辑后再处理。
|
||
5. 不要盲目回滚或再次执行全部迁移,避免表已存在导致二次错误。
|
||
|
||
## 校验清单
|
||
|
||
### 后端校验
|
||
|
||
对新增 PHP 文件执行语法检查:
|
||
|
||
```bash
|
||
php -l app/model/{module}/{Model}.php
|
||
php -l app/dao/{module}/{Model}Dao.php
|
||
php -l app/service/admin/{module}/{Model}Service.php
|
||
php -l app/adminapi/validate/{module}/{Model}Validate.php
|
||
php -l app/adminapi/schema/request/{module}/{Model}FormRequest.php
|
||
php -l app/adminapi/schema/request/{module}/{Model}QueryRequest.php
|
||
php -l app/adminapi/schema/response/{module}/{Model}Response.php
|
||
php -l app/adminapi/controller/{module}/{Model}Controller.php
|
||
php -l resource/database/migrations/{migration_file}.php
|
||
php -l resource/data/menu/admin.php
|
||
```
|
||
|
||
### 前端校验
|
||
|
||
只检查新增文件:
|
||
|
||
```bash
|
||
pnpm exec eslint src/views/{module}/{feature}/index.vue src/views/{module}/{feature}/schemas/index.tsx src/api/{module}/{feature}/index.ts src/api/{module}/{feature}/types.ts
|
||
```
|
||
|
||
### 路径一致性校验
|
||
|
||
检查以下内容必须一致:
|
||
|
||
- 后端 Controller OpenAPI path。
|
||
- 前端 API `baseUrl`。
|
||
- 菜单 `path`。
|
||
- 菜单 `component`。
|
||
- 前端 view 文件路径。
|
||
- 权限码。
|
||
|
||
## Skill 自动进化规则
|
||
|
||
开发过程中如果发现 skill 与真实项目不一致,必须先更新 skill,再继续使用。
|
||
|
||
需要自动进化的典型情况:
|
||
|
||
- 迁移主键写法与项目不一致。
|
||
- 前端 API 模板导入路径不一致。
|
||
- 表单组件名不存在。
|
||
- CRUD 列类型与 TypeScript 类型不一致。
|
||
- 菜单权限结构与项目实际不一致。
|
||
- 路由路径或权限码规则与项目实际不一致。
|
||
|
||
更新要求:
|
||
|
||
- 只更新已验证的不一致点。
|
||
- 不做无关重写。
|
||
- 最终总结中说明更新了哪些 skill。
|
||
|
||
## 完整输出清单
|
||
|
||
完成一个 Admin 全栈 CRUD 功能后,应至少包含:
|
||
|
||
```text
|
||
backend/resource/database/migrations/{migration}.php
|
||
backend/app/model/{module}/{Model}.php
|
||
backend/app/dao/{module}/{Model}Dao.php
|
||
backend/app/service/admin/{module}/{Model}Service.php
|
||
backend/app/adminapi/validate/{module}/{Model}Validate.php
|
||
backend/app/adminapi/schema/request/{module}/{Model}FormRequest.php
|
||
backend/app/adminapi/schema/request/{module}/{Model}QueryRequest.php
|
||
backend/app/adminapi/schema/response/{module}/{Model}Response.php
|
||
backend/app/adminapi/controller/{module}/{Model}Controller.php
|
||
frontend/admin/src/api/{section}/{feature}/index.ts
|
||
frontend/admin/src/api/{section}/{feature}/types.ts
|
||
frontend/admin/src/views/{section}/{feature}/index.vue
|
||
frontend/admin/src/views/{section}/{feature}/schemas/index.tsx
|
||
backend/resource/data/menu/admin.php
|
||
```
|
||
|
||
## 最终回复模板
|
||
|
||
完成后向用户说明:
|
||
|
||
- 新增了哪些后端文件。
|
||
- 新增了哪些前端文件。
|
||
- 菜单和权限是否已配置。
|
||
- 迁移是否执行,执行结果如何。
|
||
- 校验命令和结果。
|
||
- 是否自动进化了 skill。
|
||
- 是否有需要用户后续处理的事项。
|