Files
cmbuyer/docs/design/web-task-detail.html
T

101 lines
19 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>采购服务 · 任务详情原型</title>
<style>
:root{color-scheme:light;--bg:#f4f7fb;--panel:#fff;--text:#172033;--muted:#5f6b7c;--line:#d8e0eb;--primary:#155eef;--primary-dark:#0d47bd;--warn:#9a5b00;--warn-bg:#fff6df;--danger:#b42318;--danger-bg:#fff0ee;--ok:#16794a;--ok-bg:#eaf8f0;--focus:#ffbf47;--radius:10px;--shadow:0 12px 32px rgba(16,36,70,.1);font-family:"Segoe UI","Microsoft YaHei UI",sans-serif}
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-size:14px;line-height:1.55}.skip{position:fixed;left:12px;top:-60px;z-index:20;background:#fff;padding:10px}.skip:focus{top:8px}.prototype{background:#15233c;color:#fff;text-align:center;padding:7px;font-size:12px;letter-spacing:.05em}.topbar{height:58px;background:#fff;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:24px;padding:0 28px;position:sticky;top:0;z-index:5}.brand{font-weight:800;color:var(--text);text-decoration:none}.brand b{display:inline-grid;place-items:center;width:30px;height:30px;margin-right:8px;border-radius:7px;background:var(--primary);color:#fff}nav a{color:var(--muted);text-decoration:none;padding:17px 8px}nav a[aria-current]{color:var(--primary);border-bottom:2px solid var(--primary)}main{width:min(1180px,calc(100% - 32px));margin:0 auto;padding:22px 0 42px}.crumb{display:flex;gap:8px;margin-bottom:12px;color:var(--muted)}.crumb a{color:var(--primary)}.head{display:flex;justify-content:space-between;gap:16px;align-items:flex-start}.head h1{font-size:25px;margin:0}.head p{margin:3px 0;color:var(--muted)}.chip{white-space:nowrap;border:1px solid #a9c3f7;color:#16448f;background:#edf3ff;border-radius:999px;padding:5px 10px;font-weight:700}.safety{margin:16px 0;background:#ecf3ff;border:1px solid #b8cff6;border-left:5px solid var(--primary);padding:12px 14px;border-radius:8px}.layout{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:18px}.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow)}.panel-head,.panel-body,.side section{padding:18px 20px}.panel-head{border-bottom:1px solid var(--line)}.panel-head h2,.side h2{margin:0 0 4px;font-size:17px}.panel-head p,.side p{margin:0;color:var(--muted)}.state-panel[hidden]{display:none}.notice{margin-bottom:16px;border:1px solid #bad1f8;background:#f1f6ff;padding:12px;border-radius:8px}.notice strong{display:block}.notice.warn{border-color:#edcf8d;background:var(--warn-bg);color:#6f4300}.notice.danger{border-color:#efb7b2;background:var(--danger-bg);color:#8c1d14}.notice.ok{border-color:#a8dfc1;background:var(--ok-bg);color:#11633c}.summary{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0 0 16px}.summary div{border:1px solid var(--line);background:#f9fbfd;border-radius:8px;padding:10px}.summary dt{font-size:12px;color:var(--muted);font-weight:700}.summary dd{margin:3px 0 0;font-weight:700;overflow-wrap:anywhere}.timeline{list-style:none;margin:0 0 16px;padding:0}.timeline li{position:relative;margin-left:8px;padding:0 0 16px 24px;border-left:2px solid #b8cff6}.timeline li::before{content:"";position:absolute;left:-7px;top:3px;width:12px;height:12px;border-radius:50%;background:var(--primary)}.timeline li:last-child{border-left-color:transparent}.timeline strong{display:block}.gates{width:100%;border-collapse:collapse;margin:0 0 16px}.gates th,.gates td{padding:10px;border-bottom:1px solid var(--line);text-align:left}.gates th{font-size:12px;color:var(--muted)}.good{color:var(--ok);font-weight:800}.mono{font-family:Consolas,monospace}.evidence{margin:16px 0}.evidence svg{display:block;width:100%;height:auto;border:1px solid var(--line);border-radius:8px}.evidence figcaption{color:var(--muted);font-size:12px;margin-top:6px}.actions{display:flex;justify-content:flex-end;gap:10px;margin-top:16px}.button{min-height:42px;border-radius:7px;border:1px solid transparent;padding:9px 15px;font:inherit;font-weight:750;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;justify-content:center}.button.primary{background:var(--primary);color:#fff}.button.primary:hover{background:var(--primary-dark)}.button.secondary{background:#fff;border-color:#aab6c6;color:var(--text)}.button.danger{background:var(--danger);color:#fff}.button:disabled{cursor:not-allowed;opacity:.55}.button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:3px solid var(--focus);outline-offset:2px}.side{align-self:start;positio
@media(max-width:820px){.layout{grid-template-columns:1fr}.side{position:static}.side{display:grid;grid-template-columns:1fr 1fr}.side section+section{border-top:0;border-left:1px solid var(--line)}}
@media(max-width:600px){.topbar{padding:0 14px}.head{flex-direction:column}.summary{grid-template-columns:1fr}.side{display:block}.side section+section{border-left:0;border-top:1px solid var(--line)}.actions{flex-direction:column-reverse}.button{width:100%}.gates{display:block;overflow-x:auto;white-space:nowrap}}
@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}
</style>
</head>
<body>
<a class="skip" href="#main">跳到主要内容</a>
<div class="prototype">PROTOTYPE - 仅供枚举交互,非实现依据</div>
<header class="topbar"><a class="brand" href="web-task-workbench.html"><b aria-hidden="true">采</b>采购服务</a><nav aria-label="主导航"><a href="web-task-workbench.html" aria-current="page">采购任务</a><a href="web-task-create.html">创建任务</a></nav></header>
<main id="main">
<nav class="crumb" aria-label="面包屑"><a href="web-task-workbench.html">采购任务</a><span>/</span><span>任务详情</span></nav>
<header class="head"><div><h1>8 月仓库工作服补货</h1><p>任务 T-20260803-018 · 假数据</p></div><span class="chip" id="chip">待开始</span></header>
<div class="safety"><strong>开始采购会授权创建待付款订单;系统不会付款。</strong> 任务执行时实时通过三道价格闸门。围栏后只能调和同一提交,禁止再次点击。</div>
<div class="layout">
<section class="panel" aria-label="任务状态详情">
<div class="live" id="live" aria-live="polite"></div>
<article class="state-panel" data-panel="draft">
<header class="panel-head"><h2>待开始</h2><p>任务已保存,但尚未授权采购工具领取或创建订单。</p></header>
<div class="panel-body"><div class="notice"><strong>创建不等于授权</strong>请返回任务列表勾选任务,并点击“开始采购(只创建待付款订单)”。</div><dl class="summary"><div><dt>商品</dt><dd>goods_id 937122477375</dd></div><div><dt>颜色 / 尺码</dt><dd>黑色CHA(纯棉) / M(建议100-115)</dd></div><div><dt>数量</dt><dd>2 件</dd></div><div><dt>最高总价</dt><dd>¥40.00</dd></div></dl><div class="actions"><a class="button primary" href="web-task-workbench.html">返回列表选择并开始采购</a></div></div>
</article>
<article class="state-panel" data-panel="pending" hidden>
<header class="panel-head"><h2>已授权,等待采购工具领取</h2><p>管理员的开始采购动作已锁定任务字段和最高总价。</p></header>
<div class="panel-body"><div class="notice ok"><strong>一次性授权已创建</strong>允许采购工具按本任务创建一笔待付款订单;不授权付款。</div><dl class="summary"><div><dt>授权编号</dt><dd class="mono">AUTH-018-V2</dd></div><div><dt>任务版本</dt><dd>2</dd></div><div><dt>最高总价</dt><dd>¥40.00</dd></div><div><dt>提交围栏</dt><dd>尚未建立</dd></div></dl><p>本状态没有“机器选对了吗”按钮。规格与价格将在设备执行时实时校验。</p></div>
</article>
<article class="state-panel" data-panel="ordering" hidden>
<header class="panel-head"><h2>单趟采购执行中</h2><p>采购工具正在同一设备会话中完成规格、价格、数量和确认页校验。</p></header>
<div class="panel-body"><ol class="timeline"><li><strong>已打开目标商品</strong>App 8.17.0;goods_id 已核对</li><li><strong>已精确选择规格</strong>黑色CHA(纯棉) / M(建议100-115)</li><li><strong>闸门一通过</strong>SKU 单价 ¥12.88;数量前预检通过</li><li><strong>闸门二通过</strong>数量读回 2 件;面板总额 ¥32.76 ≤ ¥40.00</li><li><strong>尚未建立提交围栏</strong>不会点击提交订单</li></ol><div class="notice warn"><strong>无需中途人工确认</strong>任一读数变化或有歧义,系统会停止并转人工。</div></div>
</article>
<article class="state-panel" data-panel="fenced" hidden>
<header class="panel-head"><h2>提交围栏已建立</h2><p>只允许处理这一个 submission,不允许释放或再次提交。</p></header>
<div class="panel-body"><div class="notice danger"><strong>禁止重试</strong>唯一提交记录 <span class="mono">SUB-018-5A7C</span> 已占用本授权;关闭页面也不会释放。</div><table class="gates"><thead><tr><th>门禁</th><th>读取值</th><th>结论</th></tr></thead><tbody><tr><td>闸门一</td><td>单价 ¥12.88;数量前预检通过</td><td class="good">通过</td></tr><tr><td>闸门二</td><td>规格 / 数量不变;面板总额 ¥32.76 ≤ ¥40.00</td><td class="good">通过</td></tr><tr><td>闸门三</td><td>确认页 ¥32.76 = 闸门二;≤ ¥40.00</td><td class="good">通过</td></tr><tr><td>提交控件</td><td>精确唯一 1 个</td><td class="good">通过</td></tr></tbody></table><div class="actions"><button class="button primary" type="button" data-state="reconcile">查看同一提交的调和页</button></div></div>
</article>
<article class="state-panel" data-panel="reconcile" hidden>
<header class="panel-head"><h2>结果待人工调和</h2><p>订单可能已创建;当前页面只记录同一提交的核查结论。</p></header>
<div class="panel-body"><div class="notice danger"><strong>不得再次提交</strong>围栏和金额额度保持占用。请人工查看拼多多待付款列表。</div><fieldset class="radios"><legend><strong>核查结论</strong></legend><label><input type="radio" name="result" value="created">已确认创建待付款订单</label><label><input type="radio" name="result" value="not-created">已确认没有创建订单</label><label><input type="radio" name="result" value="unknown" checked>仍不明确,继续保留围栏</label></fieldset><label class="field-label" for="review-note">核查说明</label><textarea id="review-note">人工核查同一 submission(假数据)</textarea><div class="actions"><button class="button primary" id="save-review" type="button">保存调和记录</button></div></div>
</article>
<article class="state-panel" data-panel="payment" hidden>
<header class="panel-head"><h2>待付款</h2><p>订单已创建,系统尚未付款;请人工核对。</p></header>
<div class="panel-body"><figure class="evidence"><svg viewBox="0 0 760 260" role="img" aria-labelledby="ev-title ev-desc"><title id="ev-title">内部订单截图假数据</title><desc id="ev-desc">只表示证据位置,不代表真实拼多多布局。</desc><rect width="760" height="260" fill="#e8eef7"/><rect x="30" y="25" width="700" height="210" rx="10" fill="#fff" stroke="#b8c4d5"/><text x="55" y="65" fill="#526079" font-size="18">INTERNAL_RAW 截图占位 · 假数据</text><text x="55" y="115" fill="#172033" font-size="19">黑色CHA(纯棉) · M(建议100-115) · 2 件</text><text x="55" y="165" fill="#172033" font-size="24">确认页金额 ¥32.76</text><text x="55" y="205" fill="#9a5b00" font-size="18">订单已创建,尚未付款</text></svg><figcaption>原始截图只供已登录管理员查看;完整 XML 和支付凭据不上传。</figcaption></figure><div class="checks"><label><input type="checkbox" data-pay-check>商品与任务一致</label><label><input type="checkbox" data-pay-check>规格和数量一致</label><label><input type="checkbox" data-pay-check>金额不超过授权上限 ¥40.00</label><label><input type="checkbox" data-pay-check>我已在拼多多人工完成付款</label></div><div class="actions"><button class="button primary" id="mark-paid" type="button" disabled>标记为已付款并完成</button></div></div>
</article>
<article class="state-panel" data-panel="manual" hidden>
<header class="panel-head"><h2>围栏前需要人工处理</h2><p>系统已经停止,未申请围栏、未点击提交订单。</p></header>
<div class="panel-body"><div class="notice danger"><strong>闸门二未通过</strong>目标数量面板总额 ¥42.00 超过最高总价 ¥40.00;围栏未建立。</div><dl class="summary"><div><dt>失败阶段</dt><dd>规格面板 · 闸门二</dd></div><div><dt>原因码</dt><dd class="mono">GATE2_TOTAL_OVER_CAP</dd></div><div><dt>安全处置</dt><dd>停止并保留证据</dd></div><div><dt>可用动作</dt><dd>人工核查后重置为待开始或取消</dd></div></dl><div class="actions"><button class="button danger" id="reset-button" type="button">关闭旧授权并重置为待开始</button></div></div>
</article>
<article class="state-panel" data-panel="succeeded" hidden><header class="panel-head"><h2>任务已完成</h2><p>人工付款并核对后才进入终态。</p></header><div class="panel-body"><div class="notice ok"><strong>人工付款事实已记录</strong>系统没有执行付款,也没有读取支付凭据。</div><div class="actions"><a class="button primary" href="web-task-workbench.html">返回任务列表</a></div></div></article>
<article class="state-panel" data-panel="failed" hidden><header class="panel-head"><h2>任务失败</h2><p>人工调和确认本授权无法完成,围栏记录仍保留审计。</p></header><div class="panel-body"><div class="notice danger"><strong>确认未创建订单</strong>任务已终止;本页面没有重新提交入口。</div></div></article>
<article class="state-panel" data-panel="canceled" hidden><header class="panel-head"><h2>任务已取消</h2><p>取消发生在提交围栏建立前。</p></header><div class="panel-body"><p>旧授权已关闭,没有创建订单,也没有付款。</p></div></article>
</section>
<aside class="panel side" aria-label="原型状态与任务摘要">
<section><h2>原型状态</h2><p>只切换假数据,不发送请求。</p><label class="field-label" for="state-select">业务状态</label><select id="state-select"><option value="draft">DRAFT</option><option value="pending">PENDING</option><option value="ordering">ORDERING</option><option value="fenced">FENCED</option><option value="reconcile">RECONCILIATION_REQUIRED</option><option value="payment">WAITING_PAYMENT</option><option value="manual">NEEDS_MANUAL</option><option value="succeeded">SUCCEEDED</option><option value="failed">FAILED</option><option value="canceled">CANCELED</option></select></section>
<section><h2>任务要求</h2><p>黑色CHA(纯棉)<br>M(建议100-115)<br>2 件<br>最高总价 ¥40.00</p></section>
<section><h2>固定边界</h2><p>单趟实时三闸门;服务端围栏;提交一次;系统不付款。</p></section>
</aside>
</div>
</main>
<dialog id="reset-dialog" aria-labelledby="reset-title"><h2 id="reset-title">确认关闭旧授权并重置?</h2><div class="body"><p>当前没有提交围栏。旧授权会永久关闭,任务回到待开始;必须由管理员重新点击开始采购。</p></div><div class="actions"><button class="button secondary" data-close type="button">取消</button><button class="button danger" id="confirm-reset" type="button">重置为待开始</button></div></dialog>
<script>
(()=>{
'use strict';
const select=document.querySelector('#state-select');
const chip=document.querySelector('#chip');
const live=document.querySelector('#live');
const panels=[...document.querySelectorAll('[data-panel]')];
const labels={draft:'待开始',pending:'已授权待领取',ordering:'采购执行中',fenced:'提交围栏已建立',reconcile:'结果待核查',payment:'待付款',manual:'待人工处理',succeeded:'已完成',failed:'失败',canceled:'已取消'};
function show(state,message=''){panels.forEach(p=>p.hidden=p.dataset.panel!==state);select.value=state;chip.textContent=labels[state];live.textContent=message;document.querySelector('.panel').scrollIntoView({block:'start',behavior:matchMedia('(prefers-reduced-motion: reduce)').matches?'auto':'smooth'});}
select.addEventListener('change',()=>show(select.value));
document.querySelectorAll('[data-state]').forEach(b=>b.addEventListener('click',()=>show(b.dataset.state)));
document.querySelector('#save-review').addEventListener('click',()=>{live.textContent='调和记录已保存(假数据);没有发起新的设备动作。';live.scrollIntoView({block:'nearest'});});
const payChecks=[...document.querySelectorAll('[data-pay-check]')],markPaid=document.querySelector('#mark-paid');
payChecks.forEach(c=>c.addEventListener('change',()=>{markPaid.disabled=!payChecks.every(x=>x.checked);}));
markPaid.addEventListener('click',()=>show('succeeded','已记录人工付款事实;系统没有执行付款。'));
const dialog=document.querySelector('#reset-dialog');
document.querySelector('#reset-button').addEventListener('click',()=>dialog.showModal());
document.querySelector('[data-close]').addEventListener('click',()=>dialog.close());
document.querySelector('#confirm-reset').addEventListener('click',()=>{dialog.close();show('draft','旧授权已关闭;任务需重新由管理员开始采购。');});
dialog.addEventListener('click',e=>{if(e.target===dialog)dialog.close();});
show('draft');
})();
</script>
</body>
</html>