# AI 辅助编程规范与实战示例——以「货物类型模块」为例

> 文档目的：向业主说明我们团队如何用 AI 协作完成前端开发，包含协作流程、工程规范、以及一个可直接对照代码的真实模块示例，便于业主了解我们的工作方式、质量保障手段与可复用的经验。



---

## 一、背景：我们为什么用 AI 编程

本项目（Saber3 企业级后台）是一个模块多、表单多、校验规则多、样式规范严苛的大型 Vue 3 工程。传统人工开发存在两个痛点：

1. **重复劳动多**：每个 CRUD 模块的列表、搜索、新增、编辑、导入、导出结构高度相似，但样式细节（表格线色、偶数行底色、操作列宽度、弹窗竖条等）又极易被写错。
2. **规范易漂移**：数十个模块由不同人开发，若没有统一约束，代码风格、校验口径、审计字段展示会逐渐不一致。

我们引入 AI 编程的核心思路不是"让 AI 自由发挥"，而是**把人类沉淀的工程规范喂给 AI，让 AI 在规范的边界内批量、稳定地产出代码，再由人工做业务与视觉复核**。这样既提效，又保住质量底线。

---

## 二、我们的 AI 协作流程（总览）

```
需求澄清 ──> 需求卡（单一事实来源）──> AGENTS.md（工程规范）──> AI 生成代码
   │                                                          │
   └──────────────── 人工复核 / 验收 ──────────────────────────┘
```

四个关键阶段：

| 阶段      | 产物                          | 负责人     | 说明                               |
| ------- | --------------------------- | ------- | -------------------------------- |
| 1. 需求澄清 | 模块需求卡（.md）                  | 产品/前端   | 用 `模块需求卡生成规范.md` 统一格式，拆成 REQ 编号项 |
| 2. 规范约束 | AGENTS.md                   | 架构/前端   | 把技术栈、风格、样式、校验、审计等写成"对 AI 的强制条款"  |
| 3. 代码生成 | view / option / api / utils | AI + 前端 | AI 按 AGENTS.md 生成，前端实时纠偏         |
| 4. 复核验收 | 可运行模块                       | 前端/测试   | 校验业务规则、视觉规范、边界异常                 |

**核心原则：需求卡和 AGENTS.md 是 AI 与人对齐的"单一事实来源"，不靠口头交代。**

---

## 三、工程规范如何约束 AI（AGENTS.md 核心条款节选）

我们维护了一份 `AGENTS.md`，作为 AI 每次动手前的"必读规范"。与本示例强相关的条款有：

### 3.1 文件同构结构

```
src/
├── views/base/cargo-type.vue     # 页面（模板 + 交互逻辑）
├── option/base/cargo-type.js     # Avue 表格/表单配置（与 views 同构路径）
└── api/base/cargo-type.js        # 接口层（按业务模块组织）
```

> 规范要点：Avue 配置独立存放于 `src/option/`，与 `views` 和 `api` 保持同构的模块路径映射。AI 生成时不会把配置写死在页面里。

### 3.2 样式规范（极易被写错，故用规范强制）

- 表格线条颜色统一 `#EFF1F7`；偶数行背景 `#FAFAFA`，固定列须与行背景一致；
- 操作列同时展示"查看/编辑/删除"时宽度不小于 `220px`；
- `.avue-crud__header` 顶部间距 `12px`；
- `.basic-container__card` 内层 `el-card` 去卡片化（`padding: 0`）；
- 主色统一 `#409eff`。

### 3.3 表单校验规范

- 金额类非负、经纬度范围、备注类 ≤200 字（前端阻止提交并提示）；
- 新增、导入、编辑三处的校验口径必须一致；
- 审计字段（创建人/更新人）**禁止直接展示用户 ID**，须绑定后端返回的姓名字段（`createUserName`）。

### 3.4 批量导入失败明细规范（本项目重点）

- 部分数据导入失败时，前端必须自动下载后端返回的失败 Excel；
- 失败 Excel 字段顺序须与原模板一致，最后追加"导入失败原因"列；
- 前端需根据 `content-type` 区分"JSON 成功响应"与"Excel 文件流"；
- 失败明细文件命名含业务名、导入失败明细、时间戳。

---

## 四、实例拆解：货物类型模块

### 4.1 模块能力一览

货物类型是一个**两级层级**的主数据模块：一级货物类型（2 位编码）+ 二级货物类型（4 位编码，前 2 位须与上级一致）。功能包括：列表、条件查询、新增、编辑、查看、删除、批量删除、**批量导入 + 模板下载 + 失败明细加工**、批量导出。

### 4.2 文件同构结构（真实存在）

```
src/views/base/cargo-type.vue       # 589 行，页面 + 交互
src/option/base/cargo-type.js       # 189 行，Avue 列配置 + 校验器
src/api/base/cargo-type.js          # 74 行，7 个接口方法
src/utils/import-excel.js           # 109 行，通用导入弹窗（被本模块复用）
```

### 4.3 AI 按规范落地的关键代码点

下面每一条都对应前述规范条款，可直接对照源码。

**① 三级文件分离（对应 3.1）**

页面只负责交互，配置与接口独立：

```js
// src/views/base/cargo-type.vue
import { getList, getNextCode, getParentOptions, remove, submit } from '@/api/base/cargo-type';
import { getCargoTypeOption } from '@/option/base/cargo-type';
```

**② 表单校验三处一致（对应 3.3）**

前端表单（option）与 JS 内 `validateRow` 共用同一套规则口径，避免"表单能过、导入却崩"：

