这是我为日常麻将局做的一个计分小程序。它的目标不是把麻将规则做得很复杂,而是先解决一个高频、具体的问题:线下打牌时,分数记录容易中断,累计分数容易算错,最后结算时还需要反复核对。
我希望这个小程序能把“创建牌局、添加玩家、记录每一局分数、自动汇总、查看历史、最终结算”这些动作放到一个顺手的流程里。对我来说,它既是一个实用工具,也是一次完整的小程序项目练习。
为什么做
线下打麻将时,计分这件事看起来简单,但实际使用场景里有很多容易出错的地方:
- 每局结束后需要立刻记录输赢,否则过几局就容易忘。
- 多个人累计分数时,手动加减容易出现口算误差。
- 中途有人想看上一局结果,需要翻聊天记录或纸面记录。
- 最后结算时,大家通常还要重新核对一遍总分。
所以这个项目的核心判断是:不要一开始就追求覆盖所有麻将规则,而是先把“记录”和“结算”做稳定。只要每一局的分数变化能被清楚保存,总分能被自动计算,历史记录能被随时查看,这个小程序就已经能解决真实问题。
技术栈
这个项目使用的是面向微信小程序的前端技术栈:
- uni-app:用一套 Vue 写法开发小程序页面,并通过构建命令输出微信小程序代码。
- Vue 3:负责页面组件、响应式数据和交互状态组织。
- Vite:作为开发和构建工具,启动快,适合小型前端项目快速迭代。
- JavaScript / TypeScript 风格的模块化代码:把计分逻辑、数据处理和页面展示拆开,避免所有逻辑都堆在页面文件里。
- 微信小程序本地存储:用于保存牌局历史、玩家列表和每局记录,让用户下次打开时还能继续查看。
选择 uni-app 的原因是它比较适合这类轻量工具型应用。项目本身不需要复杂后端,主要逻辑集中在前端:数据输入、分数计算、状态更新、本地持久化和页面展示。用 uni-app 可以把重点放在业务流程上,同时保留后续扩展到其它小程序平台的可能性。
项目架构
我在设计结构时,把项目拆成了三层:页面层、业务逻辑层和数据持久层。
页面层负责用户能直接看到和操作的部分,比如创建牌局、玩家管理、录入分数、查看历史和结算汇总。页面只处理交互和展示,不直接写复杂的计算规则。
业务逻辑层负责处理计分相关的核心规则。比如一局结束后,需要把本局每个玩家的分数变化写入记录,再重新计算当前总分。这里的重点是保证数据流清晰:每一局都是一条独立记录,总分则由历史记录汇总得出,而不是靠手动维护一个容易失真的数字。
数据持久层负责把牌局信息保存到本地。小程序的使用场景往往比较碎片化,可能打一半切出去,过一会儿再回来,所以本地存储必须能恢复当前牌局状态。这样即使中途关闭小程序,也不会丢失已经记录的分数。
整体结构可以理解为:
1
2
3
4
5
6
页面交互
-> 创建牌局 / 添加玩家 / 录入分数 / 查看历史
业务逻辑
-> 校验输入 / 生成对局记录 / 汇总玩家总分 / 生成结算结果
本地存储
-> 保存牌局 / 保存历史记录 / 恢复上次状态
这个拆分的好处是后续扩展会比较直接。例如以后要支持不同麻将规则,不需要重写页面,只需要在业务逻辑层增加不同的计分策略;如果以后要把本地存储升级为云端同步,也可以优先替换数据持久层。
核心数据设计
这个项目里最关键的数据不是某一个页面状态,而是“牌局”和“对局记录”。
我把一个牌局看成一个完整的上下文,里面包含玩家、每局记录、当前总分和创建时间。每一局记录则只描述这一局发生了什么:哪些玩家参与了计分,每个人分数变化是多少,记录时间是什么。
这样设计有两个优势:
- 可追溯:最终总分不是凭空来的,而是可以从每一局记录反推出来。
- 易扩展:以后增加备注、规则类型、番型、结算方式时,可以挂在单局记录或牌局配置上。
一个简化后的数据关系大致是这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Game
id
players[]
rounds[]
createdAt
updatedAt
Player
id
name
totalScore
Round
id
scoreChanges[]
note
createdAt
在实现上,我更倾向于把 totalScore 当成一个可以由 rounds 重新计算出来的结果,而不是完全依赖手动更新。这样即使后面增加“撤销上一局”或“修改某一局”的功能,也能通过重新汇总历史记录来保证结果一致。
功能流程
目前项目主要围绕以下几个流程展开:
-
创建牌局
输入玩家信息后生成一个新的牌局对象,并初始化每个玩家的分数。这个阶段重点是让开始使用的成本尽量低,不需要用户填写太多配置。
-
记录每一局
每局结束后录入玩家的分数变化。录入完成后,系统会生成一条 round 记录,并自动刷新所有玩家的累计分数。
-
查看累计分
页面会展示每个玩家当前总分,让用户不用再口算。累计分是整个工具最核心的反馈,所以展示上需要足够直接。
-
查看历史记录
历史记录用于复盘和核对。如果某一局有争议,可以回到对应记录查看当时的分数变化。
-
最终结算
根据总分生成结算结果,帮助玩家快速确认谁赢、谁输、差额是多少。
实现中重点考虑的问题
第一个问题是输入效率。计分工具如果录入成本太高,用户很快就会放弃使用。所以交互上应该尽量减少重复输入,把常用操作放在更明显的位置。
第二个问题是数据一致性。每一局的分数变化和最终总分必须对应起来,不能出现历史记录是一套结果、总分又是另一套结果的情况。因此业务逻辑里需要明确“单局记录是事实来源,总分是计算结果”。
第三个问题是异常场景。比如输错分数、想撤销上一局、中途关闭小程序、玩家名字重复等,这些虽然不是第一版最核心的功能,但在架构上需要提前留出空间。
第四个问题是项目可维护性。小程序项目很容易把逻辑都写进页面文件里,短期看开发很快,后期会越来越难改。所以我会把计分、汇总、存储这些逻辑尽量抽离出来,让页面保持清晰。
这个项目带来的收获
这个项目让我更清楚地体会到:一个小工具能不能好用,关键不只是界面做出来,而是业务流程是否顺。麻将计分看起来只是加减法,但真正落到产品里,需要考虑用户什么时候录入、怎么核对、如何恢复数据、怎样减少误操作。
从技术上看,这个项目也帮助我熟悉了 uni-app 到微信小程序的开发链路,包括页面组织、组件拆分、状态管理、本地存储和小程序构建。相比只写一个静态页面,这类工具型项目更接近真实应用,因为它有持续变化的数据,也有用户会反复使用的核心流程。
下一步
后续我计划继续完善几个方向:
- 增加撤销和修改记录功能,减少输错分后的处理成本。
- 优化分数录入方式,让连续记录多局时更快。
- 增加更清晰的结算视图,方便最后直接对账。
- 支持不同麻将规则的配置,让项目从单一计分工具逐步变成更通用的牌局记录工具。
- 继续整理项目结构,把计分逻辑沉淀成更独立的模块,方便测试和复用。
这篇博客也算是我对这个项目的第一次复盘。后面如果继续完善功能,我会把技术细节、踩坑记录和版本迭代过程继续记录下来。
修改记录
- 发布“麻将计分小程序”文章。
- 扩充技术栈、项目架构、核心数据设计和后续规划。