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

101 lines
19 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>采购服务 · 任务详情原型</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;position:sticky;top:76px}.side section+section{border-top:1px solid var(--line)}select,textarea{width:100%;min-height:42px;border:1px solid #aab6c6;border-radius:7px;padding:8px;background:#fff;color:var(--text);font:inherit}textarea{min-height:92px;resize:vertical}.field-label{display:block;font-weight:750;margin:12px 0 6px}.checks{display:grid;gap:8px}.checks label,.radios label{display:flex;gap:8px;align-items:flex-start}.checks input,.radios input{width:18px;height:18px}.radios{display:grid;gap:8px;border:0;padding:0;margin:10px 0}dialog{width:min(520px,calc(100% - 28px));border:0;border-radius:10px;padding:0;box-shadow:0 24px 70px rgba(0,0,0,.3)}dialog::backdrop{background:rgba(13,25,45,.55)}dialog h2{margin:0;padding:18px 20px;border-bottom:1px solid var(--line);font-size:18px}dialog .body{padding:18px 20px}dialog .actions{padding:0 20px 18px}.live:empty{display:none}.live{margin-bottom:12px;padding:10px;border-radius:7px;background:var(--ok-bg);color:var(--ok)}
@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>¥30.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>¥30.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;预计总额 ¥25.76</li><li><strong>数量已读回</strong>2 件;正在执行闸门二</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 × 2 = ¥25.76</td><td class="good">通过</td></tr><tr><td>闸门二</td><td>规格不变;¥12.88</td><td class="good">通过</td></tr><tr><td>闸门三</td><td>确认页 ¥25.76 ≤ ¥30.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">确认页金额 ¥25.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>金额不超过授权上限 ¥30.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>闸门一 ¥12.88,数量设置后重读 ¥13.20;不使用新价格继续。</div><dl class="summary"><div><dt>失败阶段</dt><dd>规格面板 · 闸门二</dd></div><div><dt>原因码</dt><dd class="mono">SKU_PRICE_CHANGED</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>最高总价 ¥30.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>