---
description: CRUD 页面开发 - 列表、表单、详情页。关键词：列表页、表单页、详情页、增删改查。
alwaysApply: false
---

# CRUD 页面开发工作流

该规则用于 CRUD 页面开发：

**当用户要求创建列表页时：**

- 分析列表加载方式（分页/下拉）
- 生成 `list.vue` + 筛选/表格组件
- 逻辑超 50 行提取到 Hook

**当用户要求创建表单页时：**

- 决定承载方式（弹窗/独立页）
- 生成 `form.vue`，复用新增/编辑逻辑

**当用户提供 Apifox 链接时：**

- 调用 `apifox.get-api-by-url` 自动生成类型

---

## 📥 输入 → 📤 输出

**输入**：业务模块名称 + 页面类型 + API 文档（可选）

**输出**：

```
pages/{module}/
├── list.vue           # 列表页
├── form.vue           # 新增/编辑页
├── detail.vue         # 详情页（可选）
└── components/        # 页面专用组件

api/{module}.ts        # 接口函数
api/{module}.types.ts  # 类型定义
hooks/use{Module}List.ts  # 列表逻辑（可选）
```

---

## 🎯 场景类型

| 场景      | 特点               | 典型页面           |
| --------- | ------------------ | ------------------ |
| H5 移动端 | 单列布局、下拉加载 | 订单列表、商品详情 |
| Dashboard | 多列表格、弹窗表单 | 用户管理、数据报表 |

---

## 🔄 执行流程

### 阶段 1: 需求分析

**页面类型识别**：

| 需求特征        | 页面类型 | 产物               |
| --------------- | -------- | ------------------ |
| 展示数据列表    | 列表页   | `list.vue`         |
| 新增/编辑数据   | 表单页   | `form.vue`         |
| 查看单条详情    | 详情页   | `detail.vue`       |
| 列表 + 弹窗编辑 | 列表页   | `list.vue` + Modal |

**路由结构**：

| 场景     | 路由设计                   |
| -------- | -------------------------- |
| 独立页面 | `/user/list`、`/user/form` |
| 弹窗表单 | 列表页内 Modal，无独立路由 |

---

### 阶段 2: API 准备

**接口获取方式**：

| 方式        | 操作                                      |
| ----------- | ----------------------------------------- |
| Apifox 链接 | 调用 `apifox.get-api-by-url` 自动生成类型 |
| 接口文档    | 手动定义类型                              |

**标准 CRUD 接口**：

```typescript
// api/{module}.ts
export function get{Module}ListApi(params: {Module}ListParams) {}
export function get{Module}DetailApi(id: number) {}
export function create{Module}Api(data: Create{Module}Params) {}
export function update{Module}Api(id: number, data: Update{Module}Params) {}
export function delete{Module}Api(id: number) {}
```

> 📋 接口规范详见 @modules/api.mdc

---

### 阶段 3: 页面结构

**文件组织决策**：

| 项目规模 | 组织方式 | 结构                                  |
| -------- | -------- | ------------------------------------- |
| 小型     | 扁平式   | `pages/user-list.vue`                 |
| 中大型   | 目录式   | `pages/user/list.vue` + `components/` |

> 📋 页面组织详见 @modules/pages.mdc

---

### 阶段 4: 列表页开发

**加载方式决策**：

| 场景           | 方式     | 实现                         |
| -------------- | -------- | ---------------------------- |
| H5 长列表      | 下拉加载 | `van-list` / 虚拟滚动        |
| Dashboard 表格 | 分页加载 | `el-table` + `el-pagination` |

**筛选组件拆分**：

| 筛选项数量 | 处理方式                  |
| ---------- | ------------------------- |
| ≤3 个      | 内联在页面                |
| >3 个      | 拆分 `{Module}Filter.vue` |

**逻辑提取决策**：

| 逻辑行数 | 处理方式                    |
| -------- | --------------------------- |
| ≤50 行   | 保留在页面                  |
| >50 行   | 提取到 `use{Module}List.ts` |

