产品设计 · 编程 · 已上线 · 2026.10.27
CASE 05

作业小管家

孩子没有钉钉账号,我们就给他一块能打勾的作业板

PWA iOS EdgeOne 云函数 家庭码同步 已上线
立项2026-10-18
迭代10 天 · 8 次上线
技术原生 JS · Service Worker · Blob 存储
方向亲子工具 / 低频同步
一句话核心

家长在手机上把老师发的作业粘进去,孩子在 iPad 上点卡片打勾,两台设备自动同步。没有账号、没有验证码、不会过期——一串 20 位的家庭码就是钥匙。

02BACKGROUND

背景

钉钉是给大人的,孩子被挡在了外面

// 问题
孩子上一年级,家校沟通用钉钉群,老师每天在群里发作业。孩子没有钉钉账号,也不该有——那不是给六岁孩子设计的东西。于是每天晚上的固定动作变成了:家长看群、记住、口述一遍、盯着做完、再问一遍。作业本身只有几行字,管理它的成本却落在家长身上。我要的不是另一个家长用的待办清单,而是一块孩子自己能看、能勾、不用问妈妈的板子。
// 需求拆解
  • 孩子能独立用:字要大、卡片要大、点一下就完成,不需要读说明
  • 家长零负担录入:从钉钉复制整段粘贴,自动拆成一条条,确认页默认全对
  • 两台设备随时同步:手机录的,iPad 上立刻能看到;iPad 勾的,手机上看得到完成率
  • 别让我维护它:不用注册、不用每天登录、不用手动清理数据
用户故事:孩子晚上自己打开 iPad,看到今天有几张卡片,做完一张点一下,卡片变灰沉到后面。做完最后一张时,他知道今天结束了——这个动作里,不需要家长在场。
最初写下的第一条判断:胜负手不在于解析得准不准,而在于孩子愿不愿意每天自己点开。
03APPROACH

方案

四个当时拍下的决定,两个后来被推翻

// 形态:为什么是 PWA
不做小程序,也不做原生。一个链接,两台设备各添加到主屏,改一次两端同时更新——这对一个只服务一个家庭、需求还会天天变的工具来说,是唯一合理的选择。代价是继承了 iOS 对网页的全部限制,这个代价后来付得很清楚。
// 孩子端:只借符号,不借尺寸
  • 不用勾选框,点整张卡:6 岁孩子的手指精度撑不住 22px 的圆圈
  • 完成不从列表消失:卡片消失会让孩子反复找「我的作业去哪了」,改成变灰、打勾、沉到底部
  • 只做正向计数:不显示「还差 3 项」,只显示做完了几个
// 录入:只跟文字对接
不对接钉钉的任何接口,只处理粘贴进来的纯文本。规则解析:序号、换行、分号切分;科目关键词识别;「每天」「明天」「下周一」判定重复与截止。这样学校换任何平台,这边零改动。
// 同步:从账号换成家庭码
最初用云服务的手机号登录做同步。问题是这个应用一天只用一次,而登录态按天过期——任何「打开时续期」的策略都正好撞在过期边界上,于是每天都要重收一次验证码。最后的解法不是把登录修得更稳,而是把登录删掉:一串 20 位随机码当钥匙,两台设备填同一个码就通。
家长粘贴钉钉原文
→
规则拆条科目/类型
→
确认清单默认全对
→
云端存储按家庭码分开
→
iPad 打勾状态回传
两端看到的东西设计取舍
家长端完整对齐系统待办应用:一行一条、左侧圆圈、底部悬浮输入、完成下沉
孩子端只保留符号和色标,尺寸全部放大到整屏可点
两端都不做不模拟毛玻璃质感——网页做出来又慢又假
04USAGE

应用

一天两次操作,一次在手机,一次在 iPad

家长端 · iPhone
今天
语文:朗读第 5 课 3 遍
数学:练习册 P12、P13
英语:跟读 Unit 2
右下角一键粘贴,整段自动拆条
孩子端 · iPad
今天有 3 件事
朗读第 5 课 3 遍
练习册 P12、P13
跟读 Unit 2
// 孩子这一侧
  • 打开就是作业页,没有设置、没有登录、没有别的入口
  • 点整张卡片即完成:变灰、打勾、播放一声轻响、沉到后面
  • 点错了再点一次就撤销,不会丢
  • 过了午夜自动换成新的一天,iPad 常年不关也不用管
// 家长这一侧
  • 粘贴老师原文 → 自动拆条 → 确认页只删多余的,其余全采纳
  • 写一条也行,支持「每天」「明天」「下周一」这类说法自动判类型
  • 一周视图看每天的完成率,不用问孩子做完了没有
  • 长按孩子端日期 1.5 秒进家长面板,孩子看不到
