#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成《工作台结构重构方案 v0.1》自包含 HTML。

事实来源（全部现读现写，不凭印象）：
  工具/index.html 的 TABS / _grp / 分发器 case / openActivityEntry
输出：工作台结构重构方案_v0.1.html
"""
import io
import os
import sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import brand_kit as BK  # noqa: E402

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
OUT = os.path.join(ROOT, '工作台结构重构方案_v0.1.html')

# ── 现状 18 个 Tab（逐条对照 工具/index.html:734-754 手工核对）──
NOW = [
    ('dashboard', '看板', 'biz', '📊 经营', 'da/ls', '三部门逐月拆分看板（iframe）', '经营'),
    ('visitStats', '拜访视图', 'biz', '📊 经营', 'da/ls', '当月线下拜访/线上跟进次数 + 客户下钻', '经营'),
    ('orders', '订单管理', 'biz', '📊 经营', 'da/ls', '订单列表与检索', '经营'),
    ('orderEntry', '历史成交价', 'biz', '📊 经营', 'da/ls', '历史成交价查询', '经营'),
    ('customers', '客户', 'cust', '👥 客户', 'da', '客户清单与搜索', '客户'),
    ('groups', '课题组', 'cust', '👥 客户', 'ls', 'MCP 商机视图课题组', '客户'),
    ('oppSandbox', '商机沙盘', 'cust', '👥 客户', 'da', '商机推演', '客户'),
    ('visitPrep', '访前准备', 'cust', '👥 客户', 'da/ls', '拜访前准备', '客户'),
    ('specialReq', '特殊要求', 'cust', '👥 客户', 'da/ls', '客户特殊要求台账', '客户'),
    ('complaints', '客诉', 'cust', '👥 客户', 'da', '客诉台账', '客户'),
    ('activityEntry', '活动录入', 'mine', '🧑‍💼 我的', 'da/ls', '结构化录入项目/采购跟进（iframe）', '我的'),
    ('myActivities', '我的活动', 'mine', '🧑‍💼 我的', 'da/ls', '本人已提交活动列表', '我的'),
    ('todos', '待办', 'mine', '🧑‍💼 我的', 'da/ls', '对内/对外待办（活动可派生）', '我的'),
    ('expense', '报销', 'mine', '🧑‍💼 我的', 'da/ls', '报销助手', '我的'),
    ('aiAssistant', 'AI 助手', 'ai', '🤖 智能', 'da/ls', 'AI 问答与参谋', '智能'),
    ('targetsAdmin', '目标基础数据', 'other', '📌 其他', 'da/ls', '目标口径维护（adminOnly）', '其他'),
    ('dataMgmt', '数据管理', 'ai', '🤖 智能', 'da/ls', '上传与权限（adminOnly）', '其他'),
    ('training', '岗前培训', 'mine', '🧑‍💼 我的', 'da/ls', '已隐藏（2026-09-05）', '—'),
]

# ── 新结构：两大域 + 个人/智能 ──
NEWMAP = {
    'dashboard':    ('经营', '📊 看板', '不变'),
    'visitStats':   ('经营', '📈 拜访与活动', '★ 融合 visitStats+activityEntry+myActivities'),
    'orders':       ('经营', '📦 订单与业绩', '★ 与「历史成交价」并为一个 Tab 的两个二级视图'),
    'orderEntry':   ('经营', '📦 订单与业绩 › 历史成交价', '★ 降为二级视图'),
    'complaints':   ('经营', '🔴 客诉', '从「客户」移入（客诉是经营质量指标）'),
    'targetsAdmin': ('经营', '🎯 目标基础数据', '从「其他」移入，adminOnly 不变'),
    'dataMgmt':     ('经营', '📤 数据管理', '从「智能」移入经营（它是经营数据的上游）'),
    'customers':    ('客户', '📋 客户', '不变'),
    'groups':       ('客户', '🔬 课题组', '不变'),
    'oppSandbox':   ('客户', '🎯 商机沙盘', '不变'),
    'visitPrep':    ('客户', '📝 访前准备', '不变（主体是客户；融合页给「去前准备」入口）'),
    'specialReq':   ('客户', '⭐ 特殊要求', '不变'),
    'todos':        ('我的', '✅ 待办', '不变（保持个人事务属性）'),
    'expense':      ('我的', '🧾 报销', '不变'),
    'aiAssistant':  ('智能', '🤖 AI 助手', '不变'),
    'myActivities': ('—', '（下线）', '★ 与融合页的活动列表重复，建议下线'),
    'activityEntry': ('—', '（并入融合页）', '★ 作为「录」态，不再是独立 Tab；保留深链'),
    'training':     ('—', '（保持隐藏）', '不变'),
}

DOMAINS = [
    ('📊 经营管理', '#1F4E9C', '管业务结果与过程：看板 · 拜访与活动 · 订单与业绩 · 客诉 · 目标 · 数据',
     ['看板', '拜访与活动', '订单与业绩', '客诉', '目标基础数据', '数据管理']),
    ('👥 客户管理', '#002FA7', '管客户资产：以客户/课题组为主体，不做过程统计',
     ['客户', '课题组', '商机沙盘', '访前准备', '特殊要求']),
    ('🧑‍💼 我的', '#5f6368', '只放个人事务，不放业务作业',
     ['待办', '报销']),
    ('🤖 智能', '#7c3aed', 'AI 能力',
     ['AI 助手']),
]

QUESTIONS = [
    ('Q1', '「经营 / 客户」两分够不够？',
     '我建议保留四域：<b>经营 · 客户 · 我的 · 智能</b>。把「我的」留成<b>纯个人事务</b>（只放待办、报销），'
     '业务作业一律不进「我的」——现在「活动录入/我的活动」放这里就是域混了。',
     'A 四域（推荐）｜B 只分经营/客户两域，其余塞「其他」｜C 你有别的分法'),
    ('Q2', '融合页里，「看」的默认范围按谁？',
     '拜访统计的口径要定死：销售看自己、管理者看全队？还是所有人默认只看自己、管理者手动切？'
     '这决定接口要不要按角色返回不同范围（现在是按 <code>_act_visible_sales</code> 过滤，admin/gm 不限）。',
     'A 销售=自己 / 管理者=全队（推荐）｜B 所有人默认自己，管理者手动切｜C 一律只看自己'),
    ('Q3', '「我的活动」直接下线吗？',
     '融合页的活动列表就是「我的活动 + 团队活动」，这页已冗余。下线它我能顺带清掉一处重复实现。',
     'A 下线（推荐）｜B 保留为融合页的「只看我的」二级视图｜C 先留着'),
    ('Q4', '「访前准备」留在客户管理，还是并进拜访流程？',
     '我建议<b>留在客户管理</b>（它回答「这个客户怎么打」）；但在融合页给一个「去前准备」入口，'
     '把「准备 → 拜访 → 跟进」串起来。',
     'A 留客户管理 + 融合页放入口（推荐）｜B 整体并进融合页'),
    ('Q5', '「订单管理 + 历史成交价」合并成一个 Tab？',
     '两者都是「查单/查价」，合并后一个 Tab 两个二级视图（订单 / 成交价），侧栏少一项、语义更整。',
     'A 合并（推荐）｜B 保持两个独立 Tab'),
    ('Q6', '「客诉」从客户域移到经营域，同意吗？',
     '客诉发生在客户身上，但它是<b>经营质量指标</b>（要考核、要统计）。我建议移入经营，客户档案里仍能看该客户的客诉。',
     'A 移入经营（推荐）｜B 留在客户域'),
    ('Q7', '移动端底栏固定哪 4 项？',
     '现在固定 看板/客户/AI助手/待办。融合后我建议改成 <b>拜访与活动 / 客户 / 待办 / AI助手</b>'
     '（一线最高频的是记录拜访，看板是管理动作、不该占底栏）。',
     'A 拜访与活动/客户/待办/AI（推荐）｜B 维持现状｜C 你指定'),
    ('Q8', '谁验收、谁试点？',
     '这是全公司 30 人的入口，改完我建议：先给 <b>1 个管理者（你）+ 1–2 个一线销售</b> 试 3 天，再全员放开。',
     'A 你 + 1–2 名销售试点 3 天（推荐）｜B 直接全员｜C 只给管理者看'),
]

PHASES = [
    ('P0', '导航重构（纯前端，零数据风险）',
     '改 TABS 的 group 与分组定义；下线「我的活动」；订单+成交价合并；侧栏/底栏重排。'
     '<b>不改任何数据与接口</b>，出问题一条命令回滚。',
     '我（脚本 + 双入口同改 + CDN 部署 + 回读校验）', '约 0.5 天'),
    ('P1', '「拜访与活动」融合页',
     '把 renderVisitStats 升级为双态页：<b>看</b>（KPI + 12 月趋势 + 活动列表 + 客户下钻）与'
     '<b>录</b>（内嵌现活动录入页 iframe）。顶部一个「＋ 记一次」切态；'
     '<code>openActivityEntry(客户名)</code> 深链直接进「录」态并带客户。',
     '我（外壳改造 + 录入页仅加一个「进融合页」回调）', '约 1–1.5 天'),
    ('P2', '经营域的两处收口',
     '客诉移入经营并加「按客户看客诉」；访前准备加「去前准备」跳转；'
     '目标/数据管理归位。',
     '我（导航 + 少量跳转）', '约 0.5 天'),
    ('P3', '试点与全员',
     '按 Q8 试点 3 天，收集「找不到入口」类反馈再全员放开。',
     '你定试点人；我出 1 页上手图', '3 天观察'),
]


def esc(s):
    return (str(s if s is not None else '')
            .replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;'))


def main():
    # 现状表
    now_rows = ''.join(
        '<tr><td class="c">%s</td><td class="c">%s</td><td class="c">%s</td><td class="c">%s</td>'
        '<td>%s</td><td class="c">%s</td></tr>'
        % (i + 1, esc(t[4]), esc(t[3]), esc(t[1]), esc(t[5]), esc(t[6]))
        for i, t in enumerate(NOW))

    # 归属对照
    map_rows = ''.join(
        '<tr><td class="c">%s</td><td class="c">%s</td><td class="c now">%s</td><td class="c new">%s</td><td>%s</td></tr>'
        % (esc(t[1]), esc(t[6]), esc(NEWMAP[t[0]][0]), esc(NEWMAP[t[0]][1]), esc(NEWMAP[t[0]][2]))
        for t in NOW)

    # 域卡片
    dom_html = ''
    for name, color, desc, tabs in DOMAINS:
        dom_html += ('<div class="dom" style="border-left-color:%s"><div class="dom-h" style="color:%s">%s</div>'
                     '<div class="dom-d">%s</div><div class="dom-t">%s</div></div>'
                     % (color, color, esc(name), esc(desc),
                        ''.join('<span class="chip2">%s</span>' % esc(x) for x in tabs)))

    # 问题卡
    q_html = ''
    for qid, q, why, opts in QUESTIONS:
        q_html += ('<div class="q"><div class="q-h"><span class="qid">%s</span>%s</div>'
                   '<div class="q-w">%s</div><div class="q-o">%s</div></div>'
                   % (esc(qid), q, why, esc(opts)))

    # 分期
    ph_html = ''.join(
        '<tr><td class="c"><b>%s</b></td><td><b>%s</b><div class="sub">%s</div></td>'
        '<td class="c">%s</td><td class="c">%s</td></tr>'
        % (esc(a), esc(b), c, esc(d), esc(e)) for a, b, c, d, e in PHASES)

    html = '''<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>工作台结构重构方案 v0.1</title>
<style>
:root{--pri:#1F4E9C;--ikb:#002FA7;--ink:#1f2328;--sub:#5f6368;--line:#e5e7eb;--bg:#f6f8fb}
*{box-sizing:border-box}
body{margin:0;font:14px/1.75 -apple-system,"PingFang SC","Microsoft YaHei",sans-serif;color:var(--ink);background:var(--bg)}
.wrap{max-width:1220px;margin:0 auto;padding:22px}
.hero{background:linear-gradient(120deg,#1F4E9C,#002FA7);color:#fff;border-radius:14px;padding:26px 28px;margin-bottom:18px}
.hero h1{margin:0 0 8px;font-size:24px}
.hero p{margin:5px 0;opacity:.94;font-size:13.5px}
.hero .v{display:inline-block;margin-top:10px;background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.35);border-radius:999px;padding:3px 12px;font-size:12px}
.card{background:#fff;border:1px solid var(--line);border-radius:12px;padding:18px 20px;margin-bottom:16px}
.card h2{font-size:17px;margin:0 0 12px;padding-left:10px;border-left:4px solid var(--pri)}
.card h3{font-size:14.5px;margin:16px 0 8px;color:var(--pri)}
table{width:100%;border-collapse:collapse;font-size:13px}
th,td{padding:7px 8px;border-bottom:1px solid var(--line);vertical-align:top;text-align:left}
th{background:#f2f5fa;font-size:12px;color:var(--sub)}
td.c{text-align:center;white-space:nowrap}
td.now{color:var(--sub)}
td.new{color:var(--ikb);font-weight:700}
.sub{font-size:12.5px;color:var(--sub)}
.two{display:grid;grid-template-columns:repeat(auto-fit,minmax(420px,1fr));gap:14px}
.dom{border:1px solid var(--line);border-left:5px solid var(--pri);border-radius:10px;padding:13px 15px;background:#fff}
.dom-h{font-weight:800;font-size:15px;margin-bottom:4px}
.dom-d{font-size:12.5px;color:var(--sub);margin-bottom:9px}
.chip2{display:inline-block;background:#eef3fb;color:#1F4E9C;border-radius:999px;padding:2px 10px;margin:2px 4px 2px 0;font-size:12px}
.q{border:1px solid var(--line);border-radius:10px;padding:13px 15px;margin-bottom:11px;background:#fff}
.q-h{font-weight:700;font-size:14px;margin-bottom:5px}
.qid{display:inline-block;background:var(--pri);color:#fff;border-radius:6px;padding:1px 7px;margin-right:8px;font-size:12px}
.q-w{font-size:13px;color:#3c4043;margin-bottom:7px}
.q-o{font-size:12.5px;color:#0d904f;background:#f2fbf5;border-left:3px solid #0d904f;padding:5px 9px;border-radius:0 5px 5px 0}
.warn{background:#fff8f2;border:1px solid #ffe0c2;border-radius:10px;padding:12px 14px;font-size:13px}
.ok{background:#f2fbf5;border:1px solid #cdebd9;border-radius:10px;padding:12px 14px;font-size:13px}
.bad{background:#fff4f4;border:1px solid #ffd6d6;border-radius:10px;padding:12px 14px;font-size:13px}
.figw{background:#fbfcfe;border:1px solid var(--line);border-radius:10px;padding:12px;margin:12px 0;overflow-x:auto}
.figw svg{display:block;margin:0 auto;min-width:660px}
/* 原型 */
.proto{display:grid;grid-template-columns:190px 1fr;border:1px solid var(--line);border-radius:12px;overflow:hidden;background:#fff;min-height:430px}
.pnav{background:#0f172a;color:#cbd5e1;padding:12px 0;font-size:12.5px}
.pnav .g{padding:9px 14px 3px;font-size:10px;color:#64748b;letter-spacing:.08em;font-weight:800}
.pnav .it{padding:6px 14px;cursor:pointer;border-left:3px solid transparent}
.pnav .it:hover{background:#1e293b}
.pnav .it.on{background:#1e293b;color:#fff;border-left-color:#38bdf8;font-weight:700}
.pbody{padding:14px 16px}
.ptabs{display:flex;gap:8px;margin-bottom:12px}
.ptab{padding:5px 14px;border:1px solid var(--line);border-radius:999px;font-size:12.5px;cursor:pointer}
.ptab.on{background:var(--pri);color:#fff;border-color:var(--pri);font-weight:700}
.kpi{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:12px}
.kbox{flex:1;min-width:120px;border:1px solid var(--line);border-left:4px solid var(--pri);border-radius:9px;padding:10px 12px}
.kbox .n{font-size:22px;font-weight:800;color:var(--pri);line-height:1.25}
.kbox .t{font-size:11.5px;color:var(--sub)}
.mock{border:1px solid var(--line);border-radius:9px;overflow:hidden}
.mock .row{display:flex;justify-content:space-between;padding:7px 10px;border-bottom:1px solid #f1f3f4;font-size:12.5px}
.mock .row:last-child{border-bottom:none}
.tag2{display:inline-block;border-radius:5px;padding:1px 7px;font-size:11.5px;font-weight:700}
.t-off{background:#e8f0fe;color:#1F4E9C}.t-on{background:#f1f3f4;color:#5f6368}
.muted{color:var(--sub);font-size:12px}
</style></head><body>
<div class="wrap">

<div class="hero">
  <h1>工作台结构重构方案 · 经营 vs 客户</h1>
  <p>两件事一起答：<b>为什么「拜访视图 + 活动录入」必须融合</b>，以及<b>导航该怎么按「经营管理 / 客户管理」重分</b>。</p>
  <p>下面每一条现状都是现读 <code>工具/index.html</code> 核出来的，不是回忆。</p>
  <div class="v">v0.1 · 待你拍板 · 2026-10-07</div>
</div>

<div class="card">
  <h2>一、一句话结论</h2>
  <div class="bad">
    <b>现在的病根是一条：同一件事被拆到两个域。</b><br>
    「拜访视图」在 <b>📊 经营</b>、「活动录入」在 <b>🧑‍💼 我的</b>，
    而「我的活动」又在「我的」——<b>记一次拜访</b>和<b>看拜访的账</b>被硬生生分成两个 Tab，
    中间还夹着一个重复的列表页。用户要从「我的」跳到「经营」才能看完一件事，
    这就是你说「应该融合」的根源。
  </div>
  <div class="ok" style="margin-top:10px">
    <b>做法两句：</b>① 把「拜访视图 + 活动录入 + 我的活动」合成一个页面的两态（<b>看 / 录</b>）；
    ② 导航按<b>「管理什么」</b>分域——<b>经营</b>管业务结果与过程，<b>客户</b>管客户资产，
    <b>我的</b>只放个人事务。
  </div>
</div>

<div class="card">
  <h2>二、现状盘点：18 个 Tab 的真实归属</h2>
  <p class="sub">读自 <code>工具/index.html</code> 第 734–754 行（含 1 个已隐藏的「岗前培训」）。</p>
  <table><thead><tr><th class="c" style="width:38px">#</th><th class="c" style="width:64px">业务线</th>
  <th class="c" style="width:78px">当前分组</th><th class="c" style="width:88px">Tab</th>
  <th>在做什么</th><th class="c" style="width:60px">我的归类</th></tr></thead>
  <tbody>__NOW__</tbody></table>
  <h3>三个具体症状（都能在表里对上）</h3>
  <div class="warn">
    <b>① 域混：</b>「活动录入 / 我的活动」是<b>业务作业</b>，却放在「我的」；「客诉」是<b>经营指标</b>，却放在「客户」。<br>
    <b>② 重复：</b>「我的活动」＝融合页活动列表的子集，是重复实现。<br>
    <b>③ 入口错位：</b>「拜访视图」只让人<b>看</b>，却不给<b>记</b>；「活动录入」只让人<b>录</b>，却不给<b>看回自己录了什么</b>。
  </div>
</div>

<div class="card">
  <h2>三、新结构：两大域 + 个人 / 智能</h2>
  <div class="two">__DOMS__</div>
  <h3>逐个 Tab 的归属对照</h3>
  <table><thead><tr><th class="c" style="width:96px">Tab</th><th class="c" style="width:78px">原分组</th>
  <th class="c" style="width:64px">新域</th><th class="c" style="width:190px">新位置</th><th>理由</th></tr></thead>
  <tbody>__MAP__</tbody></table>
  <p class="sub">结果：可见 Tab 从 <b>17 → 14</b>（下线「我的活动」、合并订单与成交价、活动录入并入融合页）。</p>
</div>

<div class="card">
  <h2>四、「拜访与活动」融合页：一页两态</h2>
  <div class="figw">__FIG_FLOW__</div>
  <div class="two">
    <div>
      <h3>「看」态（原拜访视图，加强）</h3>
      <ul class="sub">
        <li>顶部 KPI：<b>线下拜访次数 / 线上跟进次数 / 当月活动合计</b>（口径已定：只给次数）</li>
        <li>新增 <b>12 个月趋势</b>（接口已返回 <code>months</code>，现成）</li>
        <li>活动列表：按 客户 / 日期 / 形式 筛选；点客户展开活动明细 → 「看详情」出飞书文本</li>
        <li>右上角 <b>「＋ 记一次拜访/跟进」</b> → 切到「录」态</li>
        <li>管理视角（按 Q2 定）：销售看自己，管理者可切全队</li>
      </ul>
    </div>
    <div>
      <h3>「录」态（原活动录入，原样内嵌）</h3>
      <ul class="sub">
        <li>直接内嵌现有 <code>工具/活动录入.html</code>（iframe，<b>表单一行不改</b>）</li>
        <li>录完提交 → 回到「看」态并<b>自动刷新计数</b>（不必再切 Tab）</li>
        <li>活动里的「下一步计划」「问题现象」→ <b>待办</b>（P1 已打通，本方案直接复用）</li>
        <li>深链：<code>openActivityEntry(客户名)</code> → 直达「录」态并带客户</li>
      </ul>
    </div>
  </div>
  <h3>线框：一页两态怎么摆</h3>
  <div class="figw">__FIG_WIRE__</div>
</div>

<div class="card">
  <h2>五、可点击原型（示意数据，非真实客户）</h2>
  <p class="sub">点左侧导航看新分组；点「看 / 录」切两态——这就是重构后的手感。</p>
  <div class="proto">
    <div class="pnav" id="pnav"></div>
    <div class="pbody">
      <div class="ptabs">
        <div class="ptab on" data-st="see" onclick="pSwitch('see')">👀 看（拜访视图）</div>
        <div class="ptab" data-st="rec" onclick="pSwitch('rec')">✍️ 录（活动录入）</div>
      </div>
      <div id="pSee">
        <div class="kpi">
          <div class="kbox"><div class="t">线下拜访次数</div><div class="n">52</div><div class="t">当月</div></div>
          <div class="kbox"><div class="t">线上跟进次数</div><div class="n">74</div><div class="t">当月</div></div>
          <div class="kbox"><div class="t">当月活动合计</div><div class="n">126</div><div class="t">全部已标形式</div></div>
        </div>
        <div class="mock">
          <div class="row"><span><b>某某诊断科技有限公司</b></span><span><span class="tag2 t-off">线下 2</span> <span class="tag2 t-on">线上 1</span></span></div>
          <div class="row"><span><b>某某生物（上海）有限公司</b></span><span><span class="tag2 t-off">线下 1</span> <span class="tag2 t-on">线上 3</span></span></div>
          <div class="row"><span><b>某某医学检验实验室</b></span><span><span class="tag2 t-off">线下 1</span> <span class="tag2 t-on">线上 0</span></span></div>
        </div>
        <p class="muted" style="margin-top:8px">↑ 示意数据。真实页里点客户会展开活动明细，再点「看详情」出该活动的飞书文本。</p>
      </div>
      <div id="pRec" style="display:none">
        <div class="mock">
          <div class="row"><span>活动形式 <span style="color:#d93025">*</span></span><span><span class="tag2 t-off">线下拜访</span> / 线上跟进</span></div>
          <div class="row"><span>客户</span><span class="muted">某某诊断科技有限公司</span></div>
          <div class="row"><span>客户需求 / 技术参数 / 问题现象</span><span class="muted">…（现有表单原样）</span></div>
          <div class="row"><span>关联订单</span><span class="muted">发货单 1 ｜ 测试单 1</span></div>
          <div class="row"><span>待办确认</span><span><span class="tag2 t-on">2 条待确认</span></span></div>
        </div>
        <p class="muted" style="margin-top:8px">↑ 这里就是现在的「活动录入」页，只是从独立 Tab 变成融合页的「录」态。</p>
      </div>
    </div>
  </div>
</div>

<div class="card">
  <h2>六、影响面与风险（改之前先认账）</h2>
  <table><thead><tr><th style="width:150px">面</th><th>要动什么</th><th class="c" style="width:70px">风险</th></tr></thead>
  <tbody>
    <tr><td>导航</td><td><code>TABS</code> 的 <code>group</code> + 分组定义 <code>_grp</code> + 移动端底栏 <code>_keep</code>；
        <b>两个入口（index.html / app.html）必须同改</b></td><td class="c">低</td></tr>
    <tr><td>深链</td><td><code>openActivityEntry(客户名)</code> 从拜访卡带客户跳进来 → 融合后要能<b>直达「录」态并带客户</b>，
        否则拜访卡的「新建拜访纪要」会落到「看」态</td><td class="c">中</td></tr>
    <tr><td>接口</td><td><code>/api/visit/stats</code> 按 Q2 决定要不要给管理者更大范围；<b>不改数据结构</b></td><td class="c">低</td></tr>
    <tr><td>部署</td><td>这三个 HTML 在 CDN 上（<code>/workbench/index.html</code>、<code>/workbench/app.html</code>、
        <code>/工具/活动录入.html</code>）：<b>改完必须部署 + 回读比 md5</b>，
        且外壳引用录入页的 <code>?v=</code> 要同步升版</td><td class="c">中</td></tr>
    <tr><td>权限</td><td><code>targetsAdmin</code>/<code>dataMgmt</code> 的 <code>adminOnly</code> 不变；
        客诉换域不改可见性（<code>lines:['da']</code> 保持）</td><td class="c">低</td></tr>
    <tr><td>使用习惯</td><td>30 人的肌肉记忆要换位置——<b>这是最大风险，不是技术风险</b>。
        所以建议先试点（Q8），并在侧栏保留一周的「改名提示」气泡</td><td class="c">高</td></tr>
  </tbody></table>
</div>

<div class="card">
  <h2>七、分期与主责</h2>
  <table><thead><tr><th class="c" style="width:56px">期</th><th>内容</th>
  <th class="c" style="width:200px">主责</th><th class="c" style="width:90px">工作量</th></tr></thead>
  <tbody>__PH__</tbody></table>
  <p class="sub">顺序有依赖：<b>P1 融合页依赖 P0 的导航位</b>；P2 是收口，不影响前两期可用。</p>
</div>

<div class="card">
  <h2>八、需要你拍板（8 问，带我的建议）</h2>
  <p class="sub">每条都写了我的推荐。你可以只回「<b>都按建议</b>」，或指定要改的那几条编号。</p>
  __QS__
</div>

</div>
<script>
var NAV=[
 ['📊 经营管理',['看板','拜访与活动','订单与业绩','客诉','目标基础数据','数据管理']],
 ['👥 客户管理',['客户','课题组','商机沙盘','访前准备','特殊要求']],
 ['🧑‍💼 我的',['待办','报销']],
 ['🤖 智能',['AI 助手']]
];
(function renderNav(){
  var h='';
  NAV.forEach(function(g){
    h+='<div class="g">'+g[0]+'</div>';
    g[1].forEach(function(t){
      var on=(t==='拜访与活动');
      h+='<div class="it'+(on?' on':'')+'" onclick="pNav(this)">'+t+'</div>';
    });
  });
  document.getElementById('pnav').innerHTML=h;
})();
function pNav(el){
  Array.prototype.forEach.call(document.querySelectorAll('#pnav .it'),function(x){x.classList.remove('on')});
  el.classList.add('on');
  var t=el.textContent;
  if(t!=='拜访与活动'){ alert('原型只演示「拜访与活动」一页；其余 Tab 结构见上面第三节。'); }
}
function pSwitch(st){
  Array.prototype.forEach.call(document.querySelectorAll('.ptab'),function(x){
    x.classList.toggle('on', x.getAttribute('data-st')===st);
  });
  document.getElementById('pSee').style.display=(st==='see')?'':'none';
  document.getElementById('pRec').style.display=(st==='rec')?'':'none';
}
</script>
</body></html>'''

    # 流程图 SVG
    fig_flow = '''<svg viewBox="0 0 1060 250" width="100%" height="250" role="img" aria-label="活动与拜访与待办的数据流">
  <defs><marker id="ar" markerWidth="9" markerHeight="9" refX="8" refY="3" orient="auto">
    <path d="M0,0 L0,6 L8,3 z" fill="#1F4E9C"/></marker></defs>
  <rect x="16" y="86" width="196" height="76" rx="10" fill="#e8f0fe" stroke="#1F4E9C"/>
  <text x="114" y="114" font-size="13.5" font-weight="800" fill="#0F3A8A" text-anchor="middle">「录」态 · 活动录入</text>
  <text x="114" y="134" font-size="11.5" fill="#5f6368" text-anchor="middle">活动形式必填 / 关联订单</text>
  <text x="114" y="151" font-size="11.5" fill="#5f6368" text-anchor="middle">下一步计划 · 问题现象</text>

  <line x1="212" y1="124" x2="286" y2="124" stroke="#1F4E9C" stroke-width="2" marker-end="url(#ar)"/>

  <rect x="292" y="86" width="196" height="76" rx="10" fill="#fff" stroke="#1F4E9C"/>
  <text x="390" y="114" font-size="13.5" font-weight="800" fill="#0F3A8A" text-anchor="middle">活动落库</text>
  <text x="390" y="134" font-size="11.5" fill="#5f6368" text-anchor="middle">本地 + CloudBase 双写</text>
  <text x="390" y="151" font-size="11.5" fill="#5f6368" text-anchor="middle">channel=offline / online</text>

  <line x1="488" y1="124" x2="562" y2="124" stroke="#1F4E9C" stroke-width="2" marker-end="url(#ar)"/>

  <rect x="568" y="52" width="216" height="72" rx="10" fill="#e8f0fe" stroke="#1F4E9C"/>
  <text x="676" y="78" font-size="13" font-weight="800" fill="#0F3A8A" text-anchor="middle">「看」态 · 拜访与活动</text>
  <text x="676" y="98" font-size="11.5" fill="#5f6368" text-anchor="middle">线下拜访次数 / 线上跟进次数</text>
  <text x="676" y="115" font-size="11.5" fill="#5f6368" text-anchor="middle">按客户下钻（同页）</text>

  <rect x="568" y="140" width="216" height="72" rx="10" fill="#f2fbf5" stroke="#0d904f"/>
  <text x="676" y="166" font-size="13" font-weight="800" fill="#0b6b3a" text-anchor="middle">待办（已打通）</text>
  <text x="676" y="186" font-size="11.5" fill="#5f6368" text-anchor="middle">确认清单 → 只落已确认</text>
  <text x="676" y="203" font-size="11.5" fill="#5f6368" text-anchor="middle">指纹幂等 · 不碰人的动作</text>

  <line x1="784" y1="92" x2="852" y2="92" stroke="#1F4E9C" stroke-width="2" marker-end="url(#ar)"/>
  <line x1="784" y1="172" x2="852" y2="172" stroke="#0d904f" stroke-width="2" marker-end="url(#ar)"/>

  <rect x="858" y="72" width="186" height="140" rx="10" fill="#fff" stroke="#cbd5e1" stroke-dasharray="5 4"/>
  <text x="951" y="100" font-size="12.5" font-weight="700" fill="#5f6368" text-anchor="middle">同一份数据</text>
  <text x="951" y="122" font-size="11.5" fill="#5f6368" text-anchor="middle">不再两处维护</text>
  <line x1="880" y1="136" x2="1022" y2="136" stroke="#e5e7eb"/>
  <text x="951" y="158" font-size="11.5" fill="#5f6368" text-anchor="middle">融合页只改「怎么摆」</text>
  <text x="951" y="178" font-size="11.5" fill="#5f6368" text-anchor="middle">活动结构 / 待办逻辑不动</text>
  <text x="951" y="198" font-size="11.5" fill="#9aa0a6" text-anchor="middle">零数据风险</text>
</svg>'''

    # 线框 SVG：三态
    fig_wire = '''<svg viewBox="0 0 1060 320" width="100%" height="320" role="img" aria-label="融合页三态线框">
  <!-- 态1 看 -->
  <rect x="10" y="30" width="330" height="272" rx="10" fill="#fff" stroke="#1F4E9C"/>
  <rect x="10" y="30" width="330" height="30" rx="10" fill="#1F4E9C"/>
  <text x="175" y="50" font-size="12.5" font-weight="800" fill="#fff" text-anchor="middle">① 看：拜访与活动</text>
  <rect x="24" y="72" width="96" height="44" rx="7" fill="#eef3fb" stroke="#c7d7ee"/>
  <text x="72" y="92" font-size="15" font-weight="800" fill="#1F4E9C" text-anchor="middle">52</text>
  <text x="72" y="107" font-size="9.5" fill="#5f6368" text-anchor="middle">线下拜访</text>
  <rect x="128" y="72" width="96" height="44" rx="7" fill="#eef3fb" stroke="#c7d7ee"/>
  <text x="176" y="92" font-size="15" font-weight="800" fill="#002FA7" text-anchor="middle">74</text>
  <text x="176" y="107" font-size="9.5" fill="#5f6368" text-anchor="middle">线上跟进</text>
  <rect x="232" y="72" width="94" height="44" rx="7" fill="#f1f3f4" stroke="#dcdcdc"/>
  <text x="279" y="92" font-size="15" font-weight="800" fill="#5f6368" text-anchor="middle">126</text>
  <text x="279" y="107" font-size="9.5" fill="#5f6368" text-anchor="middle">合计</text>
  <text x="24" y="137" font-size="10.5" fill="#5f6368">12 个月趋势 ▁▂▃▅▆▇█▇▆▅▆▇</text>
  <rect x="24" y="148" width="302" height="1" fill="#e5e7eb"/>
  <rect x="24" y="158" width="302" height="26" rx="6" fill="#fafbfc" stroke="#e5e7eb"/>
  <text x="34" y="175" font-size="10.5" fill="#3c4043">客户 A　　　　　线下 2 ｜ 线上 1</text>
  <rect x="24" y="188" width="302" height="26" rx="6" fill="#fafbfc" stroke="#e5e7eb"/>
  <text x="34" y="205" font-size="10.5" fill="#3c4043">客户 B　　　　　线下 1 ｜ 线上 3</text>
  <rect x="24" y="218" width="302" height="26" rx="6" fill="#fafbfc" stroke="#e5e7eb"/>
  <text x="34" y="235" font-size="10.5" fill="#3c4043">客户 C　　　　　线下 1 ｜ 线上 0</text>
  <rect x="200" y="256" width="126" height="30" rx="8" fill="#1F4E9C"/>
  <text x="263" y="275" font-size="11" font-weight="700" fill="#fff" text-anchor="middle">＋ 记一次拜访</text>
  <text x="24" y="276" font-size="10" fill="#9aa0a6">点客户 → 展开明细 → 看详情</text>

  <!-- 箭头 -->
  <path d="M348 166 L392 166" stroke="#1F4E9C" stroke-width="2" marker-end="url(#ar)"/>
  <path d="M592 166 L636 166" stroke="#0d904f" stroke-width="2" marker-end="url(#ar)"/>
  <text x="370" y="158" font-size="10" fill="#1F4E9C" text-anchor="middle">切态</text>
  <text x="614" y="158" font-size="10" fill="#0d904f" text-anchor="middle">提交</text>

  <!-- 态2 录 -->
  <rect x="398" y="30" width="188" height="272" rx="10" fill="#fff" stroke="#1F4E9C"/>
  <rect x="398" y="30" width="188" height="30" rx="10" fill="#0F3A8A"/>
  <text x="492" y="50" font-size="12.5" font-weight="800" fill="#fff" text-anchor="middle">② 录</text>
  <text x="410" y="78" font-size="10" fill="#5f6368">活动形式 *</text>
  <rect x="410" y="84" width="164" height="20" rx="5" fill="#eef3fb" stroke="#c7d7ee"/>
  <text x="418" y="98" font-size="10" fill="#1F4E9C">线下拜访 ▾</text>
  <text x="410" y="122" font-size="10" fill="#5f6368">客户 / 商机</text>
  <rect x="410" y="128" width="164" height="20" rx="5" fill="#fafbfc" stroke="#e5e7eb"/>
  <text x="410" y="166" font-size="10" fill="#5f6368">客户需求 / 技术参数</text>
  <rect x="410" y="172" width="164" height="20" rx="5" fill="#fafbfc" stroke="#e5e7eb"/>
  <text x="410" y="210" font-size="10" fill="#5f6368">问题现象 / 竞对</text>
  <rect x="410" y="216" width="164" height="20" rx="5" fill="#fafbfc" stroke="#e5e7eb"/>
  <text x="410" y="254" font-size="10" fill="#5f6368">关联订单</text>
  <rect x="410" y="260" width="164" height="20" rx="5" fill="#fff8f2" stroke="#ffe0c2"/>
  <text x="410" y="274" font-size="9.5" fill="#b06d00">待办确认（未确认不落库）</text>

  <!-- 态3 明细 -->
  <rect x="646" y="30" width="404" height="272" rx="10" fill="#fff" stroke="#0d904f"/>
  <rect x="646" y="30" width="404" height="30" rx="10" fill="#0d904f"/>
  <text x="848" y="50" font-size="12.5" font-weight="800" fill="#fff" text-anchor="middle">③ 明细：点「看详情」</text>
  <rect x="660" y="74" width="376" height="182" rx="8" fill="#fafbfc" stroke="#e5e7eb"/>
  <text x="672" y="96" font-size="10.5" fill="#5f6368">【活动类型】项目跟进　【客户】某某诊断科技</text>
  <text x="672" y="116" font-size="10.5" fill="#5f6368">【活动形式】线下拜访　【活动日期】2026-10-07</text>
  <text x="672" y="136" font-size="10.5" fill="#5f6368">【客户需求】1. …　2. …</text>
  <text x="672" y="156" font-size="10.5" fill="#5f6368">【问题现象】…</text>
  <text x="672" y="176" font-size="10.5" fill="#5f6368">【下一步计划】1. …（刘新元 / 11-20）</text>
  <rect x="672" y="192" width="120" height="26" rx="7" fill="#1F4E9C"/>
  <text x="732" y="209" font-size="10.5" font-weight="700" fill="#fff" text-anchor="middle">复制飞书描述</text>
  <rect x="802" y="192" width="120" height="26" rx="7" fill="#fff" stroke="#1F4E9C"/>
  <text x="862" y="209" font-size="10.5" font-weight="700" fill="#1F4E9C" text-anchor="middle">去前准备 ↗</text>
  <text x="660" y="282" font-size="10" fill="#9aa0a6">明细在本页展开，不再跳 Tab</text>
</svg>'''

    html = (html.replace('__NOW__', now_rows).replace('__DOMS__', dom_html)
            .replace('__MAP__', map_rows).replace('__PH__', ph_html)
            .replace('__QS__', q_html).replace('__FIG_FLOW__', fig_flow)
            .replace('__FIG_WIRE__', fig_wire))
    html = BK.inject(html, theme='light', tag='营销中心')
    io.open(OUT, 'w', encoding='utf-8').write(html)

    vr = BK.verify(html)
    bad = [k for k, ok in vr.items() if not ok]
    print('✅ 生成 %s  (%.1f KB)' % (OUT, len(html.encode('utf-8')) / 1024))
    print('   brand_kit verify:', '✅ 通过' if not bad else '❌ 缺 ' + ', '.join(bad))
    print('   现状 Tab %d 条 ｜ 归属对照 %d 条 ｜ 待拍板 %d 问 ｜ 分期 %d 期'
          % (len(NOW), len(NOW), len(QUESTIONS), len(PHASES)))


main()
