#!/usr/bin/env python3
"""Generate the executive smart-canteen weekly strategy report."""

from __future__ import annotations

import csv
import html
from collections import Counter
from datetime import datetime, timezone, timedelta
from pathlib import Path


ROOT = Path(__file__).resolve().parents[3]
SOURCE_DIR = ROOT / "work/weekly-reports/outputs/2026-W20/smart-canteen-project-xlsx-refresh"
OUT_DIR = ROOT / "work/weekly-reports/outputs/2026-W20/smart-canteen-leadership-strategy-report"
STRATEGY_DOC = ROOT / "modules/product/products/smart-canteen/strategy/2026-05-14-smart-canteen-product-strategy/智慧食堂产品战略规划.md"
INDUSTRY_CSV = ROOT / "modules/product/strategy/smart-canteen-nutrition-system/industry-report-conclusions.csv"
XLSX_SOURCE = Path("/Users/jack/Downloads/数字技术中心工作周报2025-2026.xlsx")
PERIOD = "5月11日-5月17日"
WEEK = "2026-W20"
GENERATED_AT = datetime.now(timezone(timedelta(hours=8))).strftime("%Y-%m-%d %H:%M +0800 CST")


def read_csv(path: Path) -> list[dict[str, str]]:
    with path.open(encoding="utf-8-sig", newline="") as f:
        return list(csv.DictReader(f))