**页面模板**：

```vue
<template>
  <div class="{module}-list">
    <{Module}Filter @filter="handleFilter" /> <{Module}Table :data="list"
    :loading="loading" />
    <Pagination :total="total" @change="handlePageChange" />
  </div>
</template>

<script setup lang="ts">
const { list, total, loading, fetchList } = use{Module}List();
onMounted(() => fetchList());
</script>
```

> 📋 Hooks 规范详见 @modules/hooks.mdc

---

### 阶段 5: 表单页开发

**承载方式决策**：

| 场景              | 方式     | 组件                    |
| ----------------- | -------- | ----------------------- |
| 字段少（≤5）      | 弹窗     | `{Module}FormModal.vue` |
| 字段多 / 复杂布局 | 独立页面 | `form.vue`              |

**新增 vs 编辑判断**：

```typescript
const route = useRoute();
const isEdit = computed(() => !!route.params.id);

onMounted(async () => {
  if (isEdit.value) {
    const detail = await get{Module}DetailApi(route.params.id);
    Object.assign(formData, detail);
  }
});
```

**表单模板**：

```vue
<template>
  <div class="{module}-form">
    <el-form ref="formRef" :model="formData" :rules="rules">
      <el-form-item label="名称" prop="name">
        <el-input v-model="formData.name" />
      </el-form-item>
    </el-form>
    <div class="{module}-form__actions">
      <el-button @click="handleCancel">取消</el-button>
      <el-button type="primary" :loading="submitting" @click="handleSubmit">
        {{ isEdit ? "保存" : "创建" }}
      </el-button>
    </div>
  </div>
</template>
```

---

### 阶段 6: 详情页开发

**是否需要详情页**：

| 条件               | 决策          |
| ------------------ | ------------- |
| 列表已展示全部信息 | ❌ 不需要     |
| 需要展示更多字段   | ✅ 独立详情页 |

**详情页模板**：

```vue
<template>
  <div class="{module}-detail">
    <van-loading v-if="loading" />
    <template v-else>
      <div class="{module}-detail__item">
        <span class="label">名称</span>
        <span class="value">{{ detail.name }}</span>
      </div>
    </template>
  </div>
</template>

<script setup lang="ts">
const { detail, loading } = use{Module}Detail(route.params.id);
</script>
```

---

### 阶段 7: 路由配置

```typescript
// router/modules/{module}.ts
export default {
  path: "/{module}",
  children: [
    { path: "list", component: () => import("@/pages/{module}/list.vue") },
    { path: "form", component: () => import("@/pages/{module}/form.vue") },
    { path: "form/:id", component: () => import("@/pages/{module}/form.vue") },
    {
      path: "detail/:id",
      component: () => import("@/pages/{module}/detail.vue"),
    },
  ],
};
```

> 📋 路由规范详见 @modules/router.mdc

---

## ✅ 检查清单

### API

- ✅ 接口函数以 `Api` 结尾
- ✅ 类型定义独立文件
- ❌ 禁止页面直接调用 HTTP 客户端

### 列表页

- ✅ 已决定加载方式（分页/下拉）
- ✅ 筛选项 >3 个已拆分组件
- ✅ 逻辑 >50 行已提取 Hook
- ❌ 禁止页面超过 200 行逻辑代码

### 表单页

- ✅ 已决定承载方式（弹窗/独立页）
- ✅ 新增/编辑复用同一 form.vue
- ✅ 表单验证规则完整
- ❌ 禁止新增/编辑写两个独立页面

### 路由

- ✅ 路由配置完成
- ✅ 路由命名 PascalCase

---

## 📚 规范引用

| 规范                    | 用途                  |
| ----------------------- | --------------------- |
| @modules/pages.mdc      | 页面职责、文件组织 ⭐ |
| @modules/api.mdc        | 接口封装、类型定义 ⭐ |
| @modules/components.mdc | 组件拆分、Props 设计  |
| @modules/hooks.mdc      | 逻辑提取              |
| @modules/router.mdc     | 路由配置              |
