6.2 KiB
6.2 KiB
Design Document: Menu CRUD
Overview
完善菜单管理页面的 CRUD 功能。后端 API 已完整实现,本设计主要关注前端实现:补充 API 接口定义、实现表单对话框、完善操作逻辑。
Architecture
┌─────────────────────────────────────────────────────────┐
│ Menu Page (index.vue) │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Menu Table │ │ Menu Dialog │ │ Delete Confirm │ │
│ │ (Tree View) │ │ (Form) │ │ Dialog │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ Menu API (menu.ts) │
│ getMenuTree | createMenu | updateMenu | deleteMenu │
├─────────────────────────────────────────────────────────┤
│ Backend API (已实现) │
│ GET /menus | POST /menus | PUT /menus/{id} | DELETE │
└─────────────────────────────────────────────────────────┘
Components and Interfaces
Menu API 接口补充
// 创建菜单请求
export interface CreateMenuRequest {
parentId: number
name: string
path?: string
component?: string
icon?: string
menuType: number // 1=目录, 2=菜单, 3=按钮
permission?: string
sortOrder: number
status: number // 1=显示, 0=隐藏
isExternal: boolean
isCache: boolean
}
// 更新菜单请求
export interface UpdateMenuRequest {
parentId: number
name: string
path?: string
component?: string
icon?: string
menuType: number
permission?: string
sortOrder: number
status: number
isExternal: boolean
isCache: boolean
}
// API 函数
export function createMenu(data: CreateMenuRequest): Promise<ApiResponse<number>>
export function updateMenu(id: number, data: UpdateMenuRequest): Promise<ApiResponse<void>>
export function deleteMenu(id: number): Promise<ApiResponse<void>>
export function getMenuById(id: number): Promise<ApiResponse<MenuTree>>
Menu Form 表单字段
| 字段 | 类型 | 组件 | 验证规则 |
|---|---|---|---|
| parentId | number | el-tree-select | 可选,默认0表示顶级 |
| name | string | el-input | 必填 |
| menuType | number | el-radio-group | 必填,1/2/3 |
| icon | string | el-input | 可选,目录/菜单时显示 |
| path | string | el-input | 菜单类型时必填 |
| component | string | el-input | 菜单类型时必填 |
| permission | string | el-input | 按钮类型时必填 |
| sortOrder | number | el-input-number | 必填,>=0 |
| status | number | el-radio-group | 必填,0/1 |
| isExternal | boolean | el-switch | 可选 |
| isCache | boolean | el-switch | 可选 |
表单验证逻辑
const formRules = {
name: [{ required: true, message: '请输入菜单名称' }],
menuType: [{ required: true, message: '请选择菜单类型' }],
path: [{
required: true,
validator: (rule, value, callback) => {
if (formData.menuType === 2 && !value) {
callback(new Error('菜单类型必须填写路由路径'))
} else {
callback()
}
}
}],
component: [{
required: true,
validator: (rule, value, callback) => {
if (formData.menuType === 2 && !value) {
callback(new Error('菜单类型必须填写组件路径'))
} else {
callback()
}
}
}],
permission: [{
validator: (rule, value, callback) => {
if (formData.menuType === 3 && !value) {
callback(new Error('按钮类型必须填写权限标识'))
} else {
callback()
}
}
}]
}
Data Models
表单数据模型
interface MenuFormData {
id: number
parentId: number
name: string
path: string
component: string
icon: string
menuType: number
permission: string
sortOrder: number
status: number
isExternal: boolean
isCache: boolean
}
// 默认值
const defaultFormData: MenuFormData = {
id: 0,
parentId: 0,
name: '',
path: '',
component: '',
icon: '',
menuType: 2,
permission: '',
sortOrder: 0,
status: 1,
isExternal: false,
isCache: true
}
Correctness Properties
A property is a characteristic or behavior that should hold true across all valid executions of a system.
本功能主要是 UI 交互,大部分验证在后端完成。以下是可测试的属性:
Property 1: 表单提交数据完整性 For any valid form submission, the request payload SHALL contain all required fields based on menuType. Validates: Requirements 6.1, 6.2, 6.3
Property 2: 父菜单选择排除自身 For any menu being edited, the parent menu selector SHALL NOT include the menu itself or its descendants. Validates: Requirements 4.3
Error Handling
| 场景 | 处理方式 |
|---|---|
| API 请求失败 | 显示 ElMessage.error 提示错误信息 |
| 表单验证失败 | 阻止提交,显示字段错误提示 |
| 删除有子菜单的菜单 | 后端返回错误,前端显示提示 |
| 网络超时 | 显示网络错误提示 |
Testing Strategy
由于本功能主要是 UI 交互,测试策略以手动测试为主:
- 功能测试:验证新增、编辑、删除操作正常工作
- 表单验证测试:验证必填字段和条件必填逻辑
- 边界测试:测试空数据、特殊字符等边界情况