# bench 交互设计与施工方案 > new-api-key-bench:NewAPI sk-key 接口的「文档 + 调试」二合一前端工具。 > > 本文档是施工蓝图:所有交互与技术决策已定案,按此施工,不再讨论结构性问题。 --- ## 1. 项目定位 替代 Postman 的专用调试台(bench):左侧选接口 → 右侧 tab 内看文档、填 key、发请求、看原始响应。对接 6 个接口,服务 karpool 拼车项目的接口调试与换算验证。 **接口清单**(数据源:`docs/NewAPI-sk-key接口文档.md`,按此顺序展示,不分组): | 序 | 路径 | 鉴权 | 响应特征 | |---|------|------|---------| | 0 | `GET /api/status` | 无(完全公开) | 站点配置与计费参数:`quota_per_unit`(换算比率权威来源)、`quota_display_type`、汇率等 | | 1 | `GET /v1/dashboard/billing/subscription` | TokenAuth(严格) | 小 JSON,美元额度(无限额时 1 亿占位) | | 2 | `GET /v1/dashboard/billing/usage` | TokenAuth(严格) | 小 JSON,累计美分 | | 3 | `GET /v1/models` | TokenAuth(严格) | 中等 JSON,模型数组 | | 4 | `GET /api/usage/token` | TokenAuthReadOnly(宽松) | 小 JSON,累计 quota | | 5 | `GET /api/log/token` | TokenAuthReadOnly(宽松) | **大响应**:最近 1000 条日志,pretty-print 2~4MB | > 0 完全公开(无需任何凭证,面板隐藏 sk-key 输入行);4、5 宽松鉴权(key 过期/耗尽仍可查);1~3 严格鉴权(key 无效直接被拒)。tab 内标出该差异,避免误判「接口坏了」。 > 4 与 2 构成换算交叉验证对(total_used ÷ 500000 ≈ total_usage ÷ 100),Tabs 并行对账是核心工作流。0 是换算比率的权威来源(quota_per_unit 可被管理员修改,500000 只是默认值)。 --- ## 2. 布局 ``` ┌────────────────────────────────────────────────────────────────────────────┐ │ new-api-key-bench (暗色默认) │ ├──────────────────────────┬─────────────────────────────────────────────────┤ │ 接口列表 │ ┌──────────────┬──────────────┬───────────┐ │ │ │ │/v1/dashboar… │/api/log/token│/api/usage…│ × │ │ /v1/dashboard/billing/ │ ├──────────────┴──────────────┴───────────┴──┤ │ │ subscription │ │ GET /v1/dashboard/billing/subscription │ │ │ /v1/dashboard/billing/ │ ├─────────────────────────────────────────────┤ │ │ usage │ │ sk-key ┌─────────────────────────┐ │ │ │ /v1/models │ │ │ sk-xxxxxxxxxxxx 👁 │ [发送请求]│ │ │ /api/usage/token │ │ └─────────────────────────┘ │ │ │ /api/log/token │ ├─────────────────────────────────────────────┤ │ │ │ │ 200 OK · 156ms · 234 KB [复制] [⤓] │ │ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ │ │ │ 1 { │ │ │ │ │ │ │ 2 "object": "billing_subscription", │ │ │ │ │ │ │ 3 "hard_limit_usd": 100000000, │ │ │ │ │ │ │ (虚拟滚动 JSON · DOM 恒 ~40 行) │ │ │ │ │ │ └─────────────────────────────────────────┘ │ │ └──────────────────────────┴─────────────────────────────────────────────────┘ ~300px sider(纯路径列表, 自适应(tab 内自带 sk-key 框) 无分组无编号,按清单顺序) ``` - **左 sider**(~300px):接口列表,**不分组、不编号**,按 §1 清单顺序平铺 6 个路径;选中态高亮 - **右主区**:`t-tabs` 顶部,激活 tab 内容 = 请求行(method + 路径 + 鉴权徽标)→ 调试行(sk-key 输入 + 发送按钮)→ 响应区(元信息 + 虚拟滚动 JSON) - 暗色默认(TDesign dark theme + CSS 变量) --- ## 3. 交互细则 ### 3.1 Tabs - 点击 sider 接口:该接口**无 tab 则新开,有则激活**(Postman 语义) - 关闭 tab:丢弃该 tab 状态(响应缓存随之释放);若关的是激活 tab,激活相邻 tab;全部关光 → 空态引导页(提示从左侧选择接口) - tab 标签直接显示接口路径(如 `/v1/models`、`/api/log/token`),与 sider 列表一致;宽度不够时省略号截断 - tab 上限即 5(接口总数),无需溢出策略 ### 3.2 sk-key(每 tab 独立) - 每个 tab 自带 key 输入框(`t-input` type=password + 显隐切换),互不影响,可并行调试多把 key - **不做持久化**:key 仅存 Pinia 内存——切 tab 不丢,F5 刷新随整页状态一并重置(tabs、key、响应缓存同生共死,语义干净);不写 localStorage / sessionStorage,sk-key 不落盘 ### 3.3 请求 - 纯手动:点「发送」才发请求;TanStack Query `staleTime: Infinity`,切走再切回 tab **不自动重发** - queryKey:`[endpointId, skKey]`——同 tab 换 key 视为新查询;不同 tab(不同 key)缓存天然隔离 - 发送前校验:key 为空 → 输入框标红提示,不发请求 - 请求中按钮 loading;响应元信息记录:状态码、耗时 ms、响应体字节数 ### 3.4 响应区 - **虚拟滚动 JSON 文本视图**(对齐 DevTools Network Response): - `JSON.stringify(data, null, 2)` → 按 `\n` 切行 → 虚拟滚动窗口渲染 - 行号列 + 等宽字体;**语法高亮仅对可视区行**做正则着色(行级懒高亮) - DOM 恒定 ~40 行,1000 条日志滚动帧率与 10 条无异 - JSON 解析失败(非 JSON 响应)→ 原样文本展示,不高亮 - 空态(未发送):占位提示「填写 sk-key 后发送请求」 - 错误态:网络错误(fetch reject)与 HTTP 非 2xx 分开展示;非 2xx 时仍展示响应体(调试 401/403 场景是刚需) - 操作:复制(格式化 JSON)、下载 `.json` 文件 --- ## 4. 数据与状态设计 ### 4.1 端点元数据(静态) `src/api/endpoints.ts`——接口定义(按清单顺序)、鉴权方式、注意事项文案、示例响应。纯数据无逻辑,不含分组概念。 ### 4.2 Pinia stores - `useBenchStore`:`openTabs: EndpointId[]`(开启顺序)、`activeTab: EndpointId | null`;tab 的 key 由 queryKey 直接承载,无需单独 store - sk-key 不做独立 store 与持久化:作为 EndpointPanel 内的组件局部状态(`ref`),生命周期与 tab 内容一致,随刷新重置 ### 4.3 请求层 - `src/api/client.ts`:薄 fetch wrapper——拼 Authorization 头、计时、返回 `{ status, ms, bytes, text, json }`;无拦截器无重试(调试工具要看到真实失败) - `src/api/queries.ts`:TanStack Query 接入,`useQuery({ queryKey: [epId, skKey], enabled: 手动触发 })` ### 4.4 组件结构 ``` src/ ├── api/ │ ├── endpoints.ts # 5 接口静态元数据 │ ├── client.ts # fetch wrapper(计时/字节数/解析) │ └── queries.ts # TanStack Query 查询定义 ├── stores/ │ └── bench.ts # tabs 状态 ├── components/ │ ├── side-nav.vue # 左侧接口菜单(平铺路径列表) │ ├── request-tabs.vue # t-tabs 容器(开/关/激活) │ ├── endpoint-panel.vue # 单接口完整面板(请求行+调试+响应) │ ├── doc-card.vue # 请求行/鉴权徽标/注意事项(tab 内文档信息) │ └── json-text-view.vue # 虚拟滚动 JSON 文本视图(核心性能组件) ├── lib/ │ └── jsonView.ts # 行窗口计算、行级高亮(纯函数,vitest 覆盖) ├── App.vue # 双栏布局骨架 └── main.ts # 装配 pinia / vue-query / tdesign / router ``` --- ## 5. 工程配置 ### 5.1 代理(vite.config.ts) ```ts const GATEWAY = process.env.GATEWAY ?? 'https://ai-gateway.furtherverse.com' server: { proxy: { '/api': { target: GATEWAY, changeOrigin: true }, '/v1': { target: GATEWAY, changeOrigin: true }, }, } ``` 只配 `/api`、`/v1` 两条(5 接口仅命中此前缀);`GATEWAY` 环境变量可覆盖。`changeOrigin: true` 改写 Host 头,网关虚拟主机路由才正确。 ### 5.2 质量 - **命名规范**:文件名一律 kebab-case 且**语义化完整,宁长勿缩写**(如 `json-text-view.vue` 而非 `jtv.vue`,`endpoint-panel.vue` 而非 `ep.vue`;变量/函数同理,`endpointList` 优于 `epList`);模板中引用组件用大驼峰(``、``) - prettier:`semi: true`、单引号、100 宽(已生效并提交) - oxlint + eslint 双引擎(脚手架自带链路) - vitest:纯函数层测试(`lib/jsonView.ts` 的窗口/高亮计算、`client.ts` 的 URL 与头拼装);`.spec.ts` 与源码同目录 - `build` 保持 `type-check && build-only`(脚手架默认) ### 5.3 依赖(已安装) `tdesign-vue-next@1.20.7`、`@tanstack/vue-query@5.102.8`、`@vueuse/core@14.4.0`、`vitest@5.0.0` + 脚手架自带(vue-router / pinia / oxlint / eslint / prettier) > **VueUse 使用边界**(避免与既有职责重叠):`json-text-view.vue` 用 `useElementSize`(容器尺寸监听)、`useThrottleFn`(滚动节流);响应区复制按钮用 `useClipboard`。loading/error 态归 TanStack Query,tab 状态归 Pinia,输入显隐归 TDesign——这些场景**不用** VueUse。 > vue-router:空 routes 保留(单页应用,路由层暂不启用,留作后续扩展位) --- ## 6. 施工清单(按序) 1. vite.config 补代理 + vitest include;`src/` 清模板残留(counter store、HelloWorld 引用) 2. `api/endpoints.ts` 静态数据 + `lib/jsonView.ts` 纯函数(含单测) 3. `stores/bench.ts`(tabs 状态)+ `api/client.ts` + `api/queries.ts`(sk-key 为 EndpointPanel 局部状态,无持久化) 4. App 骨架 + SideNav + RequestTabs + EndpointPanel + DocCard 5. JsonTextView 虚拟滚动(大响应性能验收:`/api/log/token` 1000 条日志不卡顿) 6. 暗色主题落地 + 空态/错误态打磨 + 复制/下载 7. 全量验证:lint + type-check + build + test,真机调通 5 接口 --- ## 7. 决策记录(已闭环,不再开放) | 决策点 | 定案 | 备注 | |--------|------|------| | 组件库 | TDesign | Table/虚拟滚动成熟、腾讯周更维护、暗色 CSS 变量 | | 请求层 | TanStack Query + fetch | 不引 axios,避免双层抽象 | | JSON 展示 | 虚拟滚动文本视图 | 不解析业务结构(Postman/DevTools 先例,解析是正式项目的职责) | | 布局 | 左 sider + 右 tabs | Postman 形态;sider 平铺 5 路径,不分组不编号,tab 标签即路径 | | tab 内文档 | 鉴权徽标 + 注意事项 | 说明内容都在 tab 页里,sider 只管路径 | | key 输入 | 每 tab 独立 | queryKey 天然隔离 | | key 持久化 | 不做 | 仅 Pinia 内存(tab 组件局部 ref),刷新重置,不落盘 | | 请求语义 | 手动 + staleTime Infinity | 调试工具的响应不该自己变 | | 排除清单 | 不做 | 知识留在 docs/ 接口文档 | | 主题 | 暗色默认 | — | | 命名规范 | 文件 kebab-case 且语义化(宁长勿缩写)/ 模板引用大驼峰 | 见 §5.2 | | 目录名 | new-api-key-bench | — |