新增业务模块
下面以“部门管理”为例,说明一个标准 CRUD 模块的落地过程。
1. 定义类型
ts
export interface DepartmentRow {
id: number
name: string
status: string
createdAt: string
}
export interface DepartmentForm {
id?: number
name: string
status: string
}类型可放在模块目录,也可在多个模块共享时放入 src/types。
2. 定义 API
在 src/api/system/department/index.ts 中集中定义列表、详情、新增、更新、删除、批量删除和导出接口。列表返回 PageResult<DepartmentRow>,写接口开启成功提示。
生产接口推荐:
| 行为 | 方法 | 路径 |
|---|---|---|
| 分页列表 | GET | /api/system/departments |
| 详情 | GET | /api/system/departments/:id |
| 新增 | POST | /api/system/departments |
| 更新 | PUT | /api/system/departments/:id |
| 删除 | DELETE | /api/system/departments/:id |
| 批量删除 | DELETE | /api/system/departments/batch |
3. 创建列表页
创建 src/views/system/department/index.vue:
- 使用
SearchItem[]描述名称、状态等筛选条件。 - 使用
Table展示列、分页、选择状态和加载失败状态。 - 查询前设置 loading,失败时设置
loadError=true。 - 搜索或重置时将页码回到 1。
- 枚举选项来自
dictStore.options('common_status')。 - 状态列使用
dictStore.tag('common_status', row.status)。
4. 创建表单弹窗
创建 components/save.vue,对外暴露 open(row?):
- 新增时恢复默认表单,编辑时请求详情或复制行数据。
- 打开前清除上次校验状态。
- 提交前运行 Naive UI 表单验证。
- 根据是否存在主键选择 create/update API。
- 成功后关闭弹窗并触发
emit('success'),父页面重新查询。
不要只做前端必填校验;后端仍需执行完整的类型、长度、范围、权限和唯一性校验。
5. 配置操作列
ts
const rowActions = useRowActions<DepartmentRow>({
inline: [
{
label: '编辑',
type: 'primary',
auth: 'update',
onClick: (row) => saveRef.value?.open(row),
},
{
label: '删除',
type: 'error',
auth: 'delete',
confirm: (row) => `确认删除“${row.name}”吗?`,
onClick: async (row) => {
await deleteApi(row.id)
await queryList()
},
},
],
})列定义中使用 render: (row) => rowActions.render(row)。auth 与当前路由 meta.actionList 比对,无权限的操作自动隐藏。
6. 批量操作
给 Table 开启选择列,监听 update:checkedRowKeys,使用 useBatchOptions 分批串行处理。操作结束后清空选择并刷新列表。服务端如返回逐项结果数组,组合式函数会展示结果表格。
7. 配置后端菜单
后端菜单中增加:
json
{
"id": 120,
"parent_id": 100,
"path": "/system/department",
"name": "SystemDepartment",
"title": "部门管理",
"component": "system/department/index.vue",
"icon": "Iconpark-Peoples",
"is_hide": "N",
"fixed_tab": "N",
"action_list": [
{ "action": "create" },
{ "action": "update" },
{ "action": "delete" },
{ "action": "export" }
]
}component 必须能匹配 src/views/**/*.vue。菜单 name 应全局唯一,path 不得与静态路由冲突。
8. 验收
- 无权限账号看不到菜单和按钮,并且直接调用接口也被后端拒绝。
- 查询、分页、重置、空数据、加载失败、重复提交均表现正确。
- 新增、编辑、删除、批量操作后数据一致。
- 刷新页面与直接访问深层 URL 正常。
- 中英文、明暗主题和窄屏布局无明显问题。