Files
FreeCADWasmDev/web/public/execution.html

61 lines
7.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>FreeCAD Web 执行进度</title>
<style>
:root{font-family:system-ui,sans-serif;color:#dae4ee;background:#111923;color-scheme:dark}body{max-width:1050px;margin:32px auto;padding:0 20px;line-height:1.65}h1{font-size:25px}h2{font-size:19px;margin-top:0}.muted{color:#9babbc}section,details{background:#192532;border:1px solid #334657;border-radius:8px;padding:20px;margin:18px 0}.detail{white-space:pre-wrap;overflow-wrap:anywhere}li{overflow-wrap:anywhere}summary{cursor:pointer}a{color:#8ed9dd}.stale{color:#ffcc83}.tag{font-weight:600;color:#8ed9dd}#error{color:#ffb8ad}@media(max-width:600px){body{margin:18px auto;padding:0 12px}section,details{padding:14px}}
</style></head><body>
<h1>FreeCAD Web 执行进度</h1><p class="muted">每轮结束后自动更新结果;接续任务经调度确认后显示。本页每 5 秒刷新。</p>
<p id="heartbeat" class="muted">正在读取状态…</p><p id="error" role="status"></p>
<section id="change-section" hidden aria-label="增量巡检"><h2>输入变化与新故障巡检</h2><div id="change-watch"></div></section>
<section id="smoke-section" hidden aria-label="全面烟测"><h2>全面烟测 · 可接续</h2><div id="smoke"></div><p class="muted">烟测与历史开发轮次分别记录。通过数是检查组数量,不是全部功能完成率。</p></section>
<section aria-label="最近一轮结果"><h2>最近一轮结果</h2><div id="last">等待记录</div></section>
<section aria-label="下一轮任务"><h2>下一轮 / 当前接续任务</h2><div id="next">待调度确认</div></section>
<h2>最近轮次</h2><div id="history"></div>
<p class="muted">“已修改”不代表整项通过;未完成、阻塞和上游等待会如实保留。此页显示已有记录,不触发构建或验收。</p>
<p><a href="/">打开 FreeCAD 工作区</a> · <a href="/execution-status.json">查看结构化回执</a></p>
<script type="module">
const byId=id=>document.getElementById(id);
const element=(tag,text,cls)=>{const node=document.createElement(tag);node.textContent=text;if(cls)node.className=cls;return node;};
function renderRound(row){
const box=document.createElement('div');
box.append(element('p',`第 ${row.cycle} 轮 · ${row.module} · ${row.seconds} 秒`,'muted'),element('p',row.result,'tag'),element('p',row.detail,'detail'));
if(row.remaining&&row.remaining.trim()!==row.detail.trim())box.append(element('p',`剩余/阻塞:${row.remaining}`,'detail muted'));
if(row.firstPassIds?.length){const list=document.createElement('ul');for(const id of row.firstPassIds)list.append(element('li',id));box.append(list);}
if(row.evidence?.length){const detail=document.createElement('details');detail.append(element('summary','证据记录'));for(const item of row.evidence)detail.append(element('p',item.path,'detail'));box.append(detail);}
return box;
}
let version='';
async function update(){try{
const response=await fetch('/execution-status.json',{cache:'no-store'});if(!response.ok)throw new Error(`状态读取失败(${response.status})`);
const data=await response.json();if(data.schema!=='freecad-web-round-report/v1'||![2,3].includes(data.formatVersion))throw new Error('回执格式不正确');
const age=(Date.now()-Date.parse(data.heartbeatAt))/1000;const heartbeat=byId('heartbeat');
const waitingForGap=data.schedulerStatus==='waiting_for_confirmed_gap';
heartbeat.textContent=data.reportingActive===false?'自动逐轮回执将在当前业务回合结束、调度器重载后启用;以下为最近记录。':`调度状态:${waitingForGap?'等待已确认缺口,当前没有实施任务':data.schedulerStatus||'未知'} · 最近心跳:${data.heartbeatAt?new Date(data.heartbeatAt).toLocaleString('zh-CN'):'未知'}${age>60?' · 心跳已超过 60 秒,请核对服务':''}`;
heartbeat.className=age>60?'stale':'muted';byId('error').textContent='';
const contentVersion=JSON.stringify([data.lastCompleted,data.nextTask,data.rounds,data.schedulerStatus]);
if(version===contentVersion)return;version=contentVersion;
byId('last').replaceChildren(data.lastCompleted?renderRound(data.lastCompleted):element('p','尚无已结束轮次记录'));
const next=byId('next');next.replaceChildren();
if(data.nextTask){const task=data.nextTask;next.append(element('p',`调度已确认:第 ${task.cycle} 轮 · ${task.module}`,'tag'));const list=document.createElement('ul');for(const text of task.tasks)list.append(element('li',text));next.append(list);}
else next.append(element('p',waitingForGap?'当前没有可执行的已确认缺口;保留心跳,登记新问题后继续,不生成空轮次。':'待调度确认;选定后自动显示。'));
byId('history').replaceChildren(...[...(data.rounds||[])].reverse().map(row=>{const detail=document.createElement('details');detail.append(element('summary',`第 ${row.cycle} 轮 · ${row.module} · ${row.result}`),renderRound(row));return detail;}));
}catch(error){byId('error').textContent=String(error.message||error)+';保留上次记录,稍后自动重试。';}}
async function updateSmoke(){try{
const response=await fetch('/smoke-status.json',{cache:'no-store'});if(!response.ok)return;
const data=await response.json();if(data.schema!=='freecad-web-smoke-progress/v1')return;
byId('smoke-section').hidden=false;
const labels={running:'执行中',paused:'可接续',interrupted:'已中断,可接续',completed:'本轮烟测收口',completed_with_failures:'本轮结束,仍有未通过项'};
byId('smoke').replaceChildren(element('p',`${labels[data.status]||data.status} · 已记录 ${data.completed}/${data.total} 组 · 通过 ${data.passed} 组`,'tag'),
element('p',data.current?`当前:${data.current.module} · ${data.current.phase}`:'当前没有正在运行的烟测项'),
element('p',data.failed.length?`未通过/待定位:${data.failed.join('、')}`:'没有记录失败项','detail'),
element('p','累计结果包含已有通过证据和修复后的定向复测;不表示全部功能逐项重新验收。','muted'));
}catch{ /* Keep last successfully read smoke result. */ }}
async function updateChangeWatch(){try{
const response=await fetch('/change-watch-status.json',{cache:'no-store'});if(!response.ok)return;
const d=await response.json();byId('change-section').hidden=false;
const labels={no_changes:'本轮无变化,等待下一次检查',checking_changed_input:'正在检查变化项',check_finished:'变化项检查结束',repair_queued:'新故障已进入修复队列',waiting_for_build:'源码已变更,等待对应构建产物',waiting_for_active_work:'等待现有测试或构建结束',unchanged_failure_preserved:'保留同输入失败,不重复重试',needs_attention:'检查未完成,需查看证据',monitor_error:'巡检异常',stopping_timeout:'检查超时,正在收尾'};
byId('change-watch').replaceChildren(element('p',labels[d.status]||d.status,'tag'),element('p',`最近检查:${d.lastCheckedAt?new Date(d.lastCheckedAt).toLocaleString('zh-CN'):'尚未完成'} · 下次检查:${d.nextCheckAt?new Date(d.nextCheckAt*1000).toLocaleString('zh-CN'):'待安排'}`),element('p',`核对 ${d.checks||0} 组 · 未变化 ${d.unchanged||0} 组 · 新故障 ${d.newIssues||0} 项${d.active?' · 当前:'+d.active.check:''}`),element('p',d.error||'仅处理变化或具体故障,已完成移植直接复用。','muted'));
}catch{}}
await Promise.all([update(),updateSmoke(),updateChangeWatch()]);setInterval(()=>{void update();void updateSmoke();void updateChangeWatch();},5000);
</script></body></html>