v0.6.0: beautifului 整合 + 会话/工作区/队列/权限/命令/附件全链路
- beautifului.dev 组件直连:Sidebar Nav、Tool Chips、Approval Card(抽屉化)、Streaming/Thinking、Code Block、Selection Actions、Prompt Bar、Search
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
// 预览页视觉验收截图(Electron 离屏捕获):
|
||||
// npx electron scripts/capture-preview.cjs
|
||||
// 产出 preview-shots/*.png:整页 / 侧栏折叠 / 搜索面板 / 选区工具条
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { mkdirSync, writeFileSync } = require('node:fs')
|
||||
const { join } = require('node:path')
|
||||
|
||||
// 离屏捕获在 GPU 合成异常时会得到空白帧,改用软件合成
|
||||
app.commandLine.appendSwitch('disable-gpu')
|
||||
|
||||
const URL = 'http://localhost:4173/'
|
||||
const OUT = join(__dirname, '..', 'preview-shots')
|
||||
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
|
||||
|
||||
async function capture(win, name) {
|
||||
try {
|
||||
const image = await win.webContents.capturePage()
|
||||
writeFileSync(join(OUT, name), image.toPNG())
|
||||
console.log('saved', name, `${image.getSize().width}x${image.getSize().height}`)
|
||||
} catch (e) {
|
||||
console.log('capture failed', name, e.message)
|
||||
}
|
||||
}
|
||||
|
||||
async function js(win, code) {
|
||||
try {
|
||||
return await win.webContents.executeJavaScript(code)
|
||||
} catch (e) {
|
||||
console.log('js failed:', e.message)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
mkdirSync(OUT, { recursive: true })
|
||||
const win = new BrowserWindow({
|
||||
width: 1280,
|
||||
height: 960,
|
||||
show: false,
|
||||
webPreferences: { paintWhenInitiallyHidden: true }
|
||||
})
|
||||
await win.loadURL(URL)
|
||||
await sleep(1500)
|
||||
|
||||
// 1) 整页(上半)
|
||||
await capture(win, '01-full.png')
|
||||
|
||||
// 2) 折叠侧栏(等宽度过渡)
|
||||
await js(win, `document.querySelector('[aria-label="折叠侧栏"]')?.click()`)
|
||||
await sleep(700)
|
||||
await capture(win, '02-sidebar-collapsed.png')
|
||||
await js(win, `document.querySelector('[aria-label="展开侧栏"]')?.click()`)
|
||||
await sleep(700)
|
||||
|
||||
// 3) 搜索面板(侧栏「搜索」行)+ 输入过滤
|
||||
await js(win, `[...document.querySelectorAll('button')].find((b) => b.textContent.trim() === '搜索')?.click()`)
|
||||
await sleep(600)
|
||||
await js(win, `(() => { const i = document.querySelector('input[aria-label="搜索会话或命令"]'); if (!i) return 'no-input'; const set = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; set.call(i, '供应'); i.dispatchEvent(new Event('input', { bubbles: true })); return 'ok' })()`)
|
||||
await sleep(400)
|
||||
await capture(win, '03-search-filtered.png')
|
||||
await js(win, `document.querySelector('input[aria-label="搜索会话或命令"]')?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))`)
|
||||
await sleep(400)
|
||||
|
||||
// 4) 划选文本 → Selection Actions 工具条(展开「更多」)
|
||||
await js(win, `(() => {
|
||||
const p = [...document.querySelectorAll('p')].find((el) => el.textContent.includes('百香果'));
|
||||
if (!p) return 'no-p';
|
||||
const textNode = p.firstChild;
|
||||
const range = document.createRange();
|
||||
range.setStart(textNode, 0);
|
||||
range.setEnd(textNode, 30);
|
||||
const sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
document.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
|
||||
return 'ok';
|
||||
})()`)
|
||||
await sleep(600)
|
||||
await js(win, `document.querySelector('[aria-label="更多操作"]')?.click()`)
|
||||
await sleep(500)
|
||||
await capture(win, '04-selection-actions.png')
|
||||
|
||||
// 5) 审批卡交互:选择「允许执行」(radio 自动前进 480ms 后提交)
|
||||
await js(win, `[...document.querySelectorAll('button')].find((b) => b.textContent.trim() === '允许执行')?.click()`)
|
||||
await sleep(900)
|
||||
await capture(win, '05-approval-approved.png')
|
||||
|
||||
app.exit(0)
|
||||
}
|
||||
|
||||
app.whenReady().then(run).catch((err) => {
|
||||
console.error(err)
|
||||
app.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user