baseline: 薪酬逻辑收口到 shared/payroll.js 后的当前全量状态
这是第一个包含完整工作区的提交,也是后续「拆 SFC / 上 Vite」的回滚基线。 此前的提交均为 index.html 单文件历史快照,由 .bak 文件重建。 当前状态(提交前已实测): - index.html 内联薪酬算法已删除,改调 WHTPayroll - shared/payroll.js 为唯一薪酬实现,浏览器与 Node 共用 - 对外接口未变:aggregateMonth / isCutEdge / payDayKind 等保留同名薄包装 未入库内容见 .gitignore:依赖、Chrome 验证 profile、验证截图、 运行时 sqlite 数据与日志、时间戳备份、.trash。
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
// 复现排查:用真实浏览器分别从 127.0.0.1 与公网 IP 打开,看 boot-fail 会不会出现
|
||||
const { spawn } = require('child_process');
|
||||
const OUT = '/root/.openclaw/workspace/work-hours-tracker/png';
|
||||
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||
|
||||
const TARGETS = [
|
||||
['本机同源', 'http://127.0.0.1:9522/index.html'],
|
||||
['公网 IP ', 'http://66.235.106.12:9522/index.html']
|
||||
];
|
||||
|
||||
(async () => {
|
||||
const chrome = spawn('/usr/bin/chromium', [
|
||||
'--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage',
|
||||
'--remote-debugging-port=9264', `--user-data-dir=${OUT}/.chrome-boot`,
|
||||
'--window-size=360,900', 'about:blank'
|
||||
], { stdio: ['ignore', 'ignore', 'pipe'] });
|
||||
|
||||
const wsUrl = await (async () => {
|
||||
for (let i = 0; i < 40; i++) {
|
||||
try { const t = await (await fetch('http://127.0.0.1:9264/json/list')).json(); if (t.length) return t[0].webSocketDebuggerUrl; } catch {}
|
||||
await sleep(250);
|
||||
}
|
||||
throw new Error('CDP 起不来');
|
||||
})();
|
||||
|
||||
const ws = new WebSocket(wsUrl);
|
||||
let id = 0; const pnd = new Map();
|
||||
await new Promise(r => { ws.onopen = r; });
|
||||
|
||||
const reqs = [];
|
||||
ws.onmessage = e => {
|
||||
const m = JSON.parse(e.data);
|
||||
if (m.id && pnd.has(m.id)) { pnd.get(m.id)(m); pnd.delete(m.id); }
|
||||
if (m.method === 'Network.responseReceived') {
|
||||
reqs.push(`${m.params.response.status} ${m.params.response.url.replace(/^https?:\/\/[^/]+/, '')}`);
|
||||
}
|
||||
if (m.method === 'Network.loadingFailed') reqs.push(`FAILED ${m.params.errorText}`);
|
||||
};
|
||||
const send = (method, params = {}) => new Promise(r => { const i = ++id; pnd.set(i, r); ws.send(JSON.stringify({ id: i, method, params })); });
|
||||
const ev = async x => {
|
||||
const r = await send('Runtime.evaluate', { expression: x, awaitPromise: true, returnByValue: true });
|
||||
return r.result && r.result.result && r.result.result.value;
|
||||
};
|
||||
await send('Runtime.enable'); await send('Page.enable'); await send('Network.enable');
|
||||
|
||||
for (const [label, url] of TARGETS) {
|
||||
reqs.length = 0;
|
||||
await send('Page.navigate', { url }); await sleep(2600);
|
||||
console.log(`\n=== ${label} ${url} ===`);
|
||||
console.log(' Vue 是否加载 =', await ev(`typeof Vue`));
|
||||
console.log(' boot-fail 是否显示 =', await ev(`(function(){const b=document.getElementById('boot-fail');return b?!b.hidden:'元素不存在(旧版页面)';})()`));
|
||||
console.log(' #app 是否存在 =', await ev(`!!document.getElementById('app')`));
|
||||
console.log(' 首屏文本 =', String(await ev(`document.body.innerText.replace(/\\n+/g,' | ').slice(0,110)`)));
|
||||
console.log(' 资源请求:');
|
||||
reqs.forEach(r => console.log(' ' + r));
|
||||
}
|
||||
|
||||
ws.close(); chrome.kill();
|
||||
process.exit(0);
|
||||
})().catch(e => { console.error('FAILED:', e.message); process.exit(1); });
|
||||
Reference in New Issue
Block a user