This repository has been archived on 2026-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
new-api-key-bench/docs/bench交互设计文档.md
T
skycurtain b2e0aa4a6c docs: 接口调研与设计文档
NewAPI sk-key 接口实证调研(计费参数/接口清单/坑记录)、交互设计定稿、实施计划。数据层与应用层后续按阶段提交。
2026-09-08 00:49:12 +08:00

12 KiB
Raw Blame History

bench 交互设计与施工方案

new-api-key-bench:NewAPI sk-key 接口的「文档 + 调试」二合一前端工具。

本文档是施工蓝图:所有交互与技术决策已定案,按此施工,不再讨论结构性问题。


1. 项目定位

替代 Postman 的专用调试台(bench):左侧选接口 → 右侧 tab 内看文档、填 key、发请求、看原始响应。对接 5 个接口,服务 karpool 拼车项目的接口调试与换算验证。

接口清单(数据源:docs/NewAPI-sk-key接口文档.md,按此顺序展示,不分组):

序 路径 鉴权 响应特征
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

4、5 宽松鉴权(key 过期/耗尽仍可查);1~3 严格鉴权(key 无效直接被拒)。tab 内标出该差异,避免误判「接口坏了」。 4 与 2 构成换算交叉验证对(total_used ÷ 500000 ≈ total_usage ÷ 100),Tabs 并行对账是核心工作流。


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 清单顺序平铺 5 个路径;选中态高亮
  • 右主区: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)

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);模板中引用组件用大驼峰(<SideNav />、<JsonTextView />)
  • 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 —