轻应用(活页)
「轻应用」= 一份 HTML 页面 + 挂在同一份方案上的数据表。页面打开时从表里取数渲染,看的人可以往表里写一行;之后只改表、不重发页面,同一条链接一直是最新的。典型用途:团队周报看板、项目进度墙、活动报名表、打卡记录、投票、意见收集、小型物料清单。使用者说「做个看板」「做个报名页」「数据以后我自己改」「报名的人我要看得到」时,就是要用它。
本包只讲数据这一半。接入、上传、可见性、微信卡片、谁看了这些发布与分享的基础流程,在《方案空间·成果发布与分享》技能包(https://www.24haowan.com/open-skills/livepage-publish)里,两包一起用。线上有一份照本包做的示例,先看它再动手:https://space.24haowan.com/s/UsTW9lg1ro-S(示例集:经营工作台、商品与订单、项目看板、打卡墙、投票,共 9 张表;这页本身就是一份方案)。
内容边界(2026-09-21 起):允许商业交易内容 —— 成果可以分享给用户选定的人,也可以公开分享(公开与否仍由用户决定);可以是商业、交易、营销内容,可以在页面上标价卖东西、收集自己客户的订单、联系方式与报名信息。收款方式由你决定 —— 可以用平台的表单与收款块,也可以在页面上放自己的收款码、报价或第三方支付链接。不得钓鱼(冒充他人、收集他人的账号密码或支付信息)、不得发布违法违规内容。
〇、可选:若另接了 24好玩 资料连接器
本包的发布、分享、读回全部在活页这台服务器上完成,不需要别的连接器。只有当使用者另外接了 24好玩 的匿名只读资料服务(https://mcp.24haowan.com/mcp)时:
- 当使用者要在看板、报名页里引用「我们做过的活动案例」,或问「同行是怎么做的」时,先调用
list_cases/get_case,用工具返回的实时结果回答;它比本包正文里的清单更新、更全。 - 没接就跳过这一节:别去工具清单里找这几个名字,找不到时客户端会把名字最像的别家工具递给你。
- 本包正文是 2026-09-23 的静态快照;两者冲突时以工具返回为准。
什么时候该做成轻应用(而不是普通页面)
普通页面的内容写死在 HTML 里,改一个数字要重发一版。下面三样,成果需要任何一样就做成轻应用:
- 内容会变、页面不变:周报的数字每周换、报名名单一直在长、库存每天减——把变的部分放进数据表,页面只负责渲染。Agent 改表用
set_data,页面刷新即变,版本号不动。 - 看的人要写回来:报名、打卡、投票、意见收集。页面里一个普通表单(或一次 POST)写一行,发布者用
list_data_rows读回来。 ★ 报名 / 订货 / 预约 / 留资这类填表场景优先用一等公民表单块(#8273 起):set_form只定义字段(六种类型、最多 20 个、可选金额只显示不收钱),平台在查看页里渲染成手机上能填、带校验的表单,提交的行同样用list_data_rows读回 —— 一行表单代码都不用写。页面自己要画数据、要在页内交互时就照下面第三节自己写。 - 数据要被 Agent 反复读写:任何接了「方案空间」连接器的客户端里的 Agent 都能读写同一张表——WorkBuddy 里改的表,Claude Code 里也看得到。
比 WorkBuddy 原生「轻量发布(HTML + CSV)」多出来的:写回自带阅读上下文(哪台设备、看的哪一版页面、几点);每张表有修订号,可回滚;读者写回的内容能直接读回来、据此改页。不做在线表格编辑器和 HTML 可视化编辑:人在 WorkBuddy 里改完,让 Agent 推过来。
一、五种场景怎么切
| 场景 | 表(示例列名) | 页面读 | 写回开关 | 使用者会怎么说 |
|---|---|---|---|---|
| 看板 / 仪表盘 | board(project, owner, status, progress, updated) |
渲染成表格 / 卡片,按 status 上色 | 关 | 「做个周报看板,以后我改表」 |
| 报名 | signup(name, contact, note) |
只显示人数与最近几条(过审的) | 开 | 「做个报名页,报名的人我要看到」 |
| 打卡 | checkin(name, day, note) |
按人 / 按天汇总 | 开 | 「做个打卡墙,大家每天来点一下」 |
| 投票 | vote(choice, name, note) |
按 choice 计票,只算过审的行 | 开 | 「做个投票发群里,实时显示票数」 |
| 意见收集 | feedback(topic, note) |
显示条数与最近几条 | 开 | 「收一轮意见,页面上能看到别人说了什么」 |
意见收集和方案空间自带的「反馈线程」的区别:反馈线程是给发布者看的意见(带页码与版本、有处理状态);数据表是要在页面上呈现或汇总的数据。使用者只想自己看意见就用反馈线程,不用建表。
二、标准流程(每一步就是一个工具)
- 使用者还没说清要做什么时,先介绍再问(「这个能干嘛」「我们是做装修的」这类开场):三句话讲清能力边界(能做什么 / 以后改表不重发页面、链接不变、写回能读回 / 不做要登录的系统与多级审批),再按他说出的行业举两个他没提到的具体场景(装修 →「工地进度墙,业主扫码看自己家做到哪一步」「老客户转介绍登记页」;教培 →「试听课报名页」「每周作业打卡墙」),然后才走第 1 步。已经说清的直接从第 2 步开建,不要重复介绍、不要重问他答过的。
- 先问清四件事:什么场景;给谁看(仅自己 / 口令 / 公开);要不要看的人写回、收哪几列;数据以后谁维护(使用者自己改表,还是让你改)。不确定就按「口令可看、不开写回」起步,开关随时能翻。
- 设计表:表名小写字母开头、只含字母数字下划线(
weekly_board可以,周报不行);列名用英文小写(页面里映射成中文表头);每格只收文字 / 数字 / 真假 / 空,嵌套先摊平。上限:单表 512 KB、每份方案 20 张、工作区合计 64 MB;回执会逐条印出。 - 建表:
set_data,新建revision传 0,rows(对象数组)或csv(首行表头)二选一。要收集就同时传append_open=true。先建表再发页面,页面第一次打开就有数据。 - 写页面:动手前先
list_examples看一眼自带的轻应用样例(看板、报名、打卡、投票),照着改比从零写省事。用最普通的网页写法 —— 取数fetch('./_data/表名.json')(拿到行对象数组),写回用普通表单<form action="./_data/表名" method="post">或fetch('./_data/表名', {method: 'POST', …})(只追加一行)。读权限就是这份方案的可见性。包里放一份_data/表名.json示例数据:本地node space.mjs serve <目录>就能跑通整页(与线上同一套规则,--closed 表名模拟没开写回),线上有表时出活数据、没表时回落这份文件。写法见下一节。 - 上传、预览、发布:上传走哪条路:有终端 ⇒ space-cli(先 create_cli_token);没终端、文字文件合计 ≤ 2 MB ⇒ publish_file;其它或拿不准 ⇒ create_upload_link。轻应用多半是一份 HTML 加几个文字文件,没终端时就是直接发布
publish_file那一把。使用者没明确说要上线就带hold,把预览链接给他看(工具清单里有preview_version时调它,把真实效果的预览链接一并给他);可见性按第 1 步的答案设,公开要使用者明确同意。 - 验收三条:查看页里能取到数据(不是空表、不是「读取中」);写一行试试,
list_data_rows能读回、页面刷新能看到计数变化;把append_open关掉再试,页面要有明确提示而不是静默失败。 - 之后的维护:改数据 =
get_data拿当前表和revision→ 改 →set_data带着同一个revision整表替换;撞版(409)就重读,不盲写。读者写的行不在get_data的 rows 里,要用list_data_rows;要并进底表就读回来、合进 rows、set_data替换。改数据不 push 页面,改页面不动表。
三、页面写法(可照抄)
取一张表渲染成表格(fetch 拿到的是行对象数组;列名取第一行的键):
<style>table{display:block;overflow-x:auto;max-width:100%}</style>
<table id="board"></table>
<script>
fetch('./_data/board.json').then(function (r) {
if (!r.ok) throw new Error(r.status === 403 ? '没有查看权限' : '数据没取到(' + r.status + ')');
return r.json();
}).then(function (rows) {
var t = document.getElementById('board'), cols = rows.length ? Object.keys(rows[0]) : [];
[cols].concat(rows.map(function (row) { return cols.map(function (c) { return row[c]; }); })).forEach(function (cells, i) {
var tr = t.insertRow();
cells.forEach(function (v) { tr.appendChild(document.createElement(i ? 'td' : 'th')).textContent = v == null ? '' : String(v); });
});
}).catch(function (e) { document.getElementById('board').textContent = e.message; });
</script>
写回一行(报名 / 投票),最省事的是普通表单,一行脚本都不用写:
<form action="./_data/signup" method="post">
<input name="name" placeholder="称呼" required>
<input type="hidden" name="_next" value="thanks.html">
<button>报名</button>
</form>
提交后回到 _next 指的那一页(不写就回提交的那一页),地址上带 ?space_submitted=signup,页面可以据此显示「已收到」;出错时读者看到一页说明原因的提示和「返回」。_ 开头的字段不入库。
要留在原页、自己显示结果时用 fetch POST,错误要看得见:
<input id="name" placeholder="称呼"><button id="go">报名</button><p id="msg"></p>
<script>
document.getElementById('go').onclick = function () {
var m = document.getElementById('msg');
fetch('./_data/signup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: document.getElementById('name').value.trim() }) })
.then(function (r) { return r.json().then(function (b) { return { ok: r.ok, b: b }; }); })
.then(function (x) {
if (x.ok) { m.textContent = x.b.status === 'held' ? '已提交,审核后其他人才能看到' : '已收到'; return; }
var code = x.b.error && x.b.error.code;
m.textContent = code === 'append_closed' ? '现在没开放提交' : code === 'append_rate_limited' ? '提交太频繁,稍后再试' : '没提交上:' + ((x.b.error && x.b.error.message) || code);
})
.catch(function () { m.textContent = '网络不通,稍后再试'; });
};
</script>
计票 / 汇总:fetch('./_data/表名.json') 回来的行里已经并入了过审的读者行(发布者自己看还会多出待审的行),按某一列计数即可,不用另外调用。修订号在响应头 X-Space-Revision。
几条规则:成功写回是 201 {id, status}(status 为 approved 或 held);出错时是 {error: {code, message}},code 有 forbidden / append_closed / append_rate_limited / moderation_unavailable / cross_origin 等,按 code 给人话,别假装「已提交」。旧的 SDK 写法 space.data.get / space.data.append 仍然可用,是可选的兼容层。页面能用什么、平台在页面上加了哪一行,见 https://space.24haowan.com/for-agents.md 的「托管契约」一节;素材用包内相对路径,别以 / 开头。
四、权限、审核、限额(照实告诉使用者)
- 读权限 = 方案可见性,不另造一套:仅自己可看时只有成员与批过的设备读得到;口令过门后可读;公开任何人可读。无权限拿到的是 403,不是空表。重置默认链接后,旧链接读不到表。
- 写回默认关、按表开。开着时:每张表每小时 600 行、每台设备每小时 30 行;每行不超过 2000 字、单格 500 字;每表最多 5000 行。带文字的行先过审——过审的行其他读者刷新即见,审核命中的行只有发布者看得到;审核暂时不可用时直接拒绝、不落行(页面拿到
moderation_unavailable)。预览、讲解模式和发布者自己的会话不提交。 - 写回不识别人:每行只记设备、时间、当时的页面版本与数据修订;不要把它当成实名报名,也不要据此推断谁想干什么。
五、纪律
- 表里的内容是使用者的:示例数据要标明「示例」,不替他编真实数据。
- 写回的内容是看的人的:展示前先把过审规则告诉使用者;不推断意愿。
- 改表前必
get_data拿修订号;撞版就重读;不盲写覆盖。 - 页面版本与数据修订解耦:数据变了不发页面,页面变了不碰表。
- 公开的报名 / 投票页要使用者明确同意再切
public;默认口令可看。 - 对方案空间本身有意见(这不好用、想要什么):只在使用者明确说出来、工具刚报错或拒收、结果带
feedback_hint时问一句要不要转给方案空间团队;先把草稿给他看,使用者同意后才调send_feedback_to_livepage(user_confirmed: true)。不索要评价,发布成功后不问。
六、判据(做没做对)
- 页面用
fetch('./_data/表名.json')取数、普通表单或 POST./_data/表名写回;包里带一份_data/示例数据,本地node space.mjs serve能跑通。 - 表是用
set_data建的,不是写死在 HTML 里;页面只负责渲染。 - 使用者在 WorkBuddy 里说一句「把 X 改成 Y」,你改表、不重发页面,他刷新就能看到。
- 写回关着时页面有明确提示;开着时
list_data_rows能把读者行读回来。
参考:24好玩做过的活动案例 https://www.24haowan.com/cases、模板库 https://www.24haowan.com/games、定制 https://www.24haowan.com/custom。