diff --git a/.gitignore b/.gitignore index d4bbf26..065ac91 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,7 @@ logs/ .*.pid apps/server/bin/ *.tsbuildinfo + +# UI review / acceptance screenshots (local only) +.ui-review/ +.ui-review-*/ diff --git a/.ui-review-icon/icon-big.png b/.ui-review-icon/icon-big.png deleted file mode 100644 index 5028faf..0000000 Binary files a/.ui-review-icon/icon-big.png and /dev/null differ diff --git a/.ui-review-icon2/128.png b/.ui-review-icon2/128.png deleted file mode 100644 index 05d6904..0000000 Binary files a/.ui-review-icon2/128.png and /dev/null differ diff --git a/.ui-review-icon2/64.png b/.ui-review-icon2/64.png deleted file mode 100644 index b8b4794..0000000 Binary files a/.ui-review-icon2/64.png and /dev/null differ diff --git a/.ui-review-icon2/app-128.png b/.ui-review-icon2/app-128.png deleted file mode 100644 index c07dd4d..0000000 Binary files a/.ui-review-icon2/app-128.png and /dev/null differ diff --git a/.ui-review-layout/01-home.png b/.ui-review-layout/01-home.png deleted file mode 100644 index fd463b6..0000000 Binary files a/.ui-review-layout/01-home.png and /dev/null differ diff --git a/.ui-review-layout/02-http.png b/.ui-review-layout/02-http.png deleted file mode 100644 index 5028906..0000000 Binary files a/.ui-review-layout/02-http.png and /dev/null differ diff --git a/.ui-review-layout/03-mock.png b/.ui-review-layout/03-mock.png deleted file mode 100644 index 69b66a9..0000000 Binary files a/.ui-review-layout/03-mock.png and /dev/null differ diff --git a/.ui-review-layout/probe.json b/.ui-review-layout/probe.json deleted file mode 100644 index 0d8cd6a..0000000 --- a/.ui-review-layout/probe.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "home": { - "text": "OpsxAPI\n新建\n导入\n导出\n通道\n自动\nWeb 代理\n浏览器直连\n桌面直连\n本\n本地\n1 变量\n本\n接口\n历史\n测试\nMock\n文档\n设置\n登录\n接口\n历史\n示例集合\nHTTP · 本地回归(P0)\nGET\n回归 · GET Query\nPOST\n回归 · POST JSON\nPOST\n回归 · POST urlencoded\nPOST\n回归 · POST form-data\nGET\n回归 · 自定义 Header\nGET\n回归 · Cookie\nGET\n回归 · Bearer\nGET\n回归 · Basic Auth\nHTTP · httpbin\nGET\n获取请求回显\nPOST\n提交 JSON\nPOST\n表单提交\nGET\nBearer 鉴权示例\nGET\n状态码 · 404\nGraphQL\n国家查询 · countries\n实时协议\nWebSocket · echo\nSSE · 维基媒体变更流\nMQTT · EMQX 公共 Broker\nSocket.IO · 本地服务\n没有打开的请求\nOpsxAPI · 接口工作台\n从左侧选择接口,或导入数据/新建请求\nHTTP · GraphQL · WebSocket · SSE · Socket.IO · MQTT\n支持 OpenAPI / Postman / Apifox / cURL / HAR 等格式导入导出", - "title": "OpsxAPI · 接口工作台" - }, - "mockProbe": { - "hasShareable": false, - "hasLocal": false, - "hasComing": false, - "snippet": "\nWeb 代理\n浏览器直连\n桌面直连\n本\n本地\n1 变量\n本\n接口\n历史\n测试\nMock\n文档\n设置\n登录\n接口\n历史\n示例集合\nHTTP · 本地回归(P0)\nHTTP · httpbin\nGET\n获取请求回显\nPOST\n提交 JSON\nPOST\n表单提交\nGET\nBearer 鉴权示例\nGET\n状态码 · 404\nGraphQL\n国家查询 · countries\n实时协议\nWebSocket · echo\nSSE · 维基媒体变更流\nMQTT · EMQX 公共 Brok" - }, - "layout": { - "top": { - "w": 1440, - "h": 48 - }, - "side": { - "w": 256, - "h": 765 - }, - "rail": { - "w": 34, - "h": 50 - }, - "main": { - "w": 1128, - "h": 765 - }, - "topBtns": 5, - "minFs": 8, - "bodyBg": "rgb(11, 18, 32)" - } -} \ No newline at end of file diff --git a/.ui-review-layout2/home.png b/.ui-review-layout2/home.png deleted file mode 100644 index 0df2fc7..0000000 Binary files a/.ui-review-layout2/home.png and /dev/null differ diff --git a/.ui-review/01-home.png b/.ui-review/01-home.png deleted file mode 100644 index 655ab39..0000000 Binary files a/.ui-review/01-home.png and /dev/null differ diff --git a/.ui-review/02-after-click.png b/.ui-review/02-after-click.png deleted file mode 100644 index 655ab39..0000000 Binary files a/.ui-review/02-after-click.png and /dev/null differ diff --git a/.ui-review/03-ws.png b/.ui-review/03-ws.png deleted file mode 100644 index 655ab39..0000000 Binary files a/.ui-review/03-ws.png and /dev/null differ diff --git a/.ui-review/04-http.png b/.ui-review/04-http.png deleted file mode 100644 index cd12242..0000000 Binary files a/.ui-review/04-http.png and /dev/null differ diff --git a/.ui-review/05-ws.png b/.ui-review/05-ws.png deleted file mode 100644 index cd12242..0000000 Binary files a/.ui-review/05-ws.png and /dev/null differ diff --git a/.ui-review/10-http.png b/.ui-review/10-http.png deleted file mode 100644 index bd7922a..0000000 Binary files a/.ui-review/10-http.png and /dev/null differ diff --git a/.ui-review/11-ws.png b/.ui-review/11-ws.png deleted file mode 100644 index bd7922a..0000000 Binary files a/.ui-review/11-ws.png and /dev/null differ diff --git a/.ui-review/20-http-sent.png b/.ui-review/20-http-sent.png deleted file mode 100644 index 927d9bd..0000000 Binary files a/.ui-review/20-http-sent.png and /dev/null differ diff --git a/.ui-review/21-ws.png b/.ui-review/21-ws.png deleted file mode 100644 index d2cef87..0000000 Binary files a/.ui-review/21-ws.png and /dev/null differ diff --git a/.ui-review/30-http.png b/.ui-review/30-http.png deleted file mode 100644 index 0cb18a2..0000000 Binary files a/.ui-review/30-http.png and /dev/null differ diff --git a/.ui-review/31-dirty.png b/.ui-review/31-dirty.png deleted file mode 100644 index 6be8d71..0000000 Binary files a/.ui-review/31-dirty.png and /dev/null differ diff --git a/.ui-review/32-ws.png b/.ui-review/32-ws.png deleted file mode 100644 index bf9336b..0000000 Binary files a/.ui-review/32-ws.png and /dev/null differ diff --git a/.ui-review/33-mock.png b/.ui-review/33-mock.png deleted file mode 100644 index 32150bd..0000000 Binary files a/.ui-review/33-mock.png and /dev/null differ diff --git a/.ui-review/40-home.png b/.ui-review/40-home.png deleted file mode 100644 index 2ed7344..0000000 Binary files a/.ui-review/40-home.png and /dev/null differ diff --git a/.ui-review/41-http.png b/.ui-review/41-http.png deleted file mode 100644 index 2567d32..0000000 Binary files a/.ui-review/41-http.png and /dev/null differ diff --git a/.ui-review/42-ws.png b/.ui-review/42-ws.png deleted file mode 100644 index 8e9c6c7..0000000 Binary files a/.ui-review/42-ws.png and /dev/null differ diff --git a/.ui-review/43-proxy-attempt.png b/.ui-review/43-proxy-attempt.png deleted file mode 100644 index 6879fbe..0000000 Binary files a/.ui-review/43-proxy-attempt.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/d3-retest-ws.png b/.ui-review/accept-2026-09-19/d3-retest-ws.png deleted file mode 100644 index 4c3b4e5..0000000 Binary files a/.ui-review/accept-2026-09-19/d3-retest-ws.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/desk-after-new.png b/.ui-review/accept-2026-09-19/desk-after-new.png deleted file mode 100644 index 98a3d88..0000000 Binary files a/.ui-review/accept-2026-09-19/desk-after-new.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/desk-menu.png b/.ui-review/accept-2026-09-19/desk-menu.png deleted file mode 100644 index 053fbe0..0000000 Binary files a/.ui-review/accept-2026-09-19/desk-menu.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/desk-win.png b/.ui-review/accept-2026-09-19/desk-win.png deleted file mode 100644 index d131262..0000000 Binary files a/.ui-review/accept-2026-09-19/desk-win.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/desktop-full.png b/.ui-review/accept-2026-09-19/desktop-full.png deleted file mode 100644 index 867805f..0000000 Binary files a/.ui-review/accept-2026-09-19/desktop-full.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-01-home.png b/.ui-review/accept-2026-09-19/web-01-home.png deleted file mode 100644 index 4fb0c7d..0000000 Binary files a/.ui-review/accept-2026-09-19/web-01-home.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-02-channel.png b/.ui-review/accept-2026-09-19/web-02-channel.png deleted file mode 100644 index 4fb0c7d..0000000 Binary files a/.ui-review/accept-2026-09-19/web-02-channel.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-03-env.png b/.ui-review/accept-2026-09-19/web-03-env.png deleted file mode 100644 index 2f535b1..0000000 Binary files a/.ui-review/accept-2026-09-19/web-03-env.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-04-tree.png b/.ui-review/accept-2026-09-19/web-04-tree.png deleted file mode 100644 index ac01af9..0000000 Binary files a/.ui-review/accept-2026-09-19/web-04-tree.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-05-dirty.png b/.ui-review/accept-2026-09-19/web-05-dirty.png deleted file mode 100644 index 028b3f4..0000000 Binary files a/.ui-review/accept-2026-09-19/web-05-dirty.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-06-new-menu.png b/.ui-review/accept-2026-09-19/web-06-new-menu.png deleted file mode 100644 index 9abe24b..0000000 Binary files a/.ui-review/accept-2026-09-19/web-06-new-menu.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-07-ws-editor.png b/.ui-review/accept-2026-09-19/web-07-ws-editor.png deleted file mode 100644 index 8a71cba..0000000 Binary files a/.ui-review/accept-2026-09-19/web-07-ws-editor.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-08-ws-filled.png b/.ui-review/accept-2026-09-19/web-08-ws-filled.png deleted file mode 100644 index 8672746..0000000 Binary files a/.ui-review/accept-2026-09-19/web-08-ws-filled.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-10-history.png b/.ui-review/accept-2026-09-19/web-10-history.png deleted file mode 100644 index ae4d443..0000000 Binary files a/.ui-review/accept-2026-09-19/web-10-history.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-11-replay.png b/.ui-review/accept-2026-09-19/web-11-replay.png deleted file mode 100644 index f62e4eb..0000000 Binary files a/.ui-review/accept-2026-09-19/web-11-replay.png and /dev/null differ diff --git a/.ui-review/accept-2026-09-19/web-reg-result.json b/.ui-review/accept-2026-09-19/web-reg-result.json deleted file mode 100644 index af523be..0000000 --- a/.ui-review/accept-2026-09-19/web-reg-result.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "verdict": "有缺陷", - "pass": [ - "通道切换往返: 自动|Web 代理|浏览器直连|桌面直连", - "打开环境变量面板", - "集合树切换到回归 GET", - "URL 脏点已写入", - "脏点/保存相关 UI 可见或已 Cmd+S", - "发送 HTTP 以产生历史", - "新建 WebSocket", - "填写 WS URL", - "填写 Authorization Header", - "连接后出现状态文案", - "重放 toast: 重放成功 · HTTP 200 · 22ms" - ], - "fail": [ - "WS流程: locator.click: Timeout 15000ms exceeded.\nCall log:\n - waiting for getByRole('button', { name: /发送/ }).first()\n - locator resolved to \n - attempting click action\n 2 × waiting for element to be visible, enabled and stable\n - element is not enabled\n - retrying click action\n - waiting 20ms\n 2 × waiting for element to be visible, enabled and stable\n - element is not enabled\n - retrying click action\n - waiting 100ms\n 28 × waiting for element to be visible, enabled and stable\n - element is not enabled\n - retrying click action\n - waiting 500ms\n" - ], - "notes": [ - "title=OpsxAPI · 接口工作台", - "selectCount=1", - "select0=自动/Web 代理/浏览器直连/桌面直连" - ] -} \ No newline at end of file diff --git a/.ui-review/accept-2026-09-19/web-reg.mjs b/.ui-review/accept-2026-09-19/web-reg.mjs deleted file mode 100644 index 765a6ec..0000000 --- a/.ui-review/accept-2026-09-19/web-reg.mjs +++ /dev/null @@ -1,255 +0,0 @@ -import { chromium } from 'playwright'; -import fs from 'fs'; -import path from 'path'; - -const outDir = path.resolve('.ui-review/accept-2026-09-19'); -const log = []; -const shot = async (page, name) => { - const p = path.join(outDir, name); - await page.screenshot({ path: p, fullPage: false }); - log.push(`shot:${name}`); -}; - -const result = { pass: [], fail: [], notes: [] }; - -async function main() { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); - page.setDefaultTimeout(12000); - await page.goto('http://127.0.0.1:5173/', { waitUntil: 'networkidle' }); - await shot(page, 'web-01-home.png'); - - // Channel switch - try { - const channel = page.getByRole('combobox').or(page.locator('select, [aria-label*="通道"], button:has-text("通道")')).first(); - // Top bar has 通道 popup - from AX it was AXPopUpButton 发信通道 - const pop = page.locator('text=通道').first(); - await pop.click({ timeout: 5000 }).catch(() => {}); - // Try select options visible - const modes = ['自动', 'Web代理', '浏览器', '桌面']; - let switched = false; - for (const m of modes) { - const opt = page.getByText(m, { exact: true }).first(); - if (await opt.isVisible().catch(() => false)) { - await opt.click(); - switched = true; - result.pass.push(`通道切换点击到「${m}」`); - break; - } - } - // Also try native select - const select = page.locator('select').filter({ hasText: /自动|代理|浏览器|桌面/ }).first(); - if (await select.count()) { - const options = await select.locator('option').allTextContents(); - result.notes.push('channel select options: ' + options.join('|')); - if (options.length > 1) { - await select.selectOption({ index: 1 }); - await select.selectOption({ index: 0 }); - switched = true; - result.pass.push('通道 select 往返切换'); - } - } - if (!switched) result.fail.push('通道切换:未找到可点选项'); - await shot(page, 'web-02-channel.png'); - } catch (e) { - result.fail.push('通道切换异常: ' + e.message); - } - - // Env switch - button 本地 1 变量 - try { - const envBtn = page.getByRole('button', { name: /变量|环境/ }).first(); - if (await envBtn.count()) { - await envBtn.click(); - result.pass.push('打开环境/变量'); - await page.keyboard.press('Escape').catch(() => {}); - } else { - result.fail.push('环境切换:未找到环境按钮'); - } - await shot(page, 'web-03-env.png'); - } catch (e) { - result.fail.push('环境: ' + e.message); - } - - // Collection tree - click an existing request - try { - const req = page.getByText('回归 · GET Query').first(); - await req.click({ timeout: 5000 }); - result.pass.push('集合树点击切换到「回归 · GET Query」'); - await shot(page, 'web-04-tree.png'); - } catch (e) { - result.fail.push('集合树点击: ' + e.message); - } - - // Dirty save - edit URL then look for save/dirty indicator - try { - const urlInput = page.locator('input').filter({ hasText: '' }).nth(0); - // Prefer visible URL field near method - const candidates = page.locator('input[value*="http"], input[placeholder*="http"], textarea, input'); - let edited = false; - const count = await candidates.count(); - for (let i = 0; i < Math.min(count, 30); i++) { - const el = candidates.nth(i); - const val = await el.inputValue().catch(() => ''); - if (val.includes('http') || val.includes('127.0.0.1') || val.includes('/v1/')) { - await el.click(); - await el.fill(val + (val.includes('?') ? '&' : '?') + '_dirty=1'); - edited = true; - result.pass.push('编辑 URL 制造脏点'); - break; - } - } - if (!edited) result.notes.push('未定位到 URL 输入框,跳过脏点编辑'); - // Try save shortcut or save button - await page.keyboard.press('Meta+s').catch(() => {}); - const saveBtn = page.getByRole('button', { name: /保存/ }).first(); - if (await saveBtn.isVisible().catch(() => false)) { - await saveBtn.click(); - result.pass.push('点击保存'); - } else { - result.notes.push('未见「保存」按钮(可能自动持久化)'); - } - await shot(page, 'web-05-dirty.png'); - } catch (e) { - result.fail.push('脏点保存: ' + e.message); - } - - // New WebSocket via 新建 menu - try { - await page.getByRole('button', { name: '新建' }).first().click(); - await page.waitForTimeout(400); - const wsItem = page.getByText(/WebSocket|WS/i).first(); - if (await wsItem.isVisible().catch(() => false)) { - await wsItem.click(); - result.pass.push('新建 WebSocket'); - } else { - // menu items - const items = await page.locator('[role="menu"] >> text=/WebSocket|websocket|WS/i').allTextContents().catch(() => []); - result.notes.push('新建菜单项: ' + JSON.stringify(items)); - result.fail.push('新建菜单未见 WebSocket'); - } - await shot(page, 'web-06-new-ws.png'); - } catch (e) { - result.fail.push('新建 WS: ' + e.message); - } - - // Fill WS url + header if editor present - try { - const urlBox = page.locator('input').filter({ hasNot: page.locator('[type=checkbox]') }); - // fill first empty-ish or wss field - let filledUrl = false; - const n = await page.locator('input').count(); - for (let i = 0; i < n; i++) { - const el = page.locator('input').nth(i); - const ph = (await el.getAttribute('placeholder').catch(() => '')) || ''; - const val = await el.inputValue().catch(() => ''); - if (/wss?|url|地址/i.test(ph) || val.startsWith('ws') || (val === '' && /url/i.test(ph))) { - await el.fill('wss://ws.postman-echo.com/raw'); - filledUrl = true; - break; - } - } - if (!filledUrl) { - // try active tab url field - often the long input - const longInputs = page.locator('input.ops-input, input[class*="input"]'); - if (await longInputs.count()) { - await longInputs.first().fill('wss://ws.postman-echo.com/raw'); - filledUrl = true; - } - } - if (filledUrl) result.pass.push('填写 WS URL'); - else result.fail.push('未能填写 WS URL'); - - // Headers tab - const hdrTab = page.getByRole('tab', { name: /Header|请求头|头/i }).or(page.getByText('Headers')).first(); - if (await hdrTab.isVisible().catch(() => false)) await hdrTab.click(); - // Add Authorization row - const addHdr = page.getByRole('button', { name: /添加|Add/ }).first(); - if (await addHdr.isVisible().catch(() => false)) await addHdr.click(); - // Fill key/value - best effort - await page.getByPlaceholder(/[Kk]ey|名称|Header/).first().fill('Authorization').catch(() => {}); - await page.getByPlaceholder(/[Vv]alue|值/).first().fill('Bearer smoke').catch(() => {}); - // fallback: any two empty inputs in header editor - result.notes.push('Header 填写尽力而为'); - await shot(page, 'web-07-ws-filled.png'); - - const connectBtn = page.getByRole('button', { name: /连接|Connect/ }).first(); - if (await connectBtn.isVisible().catch(() => false)) { - await connectBtn.click(); - await page.waitForTimeout(2500); - result.pass.push('点击连接'); - const bodyText = await page.locator('body').innerText(); - if (/open|已连接|连接成功|ping|tunnel|自定义 Header/i.test(bodyText)) { - result.pass.push('连接后 UI 出现成功/系统相关文案'); - } else { - result.notes.push('连接后未明确看到成功文案,需人工看截图'); - } - // try send - const sendBox = page.locator('textarea, input[placeholder*="消息"], input[placeholder*="发送"]').first(); - if (await sendBox.isVisible().catch(() => false)) { - await sendBox.fill('ping-gui-reg'); - const sendBtn = page.getByRole('button', { name: /发送|Send/ }).first(); - if (await sendBtn.isVisible().catch(() => false)) await sendBtn.click(); - await page.waitForTimeout(1500); - result.pass.push('尝试发送消息'); - } - } else { - result.fail.push('未见连接按钮'); - } - await shot(page, 'web-08-ws-connected.png'); - } catch (e) { - result.fail.push('WS 填表/连接: ' + e.message); - } - - // History replay toast - try { - await page.getByRole('button', { name: /历史/ }).first().click(); - await page.waitForTimeout(500); - await shot(page, 'web-09-history.png'); - const replay = page.getByRole('button', { name: /重放/ }).first(); - if (await replay.isVisible().catch(() => false)) { - await replay.click(); - await page.waitForTimeout(2000); - const toast = page.locator('.ops-toast, [class*="toast"]'); - const toastText = (await toast.allTextContents().catch(() => [])).join(' | '); - const body = await page.locator('body').innerText(); - if (/正在重放|重放成功|重放完成|重放失败|重放连接/i.test(toastText + body)) { - result.pass.push('历史重放出现 toast/文案: ' + (toastText || 'body匹配').slice(0, 120)); - } else { - result.fail.push('点了重放但未见 toast 文案'); - } - } else { - // hover history rows - const rows = page.locator('text=/GET|POST|WS|重放/'); - result.notes.push('历史面板打开;重放按钮可能需悬停'); - const hist = page.locator('.ops-tree-row, [class*="history"]'); - if (await hist.count()) { - await hist.first().hover(); - await page.waitForTimeout(300); - if (await page.getByRole('button', { name: /重放/ }).first().isVisible().catch(() => false)) { - await page.getByRole('button', { name: /重放/ }).first().click(); - await page.waitForTimeout(2000); - const body = await page.locator('body').innerText(); - if (/正在重放|重放成功|重放完成|重放失败|重放连接/i.test(body)) { - result.pass.push('悬停后重放 toast 文案可见'); - } else result.fail.push('悬停重放后未见 toast'); - } else result.fail.push('悬停后仍无重放按钮'); - } else result.fail.push('历史为空或结构不符'); - } - await shot(page, 'web-10-replay.png'); - } catch (e) { - result.fail.push('历史重放: ' + e.message); - } - - await browser.close(); - const summary = { - verdict: result.fail.length ? '有缺陷' : '通过', - ...result, - }; - fs.writeFileSync(path.join(outDir, 'web-reg-result.json'), JSON.stringify(summary, null, 2)); - console.log(JSON.stringify(summary, null, 2)); -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/.ui-review/accept-2026-09-19/web-reg2.mjs b/.ui-review/accept-2026-09-19/web-reg2.mjs deleted file mode 100644 index 6b2ee06..0000000 --- a/.ui-review/accept-2026-09-19/web-reg2.mjs +++ /dev/null @@ -1,275 +0,0 @@ -import { chromium } from 'playwright'; -import fs from 'fs'; -import path from 'path'; - -const outDir = path.resolve('.ui-review/accept-2026-09-19'); -const result = { pass: [], fail: [], notes: [] }; -const shot = async (page, name) => { - await page.screenshot({ path: path.join(outDir, name) }); -}; - -async function main() { - const browser = await chromium.launch({ - headless: true, - channel: 'chrome', - }); - const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); - page.setDefaultTimeout(15000); - await page.goto('http://127.0.0.1:5173/', { waitUntil: 'domcontentloaded' }); - await page.waitForTimeout(1500); - await shot(page, 'web-01-home.png'); - const title = await page.title(); - result.notes.push('title=' + title); - - // Channel: look for select near 通道 - try { - const selects = page.locator('select'); - const sc = await selects.count(); - result.notes.push('selectCount=' + sc); - let channelDone = false; - for (let i = 0; i < sc; i++) { - const sel = selects.nth(i); - const opts = await sel.locator('option').allTextContents(); - result.notes.push('select' + i + '=' + opts.join('/')); - if (opts.some((o) => /自动|代理|浏览器|桌面|Web|browser|tauri|auto/i.test(o))) { - const values = await sel.locator('option').evaluateAll((os) => os.map((o) => o.value)); - if (values.length > 1) { - await sel.selectOption(values[1]); - await page.waitForTimeout(300); - await sel.selectOption(values[0]); - result.pass.push('通道切换往返: ' + opts.join('|')); - channelDone = true; - break; - } - } - } - if (!channelDone) { - // click text 通道 then options - await page.getByText('通道', { exact: true }).first().click().catch(() => {}); - await page.waitForTimeout(300); - for (const m of ['Web 代理', 'Web代理', '浏览器', '桌面', '自动']) { - const o = page.getByText(m, { exact: true }); - if (await o.count()) { - await o.first().click(); - result.pass.push('通道点选 ' + m); - channelDone = true; - break; - } - } - } - if (!channelDone) result.fail.push('通道切换失败'); - await shot(page, 'web-02-channel.png'); - } catch (e) { - result.fail.push('通道: ' + e.message); - } - - // Env - try { - const envBtn = page.getByRole('button', { name: /变量/ }); - if (await envBtn.count()) { - await envBtn.first().click(); - await page.waitForTimeout(500); - result.pass.push('打开环境变量面板'); - await page.keyboard.press('Escape'); - } else result.fail.push('无环境变量按钮'); - await shot(page, 'web-03-env.png'); - } catch (e) { - result.fail.push('环境: ' + e.message); - } - - // Tree - try { - await page.getByText('回归 · GET Query').first().click({ timeout: 8000 }); - result.pass.push('集合树切换到回归 GET'); - await page.waitForTimeout(500); - await shot(page, 'web-04-tree.png'); - } catch (e) { - result.fail.push('集合树: ' + e.message); - } - - // Dirty - try { - let edited = false; - const inputs = page.locator('input'); - const n = await inputs.count(); - for (let i = 0; i < n; i++) { - const el = inputs.nth(i); - const val = await el.inputValue().catch(() => ''); - if (/https?:|127\.0\.0\.1|\/v1\//.test(val)) { - await el.fill(val.replace(/([?&]_dirty=1)/g, '') + (val.includes('?') ? '&' : '?') + '_dirty=1'); - edited = true; - result.pass.push('URL 脏点已写入'); - break; - } - } - if (!edited) result.fail.push('未找到可编辑 URL'); - // look for dirty marker / save - await page.keyboard.press('Meta+s'); - await page.waitForTimeout(400); - const body = await page.locator('body').innerText(); - if (/未保存|脏|dirty|\*/i.test(body) || (await page.getByRole('button', { name: /保存/ }).count())) { - result.pass.push('脏点/保存相关 UI 可见或已 Cmd+S'); - } else { - result.notes.push('可能自动持久化,未见显式脏标记'); - } - await shot(page, 'web-05-dirty.png'); - } catch (e) { - result.fail.push('脏点: ' + e.message); - } - - // First send HTTP to create history - try { - const send = page.getByRole('button', { name: /发送/ }).first(); - if (await send.count()) { - await send.click(); - await page.waitForTimeout(2000); - result.pass.push('发送 HTTP 以产生历史'); - } - } catch (e) { - result.notes.push('发送: ' + e.message); - } - - // New WS - try { - await page.getByRole('button', { name: '新建' }).first().click(); - await page.waitForTimeout(500); - await shot(page, 'web-06-new-menu.png'); - const cand = page.locator('text=/WebSocket|Websocket|WS/i'); - if (await cand.count()) { - await cand.first().click(); - result.pass.push('新建 WebSocket'); - } else { - result.fail.push('新建菜单无 WebSocket: ' + (await page.locator('body').innerText()).slice(0, 200)); - } - await page.waitForTimeout(600); - await shot(page, 'web-07-ws-editor.png'); - } catch (e) { - result.fail.push('新建WS: ' + e.message); - } - - // Fill WS - try { - // URL field - const inputs = page.locator('input'); - let ok = false; - for (let i = 0; i < await inputs.count(); i++) { - const el = inputs.nth(i); - const ph = ((await el.getAttribute('placeholder')) || '') + (await el.getAttribute('aria-label') || ''); - const val = await el.inputValue().catch(() => ''); - if (/ws|url|地址|主机/i.test(ph + val) || val.startsWith('ws') || (i < 5 && val === '')) { - // prefer empty or ws-looking near top of editor - } - } - // Prefer the main URL bar: often largest width input with ws default - const urlCandidates = await page.locator('input.ops-input, input').all(); - for (const el of urlCandidates) { - const val = await el.inputValue().catch(() => ''); - const box = await el.boundingBox().catch(() => null); - if (!box || box.width < 200) continue; - if (val.startsWith('ws') || val === '' || /echo|localhost|127/.test(val)) { - await el.fill('wss://ws.postman-echo.com/raw'); - ok = true; - break; - } - } - if (ok) result.pass.push('填写 WS URL'); - else { - // force first wide input - for (const el of urlCandidates) { - const box = await el.boundingBox().catch(() => null); - if (box && box.width > 300) { - await el.fill('wss://ws.postman-echo.com/raw'); - ok = true; - result.pass.push('填写 WS URL(宽输入框)'); - break; - } - } - } - if (!ok) result.fail.push('WS URL 填写失败'); - - // Headers - const headerTab = page.getByText('Headers', { exact: true }).or(page.getByText('请求头')).or(page.getByRole('tab', { name: /Header/i })); - if (await headerTab.count()) await headerTab.first().click().catch(() => {}); - await page.waitForTimeout(300); - // try add row - const addBtns = page.getByRole('button', { name: /添加|+|\+/ }); - if (await addBtns.count()) await addBtns.first().click().catch(() => {}); - // fill key values in kv editor - const placeholders = page.locator('input[placeholder*="Key"], input[placeholder*="键"], input[placeholder*="Header"], input[placeholder*="名称"]'); - if (await placeholders.count()) { - await placeholders.first().fill('Authorization'); - const valPh = page.locator('input[placeholder*="Value"], input[placeholder*="值"]'); - if (await valPh.count()) await valPh.first().fill('Bearer smoke'); - result.pass.push('填写 Authorization Header'); - } else { - // generic: last two empty inputs in view - result.notes.push('Header 占位符未命中,尝试通用 KV'); - const all = page.locator('input'); - const vals = []; - for (let i = 0; i < await all.count(); i++) { - const v = await all.nth(i).inputValue().catch(() => null); - vals.push(v); - } - result.notes.push('inputs snapshot count=' + vals.length); - } - - await shot(page, 'web-08-ws-filled.png'); - const connect = page.getByRole('button', { name: /连接/ }); - if (await connect.count()) { - await connect.first().click(); - await page.waitForTimeout(3000); - const text = await page.locator('body').innerText(); - if (/桌面原生|Gin 隧道|自定义 Header|open|已连接|连接成功|status/i.test(text)) { - result.pass.push('连接后出现状态文案'); - } else result.notes.push('连接后文案不明确'); - const sendInput = page.locator('textarea, input[placeholder*="消息"], input[placeholder*="发送"]'); - if (await sendInput.count()) { - await sendInput.first().fill('ping-gui-reg'); - const sendBtn = page.getByRole('button', { name: /发送/ }); - if (await sendBtn.count()) { - await sendBtn.first().click(); - await page.waitForTimeout(1500); - result.pass.push('已发送 ping-gui-reg'); - } - } - await shot(page, 'web-09-ws-live.png'); - } else result.fail.push('无连接按钮'); - } catch (e) { - result.fail.push('WS流程: ' + e.message); - } - - // History replay - try { - await page.getByRole('button', { name: /历史/ }).first().click(); - await page.waitForTimeout(600); - await shot(page, 'web-10-history.png'); - const rows = page.locator('.ops-tree-row, [class*="history"] >> ..'); - // hover first history-like row - const replayBtn = page.getByRole('button', { name: '重放' }); - if (!(await replayBtn.count()) || !(await replayBtn.first().isVisible())) { - const anyRow = page.locator('button:has-text("GET"), button:has-text("POST"), div.ops-tree-row').first(); - if (await anyRow.count()) await anyRow.hover(); - await page.waitForTimeout(400); - } - if (await replayBtn.count()) { - await replayBtn.first().click({ force: true }); - await page.waitForTimeout(2200); - const toast = page.locator('.ops-toast'); - const t = (await toast.allTextContents()).join(' | '); - const body = await page.locator('body').innerText(); - if (/正在重放|重放成功|重放完成|重放失败|重放连接/i.test(t + body)) { - result.pass.push('重放 toast: ' + (t || 'body命中').slice(0, 160)); - } else result.fail.push('重放后无 toast,toast=' + t); - } else result.fail.push('无重放按钮'); - await shot(page, 'web-11-replay.png'); - } catch (e) { - result.fail.push('重放: ' + e.message); - } - - await browser.close(); - const summary = { verdict: result.fail.length ? '有缺陷' : '通过', ...result }; - fs.writeFileSync(path.join(outDir, 'web-reg-result.json'), JSON.stringify(summary, null, 2)); - console.log(JSON.stringify(summary, null, 2)); -} - -main().catch((e) => { console.error(e); process.exit(1); }); diff --git a/.ui-review/accept-2026-09-19/web-ws-recheck.png b/.ui-review/accept-2026-09-19/web-ws-recheck.png deleted file mode 100644 index 26bdd3b..0000000 Binary files a/.ui-review/accept-2026-09-19/web-ws-recheck.png and /dev/null differ diff --git a/.ui-review/ax.json b/.ui-review/ax.json deleted file mode 100644 index 317737c..0000000 --- a/.ui-review/ax.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "clicked": "ws:WebSocket · echo", - "interesting": [] -} \ No newline at end of file diff --git a/.ui-review/body.txt b/.ui-review/body.txt deleted file mode 100644 index e48e6dd..0000000 --- a/.ui-review/body.txt +++ /dev/null @@ -1,85 +0,0 @@ -OpsxAPI -HTTP · GraphQL · WS · SSE · Socket.IO · MQTT -新建 -导入 -导出 -通道 -自动 -Web 代理 -浏览器直连 -桌面直连 -本 -本地 -1 变量 -本 -接口 -历史 -测试 -Mock -文档 -设置 -登录 -接口 -历史 -示例集合 -HTTP · 本地回归(P0) -GET -回归 · GET Query -POST -回归 · POST JSON -POST -回归 · POST urlencoded -POST -回归 · POST form-data -GET -回归 · 自定义 Header -GET -回归 · Cookie -GET -回归 · Bearer -GET -回归 · Basic Auth -HTTP · httpbin -GET -获取请求回显 -POST -提交 JSON -POST -表单提交 -GET -Bearer 鉴权示例 -GET -状态码 · 404 -GraphQL -国家查询 · countries -实时协议 -WebSocket · echo -SSE · 维基媒体变更流 -MQTT · EMQX 公共 Broker -Socket.IO · 本地服务 -GET -回归 · GET Query -× -GET -POST -PUT -PATCH -DELETE -HEAD -OPTIONS -发送 -代码 -Mock 链接 -Params1 -Body -Headers -Cookies -Auth -说明 -共 1 行 · 启用 1 行 -添加 -响应体 -Raw -响应头 -Status · Time · Size -发送请求后这里显示响应 \ No newline at end of file diff --git a/.ui-review/body2.txt b/.ui-review/body2.txt deleted file mode 100644 index d7ae29a..0000000 --- a/.ui-review/body2.txt +++ /dev/null @@ -1,91 +0,0 @@ -OpsxAPI -HTTP · GraphQL · WS · SSE · Socket.IO · MQTT -新建 -导入 -导出 -通道 -自动 -Web 代理 -浏览器直连 -桌面直连 -本 -本地 -1 变量 -本 -接口 -历史 -测试 -Mock -文档 -设置 -登录 -接口 -历史 -1 -示例集合 -HTTP · 本地回归(P0) -GET -回归 · GET Query -POST -回归 · POST JSON -POST -回归 · POST urlencoded -POST -回归 · POST form-data -GET -回归 · 自定义 Header -GET -回归 · Cookie -GET -回归 · Bearer -GET -回归 · Basic Auth -HTTP · httpbin -GET -获取请求回显 -POST -提交 JSON -POST -表单提交 -GET -Bearer 鉴权示例 -GET -状态码 · 404 -GraphQL -国家查询 · countries -实时协议 -WebSocket · echo -SSE · 维基媒体变更流 -MQTT · EMQX 公共 Broker -Socket.IO · 本地服务 -GET -回归 · GET Query -× -WebSocket · echo -× -WS -连接 -未连接 -↑ 0 · ↓ 0 -说明 -鉴权 / 握手 HEADERS -添加 -子协议(逗号分隔) -快捷命令 -Ping -Auth -Subscribe -Unsubscribe -点击填入发送区 · Shift+点击直发 -高级 · websocat 命令 -发送消息 -格式化 JSON -⌘/Ctrl + Enter 快速发送 -消息日志 · 0/0 -全部 -发送 -接收 -系统 -错误 -清空 -连接后收发消息会显示在这里 \ No newline at end of file diff --git a/.ui-review/dom-texts.json b/.ui-review/dom-texts.json deleted file mode 100644 index 3bc1f0a..0000000 --- a/.ui-review/dom-texts.json +++ /dev/null @@ -1,322 +0,0 @@ -[ - { - "t": "OpsxAPI\nHTTP · GraphQL · WS · SSE · Sock", - "tag": "DIV" - }, - { - "t": "OpsxAPI\nHTTP · GraphQL · WS · SSE · Sock", - "tag": "DIV" - }, - { - "t": "OpsxAPI\nHTTP · GraphQL · WS · SSE · Sock", - "tag": "DIV" - }, - { - "t": "OpsxAPI", - "tag": "DIV" - }, - { - "t": "OpsxAPI", - "tag": "SPAN" - }, - { - "t": "HTTP · GraphQL · WS · SSE · Socket.IO · ", - "tag": "SPAN" - }, - { - "t": "新建\n导入\n导出\n本\n本地\n1 变量", - "tag": "DIV" - }, - { - "t": "新建", - "tag": "BUTTON" - }, - { - "t": "导入", - "tag": "BUTTON" - }, - { - "t": "导出", - "tag": "BUTTON" - }, - { - "t": "本\n本地\n1 变量", - "tag": "BUTTON" - }, - { - "t": "本", - "tag": "SPAN" - }, - { - "t": "本地", - "tag": "SPAN" - }, - { - "t": "1 变量", - "tag": "SPAN" - }, - { - "t": "本\n接口\n历史\n测试\nMock\n文档\n设置\n登录\n接口\n历史\n示例集合\nHTTP", - "tag": "DIV" - }, - { - "t": "本", - "tag": "BUTTON" - }, - { - "t": "本", - "tag": "SPAN" - }, - { - "t": "接口", - "tag": "BUTTON" - }, - { - "t": "接口", - "tag": "SPAN" - }, - { - "t": "历史", - "tag": "BUTTON" - }, - { - "t": "历史", - "tag": "SPAN" - }, - { - "t": "测试", - "tag": "BUTTON" - }, - { - "t": "测试", - "tag": "SPAN" - }, - { - "t": "Mock", - "tag": "BUTTON" - }, - { - "t": "Mock", - "tag": "SPAN" - }, - { - "t": "文档", - "tag": "A" - }, - { - "t": "文档", - "tag": "SPAN" - }, - { - "t": "设置", - "tag": "BUTTON" - }, - { - "t": "设置", - "tag": "SPAN" - }, - { - "t": "登录", - "tag": "BUTTON" - }, - { - "t": "登录", - "tag": "SPAN" - }, - { - "t": "接口\n历史\n示例集合\nHTTP · 本地回归(P0)\nGET\n回归 · GET ", - "tag": "DIV" - }, - { - "t": "接口\n历史", - "tag": "DIV" - }, - { - "t": "接口\n历史", - "tag": "DIV" - }, - { - "t": "接口", - "tag": "BUTTON" - }, - { - "t": "历史", - "tag": "BUTTON" - }, - { - "t": "示例集合\nHTTP · 本地回归(P0)\nGET\n回归 · GET Query\n", - "tag": "DIV" - }, - { - "t": "示例集合\nHTTP · 本地回归(P0)\nGET\n回归 · GET Query\n", - "tag": "DIV" - }, - { - "t": "示例集合", - "tag": "DIV" - }, - { - "t": "示例集合", - "tag": "SPAN" - }, - { - "t": "示例集合", - "tag": "SPAN" - }, - { - "t": "HTTP · 本地回归(P0)\nGET\n回归 · GET Query\nPOST\n", - "tag": "DIV" - }, - { - "t": "HTTP · 本地回归(P0)", - "tag": "DIV" - }, - { - "t": "HTTP · 本地回归(P0)", - "tag": "SPAN" - }, - { - "t": "HTTP · 本地回归(P0)", - "tag": "SPAN" - }, - { - "t": "GET\n回归 · GET Query", - "tag": "DIV" - }, - { - "t": "GET\n回归 · GET Query", - "tag": "DIV" - }, - { - "t": "GET", - "tag": "SPAN" - }, - { - "t": "回归 · GET Query", - "tag": "SPAN" - }, - { - "t": "回归 · GET Query", - "tag": "SPAN" - }, - { - "t": "POST\n回归 · POST JSON", - "tag": "DIV" - }, - { - "t": "POST\n回归 · POST JSON", - "tag": "DIV" - }, - { - "t": "POST", - "tag": "SPAN" - }, - { - "t": "回归 · POST JSON", - "tag": "SPAN" - }, - { - "t": "回归 · POST JSON", - "tag": "SPAN" - }, - { - "t": "POST\n回归 · POST urlencoded", - "tag": "DIV" - }, - { - "t": "POST\n回归 · POST urlencoded", - "tag": "DIV" - }, - { - "t": "POST", - "tag": "SPAN" - }, - { - "t": "回归 · POST urlencoded", - "tag": "SPAN" - }, - { - "t": "回归 · POST urlencoded", - "tag": "SPAN" - }, - { - "t": "POST\n回归 · POST form-data", - "tag": "DIV" - }, - { - "t": "POST\n回归 · POST form-data", - "tag": "DIV" - }, - { - "t": "POST", - "tag": "SPAN" - }, - { - "t": "回归 · POST form-data", - "tag": "SPAN" - }, - { - "t": "回归 · POST form-data", - "tag": "SPAN" - }, - { - "t": "GET\n回归 · 自定义 Header", - "tag": "DIV" - }, - { - "t": "GET\n回归 · 自定义 Header", - "tag": "DIV" - }, - { - "t": "GET", - "tag": "SPAN" - }, - { - "t": "回归 · 自定义 Header", - "tag": "SPAN" - }, - { - "t": "回归 · 自定义 Header", - "tag": "SPAN" - }, - { - "t": "GET\n回归 · Cookie", - "tag": "DIV" - }, - { - "t": "GET\n回归 · Cookie", - "tag": "DIV" - }, - { - "t": "GET", - "tag": "SPAN" - }, - { - "t": "回归 · Cookie", - "tag": "SPAN" - }, - { - "t": "回归 · Cookie", - "tag": "SPAN" - }, - { - "t": "GET\n回归 · Bearer", - "tag": "DIV" - }, - { - "t": "GET\n回归 · Bearer", - "tag": "DIV" - }, - { - "t": "GET", - "tag": "SPAN" - }, - { - "t": "回归 · Bearer", - "tag": "SPAN" - }, - { - "t": "回归 · Bearer", - "tag": "SPAN" - } -] \ No newline at end of file diff --git a/.ui-review/full.png b/.ui-review/full.png deleted file mode 100644 index 4adf4d5..0000000 Binary files a/.ui-review/full.png and /dev/null differ diff --git a/.ui-review/home.png b/.ui-review/home.png deleted file mode 100644 index 220f608..0000000 Binary files a/.ui-review/home.png and /dev/null differ diff --git a/.ui-review/probe30.json b/.ui-review/probe30.json deleted file mode 100644 index 69d03d7..0000000 --- a/.ui-review/probe30.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "probe": { - "save": true, - "dirtyDot": false, - "runMode": true, - "l2": true, - "bannerClasses": [], - "saveButtons": [ - "● 保存" - ], - "topBits": [ - "新建", - "导入", - "导出", - "自动Web 代理浏览器直连桌面直连", - "本本地1 变量", - "本", - "接口", - "历史", - "测试", - "Mock", - "设置", - "登录", - "接口", - "历史", - "×", - "GETPOSTPUTPATCHDELETEHEADOPTIONS", - "发送", - "● 保存", - "代码", - "Mock 链接", - "Params1", - "Body", - "Headers", - "Cookies", - "Auth" - ] - }, - "forceBanner": { - "keys": [] - }, - "body": "OpsxAPI\nHTTP · GraphQL · WS · SSE · Socket.IO · MQTT\n新建\n导入\n导出\n通道\n自动\nWeb 代理\n浏览器直连\n桌面直连\n本\n本地\n1 变量\n本\n接口\n历史\n测试\nMock\n文档\n设置\n登录\n接口\n历史\n示例集合\nHTTP · 本地回归(P0)\nGET\n回归 · GET Query\nPOST\n回归 · POST JSON\nPOST\n回归 · POST urlencoded\nPOST\n回归 · POST form-data\nGET\n回归 · 自定义 Header\nGET\n回归 · Cookie\nGET\n回归 · Bearer\nGET\n回归 · Basic Auth\nHTTP · httpbin\nGET\n获取请求回显\nPOST\n提交 JSON\nPOST\n表单提交\nGET\nBearer 鉴权示例\nGET\n状态码 · 404\nGraphQL\n国家查询 · countries\n实时协议\nWebSocket · echo\nSSE · 维基媒体变更流\nMQTT · EMQX 公共 Broker\nSocket.IO · 本地服务\nGET\n回归 · GET Query\n×\nWebSocket · echo\n×\nWS\n连接\n已保存\n未连接\n↑ 0 · ↓ 0\n说明\n鉴权 / 握手 HEADERS\n添加\n子协议(逗号分隔)\n快捷命令\nPing\nAuth\nSubscribe\nUnsubscribe\n点击填入发送区 · Shift+点击直发\n高级 · websocat 命令\n发送消息\n格式化 JSON\n⌘/Ctrl + Enter 快速发送\n消息日志 · 0/0\n全部\n发送\n接收\n系统\n错误\n清空\n连接后收发消息会显示在这里\n设置\n设置\n外观\n主题与界面\n网络\n请求与超时\nMock 数据\n智能匹配规则\nAI 助手\n模型供应商\n数据管理\n工作区与备份\n关于\n版本与链接\nMock 数据\n智能匹配规则\n启用 Mock 数据\n发送时解析参数与 Body 中的 @mock 表达式(如 @cname、@integer(1,100))\n智能 Mock 匹配\nJSON Body 中字段值未写 Mock 规则时,按字段名自动匹配下方规则生成\n智能匹配规则\n按从上到下的顺序匹配,先命中先用;* 通配任意字符,类型需与 JSON 字段一致。语法速查 →\n61 条\n新增规则\n恢复默认\n数据类型\n匹配方式\n匹配规则\nMock 表达式\n备注\n启用\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配符\n完全匹配\n正则\nstring\nnumber\ninteger\nboolean\n通配" -} \ No newline at end of file diff --git a/.ui-review/probe40.json b/.ui-review/probe40.json deleted file mode 100644 index 06163df..0000000 --- a/.ui-review/probe40.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "homeProbe": { - "logoTitle": "支持协议:HTTP · GraphQL · WebSocket · SSE · Socket.IO · MQTT", - "captions": [ - "OpsxAPIAPI 工作台", - "OpsxAPIAPI 工作台", - "OpsxAPIAPI 工作台" - ], - "protoListVisible": false, - "channel": true, - "l2": [ - { - "t": "测试", - "title": "测试 · 即将推出", - "opacity": "0.35" - }, - { - "t": "Mock", - "title": "Mock · 即将推出", - "opacity": "0.35" - }, - { - "t": "文档", - "title": "文档 · 即将推出", - "opacity": "0.35" - } - ] - }, - "wsProbe": { - "emptyHeaderHint": true, - "connectCaption": true, - "backToBottom": false, - "sendDisabled": { - "t": "发送消息", - "disabled": true - }, - "headerPlaceholder": [ - { - "t": "import { injectIntoGlobalHook } from \"/@react-refresh\";\ninje", - "cls": "dark" - }, - { - "t": "OpsxAPIAPI 工作台 新建 导入 导出通道自动Web 代理浏览器直连桌面直连本本地1 变量本 接口 ", - "cls": "" - }, - { - "t": "OpsxAPIAPI 工作台 新建 导入 导出通道自动Web 代理浏览器直连桌面直连本本地1 变量本 接口 ", - "cls": "" - } - ] - }, - "errProbe": { - "hasBanner": true, - "snippet": "\n新建\n导入\n导出\n通道\n自动\nWeb 代理\n浏览器直连\n桌面直连\n本\n本地\n1 变量\n本\n接口\n历史\n测试\nMock\n文档\n设置\n登录\n接口\n历史\n1\n示例集合\nHTTP · 本地回归(P0)\nGET\n回归 · GET Query\nPOST\n回归 · POST JSON\nPOS" - } -} \ No newline at end of file diff --git a/.ui-review/rail-b-check.png b/.ui-review/rail-b-check.png deleted file mode 100644 index b8d8a93..0000000 Binary files a/.ui-review/rail-b-check.png and /dev/null differ diff --git a/.ui-review/wire-account.html b/.ui-review/wire-account.html deleted file mode 100644 index 396e9c6..0000000 --- a/.ui-review/wire-account.html +++ /dev/null @@ -1,110 +0,0 @@ - - - -OpsxAPI 左轨账号区线框 - - -

