站长头像

清酒Blog

岁岁平,岁岁安,岁岁平安!

文章 评论 标签
19 23 8

电子礼金簿2.0:把人情往来记成一本清楚账 > 收礼、送礼、还礼。

作者头像 作者头像

清酒 / 09-10 / 0 阅读 / 编辑

电子礼金簿:把人情往来记成一本清楚账,收礼、送礼、还礼

摘要:随礼是中国式人情里最绕的一笔账:谁家办事随了多少,多年后对方办事要还多少,记在纸上会丢,记在脑子里会乱。电子礼金簿把这个千年难题做成了一个 App——顺便,为了把老账本搬进来,我还搭了一台 OCR 微服务。

一、场景:一本传了几代的账

几乎每个中国家庭都有一本礼簿:红白喜事上,管事的先生坐在礼桌前,把每一个名字和每一笔金额记下来。这本账的用途只有一个——等对方家办事的时候,知道该还多少。

问题在于纸质账本的命运:搬家会丢、字迹会糊、翻找靠缘分。谁都不确定十年前那笔到底是六百还是八百,于是人情在客气里悄悄地亏欠或者超额——多还了尴尬,少还了失礼,而没有人真的记得清。

电子礼金簿要做的事很收敛:把这笔账记清楚、算明白、找得到。 不做社交,不做社区,不教你怎么做人情——就是一本可靠的账。

二、数据模型:两个实体,一条铁律

账目类产品最怕数据模型失焦,所以它的模型刻意简单,只有两个主实体:

  • 事项——一场宴席、一次满月、一桩白事,是钱的"场合";
  • 记录——某人在某事项下收的或送的某一笔,带金额、渠道、关系、日期。

收礼和送礼分两条线,同一页切换。而所有统计共用一条由服务端强制执行的铁律:口径不许客户端说了算。 比如方向和状态字段,客户端传上来什么样不算数,服务端按规则钳制归一——收礼方向的记录不允许带"已还"状态,因为那是另一条线的属性。一个脏数据进来,出来时是干净的;客户端防不住的,服务端兜住。

这些规矩看着琐碎,但账目产品的信用就是由它们垒起来的:数字对不上一次,用户就再也不信你了。

三、为礼桌设计的效率细节

想象一下真实的使用场景:礼桌上人来人往,几十秒就要记一笔,一手可能还端着茶。所以每个交互都在抢时间:

  • 大金额输入。数字键盘加大,常用金额做成快捷块,一点即填;渠道(现金、转账……)同样快捷块选择;
  • 事项快捷新建。记着记着发现还没建今天这场事,当场建,不用跳出去;
  • 姓名自动补全。输入姓氏,历史记录里的人名按频次浮上来做候选——礼簿的重复率天然极高,这个功能省一半输入;
  • 左滑操作。记录列表左滑直接"标记已还"或"删除",横滑意图做了锁定处理,跟列表的上下滚动互不打架——手势打架是移动端列表页最常见的手感灾难,值得专门写状态机去防;
  • 删除撤销窗。删除不是立即生效,六秒内可撤销,期间不落盘不同步;页面切走时才把未决的删除提交——防"手一抖、数据没了"和"删了其实没删"两个方向的灾难;
  • 长按快捷菜单。长按一条记录:标记还礼、再记一笔、复制这一条、删除——高频动作全部一按直达。

四、还礼的口径:一个容易算错的地方

做对账的时候遇到一个经典问题:标记"已还"的收礼,算不算送出去的钱?

直觉会说不算——还礼只是把收的那笔结清了。但顺着往下想就发现坑:如果"标记已还"只打个状态标记、不产生任何金额记录,那么送礼总额和对账净额里就漏掉了这笔支出,账面永远对不平——人情状态显示"已还清",净额却没减,两处矛盾。

最终的方案是"引导式对冲":标记已还时,App 主动问一句——是只做标记,还是记一笔对冲的送礼?选后者就自动生成一笔送礼记录:姓名、金额、渠道自动带过来,日期是今天,备注写明对应哪天的收礼,并且带防重复校验,同样的对冲不会生成两次。两条触发路径(左滑、长按)都收敛到这同一套逻辑。

这样之后,收礼总额、送礼总额、对账净额三个数字天然自洽。我还专门跑过一个验算:收五百、还五百,净额归零,口径闭环。

账目产品的每一个口径都要经得起"两个页面互相质询"。 这是这个项目教会我的事。

五、对账与统计:人情有了坐标系

围绕这本账做了三层视图:

  • 往来对账——按人聚合收、送、净额,三种排序,展开是和这个人的全部往来时间线。和谁亲、和谁疏、该还谁多少,数字不会说谎;
  • 年度统计——年度总览、同比去年、十二个月收送双柱图、关系分布、渠道分布、随礼排行、年度之最。年底翻开看一眼,一年的来往尽收眼底;
  • 事项详情——单场宴席的品牌头卡、随礼人排行、全部记录、快捷记账,随礼名单完整可查。

记录页还支持按日期/金额排序和金额区间筛选——查"去年随过的两三千的几笔"这种问题,是纸质账本永远做不到的。

