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:
maogeigei committed 2026-08-31 15:27:54 +08:00
1 parent ab97842030
commit 268ce29aae
35 files changed
+2567 -117

No files matched your search

@@ -0,0 +1,70 @@
// 验证「账号设定」内容区左右 20px 间隔(persona-wrap padding 0 20px)
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, 300) }; return r.result.value; };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
await send('Page.enable'); await send('Runtime.enable');
const goto = async (url) => {
await send('Page.navigate', { url });
await sleep(2500);
await send('Page.reload', { ignoreCache: true });
await sleep(3000);
};
console.log('=== 旧梦留声机 1629(有卡片)===');
await goto('http://localhost:8899/#/account/1629');
const tabClick = await ev(`(() => {
const b = document.querySelector('[data-tab="persona"]');
if (!b) return { err: 'no persona tab' };
b.click();
return 'clicked persona tab';
})()`);
console.log('切tab:', JSON.stringify(tabClick));
await sleep(1800);
const s1 = await ev(`(() => {
const wrap = document.querySelector('.persona-wrap');
const card = document.querySelector('.card-view');
const img = card && card.querySelector('img');
if (!wrap) return { err: 'no .persona-wrap' };
const cs = getComputedStyle(wrap);
const dbody = document.querySelector('.detail-body');
const dw = dbody ? dbody.getBoundingClientRect().width : null;
const ww = wrap.getBoundingClientRect().width;
const iw = img ? img.getBoundingClientRect().width : null;
return {
paddingLeft: cs.paddingLeft,
paddingRight: cs.paddingRight,
detailBodyW: dw,
wrapW: ww,
imgW: iw,
imgInset: iw !== null && dw !== null ? (dw - iw).toFixed(1) : null, // 卡片比内容区窄多少(两侧总和)
};
})()`);
console.log('persona padding 检查:', JSON.stringify(s1, null, 2));
// 切文字版后再看文字容器
const s2 = await ev(`(() => {
const btn = document.querySelector('.persona-vs-icons [data-vs="text"]');
if (btn) btn.click();
return 'switched to text';
})()`);
await sleep(600);
const s3 = await ev(`(() => {
const md = document.querySelector('.persona-text');
if (!md) return { err: 'no .persona-text' };
const dbody = document.querySelector('.detail-body');
const dw = dbody ? dbody.getBoundingClientRect().width : null;
const mw = md.getBoundingClientRect().width;
return { mdW: mw, inset: dw !== null ? (dw - mw).toFixed(1) : null };
})()`);
console.log('文字版检查:', JSON.stringify(s3, null, 2));
ws.close();
console.log('DONE');