# 青柚 App 3.0 改版 · 项目进度看板

> 活页公开模板 `sample-project-board` · 场景: 数据看板 · 战报 · 行业: 科技互联网 / 企业内部
> 任何人、任何 Agent 都可以读、照着改，不需要账号。示例内容均为虚构。
> 真页面: https://space.24haowan.com/s/1FGFGQspWggn · 详情: https://space.24haowan.com/examples/sample-project-board

## 这是什么

项目进度看板 · 每周更新，开会时打开看甘特图

## 什么时候用

一个跨好几个组、要排几个月的项目（App 改版、系统上线、新店筹备、展会筹备），项目经理每周更新同一个链接，老板和各组开会时在电脑上打开看谁卡住了，选它：记忆点是按真实日期画的甘特图，各组还能在页末自己报状态。只是每周同步本周做了什么、没有多条并行任务的选 sample-weekly-report；一天里数字一直在变的销售战报选 sample-sales-live；给客户看的一次性方案选 sample-client-proposal。

## 用户对助手说的原话

帮我做一个项目进度看板，发成一个网页链接，主要在电脑上开会时投屏看：页头是公司和项目组、标题、更新时间、项目经理、报送谁、涉及哪些组；下面四个指标：整体进度（按工期加权，带一条进度条标出按计划今天应到的位置）、按期率、风险与阻塞数（分高中低）、离上线还有几天；主体是一张按真实日期比例画的甘特图，几个阶段各几条任务，每条写负责人，已完成段深色、剩余计划浅色，延期的部分用红色斜纹延长并写延期几天，标出今天、里程碑菱形、任务之间的依赖箭头和假期底纹，点任务条在图下看明细，电脑上占满宽度、窄屏可以横向滚动，手机上改成一条六行的阶段小图加按阶段竖排的进度卡；接着左右两栏：左边风险与阻塞清单（左侧一条细色线标高中低，写负责人和截止日），右边本周完成和下周按天的计划；最后一张「我这块有更新」表单（名字、哪一项、按计划/有风险/受阻/已完成、一句话），提交存到数据表，甘特图上那条任务旁边标出最新状态。少用底色块，用细线分隔。以后每周更新到同一个链接。

如果你还没有活页连接器（MCP），先读 https://space.24haowan.com/for-agents.md ，照里面的说明接入，或不登录直接发布。

## 照着做一份

1. 读入口文件 https://space.24haowan.com/examples/sample-project-board/source/index.html（它引用的其他文件见下方列表）。
2. 保留结构、版式和交互，把内容**全部**换成用户自己的；模板里的公司、人名、数字都是虚构的，一样都别留。
3. 交付一个自包含的单文件 HTML：样式写在页面里，不引外部字体 / 脚本 / CDN；手机 375 宽和电脑 1440 宽都要好看，模板有暗色就保留暗色。
4. 要发成微信里能打开、改了链接不变的网页：接入活页（https://space.24haowan.com/for-agents.md）后发布；没有账号也可以让用户在 https://space.24haowan.com/quick 上传这个文件。
5. 没有活页工具、但能发 HTTPS 请求：把做好的 HTML 以 Content-Type: text/html POST 到 https://space.24haowan.com/api/quick?client=template-sample-project-board ，返回预览链接、7 天分享与认领链接（登录后保留、链接不变）。

## 页面结构

- 进度甘特图
- 风险与阻塞
- 本周完成 · 下周计划
- 我这块有更新

## 文件（公开，纯文本）

- https://space.24haowan.com/examples/sample-project-board/source/index.html（入口）

## 发成活页之后还能做的

- 同一链接每周更新不变（项目经理每期换内容，老板收藏一次）
- 页末「我这块有更新」原生表单写回数据表 updates，甘特图上那一条读回最新状态小标
- 阅读回执（谁看了 / 看到哪一节）

## 发之前要备好

- 数据表 updates（列 owner / task / status / note，append_open=true）：页末「我这块有更新」写进这里，页面读回把每项最新状态标在甘特图的任务条上；task 写任务名，要和页面里的任务名一字不差；发布前先用 set_data 建好

## 模板说明（README）

项目经理每周更新同一个链接，发给老板和各组；主要在电脑上开会时打开看。示例内容均为虚构（公司「青柚科技」、人名、日期与数字都是编的）。

## 演示哪个特色

**同一条链接每周更新 + 各组在页面上自己报状态（写回数据表、读回到甘特图）。**

- 记忆点是一张**按真实日期比例**画的甘特图（内联 SVG）：横轴 9/7–12/20、周刻度与月份、国庆假期底纹、今天的竖线（带一处很小的呼吸光晕）、
  里程碑菱形、依赖箭头、已完成 / 剩余计划两段颜色，延期的部分用红色斜纹延长段并写「延期 7 天」。点任务条，图下那一行显示负责人、计划与实际日期、进度、受阻原因和最新状态。