OpsxAPI · 左轨账号 / 工作区线框 v1

-

去掉「本」;本地/团队只在底部;已登录=头像菜单

-
-
-

A · 未登录

-
-
-
接口
-
测试
-
Mock
-
-
文档
-
设置
- -
-
-
变量入口并入账号区 →
- 左轨顶无「本」字标
底栏仅「登录」入口 -
-
-

点击 → 登录弹层。登录后变头像。

-
-
-

B · 已登录 · 菜单开主方案

-
-
-
接口
-
测试
-
Mock
-
-
文档
-
设置
-
L - -
-
-
-
顶栏变量可弱化/去掉
- 头像角标:绿=本地 / 蓝=团队
菜单内切工作区 + 变量入口 -
-
-

角标绿本地、蓝团队。变量进菜单。

-
-
-

C · 团队态(角标)

-
-
-
接口
-
测试
-
Mock
-
-
文档
-
设置
-
L
-
-
-
团队 · 已同步
- 切到团队后角标变蓝;配置鉴权同步(加密) -
-
-

不登录也能用本地;登录后才可切团队。

-
-
- - diff --git a/.ui-review/wire-account.png b/.ui-review/wire-account.png deleted file mode 100644 index fa55196..0000000 Binary files a/.ui-review/wire-account.png and /dev/null differ