diff --git a/homepage/dist/docs/account/index.html b/homepage/dist/docs/account/index.html new file mode 100644 index 0000000..168f8a0 --- /dev/null +++ b/homepage/dist/docs/account/index.html @@ -0,0 +1,229 @@ + + + + + +账号与团队 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

账号与团队

+
更新于 2026-09-17
+
+

账号与团队

+

登录后可使用云端空间:个人空间「我的空间」与团队共享空间,数据保存在本机服务的 SQLite 数据库(apps/server/data/opsxapi.db),不上传任何第三方。

+

注册 / 登录

+

最左活动栏底部 登录 按钮打开弹窗:

+
    +
  • 注册只需 昵称 + 邮箱 + 密码(≥ 6 位);
  • +
  • 登录态保存在本机,令牌失效会自动清除。
  • +
+

空间切换

+

活动栏顶部空间徽标(未登录时为产品 Logo,云端空间显示彩色徽标)点击弹出空间列表:

+ + + + + + + + + + + + + + + + + + + + + +
空间说明
本地空间未登录时默认;数据在浏览器 localStorage,不上云
我的空间个人云端空间,注册即有;换浏览器 / 换设备登录即得同一份数据
团队 · ××团队共享空间,成员读写同一份数据
+
    +
  • 首次切入空的云端空间时,会自动把当前本地数据播种上去;
  • +
  • 在云端空间内的所有改动(接口、环境、测试用例、设置)自动同步(改动后约 1.5 秒),活动栏底部头像上的状态点显示 已同步 / 同步中(闪烁)/ 同步失败(红);
  • +
  • 切回本地空间时恢复离开前的本地快照,两端互不覆盖;
  • +
  • 同步策略为后写覆盖:多人同时编辑以最后一次保存为准。
  • +
+

团队管理

+

活动栏账号菜单或空间菜单 → 团队管理:

+
    +
  • 新建团队:创建后自动获得同名共享空间;
  • +
  • 重命名 / 删除:团队卡片右上角的 ✎ / 🗑(仅创建者可见)。重命名就地保存;删除需二次确认,将同时删除成员关系、共享空间与已发布 Mock 数据,不可恢复(若当前正停在该团队空间,会自动切回本地空间);
  • +
  • 添加成员:输入已注册成员邮箱(创建者可操作),邀请时可顺手点选擅长预设;成员登录后即可看到并切换到该团队空间;
  • +
  • 成员与擅长:每个团队卡片展示成员列表(头像 / 名称 / 角色 / 擅长标签)。擅长支持预设点选(前端、后端、全栈、测试、运维、移动端、数据库、AI、接口设计、安全)与自定义输入,空格或顿号分隔;创建者可修改任何成员的擅长,成员只能修改自己的(行尾「擅长」按钮)。
  • +
+

数据与安全

+
    +
  • 密码加盐哈希后存储;令牌为随机 Bearer Token,可随时退出登录作废;
  • +
  • 云端空间单份数据上限 20MB;
  • +
  • 团队空间权限:全体成员可读写,仅创建者可管理成员与修改他人擅长;
  • +
  • 不登录不影响任何本地功能。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/ai/index.html b/homepage/dist/docs/ai/index.html new file mode 100644 index 0000000..4ee9007 --- /dev/null +++ b/homepage/dist/docs/ai/index.html @@ -0,0 +1,239 @@ + + + + + +AI 助手 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

AI 助手

+
更新于 2026-09-17
+
+

AI 助手

+

接入 OpenAI 兼容协议的大模型,为接口调试与自动化测试提供 AI 能力。密钥只保存在本机(localStorage),请求直连供应商,不经过任何第三方中转。

+

配置模型供应商

+

设置 → AI 助手 → 模型供应商,点「添加供应商」,内置常用预设:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
供应商Base URL模型示例
DeepSeekhttps://api.deepseek.com/v1deepseek-chat
智谱 GLMhttps://open.bigmodel.cn/api/paas/v4glm-4-flash
Moonshot Kimihttps://api.moonshot.cn/v1moonshot-v1-8k
OpenAIhttps://api.openai.com/v1gpt-4o-mini
Ollama 本地http://127.0.0.1:11434/v1qwen2.5:7b
+
    +
  • API Key:Ollama 等本地服务可留空;
  • +
  • 测试连接:保存前先发一条 ping 验证地址 / 密钥 / 模型名;
  • +
  • 多个供应商时可切换「当前使用」的模型。
  • +
+

AI 生成场景用例

+

自动化测试视图 →「AI 生成」:

+
    +
  1. 选择集合(AI 读取其中全部 HTTP 接口:方法、URL、Body 示例);
  2. +
  3. 可选填写一句要求,如「覆盖下单 → 支付 → 查询流程,重点断言金额字段」;
  4. +
  5. 模型按业务依赖编排步骤,输出断言与变量提取(如 $.data.token → token,后续步骤用 {{token}});
  6. +
  7. 预览生成的步骤清单(未识别的接口会自动跳过并提示),确认后保存为正式用例。
  8. +
+

生成结果只是起点 —— 步骤、断言、提取规则都可再手动调整。

+

隐私与边界

+
    +
  • API Key 仅存本机,随工作区数据一起持久化;导出全量备份时会包含,分享备份文件前请注意;
  • +
  • 供应商收到的内容为接口清单摘要(方法 / URL / Body 片段)与你的指令,不含环境变量值与 API Key;
  • +
  • 未配置供应商时,Mock 数据、环境变量等离线功能不受影响。
  • +
+

常见问题

+

生成失败? 依次检查:Base URL 是否带 /v1、模型名是否属于该供应商、Key 是否有效(用「测试连接」验证)、本机能否直连该域名(内网代理环境注意放行)。

+

