Files
xiaotutongxue/frontend-pc/.agents/skills/project-api/SKILL.md
T
lovife db6a51d617 docs: 清掉三处"会静默过期"的小账 + check-test-profile 加固(F-98)
一、附录 A 从"手抄表"改成"可再生成的命令"
   check-api-parity.py 加 --extra,现算"代码有、契约 §4 没有"的接口 = 41 个
   (旧手抄表写 83/62/21,已差近一倍,而且没人会记得回来改它)。
   并按"谁去改什么"分六类 —— 只有 E 类(8 个)要客户定口径,其余是文档侧补记。

二、F-6 已修:frontend-pc 的 Mock 说明
   AGENTS.md 那句改正之外,连带修了 .agents/skills/project-api/SKILL.md ——
   它整篇仍以 vite-plugin-mock / mock/** 为主线,而该项目里 mock/ 目录与插件都已删除。
   只改指路牌、不改路的尽头,等于没改。

三、docs/03 两处文档内部口径冲突加 ⚠️ 注(不改口径,只把冲突摆明)
   §2 notifyBizType 的 5/6 与 §13.5、落库值不一致 → 实现以 §13.5 为准(催报去重按 5);
   §3.6/§9.5 的 collect_file.source 字段表(入口来源)与建表注释(谁传的)冲突 →
   实现以建表口径为准。两处都写明"待客户确认",见 F-30 / F-38 / F-39。

四、check-test-profile.py 加固(新增 F-98)
   · 子进程输出落盘(不再用没人读的 PIPE):失败时能看见"停在哪一行",
     成功时打出启动用时(基线 ~10 秒 / 72 行 / 9.5KB);
   · 开跑前按 jar + profile 清残留 JVM,且保留 dev 后端(E2E 正打着它);
   · 等待期间每 15 秒报一次进度,卡住时不留沉默。
   教训:随机端口这个防撞设计把残留 JVM 藏起来了 —— 撞不到端口就永远发现不了,
   于是表现成"时好时坏",而失败时连日志都读不到。

验证:python scripts/verify-all.py --with-e2e → 通过 8 / 失败 0 / 跳过 0
      (E2E 36 脚本 / 1548 断言 / 278s;prodguard 9/9;test profile 能起)
      python scripts/verify-docs.py → 22 项全部通过
2026-09-30 09:10:34 +08:00

163 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: project-api
description: 在本模板项目中新增或修改 API 接口与类型定义(本仓库已不用 Mock,见开头说明)。涉及 http、baseAPI、分页响应格式、响应体适配时使用。
---
# API 与 Mock
> ⚠️ **本仓库不用 Mock(2026-09-30 核实)**:`mock/` 目录与 `vite-plugin-mock` 都已删除,
> `.env.development` 里 `VITE_API_PREFIX = '/api/v1'`、`VITE_API_BASE_URL = 'http://localhost:8080'`,
> `pnpm dev` 把 `/api` 代理到真实后端 —— **后端不起着就没有数据**(这不是故障)。
>
> 所以本文档里所有关于 Mock 的部分(`mock/**`、`defineMock`、`getBaseApi` 生成 mock、
> Mock 目录约定)在本仓库**不适用**,保留它们只是因为 Gi 模板升级时要做差异比对。
> 新增接口照 `src/apis/xt/*.ts` 的写法:用 `@/utils/http`,响应体 `{ code, msg, data }`
> (适配层会补 `records`)已在 `@/utils/http` 统一处理,业务模块不要再自己解一层。
## 接口层结构
每个业务模块一个文件,例如 `src/apis/system/user.ts`:
```ts
import { getBaseApi } from '@/apis/base'
import http from '@/utils/http'
export interface ListItem {
id: string
name: string
status: Status
createTime: string
// ...
}
/** 标准 CRUD */
export const baseAPI = getBaseApi<ListItem>({ baseUrl: '/system/user' })
/** 非标准接口单独声明 */
export function getDictDataList(params: { code: string } & Pagination) {
return http.get<PageRes<DictDataItem[]>>('/system/dict/getDictDataList', params)
}
```
## getBaseApi 约定路径
| 方法 | HTTP | 路径 |
|------|------|------|
| getList | GET | `{baseUrl}/getList` |
| getDetail | GET | `{baseUrl}/getDetail` |
| add | POST | `{baseUrl}/add` |
| update | POST | `{baseUrl}/update` |
| delete | POST | `{baseUrl}/delete` |
列表参数:`{ page, size, ...filters }`
删除参数:`{ ids: string[] }`
## 响应格式
```ts
// 单条/布尔
interface ApiRes<T> {
code: number
data: T
message: string
success: boolean
}
// 分页列表 data 结构
interface PageRes<T> {
records: T
total: number
}
```
`useTable` 同时兼容 `data` 为数组或 `PageRes` 两种形态。
## http 封装
- 实例:`src/utils/http.ts`,`baseURL` = `import.meta.env.VITE_API_PREFIX`
- 开发环境 `.env.development`:`VITE_API_PREFIX = '/mock'`
- Token:请求头 `token` 字段(`getToken()`)
- 业务失败:`success === false` 时 Message/Notification 提示并 reject
- 401:跳转 `/login`
```ts
import http from '@/utils/http'
http.get<PageRes<Item[]>>('/path', { page: 1, size: 10 })
http.post<boolean>('/path', { ids: ['1'] })
```
## Mock 开发流程
### 1. 静态数据
在 `mock/_data/` 下维护 JSON/TS 数据,如 `system_dict.ts`。
### 2. 路由 Mock
在 `mock/system/`(或对应模块)新建文件:
```ts
import { defineMock } from '../_base'
import { getBaseApi, getDelayTime, resultError, resultSuccess } from '../_utils'
export default defineMock([
...getBaseApi({
baseUrl: '/system/xxx',
getListData: () => resultSuccess({ total: list.length, records: list }),
getDetailData: (query) => {
const obj = list.find((i) => i.id === query.id)
return obj ? resultSuccess(obj) : resultError(null, '未找到', 400)
}
}),
{
url: '/system/xxx/customAction',
method: 'get',
timeout: getDelayTime(),
response: ({ query }) => {
// 筛选、分页后返回
return resultSuccess({ total, records })
}
}
])
```
### 3. 工具函数
| 函数 | 用途 |
|------|------|
| `resultSuccess(data)` | `{ code:200, success:true, data, message }` |
| `resultError(data, message, code?)` | 失败响应 |
| `getDelayTime()` | 50–300ms 随机延迟 |
| `getBaseApi({ baseUrl, getListData, ... })` | 生成标准 CRUD mock |
`defineMock` 会自动给 url 加前缀 `/mock`,与 `VITE_API_PREFIX` 对应。
### 4. 注册
确保 mock 文件被 `mock/index` 或同级聚合引入(遵循现有 `mock/system/*.ts` 模式)。
## 新增模块检查清单
- [ ] `src/apis/{module}/{name}.ts`:类型 + `baseAPI` 或自定义方法
- [ ] `mock/{module}/{name}.ts`:与接口路径一致
- [ ] 列表 Mock 返回 `{ total, records }`
- [ ] 字段类型与 `Status`、`Gender` 等全局类型对齐
- [ ] 在页面通过 `useTable({ listAPI, deleteAPI })` 接入
## 自定义 listAPI 示例
```ts
useTable({
listAPI: (page) => getDictDataList({
...page,
code: dictCode.value,
name: query.name || undefined,
status: query.status === '' ? undefined : query.status
}),
immediate: false
})
```
`immediate: false` 用于依赖左侧选中项后再 `search()` 的场景。