六、礼簿图片:把仪式感留在家庭群里

事项详情可以一键生成一张"礼簿图片":画布上合成品牌头图、事项信息、随礼人排行和金额——存进相册,直接转发家庭群。

这是给长辈做的功能。很多老人不会也不愿意用 App,但家庭群里转一张体面的礼簿图,他们看得懂、也愿意看。数字账本以这种方式回到了它原本的生活场景里——不是替代那本纸质礼簿,是给它续了命。

配套的还有一个克制的提醒设计:记录备注里约定一种轻量写法就能标记待还的截止日期,首页的未还卡会显示最近的到期项。不动数据结构、不做迁移,用一个约定俗成的语法解决八成的需求——能用约定解决的,就不上重型机制。

七、拍照导入:一台自己搭的 OCR 微服务

最有意思的部分在这:把家里那本老礼簿搬进 App。

一张手写礼簿照片,人名一列、金额一列,手工录入一页要半个多小时。所以做了拍照导入:拍一张照片,识别出人名和金额,逐行确认后批量入账。

先说一个架构决定:识别不用任何云服务。 礼簿是极隐私的东西——谁家的人情账愿意传到别人的服务器上?所以识别全程在本机:后端通过带密钥的内网调用,打到一个只监听回环地址的识别微服务上。独立成服务而不是塞在网页进程里,是因为运行环境的安全策略禁掉了网页进程执行外部程序的能力——进程没权限做这件事,那就让有权限的进程来做,两个进程之间用一把只有它们知道的密钥互相认证。

识别引擎选了开源 OCR 的中文模型,但真正决定可用性的是引擎之上的业务解析层:

  • 按坐标配对。识别引擎输出的是"文字 + 坐标",解析层按列的横向位置把人名和金额配对——礼簿的排版天然是两列结构,坐标比内容更可靠;
  • 大写金额换算。"陆佰贰拾元"要变成六百二十——中文大写金额的换算是手写礼簿的标配,规则繁但值得写;
  • 置信度过滤。低置信度的行标出来让人多看一眼。

识别结果进一个可编辑的预览列表,用户逐行确认后批量入账——机器打草稿,人做终审。识别准确率不是百分之百,但配合人工确认,一页账从半小时变成两分钟,这已经值回票价。老账本就这样一页一页搬了进来,而且从第一笔起就是干净的、可搜索的、丢不了的。

八、老账本的搬家:一次数据迁移的诚意

App 之前,这个产品有一个更老的原生版本,带着几年的真实数据。迁到新架构时,账号体系和数据模型都变了,迁移方案做了三件容易忽略的事:

  • 密码平移。老用户的密码哈希原样搬过来——老用户用老密码直接登录,"换系统所以请大家重置密码"这种事,能免则免;
  • 标识延续。所有老数据挂上带"遗产"前缀的标识,新旧数据的唯一标识空间互不侵占;
  • 账号归并。几个老管理员账号归并进新体系,权限不变。

用户感知到的迁移体验是:下载新 App,用原来的密码登录,数据全在。最好的迁移就是没有被察觉的迁移。

九、一本账的保险柜

App 之外还有网页版(登录后可用,适合在电脑前批量录入和导出表格)、管理后台,三个入口操作的是同一本账,改动即时互通——后台改的,App 马上能看到;App 删的,回收站里捞得回来。

配套的还有 QQ 一键登录、家庭多成员共用一本账、应用内自更新。整套跑在我自己的云端底座上,每日加密备份、异地推送——人情账和孩子的成长记录一样,属于丢了就真的没了的数据,备份这件事它没有资格出任何差错。

十、功能全景与技术栈

功能全景:

  • 账目——收送双线、事项管理、服务端口径钳制、引导式对冲还礼、未还人情聚合;
  • 视图——往来对账(按人聚合)、年度统计(同比/双柱/分布/排行/之最)、事项详情与礼簿图片一键生成;
  • 效率——快捷金额与渠道块、姓名频次补全、左滑手势(意图锁定)、删除撤销窗、长按快捷菜单、CSV 导出(防公式注入);
  • 导入——拍照 OCR(列坐标配对、大写金额换算、置信度标注、可编辑预览);
  • 多端——App / 网页 / 后台同一本账实时互通、家庭多成员、QQ 一键登录、应用内自更新、轻量待还提醒。

技术栈:

层选型
运行环境Linux + Nginx + PHP 8.2
后端自研 KX-Verse 底盘(Laravel 12)
数据库/缓存MySQL / 文件缓存 + 全页缓存
App 端uni-app(Vue 3),云打包分发
识别服务Python + 开源 OCR 中文模型(TSV 坐标输出),systemd 微服务,回环监听 + 密钥互认
图像合成服务端画布离屏合成礼簿分享图
登录QQ 互联原生登录

十一、写在最后

电子礼金簿目前迭代到 1.8 版本。它大概是四个产品里最有"烟火气"的一个:记录的不是工作也不是孩子,而是中国人情社会里那本最微妙的小账。

技术做的所有事——双线模型、对冲口径、坐标配对、大写换算、多端同步——最终都服务于一件事:让下一代人翻起这本账的时候,清清楚楚,明明白白。