关键约束:家长每晚只用一次,孩子当晚只用一次。整体节奏是一天两次,不是随时在线。这条约束后来决定了整个同步方案的技术上限。
05RESULTS

效果

真正跑起来之后,才有数字可看

57
云端累计作业
40
打勾记录
0
需要登录的次数
改造前后的硬指标之前之后
定时器唤醒8640 次/天1 次/天
空闲同步请求每 10 秒拉全量数据只拉版本号,几十字节
数据体积只增不删,一年约 421KB封顶约 161KB(90 天自动清理)
同步故障恢复一次网络抖动就判定退登自动重试,不打扰
// 关于「一天只跑一次」
最早用 30 秒轮询检查日期是否跨天,一天 2880 次。后来改成算出到明天零点还有多少毫秒,只设一个闹钟,醒来后重排下一次——一天 1 次,而且准时。省下来的不只是耗电,还有「一个简单工具在后台偷偷跑着什么」这件事本身带来的心理负担。
顺带发现真正的浪费不是那个 30 秒的检查(一次 new Date 加字符串比较,微秒级),而是另一端 15 秒一次的全量字符串比对——一天 5760 次,而那个功能早被云同步取代了。
06POSTMORTEM

复盘

六次撞墙,四次是我的判断问题

01每天同步都要重新登录
问题手机和 iPad 每晚都要重新输一次手机号验证码,30 秒的事变成两分钟。
原因access token 剩 90 秒才刷新,而使用间隔是 24 小时——第一次需要刷新时,refresh token 正好也到期了。
解法先做了每 6 小时主动续期,被一句话推翻:没人会为了续期专门打开应用。最后删掉整个认证层,换成 20 位家庭码。
任何依赖「用户会经常打开」的续期方案,在低频应用里都不成立。
02时不时自己退登
问题登录后隔几天就弹一次登录框,说不清是杀进程还是放太久。
原因会话接口返回空有三种含义:网络抖动、刷新冷却中、并发刷新被顶掉。旧代码一律当成退登。
解法加三态判定,只有确实收到 401 且本地票据被清才算出局;再加跨页面互斥锁,避免两个页面同时续期互相顶。
一次网络抖动就是一次假退登。判死的门禁,要设得最高。
03iPad 装出来是家长界面
问题明明从孩子页地址添加到主屏,打开却是家长端。
原因两个页面共用一份启动配置,启动地址指向家长端。iOS 在「添加到主屏」那一刻就把它固化了。
解法给孩子端单独建一份启动配置,并让用户删掉旧图标重装一次。
一个域名做多入口 PWA,每个入口都要独立配置。平台规则在安装那一刻写死,改代码改不回来。
04孩子端打开后没有任何入口
问题iPad 上只剩大字作业,没有设置、没有登录,也没法同步,家长同样找不到办法。
原因自动弹登录框的条件是「本地一条作业都没有」,而 iPad 有旧数据就不会弹;孩子端为防误触又把所有入口藏了起来。两个各自合理的设计叠在一起,成了死胡同。
解法加一条状态提示条:没连上就提示连上,断了就提示重试。入口跟状态走,不跟身份走。
防误触不能把家长也挡在外面。
05家庭码显示成 184 位字符
问题规则说好是 20 位,生成出来却是一长串看不懂的字符。
原因设置页还留着旧版的「生成同步码」按钮,位置比家庭码入口更显眼;而家庭码入口在连上之后还会消失。用户找不到对的,只能点错的那个。
解法删掉旧通道,家庭码随时可回看,换码加二次确认。
废弃功能要连入口一起删。「没坏」不是保留它的理由。
06定时器一天唤醒 8640 次
问题应用常驻后台,担心耗电,于是提出「12 小时检查一次就行」。
原因真正的浪费不是那个 30 秒的日期检查,而是另一端 15 秒一次的全量字符串比对,一天 5760 次,且功能早已被云同步取代。
解法日期检查改零点单次闹钟;删掉全量比对改用存储事件;同步轮询改自适应退避。
说「太重了」的时候,先把所有定时器列出来量一遍,别只改被指出的那一个。直觉的方向通常对,指的位置常常错。
// 把六条放到一起看
前两条是判断逻辑写错了,第三条是平台规则没先查,第四第五条是在修表象没理顺结构,第六条是照字面执行了一个方向对但不成立的方案。
最后留下的那句话

前两次我在问「它为什么坏了」,第三次才开始问「它为什么在这里」。
修一个不该存在的层,修得再好也是错的。

// 判断信号
同一个问题修到第三次,就该停下来问:这一层是不是根本不需要存在? 第二次失败是运气,第三次失败是信号。
// 这个项目还长出了一个方法
复盘之后整理出一张开需求对齐卡:谁在什么时间用它几次、谁不能操作它、什么绝对不能发生、什么可以牺牲、什么时候算失败。这五条如果第一天就写下来,上面六条问题里至少三条不会发生。