- 电脑上甘特图占满 1200 版心，窄于 1200 时在容器里横向滚动；**手机上不缩小甘特图**，换成一张六行的阶段小图 + 按阶段竖排的进度卡（每条任务的状态、延期红字、最新状态）。
- 页末「我这块有更新」是原生表单 `<form method="post" action="./_data/updates">`：不跑脚本也能提交；脚本在时页内提交，提交完那条任务旁边立刻标出「受阻 · 钱程 10/28」这样的小标。
  页面打开时读 `./_data/updates.json`，每项取最新一条（按 `_at`）标到任务条和手机卡片上。
- 发出去之后：项目经理每周换内容再发一版（链接不变）；`list_data_rows table=updates` 读各组报上来的状态汇总进下一期；阅读回执看老板看到了哪一节（锚点 = 每个 `<section>` 的 `data-track-section`）。
- 没有外链；manifest 不写 `render`。

## 改哪里变成我的

甘特图的坐标是按日期算出来的，改日期时要两套图一起改：

| 位置 | 改什么 |
|---|---|
| 页头 `.org` / `h1` / `.facts` | 公司抬头（内联 SVG 标志）、期号与文档编号、标题、更新时间、项目经理、报送、涉及的组 |
| 四个指标 `.kpis` | 整体进度 = Σ(任务工期 × 进度) ÷ Σ工期；「应到」= 按今天日期每条任务应过去的天数之和 ÷ Σ工期（进度条上那根竖线的 `left` 也是它）；按期率 = 计划完成日已到的任务里按期的比例；风险数与下面清单条数一致；距上线天数 |
| 甘特图 `svg.gantt`（电脑） | 宽 1168，左侧 236px 是任务名与负责人，横轴 x = 236 + 距 9/7 的天数 × 8.762（105 天占 920px）。每条任务一个 `<g class="task" data-task="t?">`：`rect.plan` 计划起止、`rect.fill` 宽 = 计划宽 × 进度、`rect.late` 从计划结束画到预计结束、`g.upd` 是最新状态小标。阶段行是 `path.sum`，里程碑是 `path.ms`（`done` 已达成、`launch` 上线） |
| 阶段小图 `svg.strip`（手机） | 宽 343，左 46px 放阶段简称，x = 46 + 天数 × 2.771 |
| 进度卡 `.cards` | 每个阶段一个 `.ph`，每条任务一个 `<li data-task>`，状态字 `.c-s`、最新状态 `.upd-m` |
| 脚本顶部 `T` / `BY_NAME` / `LATEST` | 任务明细（点任务条时显示）、任务名 → id 对照（数据表里 `task` 列写任务名）、页面里预先写好的最新状态 |
| 风险与阻塞 `.risks` | 每条一个 `<li class="hi|mid|lo">`：级别、标题、负责人、截止日、一句说明 |
| 本周完成 · 下周计划 | 两张清单共用 `.rows` 三列网格 |
| 表单的「哪一项」 | `<select name="task">` 只列没完成的任务，`value` 用任务名 |
| `manifest.json` | `title` / `share.title` / `share.desc`；节增减时 `sections` 与页里的 `id` / `data-track-section` 三处同改 |
| 页脚 | 平台标志与名称（与 `core/space/src/theme.ts` 的 `MARK_SVG` / `PUBLIC_NAME` 逐字一致）+ 一句适用场景；发自己的看板时整段删掉 |

## 数据表

`updates`（列 `owner` / `task` / `status` / `note`，一次提交一行，`append_open=true`）。`task` 写任务名，必须和页面上的任务名一字不差；`status` 只有 按计划 / 有风险 / 受阻 / 已完成 四个值。发布前先建表：

```
set_data  proposal_id: <id>  table: "updates"  columns: ["owner","task","status","note"]  rows: []  append_open: true  revision: 0
```

读回：`list_data_rows table=updates`。本地 `space-cli serve` 会把提交写进包里的 `_data/updates.json`，试完改回 `[]`。

## 怎么发出去

单文件，最省事的是 MCP `publish_file`（不需要终端）：

```
publish_file
  filename: "index.html"
  content: <index.html 全文>
  title: "青柚 App 3.0 改版 · 项目进度看板"
  manifest: <manifest.json 的内容，去掉 entry>
  hold: true            # 先看预览，确认后 publish_version
```

然后 `set_data` 建 `updates` 表。**每周更新**：换掉内容再调一次 `publish_file`，这次传 `proposal_id`（不传 `title`）—— 链接不变，表里各组报的状态也还在。

有终端时用 CLI：

```bash
export SPACE_TOKEN=sk-space-…            # MCP create_cli_token
node core/space/cli/space-cli.mjs push core/space/examples/sample-project-board \
  --proposal <proposal_id> --manifest core/space/examples/sample-project-board/manifest.json --note "第 8 期" --hold
```

给谁看：默认仅自己可见；发给老板和各组用 `set_visibility`（`passcode` 口令可看，或 `public`）。

## 素材

- 没有位图，标志与图表都是内联 SVG。`thumb.webp` / `phone.webp` 由 `examples/verify-shots.mjs --write-thumb --write-phone` 从成品截出，不进发布包。
