This repository has been archived on 2026-09-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BPOS-MVP/docs/SS01-客户与市场/e04-html/E04-执行工单-01-覆盖范围确认.html
xcsandClaude Opus 5 0aa2fc11b0 资料文件真产出来了;E04/I01 补到验收线,顺手填了几个「墙拦住却不给路」的坑
**资料文件全链**(用户:审核资料这一步要真产出 word/excel/md/html,前端能渲、点资料名能开)
接手时这一步一个文件都产不出来 —— S3 剧本白纸黑字写着「file_ref 本 MVP 阶段可留空」。
文件是台账那一行的投影,不另存一份:
· 声明 `file:{titleColumn,bodyColumn,formatColumn}`,它同时是授权面(没声明就点不开)
· 现造真字节 —— docx/xlsx 是自己打的 OOXML 包(zip-write:store+CRC32,零依赖)
· 读回来渲 —— 解的就是造出来那份字节,渲得出来才证明文件是真的
· 件上 `data-file-of` → 工作区二级界面(Word 纸面/Excel 网格/渲好的 md/沙箱 html)+ 下载原件
放行落地前把每一份冻进 `sys.task_asset_file`(迁移 0029):归档件点开的必须是签字那一刻
那一份,而资料落在主数据上、试跑单不落正式表 —— 不存这一份,收工后一个都点不开。
工作成果里「产出的资料」自成一摞。Markdown 富文本渲染顺带销账(仍零依赖)。

**Harness**
· 画面按「这一拍办完之后」在办的那一步挑 —— 从前拿拍首的局面决定拍尾的事:
  收掉 S4、发出 S5 的卡,而屏上还摆着 S4 的只读件,人无处可填(墙要配路第四次现形)
· 验收「重做」真能退回重做,且打回后台账没动就不许再提交(软硬两段,不锁死单子)
· 立监听的授权面是清单声明;发卡的授权面是调人预算,不是计划项
· 读工具同参重调有兜底;空转写身后还有行动就不废串;finish 的 doneWhen 按写完后的草稿算

**界面**
· 翻件与翻页各归各位(从前二选一,多卡多页时页翻不动);没得翻写「—」不写 0/0
· 工作成果详情能翻份;表宽超出能横滑(E04/I01 抄版式时把 overflow-x 抄丢了)
· 查看面灰底滚过一屏变白 —— 两条独立的路都治了(沙箱内不同色 / 弹性子项不长个)
· 测试台「取不到」不再当成「还活着」

**活动**
E04 关系覆盖、I01 品牌内容各自补到验收线:判据全读基座数、判据指向的东西摆上卡面、
样例满载且名字 ≤14 字;提交前要裁的判据搬进说明书(模型会压拍,压过之后只有说明书还在)。

验收:e2e i01 4/4、e04 3/3 全部 released,资料在办中渲得出、放行后存了档点得开;
门禁 typecheck/lint/depcruise/1628 测全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EEJX8Z7CHejvwmDQyPQuBX
2026-08-24 10:26:45 +08:00

