核心价值:第一个模块 1.5 天(含建规范),后续每个模块平均 4 小时,边际成本趋近于零。
AI
核心思路
把一个 CRUD 模块拆成 3 层 Spec,AI 每次只生成对应层,互不污染:
| Spec 文件 | 用途 | 维护频率 |
|---|---|---|
crud-template.spec.md |
所有模块的通用骨架,写一次永久用 | 极低,有新规范才改 |
ui-token.spec.md |
Element Plus 组件库用法规范 | 低,升级时更新 |
{module}.spec.md |
本次业务模块的字段、接口、权限 | 每个新模块写一份 |
每次跑 Prompt 生成 5 个文件:列表页 / 表单弹窗 / API 封装 / 类型定义 / 路由配置
Step 1 — 写 crud-template.spec.md(一次性,永久复用)
# crud-template.spec.md(通用模板,不要改)
## 列表页结构(固定)
顶部:搜索区(折叠/展开)+ 右侧操作按钮组(新增 / 导出)
中部:数据表格,支持列排序,固定操作列在最右
底部:分页器,每页 20 条,显示总数
## 表格必须包含的列(所有模块通用)
- 序号列(宽 60px,不排序)
- 业务数据列(由 module.spec.md 定义)
- 状态列(宽 100px,Tag 展示)
- 创建时间(宽 180px,默认降序排列)
- 操作列(固定右侧 120px:编辑 / 删除)
## 新增/编辑弹窗规范
- 统一用 el-dialog,宽 600px,移动端全屏
- 表单双列布局(label 在左,宽 80px)
- 校验时机:失焦触发,不是提交时
- 底部按钮:左对齐"取消",右对齐"确定"
- 提交期间:确定按钮 loading,禁止重复点击
## 删除确认
- 单条:el-popconfirm(不用 el-message-box)
- 批量:el-message-box,展示将删除的条数
## 接口规范(RESTful)
GET /api/{module} 列表(分页 + 筛选)
POST /api/{module} 新增
PUT /api/{module}/:id 编辑
DELETE /api/{module}/:id 删除(软删除)
## 请求/响应结构(固定格式)
请求分页参数:{ page, pageSize, ...filters }
响应格式:{ code, data: { list, total }, message }
## 权限控制(按钮级别)
新增按钮:v-permission="'{module}:add'"
编辑按钮:v-permission="'{module}:edit'"
删除按钮:v-permission="'{module}:delete'"
## 公共组件(必须复用,不重复造轮子)
- SearchForm:搜索区表单
- PageTable:数据表格(含分页)
- StatusTag:状态 Tag 展示
- OperateButtons:操作按钮组(编辑/删除)
## 错误处理规范
- 接口错误:统一由 request.ts 拦截,ElMessage.error 提示
- 表单校验失败:高亮字段,不弹 Toast
- 网络超时:提示"网络异常,请稍后重试",不暴露技术细节
Step 2 — 写 ui-token.spec.md(Element Plus 用法规范)
# ui-token.spec.md(Element Plus 规范)
## 表单组件
- 输入框:el-input,clearable 默认开启
- 下拉:el-select,filterable 超过 10 条开启
- 日期:el-date-picker,format="YYYY-MM-DD",value-format="YYYY-MM-DD"
- 数字:el-input-number,controls-position="right"
- 开关:el-switch,active-value=1 inactive-value=0(对应后端 0/1)
## 校验规则格式(统一写法)
rules: {
fieldName: [
{ required: true, message: '请输入XX', trigger: 'blur' },
{ min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
]
}
## 表格规范
- stripe: true(斑马纹)
- border: true(边框)
- highlight-current-row: true
- 空数据:empty-text="暂无数据"
- 加载:v-loading="loading"(不用骨架屏)
## 弹窗规范
- width="600px"
- :close-on-click-modal="false"(禁止点遮罩关闭)
- @close 时重置表单:formRef.value?.resetFields()
## 消息提示
- 成功:ElMessage.success('操作成功')
- 失败:ElMessage.error(err.message || '操作失败')
- 确认删除(批量):ElMessageBox.confirm
- 确认删除(单条):ElPopconfirm
## 按钮规范
- 主操作(新增/确定):type="primary"
- 次操作(导出/重置):无 type(默认样式)
- 危险操作(删除):type="danger"
- 按钮间距:gap: 8px
Step 3 — 写 module.spec.md(每个新模块 5 分钟,以"角色管理"为例)
只写业务差异,通用规范已在 crud-template.spec.md 里:
# role-module.spec.md(角色管理模块)
## 引用
遵循 @crud-template.spec.md 和 @ui-token.spec.md 的所有规范
## 模块基本信息
- 路由路径:/system/role
- API 前缀:/api/system/role
- 权限前缀:system:role
## 业务字段定义
| 字段名 | 类型 | 必填 | 说明 | 表格展示 | 表单展示 |
|-----------|----------|------|----------------------------|----------|--------------------------|
| roleName | string | 是 | 角色名称,2~20字 | 是 | 是 |
| roleCode | string | 是 | 角色编码,大写+下划线 | 是 | 新增可编辑,编辑时 disabled |
| roleSort | number | 是 | 排序,默认0,越小越前 | 否 | 是 |
| status | 0 \| 1 | 是 | 0=禁用 1=启用 | 是(Tag)| 是(Switch) |
| menuIds | number[] | 否 | 绑定菜单ID列表 | 否 | 是(树形选择) |
| remark | string | 否 | 备注,最多200字 | 否 | 是 |
## 搜索条件
- roleName(el-input,模糊搜索)
- status(el-select:全部 / 启用 / 禁用)
- 创建时间范围(el-date-picker,type="daterange")
## 特殊交互(超出通用规范的部分)
1. roleCode 新增时可编辑,编辑时 disabled(通过 isEdit props 控制)
2. 编辑弹窗底部额外有"权限配置"区域
- el-tree 树形菜单,支持全选/反选
- 接口:GET /api/system/menu/tree 获取菜单树
3. status=禁用时,编辑/删除按钮仍可操作(不 disabled)
## 接口定义
| 方法 | 路径 | 参数说明 |
|--------|-------------------------|------------------------------------------------------|
| GET | /api/system/role | { roleName?, status?, startTime?, endTime?, page, pageSize } |
| POST | /api/system/role | { roleName, roleCode, roleSort, status, menuIds?, remark? } |
| PUT | /api/system/role/:id | 同新增(roleCode 字段后端忽略) |
| DELETE | /api/system/role/:id | 无 body |
| GET | /api/system/menu/tree | 无参数,返回菜单树结构 |
Step 4 — 一次性 Prompt 生成 5 个文件
请基于以下 Spec,为"角色管理"模块生成完整代码:
【通用规范】@crud-template.spec.md
【UI 规范】@ui-token.spec.md
【模块定义】@role-module.spec.md
【参考代码】@src/views/system/user/index.vue(风格最接近的已有模块)
需要生成的 5 个文件:
1. src/views/system/role/index.vue ← 列表页(含搜索 + 表格 + 分页)
2. src/views/system/role/RoleDialog.vue ← 新增/编辑弹窗(含权限配置树)
3. src/api/system/role.ts ← 接口封装
4. src/types/system/role.d.ts ← TypeScript 类型定义
5. src/router/modules/system.ts ← 新增路由(追加,不替换原有配置)
约束:
- 严格复用已有公共组件(SearchForm / PageTable / StatusTag / OperateButtons)
- 权限指令使用 v-permission,不自己实现权限逻辑
- 所有 CSS 使用 scoped + CSS 变量,不写内联样式
- roleCode 的 disabled 逻辑通过 isEdit prop 控制,不用 v-if 条件渲染两个 input
- 生成完成后列出每个文件的核心改动点,方便 diff 检查
Step 5 — 验证四件事
npx tsc --noEmit # 类型无误
npx eslint src --ext .vue,.ts # 规范符合
git diff --stat # 确认只改了预期文件
# 浏览器跑通:列表 → 搜索 → 新增 → 编辑 → 删除 → 权限配置
下一个新模块怎么做(以"菜单管理"为例)
- 新建
menu-module.spec.md(5 分钟填字段表,只写业务差异) - Step 4 的 Prompt 里把
@role-module.spec.md换成@menu-module.spec.md - 参考代码换成
src/views/system/role/index.vue(刚生成的,风格最新) - 跑 Prompt → 5 个文件生成 → 验证
第 1 个模块:1.5 天(含建规范)
第 2~N 个模块:每个约 4 小时
收益(面试话术)
"我们项目有 12 个管理模块,传统方式每个需要 2~3 天。SDD 之后第一个模块 1.5 天(含建规范),后续每个平均 4 小时,节省约 60% 的时间。而且代码风格高度一致,Code Review 基本不在结构和样式上花时间,只看业务逻辑。"
Spec 目录结构建议
docs/specs/
crud-template.spec.md ← 永久复用,轻易不改
ui-token.spec.md ← 升级 Element Plus 时更新
modules/
user-module.spec.md ← 用户管理
role-module.spec.md ← 角色管理
menu-module.spec.md ← 菜单管理
dept-module.spec.md ← 部门管理
...