Files
storage-labos/前端UI八页面完成/Workflows.dc.html
T
yuanshuai c91a64fddb
CI / Python 3.12 (push) Waiting to run
CI / Python 3.9 (push) Waiting to run
chore(repo): initialize team collaboration repository
2026-07-27 20:40:12 +08:00

240 lines
18 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>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="_ds/industry-22c874fd-9888-4e99-8234-d60d39b3d719/styles.css">
<script src="_ds/industry-22c874fd-9888-4e99-8234-d60d39b3d719/_ds_bundle.js"></script>
<style>
body{margin:0;background:#f2f2f3;min-width:1280px}
*{scrollbar-width:thin;scrollbar-color:var(--color-accent-300) transparent}
a{color:#5980a6}a:hover{color:#416180}
@keyframes omIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@keyframes omScan{to{background-position:28px 0}}
@keyframes omDraw{to{stroke-dashoffset:0}}
@keyframes omGrow{from{width:0}}
</style>
</helmet>
<dc-import name="ConsoleNav" active="workflows" hint-size="100%,92px"></dc-import>
<div data-screen-label="工作流模板" style="max-width:1400px;margin:0 auto;padding:22px 24px 64px;font-family:var(--font-body);animation:omIn .5s cubic-bezier(.2,.7,.2,1) both">
<div style="display:flex;align-items:flex-end;gap:16px;margin-bottom:18px">
<div>
<div style="font-size:10px;letter-spacing:.18em;color:var(--color-accent-700);font-weight:500">08 · WORKFLOWS</div>
<h2 style="margin:2px 0 0;font-size:30px">工作流模板</h2>
<div class="text-muted" style="font-size:12.5px;margin-top:2px">SOP 结构化 · 版本化 · 审批与签名 — 运行时禁止拼接未审核的危险命令</div>
</div>
<span style="margin-left:auto"></span>
<button class="btn btn-secondary" style="font-size:12.5px">从 SOP 文档草拟(AI)</button>
<button class="btn btn-primary" style="font-size:13px">新建模板</button>
</div>
<div style="display:grid;grid-template-columns:330px 1fr;gap:18px;align-items:start">
<div style="display:flex;flex-direction:column;gap:10px">
<sc-for list="{{ list }}" as="tp" hint-placeholder-count="4">
<div onClick="{{ tp.pick }}" tabindex="0" style="{{ tp.itemStyle }}">
<div style="display:flex;align-items:center;gap:8px">
<span style="font-family:ui-monospace,Menlo,monospace;font-size:12.5px;font-weight:700">{{ tp.name }}</span>
<span style="margin-left:auto;font-family:ui-monospace,Menlo,monospace;font-size:10px;color:var(--color-neutral-500)">{{ tp.ver }}</span>
</div>
<div style="font-size:12px;color:var(--color-neutral-700);margin:4px 0 6px">{{ tp.desc }}</div>
<div style="display:flex;gap:6px;align-items:center">
<span style="{{ tp.stStyle }}">{{ tp.status }}</span>
<sc-for list="{{ tp.risks }}" as="rk" hint-placeholder-count="2"><span style="font-family:ui-monospace,Menlo,monospace;font-size:9px;background:var(--color-accent-800);color:#f2f2f3;padding:1px 6px">{{ rk }}</span></sc-for>
<span style="margin-left:auto;font-size:10px;color:var(--color-neutral-500)">{{ tp.updated }}</span>
</div>
</div>
</sc-for>
<div style="border:1px dashed var(--color-divider);padding:11px 12px;font-size:11.5px;color:var(--color-neutral-600);line-height:1.6">每接入一套真实 SOP,就沉淀为可复用模板与连接器 · 模板参数化,严格控制定制边界</div>
</div>
<div style="display:flex;flex-direction:column;gap:16px">
<div class="card blueprint" style-hover="border-color:var(--color-accent-400);box-shadow:var(--shadow-sm)" style="transition:border-color .15s ease,box-shadow .15s ease;padding:14px 18px;gap:10px">
<i class="corner tl"></i><i class="corner tr"></i><i class="corner bl"></i><i class="corner br"></i>
<div style="display:flex;align-items:center;gap:10px">
<h4 style="margin:0;letter-spacing:.01em">{{ selName }}</h4>
<span style="{{ selStStyle }}">{{ selStatus }}</span>
<span style="margin-left:auto"></span>
<button class="btn btn-secondary" style="font-size:12px;padding:5px 12px">复制为新版本</button>
<button class="btn btn-secondary" style="font-size:12px;padding:5px 12px">导出 YAML</button>
<button class="btn btn-primary" disabled="{{ selPublished }}" style="font-size:12px;padding:5px 14px">提交审批</button>
</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;font-family:ui-monospace,Menlo,monospace;font-size:10.5px;color:var(--color-neutral-700)">
<span style="border:1px solid var(--color-divider);padding:2px 8px">{{ selVer }} · workflow_version 1</span>
<span style="border:1px solid var(--color-divider);padding:2px 8px">签名 {{ selSig }}</span>
<span style="border:1px solid var(--color-divider);padding:2px 8px">来源 {{ selSource }}</span>
<span style="border:1px solid var(--color-divider);padding:2px 8px">检查点:每循环</span>
<span style="border:1px solid var(--color-divider);padding:2px 8px">恢复策略 esc-default-v2</span>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 340px;gap:16px;align-items:start">
<div class="card blueprint" style-hover="border-color:var(--color-accent-400);box-shadow:var(--shadow-sm)" style="transition:border-color .15s ease,box-shadow .15s ease;padding:14px 16px;gap:4px">
<i class="corner tl"></i><i class="corner tr"></i><i class="corner bl"></i><i class="corner br"></i>
<h6 style="margin:0 0 8px;color:var(--color-neutral-700)">步骤定义 · STEPS</h6>
<sc-for list="{{ steps }}" as="st" hint-placeholder-count="10">
<div style="{{ st.rowStyle }}">
<span style="{{ st.numStyle }}">{{ st.num }}</span>
<div style="flex:1">
<div style="display:flex;align-items:center;gap:8px">
<span style="font-family:ui-monospace,Menlo,monospace;font-size:12px;font-weight:600">{{ st.name }}</span>
<sc-if value="{{ st.risk }}" hint-placeholder-val="{{ false }}"><span style="font-family:ui-monospace,Menlo,monospace;font-size:9px;background:var(--color-accent-800);color:#f2f2f3;padding:1px 6px">{{ st.risk }}</span></sc-if>
</div>
<div style="font-size:11.5px;color:var(--color-neutral-600);margin-top:1px">{{ st.note }}</div>
</div>
<span style="font-family:ui-monospace,Menlo,monospace;font-size:10px;color:var(--color-neutral-500);white-space:nowrap">{{ st.meta }}</span>
</div>
</sc-for>
<div style="border:1px dashed #b03d2e;padding:10px 12px;margin-top:10px">
<div style="font-size:10px;letter-spacing:.12em;color:#8a2e22;margin-bottom:6px">ON_FAILURE · 失败处理管道</div>
<div style="display:flex;gap:8px;align-items:center;font-family:ui-monospace,Menlo,monospace;font-size:11px;color:var(--color-neutral-800);flex-wrap:wrap">
<span style="border:1px solid var(--color-divider);padding:3px 9px;background:var(--color-bg)">evidence.capture_all</span>
<span style="color:var(--color-neutral-400)"></span>
<span style="border:1px solid var(--color-divider);padding:3px 9px;background:var(--color-bg)">recovery.escalate</span>
<span style="color:var(--color-neutral-400)"></span>
<span style="border:1px solid var(--color-divider);padding:3px 9px;background:var(--color-bg)">failure.classify</span>
<span style="font-size:10px;color:var(--color-neutral-600);margin-left:4px">取证先于恢复 · 破坏性步骤不自动重试</span>
</div>
</div>
</div>
<div style="display:flex;flex-direction:column;gap:16px">
<div class="card blueprint" style-hover="border-color:var(--color-accent-400);box-shadow:var(--shadow-sm)" style="transition:border-color .15s ease,box-shadow .15s ease;padding:12px 14px;gap:8px;border-color:var(--color-accent-600)">
<i class="corner tl"></i><i class="corner tr"></i><i class="corner bl"></i><i class="corner br"></i>
<h6 style="margin:0;color:var(--color-neutral-700)">安全声明 · SAFETY</h6>
<div style="font-family:ui-monospace,Menlo,monospace;font-size:10.5px;line-height:1.9;background:var(--color-neutral-100);border:1px solid var(--color-divider);padding:9px 11px;color:var(--color-neutral-800)">safety:<br>&nbsp;&nbsp;allowed_dut_serials: {{ selSerials }}<br>&nbsp;&nbsp;destructive_write: {{ selDestr }}<br>&nbsp;&nbsp;require_approval: true<br>&nbsp;&nbsp;system_disk_guard: enforce<br>variables:<br>&nbsp;&nbsp;cycles: {{ selCycles }}<br>&nbsp;&nbsp;firmware: "${firmware}"</div>
<div style="font-size:11px;color:var(--color-neutral-600)">Format / Sanitize / 刷写只能来自签名模板,参数受 Schema 限制</div>
</div>
<div class="card blueprint" style-hover="border-color:var(--color-accent-400);box-shadow:var(--shadow-sm)" style="transition:border-color .15s ease,box-shadow .15s ease;padding:12px 14px;gap:8px">
<i class="corner tl"></i><i class="corner tr"></i><i class="corner bl"></i><i class="corner br"></i>
<h6 style="margin:0;color:var(--color-neutral-700)">审批记录 · AUDIT</h6>
<div style="display:flex;flex-direction:column">
<sc-for list="{{ approvals }}" as="ap" hint-placeholder-count="4">
<div style="display:flex;gap:10px;padding:5px 0;border-bottom:1px solid rgba(29,31,32,.06);font-size:11.5px">
<span style="font-family:ui-monospace,Menlo,monospace;font-size:10px;color:var(--color-neutral-500);min-width:44px">{{ ap.t }}</span>
<span style="{{ ap.dotStyle }}"></span>
<span style="flex:1">{{ ap.what }}</span>
<span style="color:var(--color-neutral-600)">{{ ap.who }}</span>
</div>
</sc-for>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{&quot;$preview&quot;:{&quot;width&quot;:1440,&quot;height&quot;:880}}">
class Component extends DCLogic {
state = { sel: 0 };
renderVals() {
const mono = { fontFamily: 'ui-monospace,Menlo,monospace' };
const stOf = st => {
const b = { fontSize: '10px', padding: '2px 9px', letterSpacing: '.04em' };
if (st === '已发布') return { ...b, background: 'var(--color-accent-100)', color: 'var(--color-accent-800)' };
if (st === '审批中') return { ...b, border: '1px solid var(--color-accent-600)', color: 'var(--color-accent-700)' };
return { ...b, border: '1px dashed var(--color-neutral-500)', color: 'var(--color-neutral-700)' };
};
const T = [
{ name: 'fw_ab_powerstate_regression', ver: 'v3', status: '已发布', risks: ['破坏写', '刷写'], desc: '固件 A/B 休眠/唤醒 100 循环回归 — 首个落地 SOP', updated: '07-15', sig: '8e02…c4', source: 'SOP-FW-012(客户脱敏版)', serials: '["SAMPLE-001","SAMPLE-002"]', destr: 'true', cycles: '100',
steps: [
{ num: '01', name: 'lab.precheck', note: '安全预检 · 环境指纹 · 序列号/系统盘校验', meta: 'timeout 120s', risk: null, lvl: 0 },
{ num: '02', name: 'vendor.flash_firmware', note: 'image: ${firmware} · 哈希校验 · slot 激活', meta: 'timeout 300s · retry 1', risk: '固件更新', lvl: 0 },
{ num: '03', name: 'host.reboot', note: 'wait_for agent_online · 版本确认', meta: 'timeout 600s', risk: null, lvl: 0 },
{ num: 'L', name: 'loop · repeat ${cycles}', note: '检查点:每循环写入,失败从安全点续跑', meta: 'cycles 100', risk: null, lvl: -1 },
{ num: '·1', name: 'nvme.collect_baseline', note: 'SMART / Error Log / Telemetry 基线', meta: '30s', risk: null, lvl: 1 },
{ num: '·2', name: 'io.run_profile', note: 'profile 4k_mixed · duration 300s · QD32', meta: '写入', risk: '破坏写', lvl: 1 },
{ num: '·3', name: 'host.hibernate', note: 'S4 · 断言电源状态达成', meta: 'timeout 180s', risk: null, lvl: 1 },
{ num: '·4', name: 'host.wait_resume', note: 'RTC 唤醒 · Agent 上线', meta: 'timeout 300s', risk: null, lvl: 1 },
{ num: '·5', name: 'dut.verify_enumeration', note: '设备节点 · 链路宽度/速率断言', meta: 'retry 3', risk: null, lvl: 1 },
{ num: '·6', name: 'data.verify_hash', note: '校验集 sha256 对比 · 失败范围定位', meta: '120s', risk: null, lvl: 1 }
],
approvals: [
{ t: '07-15', what: 'v3 审核通过并发布 · 签名 8e02…c4', who: '李工 · 验证组长', kind: 'ok' },
{ t: '07-12', what: 'v3 提交审批:唤醒断言加严(+链路速率)', who: 'quan.zhang', kind: 'n' },
{ t: '07-08', what: 'v2 修订:循环 50→100 · 检查点改每循环', who: 'quan.zhang', kind: 'n' },
{ t: '06-30', what: 'v1 由 SOP-FW-012 草拟(AI 初稿+人工修订)', who: 'quan.zhang', kind: 'n' }
] },
{ name: 'fw_retention_72h', ver: 'v1', status: '审批中', risks: ['破坏写'], desc: '高温 72h 数据保持,分段校验', updated: '07-24', sig: '待签名', source: 'SOP-FW-019', serials: '["SAMPLE-004"]', destr: 'true', cycles: '3 段 ×24h',
steps: [
{ num: '01', name: 'lab.precheck', note: '含温箱通道检查', meta: 'timeout 120s', risk: null, lvl: 0 },
{ num: '02', name: 'io.write_retention_set', note: '写入 1.2TB 校验集 · 记录 LBA 映射', meta: '≈70min', risk: '破坏写', lvl: 0 },
{ num: 'L', name: 'loop · repeat 3', note: '每 24h 一段,段间校验', meta: '72h', risk: null, lvl: -1 },
{ num: '·1', name: 'chamber.hold_temp', note: '55°C 恒温 24h · 温度证据采集', meta: '24h', risk: null, lvl: 1 },
{ num: '·2', name: 'data.verify_hash', note: '分段读校验 · 错误率统计', meta: '90min', risk: null, lvl: 1 }
],
approvals: [
{ t: '07-24', what: 'v1 提交审批 · 等待验证组长', who: 'quan.zhang', kind: 'n' },
{ t: '07-22', what: 'v1 由 SOP-FW-019 草拟', who: 'quan.zhang', kind: 'n' }
] },
{ name: 'fw_coldboot_matrix', ver: 'v2', status: '已发布', risks: ['刷写'], desc: '500 次冷启动 · 枚举与启动时序断言', updated: '07-10', sig: '5fd0…9a', source: 'SOP-FW-007', serials: '["SAMPLE-006"]', destr: 'false', cycles: '500',
steps: [
{ num: '01', name: 'lab.precheck', note: '安全预检 · OOB AC 通道确认', meta: 'timeout 120s', risk: null, lvl: 0 },
{ num: 'L', name: 'loop · repeat 500', note: '冷启动矩阵', meta: 'cycles 500', risk: null, lvl: -1 },
{ num: '·1', name: 'oob.power_cycle', note: '整机 AC 断电 · 安全间隔 30s', meta: 'OOB 动作', risk: null, lvl: 1 },
{ num: '·2', name: 'host.wait_boot', note: 'POST → OS → Agent 上线计时', meta: 'timeout 600s', risk: null, lvl: 1 },
{ num: '·3', name: 'dut.verify_enumeration', note: '枚举耗时断言 <5s', meta: 'retry 0', risk: null, lvl: 1 }
],
approvals: [
{ t: '07-10', what: 'v2 审核通过并发布', who: '李工 · 验证组长', kind: 'ok' },
{ t: '07-06', what: 'v2 修订:加启动时序断言', who: 'quan.zhang', kind: 'n' }
] },
{ name: 'incoming_qc_quick', ver: 'v5', status: '草稿', risks: [], desc: '来料抽检 30min 快检(只读+短写)', updated: '今日', sig: '未签名', source: '内部模板', serials: '["批量·入库检标签"]', destr: 'false', cycles: '1',
steps: [
{ num: '01', name: 'lab.precheck', note: '批量扫码 · 序列号登记比对', meta: 'timeout 120s', risk: null, lvl: 0 },
{ num: '02', name: 'nvme.identify_baseline', note: 'Identify / SMART / 固件版本核对', meta: '60s', risk: null, lvl: 0 },
{ num: '03', name: 'io.short_stress', note: '5min 混合负载 · 温升记录', meta: '5min', risk: '破坏写', lvl: 0 },
{ num: '04', name: 'report.batch_summary', note: '批次基线对比 · 标签打印', meta: '30s', risk: null, lvl: 0 }
],
approvals: [
{ t: '今日', what: 'v5 草稿修订中(批次基线阈值)', who: 'quan.zhang', kind: 'n' }
] }
];
const sel = T[this.state.sel];
const list = T.map((tp, i) => ({
...tp,
pick: () => this.setState({ sel: i }),
stStyle: stOf(tp.status),
itemStyle: {
border: i === this.state.sel ? '1px solid var(--color-accent-600)' : '1px solid var(--color-divider)',
background: i === this.state.sel ? 'var(--color-accent-100)' : 'transparent',
padding: '11px 13px', cursor: 'pointer', transition: 'border-color .15s ease, background .15s ease'
}
}));
const steps = sel.steps.map((st, i) => {
const isLoop = st.lvl === -1;
return {
...st,
rowStyle: {
animation: 'omIn .4s cubic-bezier(.2,.7,.2,1) both', animationDelay: (i * 45) + 'ms',
display: 'flex', gap: '12px', alignItems: 'flex-start', padding: '8px 6px',
borderBottom: '1px solid rgba(29,31,32,.07)',
marginLeft: st.lvl === 1 ? '26px' : 0,
borderLeft: st.lvl === 1 ? '2px solid var(--color-accent-300)' : isLoop ? '2px solid var(--color-accent)' : '2px solid transparent',
paddingLeft: '12px',
background: isLoop ? 'var(--color-accent-100)' : 'transparent'
},
numStyle: { ...mono, minWidth: '24px', fontSize: '10.5px', color: isLoop ? 'var(--color-accent-800)' : 'var(--color-neutral-500)', paddingTop: '2px', fontWeight: isLoop ? 700 : 400 }
};
});
const approvals = sel.approvals.map(ap => ({
...ap,
dotStyle: { width: '8px', height: '8px', borderRadius: '50%', flex: 'none', marginTop: '4px', background: ap.kind === 'ok' ? 'var(--color-accent)' : 'var(--color-bg)', border: ap.kind === 'ok' ? 'none' : '1.5px solid var(--color-neutral-400)' }
}));
return {
list, steps, approvals,
selName: sel.name, selVer: sel.ver, selStatus: sel.status, selStStyle: stOf(sel.status),
selSig: sel.sig, selSource: sel.source, selSerials: sel.serials, selDestr: sel.destr, selCycles: sel.cycles,
selPublished: sel.status === '已发布'
};
}
}
</script>
</body>
</html>