198 lines
13 KiB
HTML
Raw Permalink 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>执行工单 1 · 覆盖范围确认 · E04 关系覆盖与关键人经营</title>
<style>
:root{
--ink:#1f2329; --ink-2:#41464e; --ink-3:#646a73; --ink-4:#8f959e;
--line:#dee0e3; --line-soft:#e8eaed; --soft:#f8f9fb;
--brand:#3370ff; --brand-deep:#245bdb; --brand-soft:#e1eaff; --brand-wash:#f0f4ff;
--human:#a9711e; --human-soft:#f6ecd8; --human-line:#e6d3a8;
--ok:#278717; --ok-soft:#e8f8e4; --danger:#d83931; --danger-soft:#feeae9;
--mono:"SF Mono",Menlo,Consolas,monospace;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:#eef1f6;color:var(--ink);font-size:14px;line-height:1.7;-webkit-font-smoothing:antialiased}
.page{margin:0;padding:0}
.card{background:#fff;overflow:hidden;border:0;border-radius:0;box-shadow:none}
.card-head{display:flex;align-items:center;gap:14px;padding:18px 22px;border-bottom:2px solid var(--ink);background:linear-gradient(120deg,#fffaf1 0%,#fff 55%,#fbf6ea 100%)}
.badge{flex:none;width:44px;height:44px;border-radius:10px;display:grid;place-items:center;background:var(--human);color:#fff;font-weight:800;font-size:13px;box-shadow:0 6px 16px rgba(169,113,30,.25)}
.tit{flex:1;min-width:0}
.tit .kick{font-size:11px;letter-spacing:.08em;color:var(--ink-4);font-weight:700}
.tit h1{margin:2px 0 0;font-size:19px;font-weight:800;line-height:1.3}
.tit .sub{font-size:12px;color:var(--ink-3);margin-top:3px}
.side{display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex:none}
.tag{font-size:11px;font-weight:800;padding:2px 10px;border-radius:999px;color:var(--human);background:var(--human-soft);border:1px solid var(--human-line)}
.step{font-size:12px;color:var(--ink-3)}
.deadline{font-size:12px;color:var(--ink-3)}
.deadline b{color:var(--danger)}
.card-bd{padding:20px 22px}
.zone{font-size:11px;font-weight:800;letter-spacing:.12em;color:var(--ink-4);margin:0 0 8px}
.zone b{color:var(--ink-3)}
.note{border:1px solid var(--line);border-left:3px solid var(--human);border-radius:8px;background:var(--soft);padding:14px 16px;margin-bottom:16px}
.note p{margin:0;font-size:13px;color:var(--ink-2)}
.note b{color:var(--ink)}
.note .done{color:var(--ok);font-weight:700}
.note .need{color:var(--human);font-weight:700}
.jc-editgate{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:14px 0 10px;padding:9px 12px;border-radius:9px;background:var(--soft);border:1px solid var(--line-soft);font-size:12px;color:var(--ink-3)}
.jc-editgate-t{flex:1 1 auto;min-width:0}
.jc-editgate-t b{color:var(--ink-2);font-weight:700}
.jc-egbtn{flex:none;display:inline-flex;align-items:center;gap:5px;cursor:pointer;border:1px solid var(--line);border-radius:7px;padding:6px 13px;font:inherit;font-size:12px;font-weight:700;color:var(--ink-2);background:#fff;transition:border-color .16s,color .16s,background .16s}
.jc-egbtn:hover{border-color:var(--brand);color:var(--brand)}
.jc-egbtn.save{color:#fff;background:var(--human);border-color:var(--human)}
.jc-egbtn.save:hover{filter:brightness(1.06);color:#fff}
.jc-editgate .eg-cancel,.jc-editgate .eg-save{display:none}
.jc-editgate.on{background:var(--human-soft);border-color:var(--human-line);color:#7c4a12}
.jc-editgate.on .eg-open{display:none}
.jc-editgate.on .eg-cancel,.jc-editgate.on .eg-save{display:inline-flex}
.tbl-wrap{border:1px solid var(--line-soft);border-radius:10px;overflow:hidden}
table{width:100%;border-collapse:collapse;font-size:12.5px}
th{text-align:left;background:var(--soft);font-size:11px;letter-spacing:.03em;font-weight:800;color:var(--ink-3);padding:9px 10px;border-bottom:1px solid var(--line)}
th.req::after{content:" *";color:var(--danger);font-size:11px}
td{padding:8px 10px;border-bottom:1px solid var(--line-soft);vertical-align:middle}
tr:last-child td{border-bottom:0}
td.rn{position:relative;width:38px;white-space:nowrap;font-family:var(--mono);font-size:11px;color:var(--ink-4);text-align:center}
.jc-vcell{display:block;font-size:12.5px;color:var(--ink);line-height:1.5;overflow-wrap:anywhere}
.jc-vcell.mono{font-family:var(--mono);font-size:11.5px;color:var(--ink-2)}
.jc-cell{display:none;width:100%;min-width:60px;border:1px solid var(--line);border-radius:6px;padding:6px 8px;font:inherit;font-size:12.5px;color:var(--ink);background:#fff}
.jc-cell.mono{font-family:var(--mono);font-size:11.5px}
.jc-cell:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-wash);outline:none}
table.on td>.jc-vcell{display:none}
table.on td>.jc-cell{display:block}
td.rn .jc-rowdel{display:none;width:22px;height:22px;margin:0 auto;cursor:pointer;border:1px solid var(--line);border-radius:6px;padding:0;font:inherit;font-size:14px;line-height:1;color:var(--ink-3);background:#fff}
td.rn .jc-rowdel:hover{border-color:var(--danger);color:var(--danger);background:var(--danger-soft)}
table.on td.rn .jc-rn-num{display:none}
table.on td.rn .jc-rowdel{display:block}
.jc-addrow{display:none;margin:8px 0 0;padding:8px 12px;border-radius:9px;background:var(--soft);border:1px dashed var(--line);font-size:12px;color:var(--ink-3)}
.jc-addrow.show{display:flex;align-items:center;gap:8px}
.jc-addrow button{cursor:pointer;border:1px solid var(--brand-soft);border-radius:7px;padding:5px 12px;font:inherit;font-size:12px;font-weight:700;color:var(--brand-deep);background:var(--brand-wash)}
.jc-addrow button:hover{background:var(--brand-soft)}
.jc-addrow em{font-style:normal;font-size:11.5px;color:var(--ink-4)}
.flow{margin-top:16px;padding:9px 12px;border-radius:8px;background:var(--soft);border:1px dashed var(--line);font-size:12px;color:var(--ink-3)}
.flow b{color:var(--ink)}
.card-foot{padding:13px 22px;border-top:1px solid var(--line-soft);font-size:11.5px;color:var(--ink-4);display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px}
@media(max-width:600px){.card-head{flex-wrap:wrap}.side{align-items:flex-start}}
</style>
</head>
<body>
<div class="page">
<div class="card">
<header class="card-head">
<div class="badge">执行</div>
<div class="tit">
<div class="kick">E04 关系覆盖与关键人经营 · 执行工单 1/2</div>
<h1>覆盖范围确认</h1>
<div class="sub">收件人:<span data-slot="meta.task.owner">AM Lead(负责人)</span> · 关联任务:<span data-slot="meta.task.id">TASK-xxx</span></div>
</div>
<div class="side">
<span class="tag">执行工单</span>
<span class="step" data-slot="meta.phase">步骤 ① 启动与覆盖范围确认</span>
<span class="deadline">最迟交回:<b data-slot="card.deadline">1 个工作日</b></span>
</div>
</header>
<div class="card-bd">
<p class="zone"><b>【做什么】</b>—— 确认本轮覆盖范围</p>
<div class="note">
<p><span class="done">AI 已完成</span>:按台账规则识别本轮触发口径与覆盖范围,产出下方客户清单(<b>候选基线</b>)。</p>
<p><span class="need">需要你查漏补缺</span>:点「编辑」直接在清单上增删改——<b>加一行 = 额外纳入</b>(AI 未识别但你有价值判断的客户)、<b>删一行 = 排除</b>(AI 纳入但实际应排除)、<b>改单元格 = 修正</b> AI 识别的内容。没有要补的直接在对话区卡里提交。</p>
</div>
<p class="zone"><b>【交回什么】</b>—— 核对后的覆盖范围客户清单(*为必填)</p>
<div class="jc-editgate" id="editgate">
<span class="jc-editgate-t"><b data-slot="sd.customer_count">AI 已识别 2 个客户</b>,点「编辑」增删改</span>
<button class="jc-egbtn eg-open" type="button">编辑</button>
<button class="jc-egbtn eg-cancel" type="button">取消</button>
<button class="jc-egbtn eg-save" type="button">保存</button>
</div>
<div class="tbl-wrap">
<table id="tbl">
<thead>
<tr>
<th style="width:38px">#</th>
<th class="req" data-h="客户编号">客户编号</th>
<th class="req" data-h="客户名称">客户名称</th>
<th data-h="客户类型">客户类型</th>
<th data-h="BT 层级">BT 层级</th>
<th data-h="状态">状态</th>
<th data-h="识别依据">识别依据 / 纳入原因</th>
<th data-h="覆盖深度">覆盖深度</th>
</tr>
</thead>
<tbody data-rows="out.customer_list">
<tr>
<td class="rn"><span class="jc-rn-num">1</span><button class="jc-rowdel" type="button" title="删除此行">×</button></td>
<td data-field="customer_id"><span class="jc-vcell mono">CUS-2025-0012</span><input class="jc-cell mono" value="CUS-2025-0012"></td>
<td data-field="customer_name"><span class="jc-vcell">AvtoKom 汽车电子</span><input class="jc-cell" value="AvtoKom 汽车电子"></td>
<td data-field="cust_type"><span class="jc-vcell mono">Tier1 OEM</span><input class="jc-cell mono" value="Tier1 OEM"></td>
<td data-field="bt_level"><span class="jc-vcell mono">BT-02</span><input class="jc-cell mono" value="BT-02"></td>
<td data-field="status"><span class="jc-vcell">正式</span><input class="jc-cell" value="正式"></td>
<td data-field="basis"><span class="jc-vcell">月度例行 + T04 攻坚联动</span><input class="jc-cell" value="月度例行 + T04 攻坚联动"></td>
<td data-field="coverage_depth"><span class="jc-vcell">决策链全节点</span><input class="jc-cell" value="决策链全节点"></td>
</tr>
<tr>
<td class="rn"><span class="jc-rn-num">2</span><button class="jc-rowdel" type="button" title="删除此行">×</button></td>
<td><span class="jc-vcell mono">CUS-2025-0027</span><input class="jc-cell mono" value="CUS-2025-0027"></td>
<td><span class="jc-vcell">Boreas 工业控制</span><input class="jc-cell" value="Boreas 工业控制"></td>
<td><span class="jc-vcell mono">模组厂</span><input class="jc-cell mono" value="模组厂"></td>
<td><span class="jc-vcell mono">BT-02</span><input class="jc-cell mono" value="BT-02"></td>
<td><span class="jc-vcell">正式</span><input class="jc-cell" value="正式"></td>
<td><span class="jc-vcell">月度例行</span><input class="jc-cell" value="月度例行"></td>
<td><span class="jc-vcell">维持性覆盖</span><input class="jc-cell" value="维持性覆盖"></td>
</tr>
</tbody>
</table>
</div>
<div class="jc-addrow" id="addrow">
<button type="button">+ 加一行(额外纳入客户)</button>
<em>新加行的「客户编号」「客户名称」为必填;「识别依据」栏填你纳入它的原因</em>
</div>
<div class="flow"><b>审批 / 提交:</b>本工单只承载内容;「提交回执」请在对话区的【执行卡】中进行。</div>
</div>
<footer class="card-foot">
<span>E04 关系覆盖与关键人经营 · 执行工单 1/2 · 覆盖范围确认</span>
<span style="font-family:'SF Mono',Menlo,Consolas,monospace">工单类型:执行 · <span data-slot="card.id">WO-E04-01</span></span>
</footer>
</div>
</div>
<script>
(function(){
var gate = document.getElementById('editgate');
var tbl = document.getElementById('tbl');
var addrow = document.getElementById('addrow');
var tbody = tbl.querySelector('tbody');
function setEdit(on){ gate.classList.toggle('on',on); tbl.classList.toggle('on',on); addrow.classList.toggle('show',on); }
gate.querySelector('.eg-open').addEventListener('click', function(){ setEdit(true); });
gate.querySelector('.eg-cancel').addEventListener('click', function(){
tbody.querySelectorAll('tr').forEach(function(tr){ tr.querySelectorAll('td').forEach(function(td){ var v=td.querySelector('.jc-vcell'),c=td.querySelector('.jc-cell'); if(v&&c){c.value=v.textContent;} }); });
setEdit(false);
});
gate.querySelector('.eg-save').addEventListener('click', function(){
tbody.querySelectorAll('tr').forEach(function(tr){ tr.querySelectorAll('td').forEach(function(td){ var v=td.querySelector('.jc-vcell'),c=td.querySelector('.jc-cell'); if(v&&c){v.textContent=c.value;} }); });
renumber(); setEdit(false);
});
addrow.querySelector('button').addEventListener('click', function(){
var tr=document.createElement('tr');
tr.innerHTML='<td class="rn"><span class="jc-rn-num"></span><button class="jc-rowdel" type="button" title="删除此行">×</button></td>'+'<td><span class="jc-vcell mono"></span><input class="jc-cell mono" placeholder="客户编号"></td>'+'<td><span class="jc-vcell"></span><input class="jc-cell" placeholder="客户名称"></td>'+'<td><span class="jc-vcell mono"></span><input class="jc-cell mono" placeholder="客户类型"></td>'+'<td><span class="jc-vcell mono"></span><input class="jc-cell mono" placeholder="BT 层级"></td>'+'<td><span class="jc-vcell"></span><input class="jc-cell" placeholder="状态"></td>'+'<td><span class="jc-vcell"></span><input class="jc-cell" placeholder="纳入原因"></td>'+'<td><span class="jc-vcell"></span><input class="jc-cell" placeholder="覆盖深度"></td>';
tbody.appendChild(tr); renumber();
});
tbody.addEventListener('click', function(e){ if(e.target.classList.contains('jc-rowdel')){ e.target.closest('tr').remove(); renumber(); } });
function renumber(){ tbody.querySelectorAll('tr').forEach(function(tr,i){ tr.querySelector('.jc-rn-num').textContent=i+1; }); }
})();
</script>
</body>
</html>