def write_csv(path: Path, rows: list[dict[str, str]], fields: list[str]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("w", encoding="utf-8-sig", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        writer.writerows(rows)


def write_text(path: Path, text: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(text, encoding="utf-8")


def find_hits(text: str, terms: list[str]) -> dict[str, int]:
    return {term: text.count(term) for term in terms if text.count(term)}


def money_summary(rows: list[dict[str, str]]) -> str:
    seen: dict[str, str] = {}
    for row in rows:
        name = row.get("project_name", "")
        amount = row.get("amount", "")
        if amount and amount != "-" and name not in seen:
            seen[name] = amount
    selected = [
        ("中国银行项目", seen.get("中国银行项目", "")),
        ("江西206项目", seen.get("江西206项目", "")),
        ("江苏国信集团项目", seen.get("江苏国信集团项目", "")),
        ("中央网信办（技术方案）", seen.get("中央网信办（技术方案）", "")),
        ("机场消费机项目（完善结算）", seen.get("机场消费机项目（完善结算）", "")),
    ]
    return "；".join(f"{name}{amount}" for name, amount in selected if amount)


def build_report() -> tuple[str, str]:
    current = read_csv(SOURCE_DIR / "team-current-week-items.csv")
    dated = read_csv(SOURCE_DIR / "dated-project-rows.csv")
    industry = read_csv(INDUSTRY_CSV)
    all_text = "\n".join(row["text"] for row in current)

    people = sorted({row["person"] for row in current})
    project_terms = [
        "金斯瑞",
        "江西206",
        "首通智诚",
        "荣海小学",
        "山西焦煤",
        "大庆油田",
        "赛迪",
        "江苏国信",
        "三全",
        "苏州福耀",
        "吉林农业大学",
        "网信办",
        "广东反兴奋剂",
        "昌平区教委",
        "北京市城市副中心",
    ]
    capability_terms = [
        "AI",
        "Codex",
        "大屏",
        "食安",
        "进销存",
        "取餐柜",
        "售卖柜",
        "消费机",
        "双秤",
        "OA",
        "接口",
        "云效",
        "标准产品",
        "小程序",
        "设备",
        "营养",
    ]
    project_hits = find_hits(all_text, project_terms)
    capability_hits = find_hits(all_text, capability_terms)
    top_projects = "、".join(project_hits.keys())
    top_caps = "、".join(capability_hits.keys())
    amount_text = money_summary(dated)
    phase_counter = Counter(
        row["phase"]
        for row in dated
        if "团餐" in row.get("project_type", "") or "食" in row.get("project_name", "")
    )
    phase_text = "、".join(f"{phase}{count}条" for phase, count in phase_counter.most_common(5))
    industry_top = [row for row in industry if row.get("priority") in {"P0", "P1"}][:8]

    report = f"""# 数字技术中心 / 交付实施部智慧食堂项目战略周报（领导版，{WEEK}）

> 周期：{PERIOD}
> 来源：`{XLSX_SOURCE}` 及项目内智慧食堂产品战略、行业结论资料
> 证据等级：B/C/D。B 级来自团队 Excel 周报和历史项目台账；C 级来自行业报告结论；D 级为本周基于证据形成的战略判断，已单独标注。
> 生成时间：{GENERATED_AT}

## 一、给领导看的总体判断

本周智慧食堂工作已经不只是项目问题处理，而是在验证一个更大的产品方向：康比特需要从“项目制交付智慧食堂系统”升级为“软硬一体、食安合规、营养健康、AI 原生、交付资产可复制的团餐数字化产品平台”。

- **当前项目侧**：Excel 当前周解析到 {len(people)} 位同事、{len(current)} 条周输入，覆盖 {top_projects} 等项目和客户线索，说明团队正在同时承担售前、交付、上线、联调、设备、接口和客户响应。
- **产品战略侧**：本周高频能力集中在 {top_caps}。这些不是零散功能，而是智慧食堂标准产品、企业/机关员工餐厅包、校园/教委监管包、食安硬件包和 AI 营养增值能力的构成件。
- **行业生态位**：行业正在从“能收银、能订餐、能看视频”升级到“控成本、保食安、管供应链、做健康干预、可监管、可复制”。康比特的合理位置不是单纯餐饮软件商，也不是硬件集成商，而是连接食堂运营者、监管者、就餐者和设备伙伴的团餐数字化产品平台。
- **本周管理重点**：一手保金斯瑞、江西 206、国信、网信办、教委大屏等项目闭环，一手把项目共性沉淀为产品包、接口文档、设备接入模板、AI 协作流程和交付 SOP，避免继续被定制化牵着走。

## 二、行业趋势与我方生态位

### 1. 行业看到什么

基于项目内行业报告结论，本周周报应向领导传达四个行业判断：

- **团餐正在规模化**：区域客户、供应链、运营标准和数字化能力共同决定竞争力，单项目定制会越来越难支撑规模复制。
- **经营效率成为客户持续付费理由**：客户要的不只是系统上线，还要采购、库存、菜品销量、补贴、结算、对账、成本和人效的可视化。
- **食安合规进入主产品闭环**：食品安全从后厨附属模块，升级为监管证据链、异常整改、设备采集、台账导出和监管大屏。
- **AI 与多模态设备会重构交付方式**：菜品识别、后厨视频、现场照片、票据台账、接口文档、测试数据和周报材料，都可以进入 AI 辅助生产链路。

### 2. 康比特站在什么位置

康比特智慧食堂的生态位可以概括为：

```text
团餐经营场景
  -> 标准软件平台
  -> 食安与智能硬件
  -> 营养健康服务
  -> AI 工程化与交付资产
```

这意味着我们面向的不是单一“食堂管理员”，而是多类用户：

| 用户 | 主要问题 | 本周可见产品抓手 |
| --- | --- | --- |
| 企业/园区/机关食堂管理方 | 支付、补贴、档口、对账、设备联动、员工体验 | 金斯瑞 OA 接口、取餐柜、补贴余额、江苏国信、苏州福耀 |
| 学校/教委/监管方 | 校园餐安全、家长透明、监管大屏、膳食经费与采购库存 | 荣海小学、昌平区教委食安大屏、教委总览、进销存大屏 |
| 团餐/物业/交付实施方 | 快速部署、设备联调、现场问题闭环、验收材料 | 江西 206 售卖柜、消费机、双秤、摄像头、留样柜、语音叫号 |
| 员工/学生/运动人群 | 便捷就餐、营养建议、健康干预、连续服务 | AI 运动营养师、小程序、手环、营养播报、菜品识别 |
| 内部销售/产品/交付团队 | 售前材料、需求拆解、投标答疑、接口文档、版本记录 | 学校版 PPT、报价单、云效、Apifox、Codex、Prompt 沉淀 |

## 三、本周项目进展如何支撑战略

### 1. 企业/机关/园区智慧食堂：当前最具现金流和复制基础

本周金斯瑞、江苏国信、苏州福耀、江西 206、网信办等项目持续推进，验证了企业/机关/园区智慧食堂的真实需求集中在：混合支付、补贴、外部 OA、取餐柜/售卖柜、自助称重、食安联动、供应商协同和现场部署。

这些项目的价值不止在“解决客户问题”，更在于形成标准包：

- **员工餐厅标准包**：账号、补贴、充值、退款、报表、付款码、小程序、对账。
- **智能取餐/售卖增强包**：取餐柜、售卖柜、双秤、消费机、打印、小票和订单闭环。
- **机关/央国企交付包**：合同需求梳理、报价单、系统部署、等保范围、供应商培训和验收材料。

历史项目台账也能支撑该判断：团餐/智慧食堂相关历史进度中，交付、售前和运维类条目集中出现；可回溯金额样本包括 {amount_text}。这些数字不能替代毛利和回款，但足以说明该方向具备真实客户和项目密度。

### 2. 校园/教委监管：战略突破线，需要从样板进入区域平台

本周首通智诚荣海小学、昌平区教委食安监管大屏、教委总览大屏、校园食安总览、进销存大屏同步推进，说明学校场景已经从单校交付向“学校端 + 教委监管端 + 家长/学生侧感知”的综合产品方向演进。

本周沉淀的关键进展包括：

- 荣海小学完成费用管控目标确认、缴费需求梳理和原型页面交付。
- 教委食安监管大屏完成 3D 地图点位联动、数据卡片弹窗、模块悬浮等交互设计。
- 总览大屏与食安大屏统一进入同一项目，并从 HTML 原型样式改造为 Vue 开发样式。
- 学校版产品 PPT 多轮更新，补充学生营养餐业务流程和说明。

对领导的表达重点：校园线不是再做一个学校项目，而是争取形成“区域教育监管 + 学校结算 + 食安监管 + 家长透明 + 营养干预”的产品包。短期先用样板项目验证，不能在缺少试点数据时直接承诺大规模复制。

### 3. 食安监管与智能硬件：从附属模块变成产品壁垒

本周食安相关工作覆盖产业园食安系统修复、得沃留样柜、大屏视频、食安设备兼容、摄像头更换、传感器、网关、取餐语音叫号和教委食安大屏。硬件侧覆盖取餐柜、售卖柜、双秤、消费机、460 称重台、厨房秤、手环和 Wattbike 等。

这说明食安和硬件不应再作为临时项目配置处理，而要进入标准产品体系：

- 每类设备必须有设备台账、协议/SDK、数据上传、异常处理、验收模板和售后责任边界。
- 食安产品要从“检查记录”升级为“环境监测 + 视频/图片证据 + 留样/晨检/消毒 + 采购库存 + 监管指数 + 大屏展示”。
- 硬件包要服务标准智慧食堂和校园/企业突破线，而不是无限扩张为独立硬件项目。

### 4. AI 工程化：从个人效率工具进入团队生产方式

本周 AI 高频出现，不是概念宣传，而是开始进入实际交付链路：

- 产品侧：ChatGPT 生成用户人设、产品人设和设计 prompt，Codex 辅助大屏原型与样式优化。
- 研发侧：Codex 开始参与需求拆解、方案梳理、代码 review、测试、云效任务关联和状态流转。
- 设备侧：AI 辅助 460 称重台三端联合开发、取餐称重会话优化和 Android 通用开发规范沉淀。
- 知识侧：Prompt、流程图、接口文档、安装使用文档和周报结构开始被固化为可复用资产。

管理上要把 AI 定位为“造产品、造流程、造资产”的生产方式，而不只是“节省写材料时间”。下周应重点沉淀可复用 Prompt、Design.md、Apifox 自动接口、代码 review 标准和项目版本记录。

## 四、计划推出的产品组合

| 产品组合 | 面向用户 | 解决问题 | 本周证据 | 下一阶段目标 |
| --- | --- | --- | --- | --- |
| 标准智慧营养健康餐厅 | 企业、机关、学校、体育训练基地食堂管理方 | 订单、支付、补贴、报表、设备、对账、营养服务的一体化管理 | 标准小程序上线、OA 补贴接口、付款码路径、登录态恢复、报表和设备需求持续沉淀 | 0-3 个月完成产品地图、核心接口回归、演示包、用户手册和版本路标 |
| 企业/园区/机关智慧食堂标准包 | 大型制造企业、央国企、园区、机关后勤和团餐运营方 | 员工餐厅运营效率、混合支付、补贴、档口、智能取餐和食安联动 | 金斯瑞、江苏国信、苏州福耀、江西 206、网信办等项目本周持续推进 | 形成员工餐厅/机关食堂售前六件套：场景图、设备点位、报价、实施计划、验收表、操作手册 |
| 校园智慧团餐 SaaS / 教委监管包 | 教委、学校、银行合作方、家长和学生 | 学校缴费、订餐核销、膳食经费、食安监管、家长透明和营养干预 | 荣海小学缴费原型、教委食安大屏、总览大屏、学校版 PPT | 选择 1-2 个样板试点，验证学校结算、监管门户、银行适配和区域复制路径 |
| 食安监管与智能硬件包 | 学校、企业、监管单位、餐企和项目交付团队 | 食安证据链、环境监测、设备采集、异常整改、现场验收 | 产业园食安修复、留样柜、摄像头、传感器、教委食安大屏、取餐/售卖/称重设备联动 | 建立设备清单、协议/SDK、报价、联调、测试、验收和售后边界模板 |
| AI 营养与增长智能体 | 内部销售/产品/交付团队，后续扩展到员工/学生/运动人群 | 需求挖掘、投标支持、营养问答、菜品识别、交付文档和项目复盘提效 | AI 菜品识别 5 月 14 日记录 90% 以上、AI 运动营养师、小程序播报、DeepSeek-TUI、Codex 工作流 | 先内部量化：需求归类准确率、报告节省时间、产品建议采纳数，再包装为增值服务 |

## 五、数字技术中心与交付实施部的协同分工

| 部门角色 | 本周体现 | 应继续固化的边界 |
| --- | --- | --- |
| 数字技术中心 | 产品规划、需求拆解、接口开发、AI 协作、数据与设备链路、标准版功能沉淀 | 定义标准产品、版本路标、接口契约、设备协议、AI 工作流和产品设计 SOP |
| 交付实施部/交付协同 | 客户沟通、现场联调、上线验证、供应商培训、设备问题反馈、验收支持 | 把现场需求转成可验证任务，把设备/部署/培训/验收沉淀为交付资产 |
| 两部门共同目标 | 保当前项目交付，同时形成可复制产品包 | 需求必须区分“标准版吸收、项目版配置、临时定制、暂缓”，防止项目定制吞噬产品路线 |

## 六、需要领导关注的风险和资源请求

| 风险 | 影响 | 建议动作 |
| --- | --- | --- |
| 多项目并行导致战略主线被项目问题打散 | 团队忙于响应，难以形成产品包和标准资产 | 明确本阶段三条主线：企业/机关标准包、校园/教委监管包、食安硬件包；每条主线指定产品负责人和交付负责人 |
| 缺毛利、成本、回款和硬件售后数据 | 无法判断哪些产品真正赚钱、哪些只是销售额好看 | 要求财务/采购/交付补齐成本回款表、硬件成本故障率表、交付工时表 |
| AI 设计和开发方法仍不稳定 | 生成内容快，但异常流程、权限、数据边界和验收可能不足 | 建立 AI 产品设计评审 SOP，重要需求必须补主流程、异常流程、角色权限、数据口径和验收方式 |
| 硬件链路复杂且供应商依赖高 | 上线和售后风险可能反向拖累软件交付 | 设备进入标准白名单，沉淀协议、固件、版本、异常码、测试记录和责任边界 |
| 定制化需求持续进入研发 | 标准产品被拉散，后续维护成本上升 | 需求评审固定四类结论：标准版吸收、配置化支持、项目临时定制、暂缓/拒绝 |

## 七、下周重点计划

1. **保交付**：金斯瑞取餐柜上线验证与现场问题闭环；江西 206 离线消费、双秤和售卖柜后续问题；江苏国信个性化需求与部署；网信办供应商培训和等保沟通。
2. **收产品**：完成校园版大屏定稿，继续优化教委食安、进销存、总览大屏；推进学校版产品 PPT、智慧食堂业务内容 PPT 和标准产品现金退款/细节优化。
3. **固硬件**：围绕食安设备兼容、取餐语音叫号、留样柜、摄像头、厨房秤、售卖柜、双秤和消费机，输出设备接入与验收模板。
4. **建 AI 流程**：推进 Codex 与 Apifox 打通、云效任务自动拆解、需求说明生成、代码 review、接口文档和测试数据生成，把可行做法沉淀为团队 Prompt 和脚本。
5. **补经营数据**：在现有项目金额和周报进展之外，补齐成本、毛利、回款、交付工时、硬件故障率和售后成本，为 7-2-1 资源配置提供管理依据。

## 八、证据边界

- 本报告已把事实、行业判断和战略假设分层表达；没有客户签字、验收截图、毛利回款数据的事项，均未写成最终验收或经营结论。
- Excel 未单列“交付实施部”组织字段，本文将现场联调、上线、设备、培训、部署、验收支持和客户沟通类事项归为交付实施协同。
- 历史金额样本来自项目台账和已有产品战略收入样本，只能说明项目密度和销售额线索，不能替代毛利、回款和净利润判断。
"""

    html_report = build_html(report, people, current, project_hits, capability_hits, phase_text, industry_top)
    return report, html_report


def build_html(
    markdown: str,
    people: list[str],
    current: list[dict[str, str]],
    project_hits: dict[str, int],
    capability_hits: dict[str, int],
    phase_text: str,
    industry_top: list[dict[str, str]],
) -> str:
    paragraphs: list[str] = []
    for block in markdown.split("\n\n"):
        block = block.strip()
        if not block:
            continue
        if block.startswith("# "):
            paragraphs.append(f"<h1>{html.escape(block[2:])}</h1>")
        elif block.startswith("## "):
            paragraphs.append(f"<h2>{html.escape(block[3:])}</h2>")
        elif block.startswith("### "):
            paragraphs.append(f"<h3>{html.escape(block[4:])}</h3>")
        elif block.startswith("| "):
            paragraphs.append(markdown_table_to_html(block))
        elif block.startswith("```"):
            code = block.strip("`").strip()
            paragraphs.append(f"<pre>{html.escape(code)}</pre>")
        elif block.startswith("- "):
            items = "\n".join(
                f"<li>{inline_html(line[2:])}</li>" for line in block.splitlines() if line.startswith("- ")
            )
            paragraphs.append(f"<ul>{items}</ul>")
        elif block[0].isdigit() and ". **" in block:
            items = "\n".join(f"<li>{inline_html(line[line.find(' ') + 1:])}</li>" for line in block.splitlines())
            paragraphs.append(f"<ol>{items}</ol>")
        elif block.startswith("> "):
            paragraphs.append(f"<blockquote>{inline_html(block[2:])}</blockquote>")
        else:
            paragraphs.append(f"<p>{inline_html(block)}</p>")

    project_badges = "".join(
        f"<span>{html.escape(name)} <b>{count}</b></span>" for name, count in project_hits.items()
    )
    capability_badges = "".join(
        f"<span>{html.escape(name)} <b>{count}</b></span>" for name, count in capability_hits.items()
    )
    industry_cards = "".join(
        f"<article><h4>{html.escape(row['theme'])}</h4><p>{html.escape(row['conclusion'])}</p></article>"
        for row in industry_top[:6]
    )

    return f"""<!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;
      --ink: #18212f;
      --muted: #5c6675;
      --line: #d8dee8;
      --soft: #f5f7fb;
      --navy: #12315c;
      --teal: #0f766e;
      --gold: #a16207;
      --red: #b42318;
    }}
    * {{ box-sizing: border-box; }}
    body {{
      margin: 0;
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
      color: var(--ink);
      background: #ffffff;
      line-height: 1.72;
    }}
    header {{
      background: linear-gradient(120deg, #102848 0%, #0f766e 100%);
      color: white;
      padding: 44px 7vw 36px;
    }}
    header p {{ max-width: 980px; margin: 14px 0 0; color: #dbeafe; font-size: 17px; }}
    .kpis {{
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 14px;
      max-width: 1160px;
      margin: -26px auto 28px;
      padding: 0 20px;
    }}
    .kpis div {{
      background: #fff;
      border: 1px solid var(--line);
      border-radius: 8px;
      padding: 16px;
      box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
    }}
    .kpis strong {{ display: block; font-size: 26px; color: var(--navy); }}
    .kpis span {{ color: var(--muted); font-size: 13px; }}
    main {{ max-width: 1120px; margin: 0 auto; padding: 0 20px 52px; }}
    h1 {{ margin: 0; font-size: 32px; line-height: 1.25; letter-spacing: 0; }}
    h2 {{
      margin-top: 34px;
      padding-top: 22px;
      border-top: 2px solid var(--line);
      font-size: 24px;
      color: var(--navy);
      letter-spacing: 0;
    }}
    h3 {{ margin-top: 24px; font-size: 18px; color: var(--teal); letter-spacing: 0; }}
    h4 {{ margin: 0 0 8px; color: var(--navy); }}
    p, li {{ font-size: 15.5px; }}
    blockquote {{
      margin: 18px 0;
      padding: 14px 18px;
      border-left: 4px solid var(--teal);
      background: var(--soft);
      color: var(--ink);
    }}
    table {{ width: 100%; border-collapse: collapse; margin: 16px 0 22px; font-size: 14px; }}
    th, td {{ border: 1px solid var(--line); padding: 10px 11px; vertical-align: top; }}
    th {{ background: #edf4f8; color: var(--navy); text-align: left; }}
    pre {{
      white-space: pre-wrap;
      background: #0f172a;
      color: #e5e7eb;
      border-radius: 8px;
      padding: 16px;
      overflow: auto;
    }}
    .badges, .industry {{
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      margin: 10px 0 18px;
    }}
    .badges span {{
      border: 1px solid var(--line);
      background: var(--soft);
      border-radius: 999px;
      padding: 5px 10px;
      font-size: 13px;
    }}
    .badges b {{ color: var(--teal); }}
    .industry {{
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 12px;
    }}
    .industry article {{
      border: 1px solid var(--line);
      border-radius: 8px;
      padding: 14px;
      background: #fff;
    }}
    .industry p {{ margin: 0; color: var(--muted); font-size: 14px; }}
    .meta {{
      max-width: 1120px;
      margin: 0 auto 18px;
      padding: 0 20px;
    }}
    .meta h2 {{ border-top: 0; margin-top: 12px; }}
    @media (max-width: 760px) {{
      header {{ padding: 32px 20px; }}
      h1 {{ font-size: 25px; }}
      .kpis {{ grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 16px; }}
      .industry {{ grid-template-columns: 1fr; }}
      table {{ display: block; overflow-x: auto; }}
    }}
  </style>
</head>
<body>
  <header>
    <h1>数字技术中心 / 交付实施部智慧食堂项目战略周报</h1>
    <p>领导版：把本周项目进展放到团餐行业、产品生态位、产品组合和资源配置中表达。</p>
  </header>
  <section class="kpis">
    <div><strong>{len(people)}</strong><span>当前周参与同事</span></div>
    <div><strong>{len(current)}</strong><span>Excel 当前周结构化输入</span></div>
    <div><strong>{len(project_hits)}</strong><span>本周命中的重点项目/客户</span></div>
    <div><strong>{len(capability_hits)}</strong><span>本周命中的产品能力关键词</span></div>
  </section>
  <section class="meta">
    <h2>本周项目与能力热区</h2>
    <h3>项目/客户</h3>
    <div class="badges">{project_badges}</div>
    <h3>能力关键词</h3>
    <div class="badges">{capability_badges}</div>
    <h3>行业判断来源</h3>
    <div class="industry">{industry_cards}</div>
    <blockquote>历史团餐/食堂相关进度阶段热区：{html.escape(phase_text)}</blockquote>
  </section>
  <main>
    {''.join(paragraphs)}
  </main>
</body>
</html>
"""


def inline_html(text: str) -> str:
    escaped = html.escape(text)
    escaped = escaped.replace("**", "")
    escaped = escaped.replace("`", "")
    return escaped.replace("\n", "<br>")


def markdown_table_to_html(block: str) -> str:
    lines = [line for line in block.splitlines() if line.startswith("|")]
    if len(lines) < 2:
        return f"<p>{inline_html(block)}</p>"
    header = [cell.strip() for cell in lines[0].strip("|").split("|")]
    body_lines = lines[2:]
    th = "".join(f"<th>{html.escape(cell)}</th>" for cell in header)
    trs = []
    for line in body_lines:
        cells = [cell.strip() for cell in line.strip("|").split("|")]
        trs.append("<tr>" + "".join(f"<td>{inline_html(cell)}</td>" for cell in cells) + "</tr>")
    return f"<table><thead><tr>{th}</tr></thead><tbody>{''.join(trs)}</tbody></table>"


def main() -> int:
    OUT_DIR.mkdir(parents=True, exist_ok=True)
    report, html_report = build_report()
    write_text(OUT_DIR / "smart-canteen-leadership-weekly-report.md", report)
    write_text(OUT_DIR / "smart-canteen-leadership-weekly-report.html", html_report)

    source_rows = [
        {
            "source_id": "S01",
            "path": str(XLSX_SOURCE),
            "type": "source_xlsx",
            "evidence_level": "B",
            "usage": "团队当前周输入、历史周报和项目进度来源；原文件不复制进仓库",
        },
        {
            "source_id": "S02",
            "path": str(SOURCE_DIR / "team-current-week-items.csv"),
            "type": "parsed_csv",
            "evidence_level": "B",
            "usage": "当前周 39 条人员周输入",
        },
        {
            "source_id": "S03",
            "path": str(SOURCE_DIR / "dated-project-rows.csv"),
            "type": "parsed_csv",
            "evidence_level": "B",
            "usage": "历史项目、阶段、金额和负责人台账",
        },
        {
            "source_id": "S04",
            "path": str(STRATEGY_DOC),
            "type": "strategy_markdown",
            "evidence_level": "B/D",
            "usage": "智慧食堂产品战略规划与 7-2-1 资源配置口径",
        },
        {
            "source_id": "S05",
            "path": str(INDUSTRY_CSV),
            "type": "industry_conclusion_csv",
            "evidence_level": "C",
            "usage": "团餐、食安、AI、多模态、营养健康等行业判断",
        },
    ]
    write_csv(
        OUT_DIR / "source-index.csv",
        source_rows,
        ["source_id", "path", "type", "evidence_level", "usage"],
    )

    evidence_rows = [
        {
            "theme": "当前项目交付",
            "claim": "本周覆盖多客户、多设备、多接口和上线联调，项目进展可支撑当前交付需要",
            "evidence_level": "B",
            "sources": "team-current-week-items.csv",
            "boundary": "未把缺少验收截图或客户签字的事项写成最终验收完成",
        },
        {
            "theme": "行业生态位",
            "claim": "康比特应定位为连接运营、监管、就餐者和设备伙伴的团餐数字化产品平台",
            "evidence_level": "C/D",
            "sources": "industry-report-conclusions.csv; 智慧食堂产品战略规划.md",
            "boundary": "生态位为战略判断，仍需毛利、回款、渠道和竞品价格复核",
        },
        {
            "theme": "产品组合",
            "claim": "标准智慧营养健康餐厅、企业/机关标准包、校园/教委监管包、食安硬件包和 AI 增值能力应并行推进",
            "evidence_level": "B/D",
            "sources": "product-rd-summary.csv; team-current-week-items.csv; 智慧食堂产品战略规划.md",
            "boundary": "AI 营养与增长智能体先作为内部效率和增值方向，不写成已商业化产品",
        },
    ]
    write_csv(
        OUT_DIR / "strategic-evidence-map.csv",
        evidence_rows,
        ["theme", "claim", "evidence_level", "sources", "boundary"],
    )

    routing = f"""# ROUTING_NOTE

## Input

- 用户要求继续解析 `/Users/jack/Downloads/数字技术中心工作周报2025-2026.xlsx`，在上一轮专项周报基础上形成面向领导的智慧食堂战略周报。
- 已有解析结果：`{SOURCE_DIR}`。
- 产品战略依据：`{STRATEGY_DOC}`。
- 行业结论依据：`{INDUSTRY_CSV}`。

## Process

- Mainline：智慧食堂产品战略体系。
- Five-module IPO：场景产品化、软件平台化、硬件体系化、AI 工程化、交付资产化全部涉及。
- Skills：team-weekly-report-generation、weekly-report、product-development-master-agent、smart-canteen-strategy-agent、output-format-preferences。

## Output

- `smart-canteen-leadership-weekly-report.md`
- `smart-canteen-leadership-weekly-report.html`
- `source-index.csv`
- `strategic-evidence-map.csv`
- `summary.md`

## Non-goals

- 不复制原始 211MB Excel。
- 不伪造毛利、回款、客户验收、设备故障率或渠道转化率。
- 不把 AI 探索写成已成熟商业产品。
"""
    write_text(OUT_DIR / "ROUTING_NOTE.md", routing)

    summary = f"""# 2026-W20 智慧食堂战略周报领导版生成记录

## Goal

在已解析 Excel 周报的基础上，生成面向领导的数字技术中心 / 交付实施部智慧食堂项目战略周报，突出行业趋势、生态位、产品组合、用户问题、项目进展、风险和下周计划。

## Outputs

- `smart-canteen-leadership-weekly-report.md`：AI 可读 Markdown 正文。
- `smart-canteen-leadership-weekly-report.html`：面向领导 review 和转发的 HTML 版本。
- `source-index.csv`：来源索引。
- `strategic-evidence-map.csv`：战略判断证据映射。
- `ROUTING_NOTE.md`：本次任务路由记录。

## Source Boundary

- 原始 Excel：`{XLSX_SOURCE}`
- Excel 解析结果：`{SOURCE_DIR}`
- 行业结论：`{INDUSTRY_CSV}`
- 产品战略：`{STRATEGY_DOC}`

## Evidence Boundary

- B 级：团队 Excel 周报、历史项目台账、产品战略已有证据。
- C 级：行业报告结论归档。
- D 级：本周战略判断与生态位表述。

## Human Review

- 状态：待 Jack review。
- 建议重点 review：是否将“交付实施协同”正式改为“交付实施部”；是否补充毛利、回款、硬件成本、故障率和渠道转化数据。
"""
    write_text(OUT_DIR / "summary.md", summary)
    print(OUT_DIR)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