想用公司内网模型? 添加自定义供应商,Base URL 填内网网关地址即可(需兼容 OpenAI Chat Completions 协议)。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/assets/docs.css b/homepage/dist/docs/assets/docs.css new file mode 100644 index 0000000..4d56f63 --- /dev/null +++ b/homepage/dist/docs/assets/docs.css @@ -0,0 +1,246 @@ +/* OpsxAPI 文档站 —— 清爽专业风格(浅色) */ +:root { + --blue: #2563eb; + --blue-dark: #1d4ed8; + --blue-soft: rgba(37, 99, 235, 0.08); + --bg: #f6f8fb; + --panel: #ffffff; + --border: #e4e9f1; + --text: #1c2434; + --text-2: #5b6880; + --text-3: #98a2b3; + --code-bg: #f3f6fb; + --code-border: #e1e8f3; + --green: #059669; + --amber: #b45309; + --red: #dc2626; + --sidebar-w: 262px; + --toc-w: 220px; + --topbar-h: 56px; + --radius: 10px; + --shadow: 0 1px 3px rgba(16, 24, 40, 0.06), 0 8px 24px rgba(16, 24, 40, 0.05); + --mono: "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace; +} +* { box-sizing: border-box; } +html { scroll-behavior: smooth; scroll-padding-top: 72px; } +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; + background: var(--bg); + color: var(--text); + font-size: 14.5px; + line-height: 1.75; +} +a { color: var(--blue); text-decoration: none; } +.i { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -2px; } +a:hover { color: var(--blue-dark); text-decoration: underline; } + +/* ---------- 顶栏 ---------- */ +.topbar { + position: sticky; top: 0; z-index: 50; + background: rgba(255, 255, 255, 0.92); + backdrop-filter: saturate(1.4) blur(8px); + border-bottom: 1px solid var(--border); +} +.topbar-inner { + max-width: 1440px; margin: 0 auto; height: var(--topbar-h); + display: flex; align-items: center; gap: 14px; padding: 0 20px; +} +.menu-btn { + display: none; border: 1px solid var(--border); background: #fff; + border-radius: 8px; width: 34px; height: 34px; cursor: pointer; color: var(--text-2); + place-items: center; +} +.menu-btn .i { width: 17px; height: 17px; } +.brand { display: flex; align-items: center; gap: 9px; text-decoration: none !important; } +.brand-logo { display: inline-flex; } +.brand-logo svg { display: block; border-radius: 7px; } +.brand-name { font-size: 16px; font-weight: 700; color: var(--text); } +.brand-name em { font-style: normal; font-weight: 500; color: var(--text-2); margin-left: 2px; } +.ver-badge { + font-size: 11px; font-weight: 600; color: var(--blue); + background: var(--blue-soft); border: 1px solid rgba(37, 99, 235, 0.22); + padding: 1px 9px; border-radius: 999px; white-space: nowrap; +} +.search { position: relative; flex: 1; max-width: 420px; margin-left: 8px; } +.search input { + width: 100%; height: 36px; border: 1px solid var(--border); border-radius: 9px; + background: var(--bg); padding: 0 14px 0 34px; font-size: 13.5px; color: var(--text); outline: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%2398a2b3' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E"); + background-repeat: no-repeat; background-position: 12px center; +} +.search input:focus { border-color: var(--blue); background: #fff; box-shadow: 0 0 0 3px var(--blue-soft); } +.search-panel { + position: absolute; top: 44px; left: 0; right: 0; background: #fff; + border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); + max-height: 420px; overflow: auto; padding: 6px; +} +.search-item { display: block; padding: 8px 12px; border-radius: 8px; text-decoration: none !important; } +.search-item:hover, .search-item.sel { background: var(--blue-soft); } +.search-item .si-title { font-weight: 600; color: var(--text); font-size: 13.5px; } +.search-item .si-group { color: var(--text-3); font-size: 11px; margin-left: 6px; } +.search-item .si-snippet { color: var(--text-2); font-size: 12px; margin-top: 2px; display: block; } +.search-empty { padding: 14px; text-align: center; color: var(--text-3); font-size: 13px; } +.top-links { margin-left: auto; display: flex; gap: 16px; align-items: center; } +.top-links a { font-size: 13.5px; font-weight: 500; } + +/* ---------- 三栏布局 ---------- */ +.layout { + max-width: 1440px; margin: 0 auto; display: grid; + grid-template-columns: var(--sidebar-w) minmax(0, 1fr) var(--toc-w); + gap: 0 28px; padding: 24px 20px 60px; +} + +/* 侧栏 */ +.sidebar { position: sticky; top: calc(var(--topbar-h) + 24px); align-self: start; max-height: calc(100vh - var(--topbar-h) - 48px); overflow-y: auto; padding-right: 8px; } +.sidebar::-webkit-scrollbar { width: 4px; } +.sidebar::-webkit-scrollbar-thumb { background: #d6dde8; border-radius: 4px; } +.nav-group { margin-bottom: 18px; } +.nav-group-title { + font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; + color: var(--text-3); padding: 0 10px 6px; +} +.nav-link { + display: block; padding: 6px 10px; border-radius: 8px; font-size: 13.5px; + color: var(--text-2); text-decoration: none !important; border-left: 2px solid transparent; +} +.nav-link:hover { background: rgba(37, 99, 235, 0.06); color: var(--text); } +.nav-link.active { + background: var(--blue-soft); color: var(--blue-dark); font-weight: 600; + border-left-color: var(--blue); +} +.sidebar-foot { margin-top: 24px; padding: 12px 10px 0; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--text-3); } + +/* 内容 */ +.content { min-width: 0; max-width: 860px; } +.breadcrumb { font-size: 12.5px; color: var(--text-3); margin-bottom: 10px; } +.breadcrumb span { margin: 0 6px; } +.page-title { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 6px; line-height: 1.3; } +.page-meta { font-size: 12.5px; color: var(--text-3); margin-bottom: 22px; } + +/* Markdown 排版 */ +.md h2 { font-size: 21px; font-weight: 700; margin: 38px 0 12px; padding-top: 8px; letter-spacing: -0.01em; } +.md h3 { font-size: 16.5px; font-weight: 700; margin: 26px 0 8px; } +.md h2 + h3, .md h1 + h2 { margin-top: 18px; } +.md p { margin: 10px 0; color: #2a3348; } +.md ul, .md ol { padding-left: 22px; margin: 10px 0; } +.md li { margin: 5px 0; color: #2a3348; } +.md li::marker { color: var(--blue); } +.md strong { color: var(--text); } +.md hr { border: none; border-top: 1px solid var(--border); margin: 30px 0; } +.md img { max-width: 100%; border-radius: var(--radius); border: 1px solid var(--border); } +.md blockquote { + margin: 14px 0; padding: 10px 16px; border-left: 3px solid var(--blue); + background: var(--blue-soft); border-radius: 0 8px 8px 0; color: #33415e; +} + +/* 表格 */ +.md table { border-collapse: collapse; width: 100%; margin: 16px 0; font-size: 13.5px; background: #fff; border-radius: var(--radius); overflow: hidden; box-shadow: 0 0 0 1px var(--border); } +.md th, .md td { padding: 9px 14px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; } +.md th { background: #f9fbfe; font-weight: 600; color: var(--text); white-space: nowrap; } +.md tr:last-child td { border-bottom: none; } + +/* 代码块 */ +.md code { font-family: var(--mono); font-size: 12.8px; background: var(--code-bg); border: 1px solid var(--code-border); border-radius: 5px; padding: 1px 6px; color: #334155; } +.md pre { + position: relative; background: #0f172a; color: #dbe4f3; border-radius: var(--radius); + padding: 16px 16px 14px; overflow-x: auto; margin: 16px 0; font-size: 13px; line-height: 1.65; +} +.md pre code { background: none; border: none; color: inherit; padding: 0; font-size: inherit; } +.md pre .lang-tag { + position: absolute; top: 8px; right: 12px; font-size: 10.5px; color: #7c8db0; + font-family: var(--mono); text-transform: lowercase; letter-spacing: 0.04em; +} +.md pre .copy-btn { + position: absolute; top: 6px; right: 60px; font-size: 11px; color: #9fb0d0; + background: rgba(255, 255, 255, 0.07); border: none; border-radius: 6px; padding: 2px 9px; cursor: pointer; + opacity: 0; transition: opacity 0.15s; +} +.md pre:hover .copy-btn { opacity: 1; } +.md pre .copy-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.14); } +/* 行内高亮 token */ +.md pre .tok-key { color: #7dd3fc; } +.md pre .tok-str { color: #86efac; } +.md pre .tok-num { color: #fcd34d; } +.md pre .tok-com { color: #64748b; font-style: italic; } + +/* 提示块(通过 blockquote 首字符约定) */ +.md blockquote.tip { border-left-color: var(--green); background: rgba(5, 150, 105, 0.07); } +.md blockquote.warn { border-left-color: var(--amber); background: rgba(180, 83, 9, 0.07); } + +/* 上下页 */ +.pn-nav { display: flex; gap: 14px; margin-top: 48px; } +.pn { + flex: 1; border: 1px solid var(--border); background: #fff; border-radius: var(--radius); + padding: 13px 16px; text-decoration: none !important; transition: border-color 0.15s, box-shadow 0.15s; +} +.pn:hover { border-color: var(--blue); box-shadow: var(--shadow); } +.pn.next { text-align: right; } +.pn-label { display: block; font-size: 11.5px; color: var(--text-3); } +.pn-title { display: block; font-weight: 600; color: var(--text); font-size: 14px; margin-top: 2px; } + +/* 反馈 */ +.feedback { + margin-top: 28px; padding: 16px 18px; border-top: 1px solid var(--border); + display: flex; align-items: center; gap: 10px; color: var(--text-2); font-size: 13px; flex-wrap: wrap; +} +.fb-btn { + border: 1px solid var(--border); background: #fff; border-radius: 8px; padding: 5px 12px; + font-size: 12.5px; cursor: pointer; color: var(--text-2); transition: all 0.15s; +} +.fb-btn:hover { border-color: var(--blue); color: var(--blue); } +.fb-btn.done { border-color: var(--green); color: var(--green); background: rgba(5, 150, 105, 0.06); } +.fb-thanks { color: var(--green); font-size: 12.5px; } + +/* 右侧目录 */ +.toc { position: sticky; top: calc(var(--topbar-h) + 24px); align-self: start; max-height: calc(100vh - var(--topbar-h) - 48px); overflow-y: auto; padding-top: 34px; } +.toc-title { font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; color: var(--text-3); margin-bottom: 8px; } +.toc-nav { display: flex; flex-direction: column; gap: 1px; border-left: 2px solid var(--border); padding-left: 0; } +.toc-nav a { + font-size: 12.5px; color: var(--text-2); padding: 4px 0 4px 12px; text-decoration: none !important; + border-left: 2px solid transparent; margin-left: -2px; line-height: 1.5; +} +.toc-nav a:hover { color: var(--blue); } +.toc-nav a.toc-l3 { padding-left: 26px; font-size: 12px; color: var(--text-3); } +.toc-nav a.active { color: var(--blue); border-left-color: var(--blue); font-weight: 600; } +.print-btn { + margin-top: 18px; width: 100%; border: 1px solid var(--border); background: #fff; + border-radius: 8px; padding: 7px; font-size: 12.5px; color: var(--text-2); cursor: pointer; +} +.print-btn:hover { border-color: var(--blue); color: var(--blue); } + +/* 404 */ +.doc-404 { display: grid; place-items: center; min-height: 100vh; text-align: center; } +.doc-404 h1 { font-size: 56px; margin: 0; color: var(--blue); } +.doc-404 .btn { + display: inline-block; margin-top: 12px; background: var(--blue); color: #fff; + padding: 8px 18px; border-radius: 8px; text-decoration: none !important; font-weight: 600; +} + +/* ---------- 响应式 ---------- */ +@media (max-width: 1200px) { + .layout { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); } + .toc { display: none; } +} +@media (max-width: 880px) { + .menu-btn { display: inline-grid; place-items: center; } + .layout { grid-template-columns: minmax(0, 1fr); padding-top: 12px; } + .sidebar { + position: fixed; z-index: 60; left: 0; top: var(--topbar-h); bottom: 0; + width: 280px; background: #fff; border-right: 1px solid var(--border); + padding: 16px; transform: translateX(-100%); transition: transform 0.2s; max-height: none; + } + .sidebar.open { transform: none; box-shadow: var(--shadow); } + .ver-badge { display: none; } + .top-links a { font-size: 12.5px; } + .page-title { font-size: 24px; } +} + +/* ---------- 打印 ---------- */ +@media print { + .topbar, .sidebar, .toc, .pn-nav, .feedback, .menu-btn { display: none !important; } + .layout { display: block; max-width: none; padding: 0; } + body { background: #fff; } + .md pre { background: #f1f5f9 !important; color: #1e293b !important; } + .md pre .copy-btn, .md pre .lang-tag { display: none; } +} diff --git a/homepage/dist/docs/assets/docs.js b/homepage/dist/docs/assets/docs.js new file mode 100644 index 0000000..005b49e --- /dev/null +++ b/homepage/dist/docs/assets/docs.js @@ -0,0 +1,219 @@ +/* OpsxAPI 文档站交互:搜索 / 代码复制 / 目录高亮 / 反馈 / 移动端导航 */ +(function () { + "use strict"; + + /* ---------- 代码块:语言标签 + 复制按钮 + 轻量高亮 ---------- */ + document.querySelectorAll("article.md pre").forEach(function (pre) { + var code = pre.querySelector("code"); + if (!code) return; + var lang = (code.className.match(/language-([\w-]+)/) || [, ""])[1]; + if (lang) { + var tag = document.createElement("span"); + tag.className = "lang-tag"; + tag.textContent = lang; + pre.appendChild(tag); + } + // 复制按钮 + var btn = document.createElement("button"); + btn.className = "copy-btn"; + btn.type = "button"; + btn.textContent = "复制"; + btn.addEventListener("click", function () { + navigator.clipboard.writeText(code.textContent).then( + function () { + btn.textContent = "已复制 ✓"; + setTimeout(function () { btn.textContent = "复制"; }, 1400); + }, + function () { btn.textContent = "复制失败"; } + ); + }); + pre.appendChild(btn); + // JSON / bash 轻量高亮 + if (lang === "json") highlightJSON(code); + else if (lang === "bash" || lang === "sh" || lang === "shell") highlightBash(code); + }); + + function esc(s) { + return s.replace(/&/g, "&").replace(//g, ">"); + } + function highlightJSON(code) { + var src = code.textContent; + code.innerHTML = esc(src).replace( + /("(?:\\.|[^"\\])*")(\s*:)?|\b(true|false|null)\b|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)/g, + function (m, str, colon, kw, num) { + if (str && colon) return '' + str + "" + colon; + if (str) return '' + str + ""; + if (kw) return '' + kw + ""; + if (num) return '' + num + ""; + return m; + } + ); + } + function highlightBash(code) { + var lines = code.textContent.split("\n"); + code.innerHTML = lines + .map(function (line) { + if (/^\s*#/.test(line)) return '' + esc(line) + ""; + return esc(line).replace(/(^|\s)(-{1,2}[\w-]+)/g, '$1$2'); + }) + .join("\n"); + } + + /* ---------- blockquote 提示样式约定:> **提示** / > **注意** ---------- */ + document.querySelectorAll("article.md blockquote").forEach(function (bq) { + var t = (bq.textContent || "").trim(); + if (/^(注意|警告|⚠)/.test(t)) bq.classList.add("warn"); + else if (/^(提示|说明|💡|Tip)/i.test(t)) bq.classList.add("tip"); + }); + + /* ---------- 搜索 ---------- */ + var input = document.getElementById("search-input"); + var panel = document.getElementById("search-panel"); + var entries = null; + var selIndex = -1; + + function ensureIndex(cb) { + if (entries) return cb(); + fetch("/docs/search-data.json") + .then(function (r) { return r.json(); }) + .then(function (data) { entries = data; cb(); }) + .catch(function () { entries = []; cb(); }); + } + + function snippet(text, q) { + var i = text.toLowerCase().indexOf(q); + if (i < 0) return text.slice(0, 60) + "…"; + var start = Math.max(0, i - 24); + return (start > 0 ? "…" : "") + text.slice(start, i + q.length + 40) + "…"; + } + + function doSearch() { + var q = input.value.trim().toLowerCase(); + selIndex = -1; + if (!q) { panel.hidden = true; return; } + ensureIndex(function () { + var hits = []; + entries.forEach(function (e) { + var titleHit = e.title.toLowerCase().indexOf(q) >= 0; + var idx = e.text.toLowerCase().indexOf(q); + if (titleHit || idx >= 0) { + hits.push({ + slug: e.slug, + title: e.title, + group: e.group, + score: (titleHit ? 10 : 0) + (idx === 0 ? 3 : 0), + snippet: titleHit ? snippet(e.text, q) : snippet(e.text, q), + }); + } + }); + hits.sort(function (a, b) { return b.score - a.score; }); + hits = hits.slice(0, 8); + if (!hits.length) { + panel.innerHTML = '
没有找到相关内容,换个关键词试试
'; + } else { + panel.innerHTML = hits + .map(function (h) { + return ( + '' + + '' + h.title + '' + h.group + "" + + '' + h.snippet + "" + ); + }) + .join(""); + } + panel.hidden = false; + }); + } + + var debounce; + if (input) { + input.addEventListener("input", function () { + clearTimeout(debounce); + debounce = setTimeout(doSearch, 160); + }); + input.addEventListener("focus", function () { + if (input.value.trim()) doSearch(); + }); + input.addEventListener("keydown", function (e) { + var items = panel.querySelectorAll(".search-item"); + if (e.key === "ArrowDown" && items.length) { + e.preventDefault(); + selIndex = Math.min(selIndex + 1, items.length - 1); + } else if (e.key === "ArrowUp" && items.length) { + e.preventDefault(); + selIndex = Math.max(selIndex - 1, 0); + } else if (e.key === "Enter") { + if (selIndex >= 0 && items[selIndex]) { location.href = items[selIndex].href; return; } + var first = items[0]; + if (first) location.href = first.href; + return; + } else if (e.key === "Escape") { + panel.hidden = true; + return; + } else { + return; + } + items.forEach(function (el, i) { el.classList.toggle("sel", i === selIndex); }); + }); + document.addEventListener("click", function (e) { + if (!e.target.closest(".search")) panel.hidden = true; + }); + } + + /* ---------- 目录滚动高亮 ---------- */ + var tocLinks = Array.prototype.slice.call(document.querySelectorAll(".toc-nav a")); + if (tocLinks.length && "IntersectionObserver" in window) { + var byId = {}; + tocLinks.forEach(function (a) { byId[a.getAttribute("href").slice(1)] = a; }); + var io = new IntersectionObserver( + function (entries) { + entries.forEach(function (en) { + if (en.isIntersecting) { + tocLinks.forEach(function (a) { a.classList.remove("active"); }); + var a = byId[en.target.id]; + if (a) a.classList.add("active"); + } + }); + }, + { rootMargin: "-72px 0px -70% 0px", threshold: 0 } + ); + document.querySelectorAll("article.md h2[id], article.md h3[id]").forEach(function (h) { io.observe(h); }); + } + + /* ---------- 反馈组件 ---------- */ + var fb = document.getElementById("feedback"); + if (fb) { + var pageKey = "opsx-docs-fb:" + location.pathname; + var voted = null; + try { voted = localStorage.getItem(pageKey); } catch (e) {} + var btns = fb.querySelectorAll(".fb-btn"); + var thanks = document.getElementById("fb-thanks"); + function mark(v) { + btns.forEach(function (b) { + if (b.dataset.v === v) b.classList.add("done"); + }); + thanks.hidden = false; + try { localStorage.setItem(pageKey, v); } catch (e) {} + } + if (voted) mark(voted); + btns.forEach(function (b) { + b.addEventListener("click", function () { mark(b.dataset.v); }); + }); + } + + /* ---------- 打印 ---------- */ + var printBtn = document.getElementById("print-btn"); + if (printBtn) printBtn.addEventListener("click", function () { window.print(); }); + + /* ---------- 移动端侧栏 ---------- */ + var menuBtn = document.getElementById("menu-btn"); + var sidebar = document.getElementById("sidebar"); + if (menuBtn && sidebar) { + menuBtn.addEventListener("click", function () { sidebar.classList.toggle("open"); }); + document.addEventListener("click", function (e) { + if (sidebar.classList.contains("open") && !e.target.closest(".sidebar") && !e.target.closest(".menu-btn")) { + sidebar.classList.remove("open"); + } + }); + } +})(); diff --git a/homepage/dist/docs/auth/index.html b/homepage/dist/docs/auth/index.html new file mode 100644 index 0000000..23420c8 --- /dev/null +++ b/homepage/dist/docs/auth/index.html @@ -0,0 +1,215 @@ + + + + + +接口鉴权 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

接口鉴权

+
更新于 2026-09-17
+
+

在 HTTP / GraphQL / SSE 请求的 Auth 标签中选择鉴权方式:

+

Bearer Token

+
Authorization: Bearer <token>
+
+

Token 支持 {{token}} 变量引用 —— 推荐把 token 放进环境变量,一次配置全局生效。

+

Basic Auth

+

填写用户名 / 密码,自动进行 Base64 编码后放入 Authorization 头。

+

API Key

+ + + + + + + + + + + + + + + + + + + + + +
字段说明
Key 名如 X-API-Key
值支持 {{变量}}
位置Header(默认)或 Query 参数
+

组合规则

+
    +
  • 鉴权产生的 Header 会与 Headers 标签中的同名项合并(鉴权优先)。
  • +
  • API Key 放 Query 时,会追加到 Params,不会重复出现在 Headers。
  • +
  • 导入 OpenAPI / Postman 时,文档中声明的 securitySchemes 会自动映射到对应鉴权方式。
  • +
+
+

注意:鉴权信息保存在本地集合数据中。如需分享集合,请先通过「导出」审查是否包含敏感 token。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/env/index.html b/homepage/dist/docs/env/index.html new file mode 100644 index 0000000..4ab033f --- /dev/null +++ b/homepage/dist/docs/env/index.html @@ -0,0 +1,265 @@ + + + + + +环境与变量 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

环境与变量

+
更新于 2026-09-17
+
+

前置 URL

+

环境可配置前置 URL(如 https://api.example.com)。配置后,请求里只需写相对路径:

+
前置 URL:https://api.example.com
+请求路径:/graphql
+实际请求:https://api.example.com/graphql
+
+
    +
  • URL 输入框会以前缀块 + 路径的形式一体展示,前缀部分不可误编辑(点击可跳转环境管理);
  • +
  • 切换环境即自动换成对应服务地址,无需改请求;
  • +
  • 路径以 / 开头(或为空)才启用拼接;写完整 https://… 地址的请求不受影响;
  • +
  • 未配置前置 URL 的环境,请求仍可写完整 URL 或用 {{变量名}}。
  • +
+
+

历史数据自动迁移:旧的 {{baseUrl}}/path 会被自动转为「前置 URL + /path」,baseUrl 变量写入环境的前置 URL 字段。

+
+

变量语法

+

在 URL、Params、Headers、Cookies、Body、鉴权字段中,使用双花括号引用变量:

+
{{baseUrl}}/v1/users?page={{page}}
+Authorization: Bearer {{token}}
+
+

发送时统一替换为当前启用环境中同名变量的值;未定义的变量保留原样,便于发现遗漏。

+

切换环境

+

顶栏环境切换器显示彩色单字徽标 + 环境名 + 变量数,点击弹出环境列表(当前环境带「当前」标记),一眼防误发;底部可进入「管理环境」或「不使用环境」。

+

管理环境

+

顶栏 环境 按钮打开管理弹窗(左侧环境列表 + 右侧编辑区):

+
    +
  • 左栏:环境列表(徽标 + 名称 + 当前标记),底部虚线按钮新建环境。
  • +
  • 右栏:提示条(变量引用语法 + 文档直达)、环境重命名、设为当前 / 取消使用、复制环境、删除;变量表支持按名称 / 描述搜索、逐行启用停用、内联编辑。
  • +
  • 所有修改即时生效并自动保存。
  • +
+

输入 {{ 自动补全

+

在 URL 输入框或任意「值」输入框键入 {{,会弹出当前环境的变量浮层:

+
    +
  • ↑↓ 选择、Enter / Tab 插入完整的 {{变量名}};Esc 关闭。
  • +
  • 浮层同时显示变量值,选之前即可确认。
  • +
+

内置示例环境:

+ + + + + + + + + + + + + + + + + + + + +
环境baseUrltoken
正式https://httpbin.orgdemo-token
本地http://127.0.0.1:8787dev-token
+

变量从哪来自动生成

+ + + + + + + + + + + + + + + + + + + + + +
来源行为
导入 OpenAPI / Swaggerservers 地址写入 baseUrl;路径参数 {id} 转为 {{id}} 并写入示例值
导入 Postmancollection.variable 写入当前环境
手动输入在环境面板随时增改
+

实际地址预览

+

URL 含 {{ }} 时,编辑器会在 URL 栏下方实时显示替换后的实际地址,切换环境立即更新。

+
+

提示:路径参数用变量而不是写死,是接口可复用的关键 —— 复制接口后只改变量值即可调试另一个资源。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/export/index.html b/homepage/dist/docs/export/index.html new file mode 100644 index 0000000..6ff870d --- /dev/null +++ b/homepage/dist/docs/export/index.html @@ -0,0 +1,239 @@ + + + + + +导出与代码生成 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

导出与代码生成

+
更新于 2026-09-17
+
+

顶栏 导出(多集合时可选择目标集合):

+ + + + + + + + + + + + + + + + + + + + + + + + + +
格式用途
OpenAPI 3.0 · JSON / YAML回流 Apifox、Swagger UI、代码生成器
Postman v2.1直接导入 Postman
Markdown 接口文档带目录、参数表格、请求体代码块,可放 Wiki
全量备份全部集合 + 环境,用于迁移与灾备
+

每种格式均支持复制到剪贴板与下载文件;对话框内实时预览导出内容。

+

全量备份与恢复

+
    +
  • 备份文件是包含 __opsxapi__: "backup" 标记的 JSON。
  • +
  • 恢复:导入对话框 → 粘贴备份内容或选择备份文件 → 格式自动识别为「OpsxAPI 备份」。
  • +
+

代码生成(单请求)

+

在 HTTP / GraphQL 编辑器点 </> 代码:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
目标说明
cURL含方法、头、体、cookie,可直接执行
JavaScript fetchasync/await 风格
Python requests含 import requests 完整脚本
Go net/http完整 main 函数
+

{{变量}} 保留原样输出,方便接入你自己的配置体系。

+
+

提示:导出的 OpenAPI 中,目录名会成为 tags,请求说明写入 description,鉴权自动生成 securitySchemes。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/faq/index.html b/homepage/dist/docs/faq/index.html new file mode 100644 index 0000000..7195e49 --- /dev/null +++ b/homepage/dist/docs/faq/index.html @@ -0,0 +1,211 @@ + + + + + +常见问题 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

常见问题

+
更新于 2026-09-17
+
+

请求报 CORS 错误?

+

Web 端请求默认经本地 Gin 代理(gin-proxy)发出,不会遇到 CORS。若仍报错:

+
    +
  • 确认 Gin 在运行:curl http://127.0.0.1:8787/health。
  • +
  • 用 ./run.sh web / gui 场景启动(Vite 已配置 /v1 反代)。
  • +
  • 桌面端优先走 Tauri 原生网络栈,同样不受 CORS 限制。
  • +
+

浏览器 WebSocket 不能加自定义 Header?

+

规范限制。在 WS「握手配置」里填写 Header 后,OpsxAPI 自动改走本地 Gin 隧道(见《WebSocket》章节),Header 由 Gin 在握手时代为携带。不填 Header 则直连。

+

外部 wss:// 地址连不上(DNS 失败)?

+

本机网络环境可能限制部分域名解析。可先用 curl -v wss://… 或换用公共 echo 服务验证;自建服务请确认防火墙与证书。

+

MQTT 一定要 wss:// 吗?

+

浏览器只能通过 WebSocket 连 MQTT。常见 Broker 的 WS 端口:EMQX 8084/mqtt(TLS)、8083/mqtt(明文,仅 http 页面)。mqtt:// TCP 直连仅在桌面原生环境可行。

+

数据存在哪里?换电脑怎么办?

+

集合 / 环境 / 历史保存在浏览器 localStorage。迁移:导出 → 全量备份 生成 JSON,在新设备 导入 即可。

+

误删了接口 / 想回到初始状态?

+

设置(顶栏 ⋯)→ 重置工作区,恢复内置示例集合。日常请养成导出备份的习惯。

+

SSE 事件流看着卡住了?

+
    +
  • 事件频率低(如告警流)属正常,等待即可。
  • +
  • 部分网关会缓冲 SSE,工具会在直连失败时自动切换 Gin 流式代理;若仍无事件,检查中间层(Nginx 需关闭 proxy_buffering)。
  • +
+

发送按钮点击后没反应?

+

查看响应区是否有红色错误提示(如代理不可达)。</> 代码 生成 cURL 在终端执行可快速分辨是工具问题还是网络 / 接口问题。

+

支持文件上传吗?

+

form-data 当前支持文本字段;文件上传请用 </> 代码 生成的 cURL / 脚本执行。

+

更多问题?

+
    +
  • 服务端能力与边界:见《服务端 API 参考》
  • +
  • 各协议用法:见左侧「请求调试」分组
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/graphql/index.html b/homepage/dist/docs/graphql/index.html new file mode 100644 index 0000000..c0fa775 --- /dev/null +++ b/homepage/dist/docs/graphql/index.html @@ -0,0 +1,216 @@ + + + + + +GraphQL · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

GraphQL

+
更新于 2026-09-17
+
+

编辑查询

+

GraphQL 请求由三部分组成:

+ + + + + + + + + + + + + + + + + + + + + +
部分说明
QueryGraphQL 查询语句,支持变量定义 $code: ID!
VariablesJSON 对象,随查询一起发送;非法 JSON 会红框提示
Headers / Auth与 HTTP 请求一致
+

发送

+

点击 执行(或 URL 栏按 Enter)。实际发送的是标准 GraphQL over HTTP:

+
{
+  "query": "query ($code: ID!) { country(code: $code) { name capital currency } }",
+  "variables": { "code": "CN" }
+}
+
+

响应面板会自动格式化 data / errors,字段名高亮。

+

内置示例

+

示例集合中的「国家查询 · countries」连接公共 GraphQL 服务 https://countries.trevorblades.com/graphql,无需鉴权,可直接体验。

+

最佳实践

+
    +
  • 把 endpoint 存为 {{baseUrl}}/graphql,环境切换即切换网关。
  • +
  • 需要鉴权时在 Auth 标签配置 Bearer,不必手写 Header。
  • +
  • 想看实际报文?点 </> 代码 生成 cURL,即为此查询的完整 HTTP 请求。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/http/index.html b/homepage/dist/docs/http/index.html new file mode 100644 index 0000000..36b05bb --- /dev/null +++ b/homepage/dist/docs/http/index.html @@ -0,0 +1,256 @@ + + + + + +发送 HTTP 请求 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

发送 HTTP 请求

+
更新于 2026-09-17
+
+

发送请求

+
    +
  1. 选择方法(GET / POST / PUT / PATCH / DELETE / HEAD / OPTIONS)。
  2. +
  3. 输入 URL,支持 {{baseUrl}}/path 形式的变量(见《环境与变量》)。
  4. +
  5. 点击 发送,或直接在 URL 输入框按 Enter。
  6. +
+

请求默认经本地 Gin 代理(/v1/proxy/http)发出,天然绕开浏览器 CORS 限制。

+

Params(查询参数)

+

键值对编辑器,每行可勾选启用 / 停用、填写说明。URL 中已有的查询串会被拆分到表格里,两边双向同步。

+

Body(请求体)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
模式适用场景
noneGET 等无体请求
JSONREST 接口(默认自动补 Content-Type: application/json,带格式化按钮)
XML / Text / HTML原始报文
x-www-form-urlencoded表单提交
form-datamultipart 文本字段(文件上传请用代码生成的 cURL)
+

Headers / Cookies

+
    +
  • Headers:键值对,支持 {{变量}};Authorization、Cookie 由 Auth / Cookies 标签统一管理时避免重复。
  • +
  • Cookies:键值对,发送时自动拼接为 Cookie 请求头。
  • +
+

代码生成

+

点击 URL 栏右侧 </> 代码,可生成:

+
    +
  • cURL(可直接在终端执行)
  • +
  • JavaScript fetch
  • +
  • Python requests
  • +
  • Go net/http
  • +
+

生成内容保留 {{变量}} 原样,便于粘贴到脚本后再替换。

+

响应面板

+ + + + + + + + + + + + + + + + + + + + + +
标签内容
响应体JSON 自动格式化 + 语法高亮;其他类型原样展示
Raw未格式化的原始文本
响应头全部响应头表格
+

右上角常驻 状态码 / 耗时 / 大小 / Content-Type,并提供「复制体」按钮。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/import/index.html b/homepage/dist/docs/import/index.html new file mode 100644 index 0000000..1a82ae0 --- /dev/null +++ b/homepage/dist/docs/import/index.html @@ -0,0 +1,284 @@ + + + + + +数据导入 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

数据导入

+
更新于 2026-09-17
+
+

顶栏 导入 打开导入对话框,支持三种来源:

+ + + + + + + + + + + + + + + + + + + + + +
来源说明
粘贴文本 / cURL直接粘贴任意受支持格式的内容
文件导入选择或拖入 .json / .yaml / .har / .md / .txt
URL 导入(Swagger)填写 OpenAPI 地址,经本地 Gin 代理拉取,避开 CORS
+

格式自动识别,也可手动指定。

+

支持格式

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
格式细节
OpenAPI 3.0 / 3.1、Swagger 2.0JSON 或 YAML;Apifox 导出的 OpenAPI 同样适用
Postman Collectionv2.0 / v2.1,含鉴权、变量、GraphQL body
Apipost 项目api_collection 格式(宽容解析)
cURL引号、续行、-d / -F / -u / --data-urlencode、cookie、代理等参数
HAR按域名分组、相同请求去重
Insomnia导出文件 v3 / v4,含 workspace / group 层级
Hoppscotch集合 JSON(数组或单对象)
Markdown提取文中的 ```curl 代码块
OpsxAPI 备份全量集合 + 环境,用于迁移恢复
+

YApi、Apidoc、Apizza、Eolink 请先在原平台导出为 OpenAPI 或 Postman 格式,再导入本工具。

+

导入时自动完成

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
原始内容转换结果
OpenAPI tags目录分组
路径参数 /pets/{petId}{{petId}} 变量 + 环境示例值
servers 地址当前环境 baseUrl 变量
requestBody schemaJSON 示例请求体
securitySchemesBearer / Basic / API Key 鉴权配置
Postman variable当前环境变量
+

结果确认

+

导入完成显示汇总:新建集合、接口数量、写入的环境变量与告警(如跳过的文件上传字段)。集合名重复时自动追加序号。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/index.html b/homepage/dist/docs/index.html new file mode 100644 index 0000000..e357fcb --- /dev/null +++ b/homepage/dist/docs/index.html @@ -0,0 +1,270 @@ + + + + + +产品介绍 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

产品介绍

+
更新于 2026-09-17
+
+

OpsxAPI 是一款本地优先的专业接口工作台,面向运维与开发,把 HTTP、GraphQL、WebSocket、SSE、Socket.IO、MQTT 六种协议的调试放进同一个窗口。

+

无需注册、无需联网同步,数据全部保存在本地浏览器(localStorage),导出备份随时带走。

+

功能总览

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
能力说明
六种协议HTTP / GraphQL / WebSocket / SSE / Socket.IO / MQTT
集合管理目录树、搜索、右键菜单、拖拽移动、多标签页
多环境变量{{baseUrl}}、{{token}} 全局替换,一键切换环境
数据导入OpenAPI/Swagger、Postman、Apifox、Apipost、cURL、HAR、Insomnia、Hoppscotch、Markdown 等
数据导出OpenAPI 3.0、Postman v2.1、Markdown 文档、全量备份
代码生成cURL / JavaScript fetch / Python requests / Go net/http
代理能力本地 Gin 代理绕开 CORS;WebSocket 隧道支持自定义握手 Header
双端形态浏览器(Web)与桌面端(Tauri)共用同一套界面
+

支持的协议与场景

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
协议典型场景特色
HTTP / REST调试 REST 接口、运维平台 API7 种方法、6 种请求体、3 种鉴权
GraphQL查询网关、中台接口Query + Variables 独立编辑
WebSocket实时推送、行情、IM自定义握手 Header(经本地隧道)
SSEAI 流式输出、监控事件流直连失败自动切代理、断点续传
Socket.IONode 实时应用事件监听、emit 参数、path/auth 配置
MQTTIoT 设备、消息总线通配符订阅、QoS、自动重连
+

为什么选 OpsxAPI

+
    +
  • 数据主权:所有集合、环境、历史保存在本机,不经过任何第三方服务器。
  • +
  • 开箱即用:./run.sh web 一条命令启动;首次打开自带覆盖全部协议的示例集合。
  • +
  • 工程友好:导入自动建目录、路径参数自动转变量;导出即标准 OpenAPI,可回流 Apifox / Swagger 生态。
  • +
  • 轻量克制:一个 Go 二进制 + 一份前端,资源占用小,内网可部署。
  • +
+
+

提示:想快速感受?直接看下一章《快速开始》,30 秒发出第一个请求。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/interface/index.html b/homepage/dist/docs/interface/index.html new file mode 100644 index 0000000..35d7903 --- /dev/null +++ b/homepage/dist/docs/interface/index.html @@ -0,0 +1,260 @@ + + + + + +界面导览 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

界面导览

+
更新于 2026-09-17
+
+

OpsxAPI 主界面分为五个区域:

+

顶栏

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
元素作用
+ 新建快捷创建各协议请求 / 目录(默认建在第一个集合)
导入 / 导出打开数据导入、导出对话框
环境选择器切换当前环境(变量随之生效),「⚙ 环境」管理环境与变量
🌙 / ☀️明暗主题切换
⋯设置(主题、超时、重置工作区)
+

左侧集合树

+
    +
  • 点击请求 → 在标签页中打开;点击目录 → 展开 / 折叠。
  • +
  • 右键任意节点:新建、重命名、复制、导出、删除。
  • +
  • 拖拽请求或目录到另一个目录,即可移动(支持跨集合)。
  • +
  • 顶部搜索框按名称 / 方法 / URL 实时过滤。
  • +
  • 底部为历史记录:显示最近请求的状态码与耗时,点击可回跳到对应接口。
  • +
+

标签页栏

+

同时打开多个接口,中键或 × 关闭;右键支持「关闭其他 / 关闭全部」。正在连接中的实时协议标签会显示呼吸圆点。

+

请求编辑区(上半部分)

+

按协议呈现不同编辑器:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
协议标签页
HTTPParams · Body · Headers · Cookies · Auth · 说明
GraphQLQuery · Variables · Headers · Auth
WebSocket消息 · 握手配置 · 说明
SSE事件流 · 连接配置 · 说明
Socket.IO事件 · 连接配置 · 说明
MQTT消息 · Broker / 订阅 · 发布 · 说明
+

响应区(下半部分)

+
    +
  • HTTP / GraphQL:响应体(Pretty JSON 高亮)、Raw、响应头,右上角状态 / 耗时 / 大小 / 复制。
  • +
  • 实时协议:分色消息日志(接收 · 绿、发送 · 蓝、系统 · 灰、错误 · 红),顶部实时统计收发条数与连接时长。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/intro/index.html b/homepage/dist/docs/intro/index.html new file mode 100644 index 0000000..e357fcb --- /dev/null +++ b/homepage/dist/docs/intro/index.html @@ -0,0 +1,270 @@ + + + + + +产品介绍 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

产品介绍

+
更新于 2026-09-17
+
+

OpsxAPI 是一款本地优先的专业接口工作台,面向运维与开发,把 HTTP、GraphQL、WebSocket、SSE、Socket.IO、MQTT 六种协议的调试放进同一个窗口。

+

无需注册、无需联网同步,数据全部保存在本地浏览器(localStorage),导出备份随时带走。

+

功能总览

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
能力说明
六种协议HTTP / GraphQL / WebSocket / SSE / Socket.IO / MQTT
集合管理目录树、搜索、右键菜单、拖拽移动、多标签页
多环境变量{{baseUrl}}、{{token}} 全局替换,一键切换环境
数据导入OpenAPI/Swagger、Postman、Apifox、Apipost、cURL、HAR、Insomnia、Hoppscotch、Markdown 等
数据导出OpenAPI 3.0、Postman v2.1、Markdown 文档、全量备份
代码生成cURL / JavaScript fetch / Python requests / Go net/http
代理能力本地 Gin 代理绕开 CORS;WebSocket 隧道支持自定义握手 Header
双端形态浏览器(Web)与桌面端(Tauri)共用同一套界面
+

支持的协议与场景

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
协议典型场景特色
HTTP / REST调试 REST 接口、运维平台 API7 种方法、6 种请求体、3 种鉴权
GraphQL查询网关、中台接口Query + Variables 独立编辑
WebSocket实时推送、行情、IM自定义握手 Header(经本地隧道)
SSEAI 流式输出、监控事件流直连失败自动切代理、断点续传
Socket.IONode 实时应用事件监听、emit 参数、path/auth 配置
MQTTIoT 设备、消息总线通配符订阅、QoS、自动重连
+

为什么选 OpsxAPI

+
    +
  • 数据主权:所有集合、环境、历史保存在本机,不经过任何第三方服务器。
  • +
  • 开箱即用:./run.sh web 一条命令启动;首次打开自带覆盖全部协议的示例集合。
  • +
  • 工程友好:导入自动建目录、路径参数自动转变量;导出即标准 OpenAPI,可回流 Apifox / Swagger 生态。
  • +
  • 轻量克制:一个 Go 二进制 + 一份前端,资源占用小,内网可部署。
  • +
+
+

提示:想快速感受?直接看下一章《快速开始》,30 秒发出第一个请求。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/manage/index.html b/homepage/dist/docs/manage/index.html new file mode 100644 index 0000000..567dd55 --- /dev/null +++ b/homepage/dist/docs/manage/index.html @@ -0,0 +1,253 @@ + + + + + +集合与历史 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

集合与历史

+
更新于 2026-09-17
+
+

新建

+ + + + + + + + + + + + + + + + + + + + + +
入口行为
顶栏「+ 新建」快捷菜单,建在第一个集合
树右键「新建请求 / 目录」精确指定位置
新建对话框选择类型(六协议 + 目录)、命名、目标集合与目录
+

接口名自动避免重复(追加序号)。

+

集合树操作

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
操作方式
重命名右键 → 重命名
复制右键 → 复制(深拷贝子树,名字加「副本」)
移动拖拽到目标目录(支持跨集合)
删除右键 → 删除(直接生效,请先备份重要数据)
搜索侧栏搜索框,匹配名称 / 方法 / URL
+

标签页

+
    +
  • 点击树节点在标签页打开;同时打开数量不限。
  • +
  • 中键 / × 关闭;右键「关闭其他 / 关闭全部」。
  • +
  • 关闭实时协议(WS / SSE / MQTT…)标签时自动断开连接。
  • +
+

历史记录

+
    +
  • 每次 HTTP / GraphQL 发送记录:时间、方法、接口名、状态码,失败标红。
  • +
  • 点击记录跳回对应接口;最多保留 100 条;可一键清空。
  • +
+

数据存储与备份

+
    +
  • 位置:浏览器 localStorage(键 opsxapi.workspace.v2),自动保存(防抖 400ms)。
  • +
  • 内容:集合、环境、历史、设置。标签页会话与实时消息不落盘。
  • +
  • 备份:导出 → 全量备份;恢复:导入备份文件。
  • +
  • 重置:设置 → 重置工作区(恢复初始示例,请先备份)。
  • +
+
+

注意:桌面端与浏览器是两份独立的 localStorage。跨端迁移请使用全量备份 / 导入。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/mock/index.html b/homepage/dist/docs/mock/index.html new file mode 100644 index 0000000..a3e8d20 --- /dev/null +++ b/homepage/dist/docs/mock/index.html @@ -0,0 +1,331 @@ + + + + + +Mock 数据 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

Mock 数据

+
更新于 2026-09-17
+
+

Mock 数据

+

联调时后端接口没就绪?OpsxAPI 内置 Mock.js 风格的数据生成器,两种用法覆盖绝大多数场景:

+
    +
  1. 显式表达式 —— 在参数值、Body 中直接写 @cname、@integer(1,100);
  2. +
  3. 智能匹配 —— 开启后按字段名自动套用规则表(username → 姓名、email → 邮箱…),一行不用写。
  4. +
+

开启与配置

+

顶栏 ⋯ → Mock 数据(或「设置 → Mock 数据」):

+
    +
  • 启用 Mock 数据:总开关,关闭后 @ 表达式按普通文本原样发送;
  • +
  • 智能 Mock 匹配:JSON Body 字段值未写表达式时,按字段名匹配规则自动生成;
  • +
  • 智能匹配规则表:数据类型(string / number / integer / boolean)、匹配方式(通配符 / 完全匹配 / 正则)、匹配规则(如 *name*)、Mock 表达式、备注与启用开关,支持搜索、新增、删除与恢复默认。
  • +
+

规则从上到下匹配,先命中先用;类型需与 JSON 字段实际类型一致(KV 参数一律按 string 匹配)。

+

表达式速查

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
表达式说明示例输出
@cname中文姓名王国强
@email邮箱kx8f2@qq.com
@phone手机号138****2733 形式 11 位
@id身份证号18 位
@guidUUID / GUID3f2b…-…
@integer(1, 100)整数42
@float(1, 9999, 2)小数(保留 2 位)128.50
@boolean布尔true
@string(8, 16)随机字符串aZ3k…
@datetime(YYYY-MM-DD HH:mm:ss)日期时间2026-09-17 14:30:00
@date(YYYY-MM-DD) / @time(HH:mm:ss)日期 / 时间—
@timestamp毫秒时间戳1760000000000
@url / @domain / @ipURL / 域名 / IPv4—
@province / @city(true) / @county(true)省市区广东省深圳市南山区
@ctitle(4, 12) / @csentence(10, 24)中文标题 / 句子—
@image(200x200)图片地址picsum 随机图
@pick("A", "B", "C")从列表中选择B
+

未列出的写法会原样发送,可放心与真实值混用。

+

在请求中使用

+

Params / x-www-form-urlencoded / form-data:值一栏直接填表达式。

+
username = @cname
+page     = @integer(1, 10)
+
+

JSON Body:叶子值写表达式,或交给智能匹配:

+
{
+  "username": "@cname",
+  "email": "@email",
+  "age": "@integer(18, 60)",
+  "vip": "@boolean"
+}
+
+

Body 工具栏提供两个辅助按钮:

+
    +
  • 智能填充:按规则把 JSON 各字段值批量替换为对应 @ 表达式,生成可编辑的 Mock 模板;
  • +
  • Mock 预览:即时查看发送时实际生成的数据,不必真的发请求。
  • +
+

生效范围

+
    +
  • 生效:Query 参数、JSON / XML / Text Body、x-www-form-urlencoded、form-data、GraphQL Variables;
  • +
  • 不生效:Headers、Cookies、鉴权字段(避免意外改坏签名与令牌)。
  • +
+
+

提示:Mock 在发送瞬间求值,同一请求每次发送都会得到新数据;预览结果仅供核对格式。

+
+

本地 Mock 服务(/mock)

+

除了发送时的离线 Mock,还能把接口发布成本地 Mock 服务,给前端 / 同事直接联调(类似 Apifox 的 Mock URL):

+
    +
  1. 登录并切换到「我的空间」或团队空间(Mock 按空间隔离);
  2. +
  3. HTTP 请求 URL 行点 Mock 链接 → 选择响应状态码与延迟 → 发布(一次发布当前空间集合内全部 HTTP 接口);
  4. +
  5. 得到地址:http://127.0.0.1:8787/mock/{空间随机地址}{路径}(每空间一个 16 位随机片段,不可枚举、不暴露归属),例如 http://127.0.0.1:8787/mock/9f2c7a1b3d5e4f60/api/users。
  6. +
+

特点:

+
    +
  • 每次请求随机生成:响应模板里的 @cname、@integer(...) 等表达式由服务端实时求值;
  • +
  • 发布时自动把智能 Mock 规则烘焙进模板(开启智能匹配时);
  • +
  • 非 GET 接口可用 ?_method=POST 快速验证;延迟最高 5 秒,用于模拟慢接口 / loading 态。
  • +
+

频率限制(防滥用)

+

本地 Mock 服务按 IP + 空间 限流:20 QPS(每秒 20 次)或 60 QPM(每分钟 60 次),超限返回 429 与 Retry-After: 60。依据服务条款:未经授权或滥用行为平台有权采取限流、暂停服务等措施;通过技术手段规避限流属于违规行为。Mock 定位是联调辅助,请勿当作对外流量服务使用。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/mqtt/index.html b/homepage/dist/docs/mqtt/index.html new file mode 100644 index 0000000..0e6c172 --- /dev/null +++ b/homepage/dist/docs/mqtt/index.html @@ -0,0 +1,237 @@ + + + + + +MQTT · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

MQTT

+
更新于 2026-09-17
+
+

连接 Broker

+

浏览器环境要求 WebSocket 形式的 Broker 地址:

+
wss://broker.emqx.io:8084/mqtt
+
+ + + + + + + + + + + + + + + + + + + + + +
配置说明
用户名 / 密码可选,支持 {{变量}}
ClientId默认随机生成;同一 Broker 上必须唯一
QoS0 至多一次 · 1 至少一次 · 2 恰好一次
+

订阅

+

「Broker / 订阅」中填写逗号分隔的主题,支持通配符:

+
opsxapi/demo, sensor/+, home/#
+
+
+

注意:订阅在建立连接时生效,修改主题后需断开重连。

+
+

发布

+

「发布」标签配置主题与 Payload(JSON / 纯文本),点击发布按钮即送达;已发布消息以蓝色出现在日志中并标注主题。

+

公共测试 Broker

+ + + + + + + + + + + + + + + + + +
Broker地址
EMQXwss://broker.emqx.io:8084/mqtt
HiveMQwss://broker.hivemq.com:8884/mqtt
+

两个浏览器窗口连接同一主题,即可互相收发验证。

+

行为说明

+
    +
  • 断线自动重连(3 秒间隔),状态点显示「重连中」。
  • +
  • 消息日志上限 500 条;QoS 与主题逐条标注。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/quickstart/index.html b/homepage/dist/docs/quickstart/index.html new file mode 100644 index 0000000..93505c5 --- /dev/null +++ b/homepage/dist/docs/quickstart/index.html @@ -0,0 +1,254 @@ + + + + + +快速开始 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

快速开始

+
更新于 2026-09-17
+
+

环境要求

+ + + + + + + + + + + + + + + + + + + + + + + + + +
组件版本用途
Node.js≥ 20Web 前端(Vite)
Go≥ 1.23本地代理服务(Gin)
Rust + Cargo可选仅编译桌面端(Tauri)时需要
+

启动

+
git clone <你的仓库地址> opsxapi
+cd opsxapi
+make install     # 安装依赖(npm install,含桌面端)
+
+./run.sh web     # 启动:Gin(:8787) + Web UI(:5173)
+
+

看到下面的输出即可打开浏览器:

+
[OK] 后端 UP  http://127.0.0.1:8787/health
+[OK] Web UP  http://127.0.0.1:5173
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
命令说明
./run.sh web浏览器版(推荐)
./run.sh gui桌面窗口(Tauri,共用同一 UI)
./run.sh allWeb + 桌面一起开
./run.sh status / stop查看状态 / 停止
+

30 秒发出第一个请求

+
    +
  1. 打开 http://127.0.0.1:5173,左侧是内置的「示例集合」。
  2. +
  3. 点击 HTTP · httpbin → 获取请求回显。
  4. +
  5. 点击右上角 发送。
  6. +
  7. 下方响应区显示 200、耗时与 JSON 高亮响应体 —— 完成!
  8. +
+

桌面端(可选)

+
./run.sh gui
+
+

桌面端复用同一份界面与数据通道,HTTP 请求走 Tauri 原生网络栈,不依赖浏览器 CORS。

+
+

提示:首次打开会自动创建两个环境(正式 / 本地)和一个覆盖全部协议的示例集合,可随时在「设置」中重置。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/search-data.json b/homepage/dist/docs/search-data.json new file mode 100644 index 0000000..3b17eab --- /dev/null +++ b/homepage/dist/docs/search-data.json @@ -0,0 +1 @@ +[{"Slug":"intro","Title":"产品介绍","Group":"开始使用","Text":"OpsxAPI 是一款 本地优先 的专业接口工作台,面向运维与开发,把 HTTP、GraphQL、WebSocket、SSE、Socket.IO、MQTT 六种协议的调试放进同一个窗口。 无需注册、无需联网同步,数据全部保存在本地浏览器(localStorage),导出备份随时带走。 功能总览 能力 说明 六种协议 HTTP / GraphQL / WebSocket / SSE / Socket.IO / MQTT 集合管理 目录树、搜索、右键菜单、拖拽移动、多标签页 多环境变量 、 全局替换,一键切换环境 数据导入 OpenAPI/Swagger、Postman、Apifox、Apipost、cURL、HAR、Insomnia、Hoppscotch、Markdown 等 数据导出 OpenAPI 3.0、Postman v2.1、Markdown 文档、全量备份 代码生成 cURL / JavaScript fetch / Python requests / Go net/http 代理能力 本地 Gin 代理绕开 CORS;WebSocket 隧道支持自定义握手 Header 双端形态 浏览器(Web)与桌面端(Tauri)共用同一套界面 支持的协议与场景 协议 典型场景 特色 HTTP / REST 调试 REST 接口、运维平台 API 7 种方法、6 种请求体、3 种鉴权 GraphQL 查询网关、中台接口 Query + Variables 独立编辑 WebSocket 实时推送、行情、IM 自定义握手 Header(经本地隧道) SSE AI 流式输出、监控事件流 直连失败自动切代理、断点续传 Socket.IO Node 实时应用 事件监听、emit 参数、path/auth 配置 MQTT IoT 设备、消息总线 通配符订阅、QoS、自动重连 为什么选 OpsxAPI 数据主权 :所有集合、环境、历史保存在本机,不经过任何第三方服务器。 开箱即用 : 一条命令启动;首次打开自带覆盖全部协议的示例集合。 工程友好 :导入自动建目录、路径参数自动转变量;导出即标准 OpenAPI,可回流 Apifox / Swagger 生态。 轻量克制 :一个 Go 二进制 + 一份前端,资源占用小,内网可部署。 提示 :想快速感受?直接看下一章《快速开始》,30 秒发出第一个请求。"},{"Slug":"quickstart","Title":"快速开始","Group":"开始使用","Text":"环境要求 组件 版本 用途 Node.js ≥ 20 Web 前端(Vite) Go ≥ 1.23 本地代理服务(Gin) Rust + Cargo 可选 仅编译桌面端(Tauri)时需要 启动 看到下面的输出即可打开浏览器: 命令 说明 浏览器版(推荐) 桌面窗口(Tauri,共用同一 UI) Web + 桌面一起开 / 查看状态 / 停止 30 秒发出第一个请求 1. 打开 \u003chttp://127.0.0.1:5173 ,左侧是内置的「示例集合」。 2. 点击 HTTP · httpbin → 获取请求回显 。 3. 点击右上角 发送 。 4. 下方响应区显示 、耗时与 JSON 高亮响应体 —— 完成! 桌面端(可选) 桌面端复用同一份界面与数据通道,HTTP 请求走 Tauri 原生网络栈,不依赖浏览器 CORS。 提示 :首次打开会自动创建两个环境(正式 / 本地)和一个覆盖全部协议的示例集合,可随时在「设置」中重置。"},{"Slug":"interface","Title":"界面导览","Group":"开始使用","Text":"OpsxAPI 主界面分为五个区域: 顶栏 元素 作用 + 新建 快捷创建各协议请求 / 目录(默认建在第一个集合) 导入 / 导出 打开数据导入、导出对话框 环境选择器 切换当前环境(变量随之生效),「⚙ 环境」管理环境与变量 🌙 / ☀️ 明暗主题切换 ⋯ 设置(主题、超时、重置工作区) 左侧集合树 点击请求 → 在标签页中打开;点击目录 → 展开 / 折叠。 右键 任意节点:新建、重命名、复制、导出、删除。 拖拽 请求或目录到另一个目录,即可移动(支持跨集合)。 顶部搜索框按名称 / 方法 / URL 实时过滤。 底部为 历史记录 :显示最近请求的状态码与耗时,点击可回跳到对应接口。 标签页栏 同时打开多个接口,中键或 × 关闭;右键支持「关闭其他 / 关闭全部」。正在连接中的实时协议标签会显示呼吸圆点。 请求编辑区(上半部分) 按协议呈现不同编辑器: 协议 标签页 HTTP Params · Body · Headers · Cookies · Auth · 说明 GraphQL Query · Variables · Headers · Auth WebSocket 消息 · 握手配置 · 说明 SSE 事件流 · 连接配置 · 说明 Socket.IO 事件 · 连接配置 · 说明 MQTT 消息 · Broker / 订阅 · 发布 · 说明 响应区(下半部分) HTTP / GraphQL :响应体(Pretty JSON 高亮)、Raw、响应头,右上角状态 / 耗时 / 大小 / 复制。 实时协议 :分色消息日志(接收 · 绿、发送 · 蓝、系统 · 灰、错误 · 红),顶部实时统计收发条数与连接时长。"},{"Slug":"http","Title":"发送 HTTP 请求","Group":"请求调试","Text":"发送请求 1. 选择方法(GET / POST / PUT / PATCH / DELETE / HEAD / OPTIONS)。 2. 输入 URL,支持 形式的变量(见《环境与变量》)。 3. 点击 发送 ,或直接在 URL 输入框按 Enter 。 请求默认经本地 Gin 代理( )发出,天然绕开浏览器 CORS 限制。 Params(查询参数) 键值对编辑器,每行可勾选启用 / 停用、填写说明。URL 中已有的查询串会被拆分到表格里,两边双向同步。 Body(请求体) 模式 适用场景 none GET 等无体请求 JSON REST 接口(默认自动补 ,带格式化按钮) XML / Text / HTML 原始报文 x www form urlencoded 表单提交 form data multipart 文本字段(文件上传请用代码生成的 cURL) Headers / Cookies Headers:键值对,支持 ; 、 由 Auth / Cookies 标签统一管理时避免重复。 Cookies:键值对,发送时自动拼接为 请求头。 代码生成 点击 URL 栏右侧 代码 ,可生成: cURL(可直接在终端执行) JavaScript fetch Python requests Go net/http 生成内容保留 原样,便于粘贴到脚本后再替换。 响应面板 标签 内容 响应体 JSON 自动格式化 + 语法高亮;其他类型原样展示 Raw 未格式化的原始文本 响应头 全部响应头表格 右上角常驻 状态码 / 耗时 / 大小 / Content Type ,并提供「复制体」按钮。"},{"Slug":"auth","Title":"接口鉴权","Group":"请求调试","Text":"在 HTTP / GraphQL / SSE 请求的 Auth 标签中选择鉴权方式: Bearer Token Token 支持 变量引用 —— 推荐把 token 放进环境变量,一次配置全局生效。 Basic Auth 填写用户名 / 密码,自动进行 Base64 编码后放入 头。 API Key 字段 说明 Key 名 如 值 支持 位置 Header(默认)或 Query 参数 组合规则 鉴权产生的 Header 会与 Headers 标签中的同名项合并(鉴权优先)。 API Key 放 Query 时,会追加到 Params,不会重复出现在 Headers。 导入 OpenAPI / Postman 时,文档中声明的 会自动映射到对应鉴权方式。 注意 :鉴权信息保存在本地集合数据中。如需分享集合,请先通过「导出」审查是否包含敏感 token。"},{"Slug":"env","Title":"环境与变量","Group":"请求调试","Text":"前置 URL 环境可配置 前置 URL (如 )。配置后,请求里只需写相对路径: URL 输入框会以 前缀块 + 路径 的形式一体展示,前缀部分不可误编辑(点击可跳转环境管理); 切换环境即自动换成对应服务地址 ,无需改请求; 路径以 开头(或为空)才启用拼接;写完整 地址的请求不受影响; 未配置前置 URL 的环境,请求仍可写完整 URL 或用 。 历史数据自动迁移:旧的 会被自动转为「前置 URL + /path」, 变量写入环境的前置 URL 字段。 变量语法 在 URL、Params、Headers、Cookies、Body、鉴权字段中,使用双花括号引用变量: 发送时统一替换为 当前启用环境 中同名变量的值;未定义的变量保留原样,便于发现遗漏。 切换环境 顶栏环境切换器显示 彩色单字徽标 + 环境名 + 变量数 ,点击弹出环境列表(当前环境带「当前」标记),一眼防误发;底部可进入「管理环境」或「不使用环境」。 管理环境 顶栏 环境 按钮打开管理弹窗(左侧环境列表 + 右侧编辑区): 左栏 :环境列表(徽标 + 名称 + 当前标记),底部虚线按钮新建环境。 右栏 :提示条(变量引用语法 + 文档直达)、环境重命名、设为当前 / 取消使用、 复制环境 、删除;变量表支持 按名称 / 描述搜索 、逐行启用停用、内联编辑。 所有修改即时生效并自动保存。 输入 {{ 自动补全 在 URL 输入框或任意「值」输入框键入 ,会弹出当前环境的变量浮层: ↑↓ 选择、Enter / Tab 插入完整的 ;Esc 关闭。 浮层同时显示变量值,选之前即可确认。 内置示例环境: 环境 baseUrl token 正式 demo token 本地 dev token 变量从哪来自动生成 来源 行为 导入 OpenAPI / Swagger 地址写入 ;路径参数 转为 并写入示例值 导入 Postman 写入当前环境 手动输入 在环境面板随时增改 实际地址预览 URL 含 时,编辑器会在 URL 栏下方实时显示替换后的实际地址,切换环境立即更新。 提示 :路径参数用变量而不是写死,是接口可复用的关键 —— 复制接口后只改变量值即可调试另一个资源。"},{"Slug":"graphql","Title":"GraphQL","Group":"请求调试","Text":"编辑查询 GraphQL 请求由三部分组成: 部分 说明 Query GraphQL 查询语句,支持变量定义 Variables JSON 对象,随查询一起发送;非法 JSON 会红框提示 Headers / Auth 与 HTTP 请求一致 发送 点击 执行 (或 URL 栏按 Enter)。实际发送的是标准 GraphQL over HTTP: 响应面板会自动格式化 / ,字段名高亮。 内置示例 示例集合中的「国家查询 · countries」连接公共 GraphQL 服务 \u003chttps://countries.trevorblades.com/graphql ,无需鉴权,可直接体验。 最佳实践 把 endpoint 存为 ,环境切换即切换网关。 需要鉴权时在 Auth 标签配置 Bearer,不必手写 Header。 想看实际报文?点 代码 生成 cURL,即为此查询的完整 HTTP 请求。"},{"Slug":"websocket","Title":"WebSocket","Group":"请求调试","Text":"连接 1. 填写 或 地址。 2. 点击 连接 ;状态点变绿(已连接)后即可收发消息。 3. 再次点击按钮即断开。 消息收发 消息日志 :接收(绿)/ 发送(蓝)/ 系统(灰)/ 错误(红)分色展示,顶部统计 ↑↓ 条数与连接时长。 发送框 :支持 JSON / 纯文本; ⌘/Ctrl + Enter 快速发送;「格式化 JSON」一键美化。 子协议 「握手配置」标签中的 子协议 填逗号分隔列表,例如: 自定义握手 Header(隧道模式) 浏览器原生 WebSocket 不能 携带自定义 Header(如 、 )。OpsxAPI 的处理方式: 1. 「握手配置」中填写 Header 后,工具自动改走 本地 Gin 隧道 : 浏览器 → Gin (普通 WS) Gin → 目标服务器(携带你填的全部 Header) 2. 不填 Header 时直连目标,零额外开销。 注意 :隧道要求本地 Gin 服务(:8787)在运行,即用 / 启动的默认形态。 调试技巧 消息过多时点「清空」;日志上限 500 条,超出自动滚动淘汰。 把常用报文保存在「说明」里,或为不同报文建多个 WS 请求节点。"},{"Slug":"sse","Title":"SSE 事件流","Group":"请求调试","Text":"连接事件流 1. 填写 SSE 地址(如 )。 2. 点击 连接 ,事件按到达顺序流入消息日志。 3. 每条消息按 名称归类显示; 为 JSON 时自动格式化。 直连与代理自动切换 默认 直连 目标站(fetch 流式读取,延迟最低)。 直连因 CORS / 网络失败时,自动降级走 本地 Gin 流式代理 ,日志中会提示切换过程,无需手工干预。 断点续传(Last Event ID) 「连接配置」中填写 Last Event ID,连接时以 请求头携带,支持断点续传的流会在该事件之后继续推送。 连接配置项 配置 说明 Query 参数 / Headers 以键值对附加 Last Event ID 断点续传游标 仅显示 data 内容 开启后只显示 载荷;关闭则连同 名称一起显示 鉴权 与 HTTP 相同(Bearer / Basic / API Key) 典型场景 LLM 流式输出接口( ) 监控 / 审计事件流 需要长期挂机观察的推送通道"},{"Slug":"socketio","Title":"Socket.IO","Group":"请求调试","Text":"连接 1. 填写服务地址( 不含 路径),如 。 2. 点击 连接 ,状态变为「已连接」后即可收发事件。 监听事件 「连接配置」→ 监听事件 填逗号分隔的事件名: 留空则接收全部服务端事件(onAny 模式)。事件名在每条日志中标注。 发送(emit) 「事件」标签底部的发送区: 事件名 :如 参数 :JSON 数组,作为 的参数 连接选项 以 JSON 配置传给 socket.io client: 选项 说明 path 服务端挂载路径,默认 transports / ,默认两者皆可 auth 握手鉴权载荷,支持 提示 :浏览器直连外部站点同样受 CORS 限制,Socket.IO 服务端需配置对应 origin,或把服务与本工具部署在同源下。"},{"Slug":"mqtt","Title":"MQTT","Group":"请求调试","Text":"连接 Broker 浏览器环境要求 WebSocket 形式 的 Broker 地址: 配置 说明 用户名 / 密码 可选,支持 ClientId 默认随机生成;同一 Broker 上必须唯一 QoS 0 至多一次 · 1 至少一次 · 2 恰好一次 订阅 「Broker / 订阅」中填写逗号分隔的主题,支持通配符: 注意 :订阅在 建立连接时 生效,修改主题后需断开重连。 发布 「发布」标签配置主题与 Payload(JSON / 纯文本),点击发布按钮即送达;已发布消息以蓝色出现在日志中并标注主题。 公共测试 Broker Broker 地址 EMQX HiveMQ 两个浏览器窗口连接同一主题,即可互相收发验证。 行为说明 断线自动重连(3 秒间隔),状态点显示「重连中」。 消息日志上限 500 条;QoS 与主题逐条标注。"},{"Slug":"import","Title":"数据导入","Group":"数据管理","Text":"顶栏 导入 打开导入对话框,支持三种来源: 来源 说明 粘贴文本 / cURL 直接粘贴任意受支持格式的内容 文件导入 选择或拖入 / / / / URL 导入(Swagger) 填写 OpenAPI 地址,经本地 Gin 代理拉取,避开 CORS 格式 自动识别 ,也可手动指定。 支持格式 格式 细节 OpenAPI 3.0 / 3.1、Swagger 2.0 JSON 或 YAML;Apifox 导出的 OpenAPI 同样适用 Postman Collection v2.0 / v2.1,含鉴权、变量、GraphQL body Apipost 项目 格式(宽容解析) cURL 引号、续行、 / / / 、cookie、代理等参数 HAR 按域名分组、相同请求去重 Insomnia 导出文件 v3 / v4,含 workspace / group 层级 Hoppscotch 集合 JSON(数组或单对象) Markdown 提取文中的 tags /pets/{petId} {{petId}} servers baseUrl variable` 当前环境变量 结果确认 导入完成显示汇总:新建集合、接口数量、写入的环境变量与告警(如跳过的文件上传字段)。集合名重复时自动追加序号。"},{"Slug":"export","Title":"导出与代码生成","Group":"数据管理","Text":"顶栏 导出 (多集合时可选择目标集合): 格式 用途 OpenAPI 3.0 · JSON / YAML 回流 Apifox、Swagger UI、代码生成器 Postman v2.1 直接导入 Postman Markdown 接口文档 带目录、参数表格、请求体代码块,可放 Wiki 全量备份 全部集合 + 环境,用于迁移与灾备 每种格式均支持 复制到剪贴板 与 下载文件 ;对话框内实时预览导出内容。 全量备份与恢复 备份文件是包含 标记的 JSON。 恢复:导入对话框 → 粘贴备份内容或选择备份文件 → 格式自动识别为「OpsxAPI 备份」。 代码生成(单请求) 在 HTTP / GraphQL 编辑器点 代码 : 目标 说明 cURL 含方法、头、体、cookie,可直接执行 JavaScript fetch 风格 Python requests 含 完整脚本 Go net/http 完整 函数 保留原样输出,方便接入你自己的配置体系。 提示 :导出的 OpenAPI 中,目录名会成为 ,请求说明写入 ,鉴权自动生成 。"},{"Slug":"mock","Title":"Mock 数据","Group":"数据管理","Text":"Mock 数据 联调时后端接口没就绪?OpsxAPI 内置 Mock.js 风格的数据生成器 ,两种用法覆盖绝大多数场景: 1. 显式表达式 —— 在参数值、Body 中直接写 、 ; 2. 智能匹配 —— 开启后按 字段名 自动套用规则表( → 姓名、 → 邮箱…),一行不用写。 开启与配置 顶栏 ⋯ → Mock 数据 (或「设置 → Mock 数据」): 启用 Mock 数据 :总开关,关闭后 表达式按普通文本原样发送; 智能 Mock 匹配 :JSON Body 字段值未写表达式时,按字段名匹配规则自动生成; 智能匹配规则表 :数据类型(string / number / integer / boolean)、匹配方式(通配符 / 完全匹配 / 正则)、匹配规则(如 )、Mock 表达式、备注与启用开关,支持搜索、新增、删除与恢复默认。 规则 从上到下 匹配,先命中先用;类型需与 JSON 字段实际类型一致(KV 参数一律按 string 匹配)。 表达式速查 表达式 说明 示例输出 中文姓名 邮箱 手机号 形式 11 位 身份证号 18 位 UUID / GUID 整数 小数(保留 2 位) 布尔 随机字符串 日期时间 / 日期 / 时间 — 毫秒时间戳 / / URL / 域名 / IPv4 — / / 省市区 / 中文标题 / 句子 — 图片地址 picsum 随机图 从列表中选择 未列出的写法会 原样发送 ,可放心与真实值混用。 在请求中使用 Params / x www form urlencoded / form data :值一栏直接填表达式。 JSON Body :叶子值写表达式,或交给智能匹配: Body 工具栏提供两个辅助按钮: 智能填充 :按规则把 JSON 各字段值批量替换为对应 表达式,生成可编辑的 Mock 模板; Mock 预览 :即时查看发送时实际生成的数据,不必真的发请求。 生效范围 生效:Query 参数、JSON / XML / Text Body、x www form urlencoded、form data、GraphQL Variables; 不生效:Headers、Cookies、鉴权字段(避免意外改坏签名与令牌)。 提示:Mock 在 发送瞬间 求值,同一请求每次发送都会得到新数据;预览结果仅供核对格式。 本地 Mock 服务(/mock) 除了发送时的离线 Mock,还能把接口 发布成本地 Mock 服务 ,给前端 / 同事直接联调(类似 Apifox 的 Mock URL): 1. 登录并切换到「我的空间」或团队空间(Mock 按空间隔离); 2. HTTP 请求 URL 行点 Mock 链接 → 选择响应状态码与延迟 → 发布 (一次发布当前空间集合内全部 HTTP 接口); 3. 得到地址: (每空间一个 16 位随机片段,不可枚举、不暴露归属),例如 。 特点: 每次请求随机生成 :响应模板里的 、 等表达式由服务端实时求值; 发布时自动把智能 Mock 规则烘焙进模板(开启智能匹配时); 非 GET 接口可用 快速验证;延迟最高 5 秒,用于模拟慢接口 / loading 态。 频率限制(防滥用) 本地 Mock 服务按 IP + 空间 限流: 20 QPS(每秒 20 次)或 60 QPM(每分钟 60 次) ,超限返回 与 。依据 :未经授权或滥用行为平台有权采取限流、暂停服务等措施; 通过技术手段规避限流属于违规行为 。Mock 定位是联调辅助,请勿当作对外流量服务使用。"},{"Slug":"manage","Title":"集合与历史","Group":"数据管理","Text":"新建 入口 行为 顶栏「+ 新建」 快捷菜单,建在第一个集合 树右键「新建请求 / 目录」 精确指定位置 新建对话框 选择类型(六协议 + 目录)、命名、目标集合与目录 接口名自动避免重复(追加序号)。 集合树操作 操作 方式 重命名 右键 → 重命名 复制 右键 → 复制(深拷贝子树,名字加「副本」) 移动 拖拽到目标目录(支持跨集合) 删除 右键 → 删除(直接生效,请先备份重要数据) 搜索 侧栏搜索框,匹配名称 / 方法 / URL 标签页 点击树节点在标签页打开;同时打开数量不限。 中键 / × 关闭;右键「关闭其他 / 关闭全部」。 关闭实时协议(WS / SSE / MQTT…)标签时自动断开连接。 历史记录 每次 HTTP / GraphQL 发送记录:时间、方法、接口名、状态码,失败标红。 点击记录跳回对应接口;最多保留 100 条;可一键清空。 数据存储与备份 位置:浏览器 localStorage(键 ),自动保存(防抖 400ms)。 内容:集合、环境、历史、设置。标签页会话与实时消息不落盘。 备份:导出 → 全量备份;恢复:导入备份文件。 重置:设置 → 重置工作区(恢复初始示例,请先备份)。 注意 :桌面端与浏览器是两份独立的 localStorage。跨端迁移请使用全量备份 / 导入。"},{"Slug":"testing","Title":"自动化测试","Group":"自动化测试与 AI","Text":"自动化测试 把日常联调的接口串成 场景用例 ,一条龙验证业务流程。三种触发方式共用同一套用例模型: 方式 说明 适合 手动运行 用例编排好后点「运行」 日常自测、回归 AI 生成 模型按接口清单自动编排步骤与断言 快速起盘、补断言思路 定时任务 应用运行期间按间隔自动执行 持续监控、冒烟 场景用例 从侧栏底部「自动化测试」进入。用例 = 有序步骤列表,每个步骤: 引用一个 HTTP 接口 (从集合中选择,可跨集合、跨目录); 断言 :状态码 / 耗时 / Header / Body 四类目标,支持 等于、不等于、大于、小于、包含、存在 与 JSONPath 取值比较; 变量提取 : → 环境变量 ,后续步骤 URL / Body 用 引用,实现「创建 → 查询 → 删除」链式传值; 可单独禁用、上下移动、删除。 用例级选项「 失败后继续 」:默认失败即停(快速定位首个问题);打开后跑完全部步骤再看整体报告。 运行报告 统计卡:通过 / 失败步骤数、总耗时、断言数、通过率; 步骤明细:方法 + URL + 状态码 + 耗时,逐条断言的期望 / 实际对照(可按 通过 / 失败 过滤); 「再次运行」一键回归;「导出报告」生成 Markdown 存档或归档到缺陷单; 每个用例保留最近 50 次运行记录,可下拉切换历史报告。 定时任务 用例头部的 ⏱ 按钮或左侧「定时任务」入口: 间隔可选 5 / 15 / 30 / 60 分钟、6 小时、每天; 独立 启用 / 暂停 开关,显示下次运行时间与上次结果; 应用保持运行时生效 :OpsxAPI 窗口(或 Web 页面)开着才会按时触发并记录报告,关闭后自动暂停 —— 适合工作时段的持续监控,不能替代服务器侧的 CI。 提示:定时触发的请求同样走当前环境与 Mock 设置;跨环境回归前先在顶栏切换环境。 AI 生成用例 见 。配置模型供应商后,「AI 生成」会读取集合的 HTTP 接口清单(方法、URL、Body 示例),按业务依赖编排步骤、断言与变量提取,生成前可附加一句要求(如「重点覆盖登录态与分页」),预览确认后保存。"},{"Slug":"ai","Title":"AI 助手","Group":"自动化测试与 AI","Text":"AI 助手 接入 OpenAI 兼容协议 的大模型,为接口调试与自动化测试提供 AI 能力。密钥只保存在本机(localStorage),请求直连供应商,不经过任何第三方中转。 配置模型供应商 设置 → AI 助手 → 模型供应商 ,点「添加供应商」,内置常用预设: 供应商 Base URL 模型示例 DeepSeek 智谱 GLM Moonshot Kimi OpenAI Ollama 本地 API Key :Ollama 等本地服务可留空; 测试连接 :保存前先发一条 ping 验证地址 / 密钥 / 模型名; 多个供应商时可切换「当前使用」的模型。 AI 生成场景用例 自动化测试视图 →「 AI 生成 」: 1. 选择集合(AI 读取其中全部 HTTP 接口:方法、URL、Body 示例); 2. 可选填写一句要求,如「覆盖下单 → 支付 → 查询流程,重点断言金额字段」; 3. 模型按业务依赖编排步骤,输出断言与变量提取(如 ,后续步骤用 ); 4. 预览生成的步骤清单(未识别的接口会自动跳过并提示),确认后保存为正式用例。 生成结果只是起点 —— 步骤、断言、提取规则都可再手动调整。 隐私与边界 API Key 仅存本机,随工作区数据一起持久化;导出全量备份时会包含,分享备份文件前请注意; 供应商收到的内容为接口清单摘要(方法 / URL / Body 片段)与你的指令, 不含 环境变量值与 API Key; 未配置供应商时,Mock 数据、环境变量等离线功能不受影响。 常见问题 生成失败? 依次检查:Base URL 是否带 、模型名是否属于该供应商、Key 是否有效(用「测试连接」验证)、本机能否直连该域名(内网代理环境注意放行)。 想用公司内网模型? 添加自定义供应商,Base URL 填内网网关地址即可(需兼容 OpenAI Chat Completions 协议)。"},{"Slug":"account","Title":"账号与团队","Group":"账号与团队","Text":"账号与团队 登录后可使用 云端空间 :个人空间「我的空间」与团队共享空间,数据保存在本机服务的 SQLite 数据库( ),不上传任何第三方。 注册 / 登录 最左 活动栏 底部 登录 按钮打开弹窗: 注册只需 昵称 + 邮箱 + 密码(≥ 6 位); 登录态保存在本机,令牌失效会自动清除。 空间切换 活动栏 顶部空间徽标 (未登录时为产品 Logo,云端空间显示彩色徽标)点击弹出空间列表: 空间 说明 本地空间 未登录时默认;数据在浏览器 localStorage,不上云 我的空间 个人云端空间,注册即有;换浏览器 / 换设备登录即得同一份数据 团队 · ×× 团队共享空间,成员读写同一份数据 首次切入空的云端空间时,会自动把 当前本地数据播种上去 ; 在云端空间内的所有改动(接口、环境、测试用例、设置) 自动同步 (改动后约 1.5 秒),活动栏底部头像上的状态点显示 已同步 / 同步中(闪烁)/ 同步失败(红); 切回本地空间时恢复离开前的本地快照,两端互不覆盖; 同步策略为 后写覆盖 :多人同时编辑以最后一次保存为准。 团队管理 活动栏账号菜单或空间菜单 → 团队管理 : 新建团队 :创建后自动获得同名共享空间; 重命名 / 删除 :团队卡片右上角的 ✎ / 🗑(仅创建者可见)。重命名就地保存;删除需二次确认,将同时删除成员关系、共享空间与已发布 Mock 数据,不可恢复(若当前正停在该团队空间,会自动切回本地空间); 添加成员 :输入已注册成员邮箱(创建者可操作),邀请时可顺手点选 擅长 预设;成员登录后即可看到并切换到该团队空间; 成员与擅长 :每个团队卡片展示成员列表(头像 / 名称 / 角色 / 擅长标签)。擅长支持预设点选(前端、后端、全栈、测试、运维、移动端、数据库、AI、接口设计、安全)与自定义输入,空格或顿号分隔;创建者可修改任何成员的擅长,成员只能修改自己的(行尾「擅长」按钮)。 数据与安全 密码加盐哈希后存储;令牌为随机 Bearer Token,可随时退出登录作废; 云端空间单份数据上限 20MB; 团队空间权限:全体成员可读写,仅创建者可管理成员与修改他人擅长; 不登录不影响任何本地功能。"},{"Slug":"server-api","Title":"服务端 API 参考","Group":"参考","Text":"本地服务(Gin)默认监听 ,可用环境变量 修改。所有端点仅监听本机回环,供 Web UI 与桌面端调用。 端点总览 方法 路径 用途 GET 健康检查 POST HTTP 代理(全方法、自定义头、超时) POST NDJSON 流式代理(SSE / chunked 透传) POST 建立到目标 WS 的隧道会话 GET 浏览器 attach 到隧道会话(双向桥接) POST 关闭隧道会话 GET 本文档站 HTTP 代理 响应: 请求体 支持 / / / / / , 为原始报文; 可选。 流式代理 请求体与 HTTP 代理一致,响应为 NDJSON 事件流: WebSocket 隧道 attach 后第一条消息为控制帧 ;此后浏览器与目标服务器双向透传。 安全边界 仅允许 (代理)与 (隧道)目标。 拒绝云元数据地址(169.254.169.254 等)防 SSRF。 单响应上限 10 MiB;隧道会话 10 分钟无活动自动回收。 部署建议 开发: (Vite :5173 反代 、 到 :8787)。 生产: 产物交给任意静态服务器, 独立部署;生产环境建议置于内网并按需增加鉴权反向代理。"},{"Slug":"faq","Title":"常见问题","Group":"参考","Text":"请求报 CORS 错误? Web 端请求默认经本地 Gin 代理(gin proxy)发出,不会遇到 CORS。若仍报错: 确认 Gin 在运行: 。 用 / 场景启动(Vite 已配置 反代)。 桌面端优先走 Tauri 原生网络栈,同样不受 CORS 限制。 浏览器 WebSocket 不能加自定义 Header? 规范限制。在 WS「握手配置」里填写 Header 后,OpsxAPI 自动改走本地 Gin 隧道(见《WebSocket》章节),Header 由 Gin 在握手时代为携带。不填 Header 则直连。 外部 wss:// 地址连不上(DNS 失败)? 本机网络环境可能限制部分域名解析。可先用 或换用公共 echo 服务验证;自建服务请确认防火墙与证书。 MQTT 一定要 wss:// 吗? 浏览器只能通过 WebSocket 连 MQTT。常见 Broker 的 WS 端口:EMQX (TLS)、 (明文,仅 http 页面)。 TCP 直连仅在桌面原生环境可行。 数据存在哪里?换电脑怎么办? 集合 / 环境 / 历史保存在浏览器 localStorage。迁移: 导出 → 全量备份 生成 JSON,在新设备 导入 即可。 误删了接口 / 想回到初始状态? 设置(顶栏 ⋯)→ 重置工作区,恢复内置示例集合。日常请养成导出备份的习惯。 SSE 事件流看着卡住了? 事件频率低(如告警流)属正常,等待即可。 部分网关会缓冲 SSE,工具会在直连失败时自动切换 Gin 流式代理;若仍无事件,检查中间层(Nginx 需关闭 )。 发送按钮点击后没反应? 查看响应区是否有红色错误提示(如代理不可达)。 代码 生成 cURL 在终端执行可快速分辨是工具问题还是网络 / 接口问题。 支持文件上传吗? form data 当前支持文本字段;文件上传请用 代码 生成的 cURL / 脚本执行。 更多问题? 服务端能力与边界:见《服务端 API 参考》 各协议用法:见左侧「请求调试」分组"}] \ No newline at end of file diff --git a/homepage/dist/docs/server-api/index.html b/homepage/dist/docs/server-api/index.html new file mode 100644 index 0000000..528a425 --- /dev/null +++ b/homepage/dist/docs/server-api/index.html @@ -0,0 +1,273 @@ + + + + + +服务端 API 参考 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

服务端 API 参考

+
更新于 2026-09-17
+
+

本地服务(Gin)默认监听 :8787,可用环境变量 OPSXAPI_ADDR 修改。所有端点仅监听本机回环,供 Web UI 与桌面端调用。

+

端点总览

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
方法路径用途
GET/health健康检查
POST/v1/proxy/httpHTTP 代理(全方法、自定义头、超时)
POST/v1/proxy/http/streamNDJSON 流式代理(SSE / chunked 透传)
POST/v1/proxy/ws/connect建立到目标 WS 的隧道会话
GET/v1/proxy/ws/attach浏览器 attach 到隧道会话(双向桥接)
POST/v1/proxy/ws/close关闭隧道会话
GET/docs本文档站
+

HTTP 代理

+
curl -s -X POST http://127.0.0.1:8787/v1/proxy/http \
+  -H 'Content-Type: application/json' \
+  -d '{"method":"GET","url":"https://httpbin.org/get","headers":{}}'
+
+

响应:

+
{
+  "status": 200,
+  "headers": { "content-type": "application/json" },
+  "body": "{ ... }",
+  "timeMs": 320,
+  "size": 274
+}
+
+

请求体 body.mode 支持 json / xml / text / html / urlencoded / form-data,raw 为原始报文;timeoutMs 可选。

+

流式代理

+

请求体与 HTTP 代理一致,响应为 NDJSON 事件流:

+
{"type":"meta","status":200,"headers":{...}}
+{"type":"chunk","data":"<base64>","size":1024}
+{"type":"end","timeMs":1200,"size":8192}
+
+

WebSocket 隧道

+
# 1. 建立会话(可带自定义 Header)
+curl -s -X POST http://127.0.0.1:8787/v1/proxy/ws/connect \
+  -H 'Content-Type: application/json' \
+  -d '{"url":"wss://echo.example.com","headers":{"Authorization":"Bearer t"}}'
+# → {"sessionId":"..."}
+
+# 2. 浏览器 / 客户端 attach(普通 WebSocket)
+#    ws://127.0.0.1:8787/v1/proxy/ws/attach?sessionId=...
+
+# 3. 关闭
+curl -s -X POST http://127.0.0.1:8787/v1/proxy/ws/close \
+  -H 'Content-Type: application/json' -d '{"sessionId":"..."}'
+
+

attach 后第一条消息为控制帧 {"type":"open"};此后浏览器与目标服务器双向透传。

+

安全边界

+
    +
  • 仅允许 http/https(代理)与 ws/wss(隧道)目标。
  • +
  • 拒绝云元数据地址(169.254.169.254 等)防 SSRF。
  • +
  • 单响应上限 10 MiB;隧道会话 10 分钟无活动自动回收。
  • +
+

部署建议

+
    +
  • 开发:./run.sh web(Vite :5173 反代 /v1、/docs 到 :8787)。
  • +
  • 生产:npm run build:web 产物交给任意静态服务器,opsxapi-server 独立部署;生产环境建议置于内网并按需增加鉴权反向代理。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/socketio/index.html b/homepage/dist/docs/socketio/index.html new file mode 100644 index 0000000..3ec4e9b --- /dev/null +++ b/homepage/dist/docs/socketio/index.html @@ -0,0 +1,227 @@ + + + + + +Socket.IO · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

Socket.IO

+
更新于 2026-09-17
+
+

连接

+
    +
  1. 填写服务地址(不含 /socket.io 路径),如 http://127.0.0.1:3000。
  2. +
  3. 点击 连接,状态变为「已连接」后即可收发事件。
  4. +
+

监听事件

+

「连接配置」→ 监听事件 填逗号分隔的事件名:

+
message, notification
+
+

留空则接收全部服务端事件(onAny 模式)。事件名在每条日志中标注。

+

发送(emit)

+

「事件」标签底部的发送区:

+
    +
  • 事件名:如 message
  • +
  • 参数:JSON 数组,作为 socket.emit(event, ...args) 的参数
  • +
+
["hello", 42]
+
+

连接选项

+

以 JSON 配置传给 socket.io-client:

+
{
+  "path": "/socket.io",
+  "transports": ["websocket"],
+  "auth": { "token": "{{token}}" }
+}
+
+ + + + + + + + + + + + + + + + + + + + + +
选项说明
path服务端挂载路径,默认 /socket.io
transportswebsocket / polling,默认两者皆可
auth握手鉴权载荷,支持 {{变量}}
+
+

提示:浏览器直连外部站点同样受 CORS 限制,Socket.IO 服务端需配置对应 origin,或把服务与本工具部署在同源下。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/sse/index.html b/homepage/dist/docs/sse/index.html new file mode 100644 index 0000000..9628892 --- /dev/null +++ b/homepage/dist/docs/sse/index.html @@ -0,0 +1,223 @@ + + + + + +SSE 事件流 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

SSE 事件流

+
更新于 2026-09-17
+
+

连接事件流

+
    +
  1. 填写 SSE 地址(如 https://stream.wikimedia.org/v2/stream/recentchange)。
  2. +
  3. 点击 连接,事件按到达顺序流入消息日志。
  4. +
  5. 每条消息按 event: 名称归类显示;data 为 JSON 时自动格式化。
  6. +
+

直连与代理自动切换

+
    +
  • 默认直连目标站(fetch 流式读取,延迟最低)。
  • +
  • 直连因 CORS / 网络失败时,自动降级走本地 Gin 流式代理,日志中会提示切换过程,无需手工干预。
  • +
+

断点续传(Last-Event-ID)

+

「连接配置」中填写 Last-Event-ID,连接时以 Last-Event-ID 请求头携带,支持断点续传的流会在该事件之后继续推送。

+

连接配置项

+ + + + + + + + + + + + + + + + + + + + + + + + + +
配置说明
Query 参数 / Headers以键值对附加
Last-Event-ID断点续传游标
仅显示 data 内容开启后只显示 data: 载荷;关闭则连同 event: 名称一起显示
鉴权与 HTTP 相同(Bearer / Basic / API Key)
+

典型场景

+
    +
  • LLM 流式输出接口(text/event-stream)
  • +
  • 监控 / 审计事件流
  • +
  • 需要长期挂机观察的推送通道
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/testing/index.html b/homepage/dist/docs/testing/index.html new file mode 100644 index 0000000..d91226c --- /dev/null +++ b/homepage/dist/docs/testing/index.html @@ -0,0 +1,232 @@ + + + + + +自动化测试 · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

自动化测试

+
更新于 2026-09-17
+
+

自动化测试

+

把日常联调的接口串成场景用例,一条龙验证业务流程。三种触发方式共用同一套用例模型:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
方式说明适合
手动运行用例编排好后点「运行」日常自测、回归
AI 生成模型按接口清单自动编排步骤与断言快速起盘、补断言思路
定时任务应用运行期间按间隔自动执行持续监控、冒烟
+

场景用例

+

从侧栏底部「自动化测试」进入。用例 = 有序步骤列表,每个步骤:

+
    +
  • 引用一个 HTTP 接口(从集合中选择,可跨集合、跨目录);
  • +
  • 断言:状态码 / 耗时 / Header / Body 四类目标,支持 等于、不等于、大于、小于、包含、存在 与 JSONPath 取值比较;
  • +
  • 变量提取:$.data.id → 环境变量 petId,后续步骤 URL / Body 用 {{petId}} 引用,实现「创建 → 查询 → 删除」链式传值;
  • +
  • 可单独禁用、上下移动、删除。
  • +
+

用例级选项「失败后继续」:默认失败即停(快速定位首个问题);打开后跑完全部步骤再看整体报告。

+

运行报告

+
    +
  • 统计卡:通过 / 失败步骤数、总耗时、断言数、通过率;
  • +
  • 步骤明细:方法 + URL + 状态码 + 耗时,逐条断言的期望 / 实际对照(可按 通过 / 失败 过滤);
  • +
  • 「再次运行」一键回归;「导出报告」生成 Markdown 存档或归档到缺陷单;
  • +
  • 每个用例保留最近 50 次运行记录,可下拉切换历史报告。
  • +
+

定时任务

+

用例头部的 ⏱ 按钮或左侧「定时任务」入口:

+
    +
  • 间隔可选 5 / 15 / 30 / 60 分钟、6 小时、每天;
  • +
  • 独立 启用 / 暂停 开关,显示下次运行时间与上次结果;
  • +
  • 应用保持运行时生效:OpsxAPI 窗口(或 Web 页面)开着才会按时触发并记录报告,关闭后自动暂停 —— 适合工作时段的持续监控,不能替代服务器侧的 CI。
  • +
+
+

提示:定时触发的请求同样走当前环境与 Mock 设置;跨环境回归前先在顶栏切换环境。

+
+

AI 生成用例

+

见 AI 助手。配置模型供应商后,「AI 生成」会读取集合的 HTTP 接口清单(方法、URL、Body 示例),按业务依赖编排步骤、断言与变量提取,生成前可附加一句要求(如「重点覆盖登录态与分页」),预览确认后保存。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/websocket/index.html b/homepage/dist/docs/websocket/index.html new file mode 100644 index 0000000..cc7834f --- /dev/null +++ b/homepage/dist/docs/websocket/index.html @@ -0,0 +1,211 @@ + + + + + +WebSocket · OpsxAPI 文档 + + + + + + + +
+
+ + + + OpsxAPI 文档 + + v1.0 + + +
+
+ +
+ + +
+ +

WebSocket

+
更新于 2026-09-17
+
+

连接

+
    +
  1. 填写 ws:// 或 wss:// 地址。
  2. +
  3. 点击 连接;状态点变绿(已连接)后即可收发消息。
  4. +
  5. 再次点击按钮即断开。
  6. +
+

消息收发

+
    +
  • 消息日志:接收(绿)/ 发送(蓝)/ 系统(灰)/ 错误(红)分色展示,顶部统计 ↑↓ 条数与连接时长。
  • +
  • 发送框:支持 JSON / 纯文本;⌘/Ctrl + Enter 快速发送;「格式化 JSON」一键美化。
  • +
+

子协议

+

「握手配置」标签中的子协议填逗号分隔列表,例如:

+
graphql-transport-ws, v1.json
+
+

自定义握手 Header(隧道模式)

+

浏览器原生 WebSocket 不能携带自定义 Header(如 Authorization、X-API-Key)。OpsxAPI 的处理方式:

+
    +
  1. 「握手配置」中填写 Header 后,工具自动改走本地 Gin 隧道: +
      +
    • 浏览器 → Gin /v1/proxy/ws/attach(普通 WS)
    • +
    • Gin → 目标服务器(携带你填的全部 Header)
    • +
    +
  2. +
  3. 不填 Header 时直连目标,零额外开销。
  4. +
+
+

注意:隧道要求本地 Gin 服务(:8787)在运行,即用 ./run.sh web / gui 启动的默认形态。

+
+

调试技巧

+
    +
  • 消息过多时点「清空」;日志上限 500 条,超出自动滚动淘汰。
  • +
  • 把常用报文保存在「说明」里,或为不同报文建多个 WS 请求节点。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/index.html b/homepage/dist/index.html new file mode 100644 index 0000000..87d473f --- /dev/null +++ b/homepage/dist/index.html @@ -0,0 +1,357 @@ + + + + + +OpsxAPI — 本地优先的全协议接口工作台 + + + + + + + + + + + + +
+
+
+
v0.1 公测 · 数据 100% 本地
+

一个工作台,
调完六种协议的接口

+

+ HTTP · GraphQL · WebSocket · SSE · Socket.IO · MQTT。
+ 集合管理、多环境变量、全格式导入导出、代码生成、内置文档站 —— 运维与开发的自托管接口利器。 +

+ +
+ 本地优先自定义 WS 握手头SSE 断点续传本机 Mock 服务 +
+
+ + + +
+
+ + +
+
+

为什么团队选择 OpsxAPI

+

不追赶云端协作的花活,专注把「调试接口」这件事做到极致。

+
+
+
+

本地优先,数据主权

+

集合、环境、历史全部保存在本机,不经过任何第三方服务器。内网、涉密项目放心用。

+
+
+
+

六协议一个窗口

+

HTTP / GraphQL / WebSocket / SSE / Socket.IO / MQTT 统一工作台,实时消息分色日志。

+
+
+
+

浏览器也能带握手头

+

内置 WebSocket 隧道与流式代理,突破浏览器 CORS 与 Header 限制,调试网关级接口。

+
+
+
+

生态互通

+

Apifox / Postman / Swagger / cURL / HAR 一键导入导出,迁移零成本,文档即代码。

+
+
+
+
+ + +
+
+

开箱即用的专业能力

+

从单人调试到团队交付,该有的都有。

+
+

集合与多标签

目录树、搜索、右键菜单、拖拽移动;多标签并行调试。

+

多环境变量

{{baseUrl}} 全局替换,正式 / 测试 / 本地一键切换。

+

鉴权管理

Bearer / Basic / API Key,token 走变量,一处配置全局生效。

+

实时协议调试

WS 握手头、SSE 断点续传、Socket.IO 事件收发、MQTT 通配符订阅。

+

代码生成

任意请求一键生成 cURL / fetch / Python / Go,直接进脚本与 CI。

+

内置文档站

随服务自带 /docs 用户文档与 Markdown 接口文档导出,交付即完整。

+
+
+
+ + +
+
+

六种协议,全覆盖

+

每个协议都有为它定制的编辑器,而不是塞进同一个表单。

+
+

HTTP / REST

7 种方法 · 6 种请求体 · 响应 Pretty 高亮 · 历史回跳

+

GraphQL

Query + Variables 编辑 · errors 高亮 · 生成 cURL 报文

+

WebSocket

自定义握手 Header(本地隧道)· 子协议 · 分色消息日志

+

SSE

直连失败自动切代理 · Last-Event-ID 续传 · 事件按名称归类

+

Socket.IO

事件监听(onAny)· emit 参数 JSON · path / auth 配置

+

MQTT

wss Broker · 通配符订阅 · QoS 0/1/2 · 断线自动重连

+
+
+
+ + +
+
+

导入导出,迁移零成本

+

粘贴、文件、URL 三种来源,格式自动识别。

+
+ OpenAPI 3.0 / 3.1Swagger 2.0ApifoxPostman v2.1 + ApipostcURLHARInsomniaHoppscotchMarkdown + YApi / Apidoc / Apizza / Eolink ① +
+

① 经 OpenAPI / Postman 格式中转导入。导入自动:tag 建目录、路径参数转变量、schema 生成示例体、security 映射鉴权。

+
+
导入
──→
OpsxAPI
──→
+
OpenAPI / Postman
Markdown 文档
代码生成
全量备份
+
+
+
+ + +
+
+

与主流工具的对比

+

价格为各官网公开标价(2026-09 整理),以官方为准。

+
+ + + + + + + + + + + + +
能力OpsxAPIApifoxApipost
入门付费价格¥99/年(个人)¥99/人/年②免费 + 商业版
专业档价格¥99/人/年(团队)¥199/人/年按席位订阅
数据存储位置100% 本地云端 / 私有化云端 / 私有化
调试协议HTTP · GraphQL · WS · SSE · Socket.IO · MQTTHTTP · WS · GraphQLHTTP · WS · gRPC 等
WS 自定义握手 Header(Web)✓ 内置隧道桌面端支持桌面端支持
自托管部署单二进制 + 静态页私有化付费私有化付费
私有化 / 买断参考价¥8,000/年起 · ¥30,000 买断询价询价
内置用户文档站✓ /docs——
+
+

② Apifox 免费版即含大部分调试能力,付费档面向团队协作;对比仅帮助按需选型,各有所长。

+
+
+ + +
+
+

简单透明的定价

+

先在工作台免费用起来,需要授权与服务时再付费。

+
+
+
个人版
+
¥99/ 年
+
单设备授权 · 全功能
+
    +
  • ✓ 六种协议全部调试能力
  • +
  • ✓ 集合 / 环境 / 历史无限量
  • +
  • ✓ 全格式导入导出 + 代码生成
  • +
  • ✓ 桌面端单机全功能
  • +
  • ✓ 1 年免费升级
  • +
+ 购买咨询 +
+ +
+
私有化 · 单法人不限席位
+
企业私有化版
+
¥8,000/ 年 · 标价
+
或 ¥30,000 一次性永久买断(标价)
+
    +
  • ✓ 整机 / 内网部署,数据不出企业
  • +
  • ✓ 不限席位,团队版全部能力
  • +
  • ✓ 远程部署协助 + 专属支持
  • +
  • ✓ 定制开发通道(另行报价)
  • +
  • ✓ 买断可选:永久使用 + 1 年升级
  • +
+ 获取报价 +
+ 标价透明,成交灵活:经早鸟 / 教育 / 多年预付 / 案例合作,常见成交区间 ¥5,000–8,000/年、买断 ¥15,000–30,000。 +
+
+
+ + +

早鸟与让利计划 —— 把优惠变成共同成长

+
+
+

早鸟创始价

+

前 20 个付费席位享 5-7 折永久优惠,并进入创始客户名单,参与需求优先排期。

+
+
+

教育 / 开源

+

高校师生、开源维护者凭证享 6-8 折。教育用途可申请批量授权。

+
+
+

多年预付

+

一次预付 2 年 9 折、3 年 8 折,锁定当期价格,改善双方现金流。

+
+
+

案例换授权

+

愿意公开使用案例、撰写评测或作为推荐客户的,可获 额外折扣或免费席位。

+
+
+

以上为官网标价机制;最终成交价支持按规模与场景商务沟通,多年预付 / 服务范围(部署协助、定制开发)可组合。

+
+
+ + +
+
+

购买常见问题

+
+
授权如何交付?包含哪些内容?

邮件交付授权码与部署包(单二进制 + Web 静态资源),含使用文档。团队版附内网部署指南。

+
一年后不续费还能用吗?

可以。授权期内下载的版本可 永久使用,续费获得后续升级与支持。

+
团队版怎么计费?人员变动怎么办?

按启用席位每年计费,5 席起。人员变动可在授权期内置换席位,无需额外费用。

+
可以开发票吗?

支持增值税普通发票与专票,对公转账或线上支付均可。

+
我们能自己部署吗?安全吗?

完全可以,这正是 OpsxAPI 的设计初衷:数据 100% 本地,服务仅监听本机回环,内网部署无外联。

+
可以永久买断吗?

可以。企业私有化版支持一次性买断(标价 ¥30,000,含 1 年免费升级与支持),买断版本永久使用,续费仅用于继续获得升级。订阅档同理:授权期内下载的版本永久可用。

+
预算有限,有优惠空间吗?

我们不直接降价,但提供四种「让利换增长」机制:早鸟创始价(前 20 席 5–7 折永久)、教育 / 开源 6–8 折、多年预付 8–9 折、以案例 / 评测换折扣。相比按年订阅的 SaaS,5 人以上团队通常 1–2 年即可回本;可自行部署(我们提供文档)或以案例分享换取创始价。

+
先试用再决定可以吗?

欢迎。工作台全部调试能力可直接体验;授权版差异主要在商业支持与升级服务。

+
+
+
+ + +
+
+

把接口调试收回自己手里

+

按快速上手启动工作台,30 秒发出第一个请求;采购事宜邮件联系,当天回复。

+ +
+
+ + + + + + diff --git a/homepage/dist/site/assets/site.css b/homepage/dist/site/assets/site.css new file mode 100644 index 0000000..6035df1 --- /dev/null +++ b/homepage/dist/site/assets/site.css @@ -0,0 +1,282 @@ +/* OpsxAPI 官网 —— 营销单页样式 */ +:root { + --blue: #2563eb; + --blue-dark: #1d4ed8; + --blue-soft: rgba(37, 99, 235, 0.08); + --bg: #ffffff; + --bg-alt: #f6f8fc; + --border: #e4e9f1; + --text: #111827; + --text-2: #5b6880; + --text-3: #98a2b3; + --green: #059669; + --amber: #d97706; + --radius: 14px; + --shadow: 0 1px 3px rgba(16,24,40,.06), 0 12px 32px rgba(16,24,40,.07); + --mono: "JetBrains Mono", SFMono-Regular, Menlo, monospace; +} +* { box-sizing: border-box; scroll-behavior: smooth; } +body { + margin: 0; font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; + color: var(--text); background: var(--bg); font-size: 15px; line-height: 1.75; +} +a { color: var(--blue); text-decoration: none; } +h1,h2,h3 { letter-spacing: -0.015em; } +section[id] { scroll-margin-top: 76px; } +.wrap { max-width: 1120px; margin: 0 auto; padding: 0 24px; } +.wrap.narrow { max-width: 820px; } +/* ---------- SVG 图标(lucide sprite) ---------- */ +.i { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -2px; } +.i-lg { width: 28px; height: 28px; vertical-align: middle; } +code { font-family: var(--mono); font-size: 13px; background: var(--blue-soft); color: var(--blue-dark); border-radius: 5px; padding: 1px 6px; } + +/* ---------- 按钮 ---------- */ +.btn { + display: inline-flex; align-items: center; justify-content: center; gap: 6px; + border-radius: 10px; padding: 9px 20px; font-size: 14.5px; font-weight: 600; cursor: pointer; + transition: all .18s; border: 1px solid transparent; white-space: nowrap; +} +.btn-lg { padding: 12px 26px; font-size: 15.5px; } +.btn-primary { background: var(--blue); color: #fff !important; box-shadow: 0 6px 18px rgba(37,99,235,.28); } +.btn-primary:hover { background: var(--blue-dark); transform: translateY(-1px); } +.btn-ghost { border-color: var(--border); color: var(--text) !important; background: #fff; } +.btn-ghost:hover { border-color: var(--blue); color: var(--blue) !important; } +.btn-inverse { background: #fff; color: var(--blue) !important; } +.btn-inverse:hover { transform: translateY(-1px); } +.btn-outline { border-color: rgba(255,255,255,.5); color: #fff !important; } +.btn-outline:hover { border-color: #fff; background: rgba(255,255,255,.1); } + +/* ---------- 导航 ---------- */ +.nav { + position: sticky; top: 0; z-index: 50; background: rgba(255,255,255,.9); + backdrop-filter: blur(10px); border-bottom: 1px solid var(--border); +} +.nav-inner { max-width: 1120px; margin: 0 auto; padding: 0 24px; height: 60px; display: flex; align-items: center; gap: 28px; } +.brand { display: flex; align-items: center; gap: 9px; } +.brand-logo { display: inline-flex; } +.brand-logo svg { display: block; border-radius: 8px; } +.brand-name { font-size: 17px; font-weight: 800; color: var(--text) !important; } +.nav-links { display: flex; gap: 22px; } +.nav-links a { font-size: 14px; font-weight: 500; color: var(--text-2) !important; } +.nav-links a:hover { color: var(--blue) !important; } +.nav-cta { margin-left: auto; } + +/* ---------- Hero ---------- */ +.hero { + position: relative; overflow: hidden; + background: + radial-gradient(1200px 500px at 85% -10%, rgba(37,99,235,.14), transparent 60%), + radial-gradient(800px 400px at -10% 10%, rgba(5,150,105,.08), transparent 55%), + linear-gradient(180deg, #f8faff 0%, #fff 100%); + border-bottom: 1px solid var(--border); +} +.hero-inner { + max-width: 1120px; margin: 0 auto; padding: 72px 24px 64px; + display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: 48px; align-items: center; +} +.hero-badge { + display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 600; color: var(--blue-dark); + background: #fff; border: 1px solid rgba(37,99,235,.25); border-radius: 999px; padding: 4px 14px; + box-shadow: 0 2px 8px rgba(37,99,235,.1); margin-bottom: 18px; +} +.hero h1 { font-size: 44px; line-height: 1.22; font-weight: 800; margin: 0 0 16px; } +.hero h1 em { font-style: normal; color: var(--blue); } +.hero-sub { color: var(--text-2); font-size: 16px; margin: 0 0 26px; } +.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; } +.hero-actions.center { justify-content: center; } +.hero-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; } +.hero-pills span { + font-size: 12px; color: var(--text-2); background: #fff; border: 1px solid var(--border); + padding: 3px 12px; border-radius: 999px; +} + +/* ---------- Mock 界面 ---------- */ +.mock { + border-radius: 14px; overflow: hidden; box-shadow: var(--shadow); border: 1px solid #1e2b45; + background: #0d1526; transform: perspective(1400px) rotateY(-4deg) rotateX(1.5deg); +} +.mock-titlebar { + display: flex; align-items: center; gap: 7px; height: 34px; padding: 0 12px; + background: #101a30; border-bottom: 1px solid #1e2b45; +} +.mock-titlebar i { width: 11px; height: 11px; border-radius: 50%; background: #3a4a6b; } +.mock-titlebar i:nth-child(1) { background: #f87171; } .mock-titlebar i:nth-child(2) { background: #fbbf24; } .mock-titlebar i:nth-child(3) { background: #34d399; } +.mock-titlebar span { margin-left: 8px; color: #8b99b0; font-size: 11px; } +.mock-body { display: grid; grid-template-columns: 158px minmax(0,1fr); min-height: 320px; } +.mock-side { border-right: 1px solid #1e2b45; padding: 10px 8px; background: #0c1322; } +.mock-search { height: 22px; border-radius: 6px; background: #16213a; margin-bottom: 10px; } +.mock-group { color: #8b99b0; font-size: 11px; padding: 6px 6px 3px; } +.mock-item { display: flex; align-items: center; gap: 6px; color: #aab8d0; font-size: 11.5px; padding: 4px 6px; border-radius: 6px; } +.mock-item.active { background: rgba(37,99,235,.18); color: #93c5fd; } +.mi { width: 11px; height: 11px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; opacity: .8; } +.m-get { color: #34d399; font-style: normal; font-size: 9.5px; min-width: 30px; } +.m-post { color: #fbbf24; font-style: normal; font-size: 9.5px; min-width: 30px; } +.mock-main { padding: 10px 12px; display: flex; flex-direction: column; gap: 9px; } +.mock-urlbar { display: flex; align-items: center; gap: 8px; } +.mock-url { + flex: 1; background: #0a1120; border: 1px solid #22304f; border-radius: 7px; color: #cbd5e1; + font-family: var(--mono); font-size: 11px; padding: 6px 10px; +} +.mock-send { + background: var(--blue); color: #fff; font-size: 11px; font-weight: 600; + border-radius: 7px; padding: 6px 14px; +} +.mock-req, .mock-resp { border: 1px solid #1e2b45; border-radius: 9px; padding: 8px 10px; background: #0c1322; } +.mock-req .tab, .mock-resp .tab { color: #5c6a83; font-size: 10.5px; margin-right: 12px; } +.mock-req .tab.on { color: #93c5fd; border-bottom: 2px solid var(--blue); padding-bottom: 2px; } +.mock-resp .tab.on { color: #6ee7b7; border-bottom: 2px solid var(--green); padding-bottom: 2px; } +.mock-status { float: right; color: #34d399; font-size: 10px; font-family: var(--mono); } +.mock pre { + margin: 8px 0 2px; font-family: var(--mono); font-size: 11px; line-height: 1.6; color: #cbd5e1; + white-space: pre-wrap; +} +.mock pre i { font-style: normal; color: #7dd3fc; } +.mock pre u { text-decoration: none; color: #86efac; } + +/* ---------- 通用 Section ---------- */ +.section { padding: 72px 0; } +.section.alt { background: var(--bg-alt); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); } +.sec-title { font-size: 30px; font-weight: 800; text-align: center; margin: 0 0 8px; } +.sec-sub { text-align: center; color: var(--text-2); margin: 0 0 40px; } +.grid { display: grid; gap: 18px; } +.g3 { grid-template-columns: repeat(3, minmax(0,1fr)); } +.g4 { grid-template-columns: repeat(4, minmax(0,1fr)); } + +/* ---------- 卡片 ---------- */ +.card { + background: #fff; border: 1px solid var(--border); border-radius: var(--radius); + padding: 22px; box-shadow: 0 1px 2px rgba(16,24,40,.04); transition: all .18s; +} +.card:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: rgba(37,99,235,.35); } +.card h3 { font-size: 16px; margin: 0 0 6px; } +.card p { color: var(--text-2); font-size: 13.5px; margin: 0; } +.card-icon { color: var(--blue); margin-bottom: 10px; } +.card-icon .i-lg { width: 30px; height: 30px; } +.card.row { display: flex; gap: 14px; align-items: flex-start; } +.card.row .card-icon { margin: 2px 0 0; } +.card.mini h3 { font-size: 15px; display: flex; align-items: center; gap: 8px; } +.card.mini h3 .i-lg { width: 20px; height: 20px; color: var(--blue); } +.card.mini p { font-size: 13px; } + +/* ---------- 协议 ---------- */ +.proto { + background: #fff; border: 1px solid var(--border); border-left: 3px solid var(--blue); + border-radius: 12px; padding: 18px 20px; +} +.proto h3 { margin: 0 0 6px; font-size: 15.5px; display: flex; align-items: center; gap: 8px; } +.proto h3 .i { color: var(--blue); width: 17px; height: 17px; } +.proto p { margin: 0; color: var(--text-2); font-size: 13.5px; } + +/* ---------- 导入导出 ---------- */ +.badges { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-bottom: 18px; } +.badges span { + background: #fff; border: 1px solid var(--border); border-radius: 999px; + padding: 6px 16px; font-size: 13px; font-weight: 500; color: var(--text); +} +.badges span.more { border-style: dashed; color: var(--text-2); } +.footnote { text-align: center; color: var(--text-3); font-size: 12.5px; margin: 10px 0 0; } +.exchange-actions { display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap; margin-top: 26px; } +.chip { + display: inline-flex; align-items: center; gap: 6px; + background: #fff; border: 1px solid var(--border); border-radius: 10px; padding: 8px 16px; + font-size: 13px; font-weight: 600; color: var(--text-2); +} +.chip.big { background: var(--blue); border-color: var(--blue); color: #fff; padding: 10px 22px; } +.exchange-arrow { color: var(--text-3); font-size: 15px; } + +/* ---------- 对比表 ---------- */ +.table-wrap { overflow-x: auto; } +.cmp { border-collapse: collapse; width: 100%; background: #fff; border-radius: 12px; overflow: hidden; box-shadow: 0 0 0 1px var(--border); font-size: 14px; } +.cmp th, .cmp td { padding: 12px 16px; text-align: left; border-bottom: 1px solid var(--border); } +.cmp th { background: #f9fbfe; font-size: 13.5px; } +.cmp tr:last-child td { border-bottom: none; } +.cmp td.hl { background: rgba(37,99,235,.05); color: var(--blue-dark); } +.cmp th.hl { background: var(--blue); color: #fff; } + +/* ---------- 定价 ---------- */ +.pricing { display: grid; grid-template-columns: repeat(2, minmax(0, 380px)); gap: 22px; justify-content: center; } +.pricing.three { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 1080px; margin: 0 auto; } +.price-card { + position: relative; background: #fff; border: 1px solid var(--border); border-radius: 16px; + padding: 30px 28px 26px; box-shadow: 0 1px 2px rgba(16,24,40,.04); display: flex; flex-direction: column; +} +.price-card.featured { border: 2px solid var(--blue); box-shadow: 0 12px 36px rgba(37,99,235,.16); } +.price-card.enterprise { + background: linear-gradient(160deg, #101a30 0%, #0d1526 70%); + border: 1px solid #2a3b5e; box-shadow: 0 14px 40px rgba(13,21,38,.4); +} +.price-card.enterprise .plan { color: #8b99b0; } +.price-card.enterprise .price b { color: #fff; font-size: 36px; } +.price-card.enterprise .price span { color: #8b99b0; } +.price-card.enterprise .plan-sub { color: #8b99b0; } +.price-card.enterprise li { color: #aab8d0; border-bottom-color: #22304f; } +.price-card.enterprise .deal-note { + margin-top: 14px; font-size: 11.5px; line-height: 1.7; color: #8b99b0; + background: rgba(255,255,255,.05); border: 1px dashed #2a3b5e; border-radius: 9px; padding: 9px 12px; +} +.price-card.enterprise .deal-note b { color: #93c5fd; } +.btn-dark { background: #fff; color: #0d1526 !important; } +.btn-dark:hover { transform: translateY(-1px); background: #e8eefc; } +.plan-tag { + position: absolute; top: -13px; left: 50%; transform: translateX(-50%); + background: var(--blue); color: #fff; font-size: 12px; font-weight: 700; + padding: 3px 14px; border-radius: 999px; white-space: nowrap; +} +.plan-tag.dark { background: #0d1526; border: 1px solid #2a3b5e; } +.plan { font-size: 16px; font-weight: 700; color: var(--text-2); } +.price { margin: 8px 0 2px; } +.price b { font-size: 44px; font-weight: 800; letter-spacing: -.02em; color: var(--text); } +.price span { color: var(--text-3); font-size: 14px; margin-left: 4px; } +.plan-sub { color: var(--text-3); font-size: 13px; margin-bottom: 18px; } +.price-card ul { list-style: none; padding: 0; margin: 0 0 22px; flex: 1; } +.price-card li { font-size: 13.5px; color: var(--text-2); padding: 6px 0; border-bottom: 1px dashed var(--border); } +.price-card li:last-child { border-bottom: none; } +.price-card .btn { width: 100%; } +.growth-title { text-align: center; font-size: 20px; font-weight: 700; margin: 52px 0 22px; } + +/* ---------- FAQ ---------- */ +.faq details { + background: #fff; border: 1px solid var(--border); border-radius: 12px; + padding: 16px 20px; margin-bottom: 12px; +} +.faq summary { font-weight: 600; cursor: pointer; font-size: 15px; list-style: none; display: flex; justify-content: space-between; } +.faq summary::after { content: "+"; color: var(--text-3); font-weight: 400; } +.faq details[open] summary::after { content: "-"; } +.faq details p { margin: 10px 0 0; color: var(--text-2); font-size: 14px; } + +/* ---------- CTA ---------- */ +.cta { + background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 55%, #3b82f6 100%); + color: #fff; text-align: center; padding: 72px 24px; +} +.cta h2 { font-size: 32px; font-weight: 800; margin: 0 0 10px; } +.cta p { color: rgba(255,255,255,.85); margin: 0 0 28px; } + +/* ---------- Footer ---------- */ +.footer { background: #0d1526; color: #8b99b0; padding: 52px 0 0; font-size: 13.5px; } +.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 32px; padding-bottom: 36px; } +.footer .brand-name { color: #fff !important; } +.footer .f-logo { display: block; border-radius: 8px; } +.footer .brand { display: flex; align-items: center; gap: 9px; } +.footer-desc { margin: 12px 0 0; font-size: 13px; line-height: 1.8; } +.footer h4 { color: #fff; font-size: 13.5px; margin: 4px 0 12px; } +.footer a { display: block; color: #8b99b0 !important; padding: 4px 0; font-size: 13px; } +.footer a:hover { color: #fff !important; } +.footer-bar { border-top: 1px solid #1e2b45; text-align: center; padding: 18px; font-size: 12px; color: #5c6a83; } + +/* ---------- 响应式 ---------- */ +@media (max-width: 1020px) { + .hero-inner { grid-template-columns: 1fr; padding-top: 52px; } + .mock { transform: none; } + .g4 { grid-template-columns: repeat(2, minmax(0,1fr)); } + .g3 { grid-template-columns: repeat(2, minmax(0,1fr)); } + .pricing, .pricing.three { grid-template-columns: minmax(0, 420px); } + .footer-grid { grid-template-columns: repeat(2, 1fr); } +} +@media (max-width: 680px) { + .nav-links { display: none; } + .hero h1 { font-size: 32px; } + .sec-title { font-size: 24px; } + .g3, .g4 { grid-template-columns: 1fr; } + .footer-grid { grid-template-columns: 1fr; } +} diff --git a/homepage/dist/terms.html b/homepage/dist/terms.html new file mode 100644 index 0000000..cedc58d --- /dev/null +++ b/homepage/dist/terms.html @@ -0,0 +1,77 @@ + + + + + + 服务条款 · OpsxAPI + + + + + + +
+ ← 返回官网 +

服务条款

+
最近更新:2026 年 9 月 17 日 · 生效范围:OpsxAPI 本地服务(含官网 /docs、/home、/mock 及 /api)
+ +

一、服务说明

+

OpsxAPI 是运行在你本机的接口调试与 Mock 服务。官网(/home)、文档(/docs)、账号与云端空间(/api)及本地 Mock 服务(/mock)默认仅监听 127.0.0.1,供个人与团队内部开发联调使用。

+ +

二、账号与安全

+ + +

三、频率限制

+

为保障本地服务稳定,Mock 接口(/mock)实施以下默认限流,超限返回 HTTP 429 与 Retry-After:

+ + + + + +
类别阈值超出行为
通用 API 请求频率60 QPM(每分钟 60 次)或 20 QPS(每秒 20 次)返回 429 错误
单空间 Mock 接口数200 个发布请求被拒绝(400)
云端空间数据体积20 MB保存请求被拒绝(413)
+ +

四、禁止滥用

+
+

若账户或使用行为存在「未经授权或滥用」情形,平台有权采取限流、暂停服务等措施。通过技术手段规避限流(如频繁更换来源地址、伪造标识等)本身即属于违规行为。

+
+ + +

五、数据与隐私

+ + +

六、免责声明

+

本软件按「现状」提供,不承诺适销性或特定用途适用性。因不可抗力、系统维护或依本条款采取措施导致的服务中断,不视为违约。在法律允许范围内,对间接损失不承担赔偿责任。

+ +

七、条款变更

+

我们可能随版本更新修订本条款,修订后在官网公示并更新日期;继续使用即视为接受修订后的条款。

+ +

如有疑问,请通过官网页脚的联系方式反馈。

+
+ +