feat(账号分析+工作台): 功能三自动联动生成设定卡+双向联动维护+玫瑰金配色定稿+首页数据预览/周榜优化+CDP验证脚本
- mcn-dou-analysis: 功能三产出设定后自动生成设定卡(Step7); 设定md与卡片SVG双向联动维护规则固化(06文档+03文档+SKILL.md); 浅色系配色定稿玫瑰金(#D6A3A9→#9A5563)+背景文字提亮规则; 新增06生成账号设定卡片文档+模板样例 - mcn-work-shop: 首页数据预览条/周榜预览表加宽/改名AI脚本诊断/tab切换/添加账号弹窗等优化 - 新增 cdp-*.mjs 验证脚本14个(可复用); .gitignore 忽略运行日志/截图/tmp
This commit is contained in:
1 parent
96fce56fba
commit
53621279a5
35 files changed
+2567
-117
No files matched your search
@@ -0,0 +1,42 @@
|
||||
// 验证:首页周榜 tab 选中样式 = 浅底色(primary-soft) + 2px 主色下划线,非选中透明
|
||||
const list = await fetch('http://localhost:9223/json').then((r) => r.json());
|
||||
let page = list.find((t) => t.type === 'page' && t.url.includes('localhost:8899'));
|
||||
if (!page) { console.log('ERR: no workbuddy page open'); process.exit(1); }
|
||||
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
||||
let id = 0; const pending = new Map();
|
||||
const send = (method, params = {}) => new Promise((res, rej) => { const i = ++id; pending.set(i, { res, rej }); ws.send(JSON.stringify({ id: i, method, params })); });
|
||||
ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.id && pending.has(m.id)) { const p = pending.get(m.id); pending.delete(m.id); m.error ? p.rej(new Error(m.error.message)) : p.res(m.result); } };
|
||||
await new Promise((r) => (ws.onopen = r));
|
||||
const ev = async (expr) => { const r = await send('Runtime.evaluate', { expression: expr, returnByValue: true, awaitPromise: true }); if (r.exceptionDetails) return { __err: (r.exceptionDetails.exception?.description || r.exceptionDetails.text).slice(0, 200) }; return r.result.value; };
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
await send('Page.enable'); await send('Runtime.enable');
|
||||
|
||||
await send('Page.navigate', { url: 'http://localhost:8899/#/' }); await sleep(1500);
|
||||
await send('Page.reload', { ignoreCache: true }); await sleep(3000);
|
||||
|
||||
const stylesOf = `(sel) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (!el) return null;
|
||||
const cs = getComputedStyle(el);
|
||||
return { bg: cs.backgroundColor, color: cs.color, border: cs.borderBottomWidth + ' ' + cs.borderBottomStyle + ' ' + cs.borderBottomColor, weight: cs.fontWeight };
|
||||
}`;
|
||||
|
||||
const states = [];
|
||||
// 初始 active = 账号周榜
|
||||
states.push({ clicked: '(初始)', active: '账号周榜', style: await ev(`(${stylesOf})('.rank-tab.active')`) });
|
||||
// 记录非 active 的样式(作品热榜)
|
||||
states.push({ clicked: '(初始)', note: '非active:作品热榜', style: await ev(`(${stylesOf})([...document.querySelectorAll('.rank-tab')].find(x => x.textContent.trim() === '作品热榜'))`) });
|
||||
|
||||
for (const name of ['作品热榜', '点赞日榜', '涨粉日榜', '账号周榜']) {
|
||||
await ev(`(() => { [...document.querySelectorAll('.rank-tab')].find((x) => x.textContent.trim() === ${JSON.stringify(name)}).click(); })()`);
|
||||
await sleep(150);
|
||||
states.push({ clicked: name, active: await ev(`([...document.querySelectorAll('.rank-tab')].find(x => x.classList.contains('active'))?.textContent.trim() || null)`), style: await ev(`(${stylesOf})('.rank-tab.active')`) });
|
||||
}
|
||||
console.log(JSON.stringify(states, null, 1));
|
||||
|
||||
// 预期:active bg=rgb(234, 241, 254) color=rgb(47, 111, 237) border=2px solid rgb(47, 111, 237) weight=600
|
||||
const isActiveStyle = (s) => s && s.bg === 'rgb(234, 241, 254)' && s.color === 'rgb(47, 111, 237)' && s.border === '2px solid rgb(47, 111, 237)' && s.weight === '600';
|
||||
const isIdleStyle = (s) => s && s.bg === 'rgba(0, 0, 0, 0)' && s.border === '2px solid rgba(0, 0, 0, 0)';
|
||||
const ok = states.every((s) => s.active === s.clicked) && isActiveStyle(states[0].style) && isIdleStyle(states[1].style) && states.slice(2).every((s) => isActiveStyle(s.style));
|
||||
console.log(ok ? 'PASS' : 'CHECK');
|
||||
ws.close();
|
||||
Reference in new issue
Block a user