```js
// src/views/base/cargo-type.vue —— 提交前的统一校验
validateRow(row) {
  const pattern = row.typeLevel === 1 ? /^\d{2}$/ : /^\d{4}$/;
  if (!pattern.test(row.cargoCode)) { this.$message.warning('货物类型编码格式不正确'); return false; }
  if (row.typeLevel === 2 && !row.cargoCode.startsWith(row.parentCargoCode)) {
    this.$message.warning('二级编码前2位必须与上级货物类型编码一致'); return false;
  }
  if (row.remark.length > 200) { this.$message.warning('备注不能超过200字'); return false; }
  return true;
}
```

```js
// src/option/base/cargo-type.js —— 弹窗表单的同源校验器
{ validator: (rule, value, callback) => {
    const form = ctx.form || {};
    const pattern = form.typeLevel === 1 ? /^\d{2}$/ : /^\d{4}$/;
    // 同样的规则：格式 + 二级前缀一致性
}, trigger: 'blur' }
```

**③ 审计字段用姓名不用 ID（对应 3.3）**

```vue

<template #createUserName="{ row }">
  {{ row.createUserName || row.createUser || '' }}
</template>
```

列表直接绑定 `createUserName`，避免出现一串无意义的用户 ID。

**④ 导入失败明细加工（对应 3.4，本项目 AI 协作的亮点）**

后端只返回原始失败原因文本，AI 被要求生成一个**可独立测试的小函数** `decorateCargoTypeFailDetail`，把原因按 A./B./C. 编号、追加规则说明、仅"导入失败原因"列标红、自动加宽列：

```js
// src/views/base/cargo-type.vue
export const decorateCargoTypeFailDetail = async workbook => {
  // 1. 映射表头列号
  // 2. 清理非原因列的多余红色字体
  // 3. 把每行原因拆条、编号、拼接规则说明
  // 4. 仅操作"导入失败原因"列样式（黑字、无填充、自动换行）
  // 5. 按 CARGO_TYPE_FAIL_COL_WIDTH 加宽各列
};
```

该函数通过通用导入工具 `import-excel.js` 的 `failDetailDecorator` 钩子注入，做到**模块零耦合复用**：

```js
// 复用通用导入弹窗，仅传入本模块的加工函数
handleImport() {
  openImportDialog(this, '货物类型', undefined, {
    failDetailDecorator: decorateCargoTypeFailDetail,
  });
}
```

**⑤ 样式规范落地（对应 3.2）**

```scss
/* src/views/base/cargo-type.vue <style> */
:deep(.el-table) {
  --el-table-border-color: #eff1f7;   /* 表格线条统一色 */
}
:deep(.el-table__body tr:nth-child(even) > td.el-table__cell) {
  background: #fafafa;                 /* 偶数行底色，固定列同色 */
}
:deep(.basic-container__card) > .el-card__body { padding: 0; }  /* 去卡片化 */
```

### 4.4 人机协作中，AI 不擅长、需要人工兜底的部分

诚实地说，AI 不是万能的。本模块在协作中由人工重点把控的有：

1. **业务规则澄清**：一级/二级层级关系、编码前缀约束这类"业务语义"，需要产品/前端先讲清，AI 才能写出正确校验。
2. **视觉细节微调**：表格行高、表头高度、间距的最终眼检，依赖人工在浏览器里确认。
3. **前后端字段契约**：`CargoTypeVO` 是否返回 `createUserName`、失败 Excel 的表头文案，必须与后端对齐，AI 无法替你确认。
4. **破坏性操作确认**：删除/批量删除的二次确认文案与风险，由人工定稿。

---

## 五、经验沉淀（可复用的 5 条）

1. **把规范写成 `AGENTS.md`，比口头交代可靠 10 倍。** AI 每次都会读，规范不会因人离职而丢失。
2. **需求卡是 AI 与人对齐的单一事实来源。** 用统一格式（REQ 编号 + 功能点/异常边界/反例）避免"我以为你要的是……"。
3. **把重复能力抽成 utils。** 如 `import-excel.js`，新模块导入直接复用，AI 只需写"本模块特有的加工函数"。
4. **校验三处一致**：前端表单、前端导入、后端校验口径对齐，且一处改、三处同步改。
5. **让 AI 生成"小而纯"的函数**（如失败明细加工函数），比让它改一整个 600 行页面更可控、更易测、更易复核。

---

## 六、给业主的价值与建议

| 维度      | 传统方式      | 我们的 AI 协作方式      |
| ------- | --------- | ---------------- |
| 单模块开发周期 | 长，易返工     | 短，规范内一次成型        |
| 多模块一致性  | 易漂移       | AGENTS.md 强制统一   |
| 规范传承    | 靠老人带      | 沉淀为文件，新人/AI 即取即用 |
| 质量风险    | 校验、审计字段易漏 | 规范条款逐项约束         |

**建议**：业主要求交付的不只是代码，更是"可持续维护的规范资产"。我们交付的每个模块背后都有需求卡 + AGENTS.md + 复用 utils 三件套，后续无论是换人维护还是扩展新模块，成本都显著更低。

---

*附：本示例涉及的全部源码路径*

- `src/views/base/cargo-type.vue`
- `src/option/base/cargo-type.js`
- `src/api/base/cargo-type.js`
- `src/utils/import-excel.js`
- `AGENTS.md`（工程规范总纲）
- `模块需求卡生成规范.md`（需求卡格式规范）
