--- name: api-contract description: 'Use when: generating TypeScript API layer (type definitions + request functions) from page-spec JSON or Swagger/OpenAPI docs. Triggers on: api contract, api generation, 接口约定, 生成api, swagger to ts, openapi, 接口文件, api层.' --- # Skill: 接口约定(api-contract) 根据 **page-spec JSON**(来自 prototype-scan)或 **Swagger/OpenAPI/接口文档**, 生成符合 Robot Admin 规范的 **TypeScript 类型定义 + API 请求函数**。 --- ## 触发 - **模式 A**:接收 page-spec JSON → 按页面字段推导请求/响应类型 - **模式 B**:接收 Swagger/OpenAPI JSON/YAML → 自动映射为 TS 类型 - **模式 C**:接收接口设计文档(MD/表格) → 手动解析接口定义 --- ## 前置约定 ### 请求方法(@robot-admin/request-core) ```typescript import { getData, postData, putData, deleteData, } from '@robot-admin/request-core/axios' ``` | 工具函数 | HTTP Method | 典型场景 | | ----------------------------- | ----------- | -------------------- | | `getData(url, params?)` | GET | 列表查询、详情获取 | | `postData(url, data?)` | POST | 新增、登录、复杂查询 | | `putData(url, data?)` | PUT | 修改更新 | | `deleteData(url, params?)` | DELETE | 删除 | ### URL 约定 ``` // — 列表/新增 ///:id — 详情/修改/删除 ///:id/ — 子资源 ``` 示例: ``` GET /sys/users → 用户列表 POST /sys/users → 新增用户 GET /sys/users/:id → 用户详情 PUT /sys/users/:id → 修改用户 DELETE /sys/users/:id → 删除用户 GET /sys/users/:id/roles → 用户角色 ``` ### 统一响应体结构 ```typescript interface ApiResponse { code: string | number // '0' | '200' | 0 | 200 为成功 data: T msg: string } ``` 列表响应: ```typescript interface ListResponse> { code: string | number data: { list: T[] total: number } msg: string } ``` --- ## 步骤 ### 1. 从 page-spec 推导类型 根据 page-spec JSON 中的 `columns`、`form`、`query` 字段自动生成类型。 **命名规则:** | HTTP Method | 命名模式 | 示例 | | -------------- | -------------------------------------- | ---------------------------- | | GET(列表) | `Get{Domain}{Resource}ListResponse` | `GetSysUsersListResponse` | | GET(详情) | `Get{Domain}{Resource}ByIdResponse` | `GetSysUsersByIdResponse` | | POST(新增) | `Post{Domain}{Resource}Response` | `PostSysUsersResponse` | | PUT(修改) | `Put{Domain}{Resource}ByIdResponse` | `PutSysUsersByIdResponse` | | DELETE(删除) | `Delete{Domain}{Resource}ByIdResponse` | `DeleteSysUsersByIdResponse` | ### 2. 生成类型定义文件 输出文件:`src/api/generated/index.ts`(追加或更新已有类型) ```typescript /* * @Author: ChenYu ycyplus@gmail.com * @Date: {{date}} * @Description: API 自动生成类型 — {{module}} 模块 * Copyright (c) {{year}} by CHENY, All Rights Reserved 😎. */ /** {{资源}}列表查询参数 */ export interface Get{{Resource}}ListParams { page?: number pageSize?: number keyword?: string // ... 从 page-spec.query 推导 } /** {{资源}}列表响应 */ export interface Get{{Resource}}ListResponse { code: string data: { list: {{Resource}}Item[] total: number } msg: string } /** {{资源}}数据项 */ export interface {{Resource}}Item { id: number | string // ... 从 page-spec.columns + page-spec.form 合并推导 createTime?: string updateTime?: string } /** {{资源}}新增/编辑表单数据 */ export interface {{Resource}}FormData { // ... 从 page-spec.form 推导 } /** {{资源}}详情响应 */ export interface Get{{Resource}}ByIdResponse { code: string data: {{Resource}}Item msg: string } /** {{资源}}新增响应 */ export interface Post{{Resource}}Response { code: string data: {{Resource}}Item msg: string } /** {{资源}}更新响应 */ export interface Put{{Resource}}ByIdResponse { code: string data: {{Resource}}Item msg: string } /** {{资源}}删除响应 */ export interface Delete{{Resource}}ByIdResponse { code: string data: Record msg: string } ``` ### 3. 生成 API 请求函数文件 输出文件:`src/api/-.ts` ```typescript /* * @Author: ChenYu ycyplus@gmail.com * @Date: {{date}} * @Description: {{模块中文名}} — API 接口 * Copyright (c) {{year}} by CHENY, All Rights Reserved 😎. */ import { getData, postData, putData, deleteData } from '@robot-admin/request-core/axios' import type { Get{{Resource}}ListResponse, Get{{Resource}}ByIdResponse, Post{{Resource}}Response, Put{{Resource}}ByIdResponse, Delete{{Resource}}ByIdResponse, } from './generated' /** * * @description: 查询{{资源中文名}}列表 * ? @param {Record} params 查询参数 * ! @return {Promise} 列表响应 */ export const get{{Resource}}ListApi = (params?: Record) => getData('//', params) /** * * @description: 新增{{资源中文名}} * ? @param {Record} data 表单数据 * ! @return {Promise} 新增响应 */ export const create{{Resource}}Api = (data: Record) => postData('//', data) /** * * @description: 获取{{资源中文名}}详情 * ? @param {number|string} id 资源ID * ! @return {Promise} 详情响应 */ export const get{{Resource}}ByIdApi = (id: number | string) => getData(`///${id}`) /** * * @description: 更新{{资源中文名}} * ? @param {number|string} id 资源ID * ? @param {Record} data 更新数据 * ! @return {Promise} 更新响应 */ export const update{{Resource}}Api = (id: number | string, data: Record) => putData(`///${id}`, data) /** * * @description: 删除{{资源中文名}} * ? @param {number|string} id 资源ID * ! @return {Promise} 删除响应 */ export const delete{{Resource}}Api = (id: number | string) => deleteData(`///${id}`) ``` ### 4. useTableCrud 集成(可选) 当页面模式为 `LIST` 且使用 C_Table 时,额外输出 useTableCrud 配置: ```typescript import { useNaiveTableCrud } from '@robot-admin/request-core/naive' const table = useNaiveTableCrud({ api: { list: '//', create: '//', update: '///:id', remove: '///:id', get: '///:id', }, columns: [...], defaultPageSize: 20, }) ``` --- ## 验证规则映射 page-spec 中的 `rules` 字段转换为 `@robot-admin/form-validate` 的预设规则: ```typescript import { PRESET_RULES } from '@robot-admin/form-validate' ``` | 规则描述 | 转换结果 | | ---------- | -------------------------------------- | | 必填 | `PRESET_RULES.required('字段名')` | | 长度2-20 | `PRESET_RULES.length('字段名', 2, 20)` | | 数值 18-65 | `PRESET_RULES.range('字段名', 18, 65)` | | 邮箱 | `PRESET_RULES.email('邮箱')` | | 手机号 | `PRESET_RULES.mobile('手机号')` | | URL | `PRESET_RULES.url('URL')` | | 身份证 | `PRESET_RULES.idCard('身份证')` | | IP | `PRESET_RULES.ip('IP')` | --- ## 输出文件清单 | 文件 | 说明 | | -------------------------------- | --------------------------------------- | | `src/api/generated/index.ts` | 追加自动生成的 TS 类型(接口响应/参数) | | `src/api/-.ts` | API 请求函数(CRUD 全套) | --- ## 注意事项 1. **不破坏已有文件**:`src/api/generated/index.ts` 采用追加模式,不清空已有类型 2. **JSDoc 强制**:所有导出函数必须包含 JSDoc(`* @description` / `? @param` / `! @return`) 3. **文件头注释**:每个新建文件必须包含 `@Author` / `@Date` / `@Description` 文件头 4. **类型优先**:所有 API 函数必须标注泛型返回类型 `getData(...)` 5. **路径别名**:内部导入使用 `@/api/generated`,不使用相对路径 `./generated` 6. **request-core 唯一来源**:请求方法从 `/axios`、Naive CRUD 从 `/naive` 导入,不直接使用 axios 或根兼容入口