我用 ArkTS 写了个“吃什么决策器“,三种模式解决选择困难症
起因每天中午最痛苦的不是工作是想吃什么说实话我做这个 App 的动机特别朴素——我和同事每天中午花在今天吃啥上的时间比吃饭本身还长。三四个人站在工位旁边你说不想吃面他说昨天刚吃了炒饭来回扯皮十分钟最后还是去了楼下那家。这事儿重复了大半年我就想干脆写个工具把决策过程自动化算了。刚好那会儿在折腾 HarmonyOS 开发ArkUI 声明式写 UI 挺顺手的就直接用 ArkTS 撸了一个。App 叫「决定今天吃什么」今年上了华为应用市场目前版本 1.2.0。做了什么不只是一个随机器市面上同类工具我翻了一圈基本都是输入几个选项点一下随机出一个。说白了就是个Math.random()没什么留存的理由。我想做的不一样我要覆盖三个场景一个人不想动脑——直接转盘从自己收藏的餐厅库里随机抽。支持按距离、价格、口味筛选不会给你推 10 公里外的店。两三个人有分歧——投票模式。每个人划掉自己不想吃的剩下的候选再随机决定。这个模式我自己用得最多情侣之间特别好使不用争了。想精确控制——筛选过滤按预算和标签缩小范围再从结果里挑。另外做了历史记录排重。比如设置最近 3 次吃过的不再出现避免连着三天吃同一家的尴尬。技术实现聊几个点整个项目纯 ArkTS数据存本地轻量级场景没必要上云。核心的随机逻辑我用了加权随机每个餐厅有一个weight字段配合历史排重一起算export function pickRandom(restaurants: Restaurant[], options: RandomOptions): { winner: Restaurant; durationMs: number } { const start Date.now() const { settings, recentHistory } options const avoidIds new Setstring() const n Math.max(0, settings.avoidRecentN) for (let i 0; i Math.min(n, recentHistory.length); i) { avoidIds.add(recentHistory[i].resultRestaurantId) } const weights restaurants.map(r { const base settings.weightedRandom ? r.weight : 1 if (avoidIds.has(r.id)) return 0 return Math.max(0, base) }) const { item: winner } weightedPick(restaurants, weights) return { winner, durationMs: Date.now() - start } } 逻辑不复杂但这个最近 N 次排除的设计在实际使用中体感差别很大。之前没做这个的时候连着两天转到同一家同事直接说这破玩意儿是不是有 bug。 投票模式的实现也贴一下平票的时候按累计票数做加权随机不会死循环 arkts export function finishVote(session: VoteSession): string { const entries Object.entries(session.votes) let max -1 let winners: string[] [] for (const [id, count] of entries) { if (count max) { max count; winners [id] } else if (count max) { winners.push(id) } } if (winners.length 1) return winners[0] const weights winners.map(id session.votes[id]) const total weights.reduce((a, b) a b, 0) const r Math.random() * total let acc 0 for (let i 0; i winners.length; i) { acc weights[i] if (r acc) return winners[i] } return winners[winners.length - 1] } 候选列表的筛选用了一个 getCandidates 函数支持按标签必须全部命中、预算上限、距离上限三个维度过滤。数据模型里每个餐厅存了 price: {min, max}、distanceKm、tags[] 这些字段UI 上用 ArkUI 的 TextInput Slider 做筛选面板交互还算流畅。 转盘动画这块我试了三个方案。一开始想用 Canvas 画发现在 HarmonyOS 上 Canvas API 和 Web 端有些差异渲染帧率不太稳。后来改成用 ArkUI 的 rotate 属性配合 animateTo 做旋转效果好多了代码量也少。最后那个 Canvas 方案的代码全删了。 ## 一些取舍和踩的坑 **没做联网功能。** 我一开始想接地图 API 自动获取附近餐厅但一来鸿蒙侧的地图服务接入流程当时文档不太全二来这个 App 的定位就是管理你自己常去的店自动推荐反而会引入大量噪音。砍了。 **投票模式目前是单机传手机的形式。** 理想状态应该是多台设备通过分布式能力同步HarmonyOS 的分布式数据管理其实天然适合这个场景。但 1.0 版本时间紧就先做了一台手机大家轮流操作的方案。后续版本打算用 ohos.distributedKVStore 把多设备同步加上。 **转盘最大分段数限制了 12 个。** 超过 12 个选项时取权重最高的前 12 个显示在转盘上。这是个 UI 层面的妥协——太多扇形区域文字根本看不清。 ## 数据情况 坦白说目前下载量不大。刚上架华为应用市场不久还在冷启动阶段。鸿蒙原生 App 的用户池确实还在增长中我看来这个时间点上架反而是占位的好时机——等 HarmonyOS NEXT 铺开纯鸿蒙应用的需求量会起来。 App 体积很小安装包 3MB 不到。启动速度在我的 Mate 60 上实测 0.3 秒左右进入主页轻量工具就该这样。 ## 后续计划 - 分布式投票多台鸿蒙设备同步 - - 支持导入高德/大众点评收藏夹 - - 桌面卡片一键转盘不用打开 App 对了如果你也在做 HarmonyOS 开发特别是 ArkUI 动画和本地存储这块欢迎交流。我在这个项目里踩的坑还挺多的有些文档没覆盖到的细节只能靠试。 华为应用市场搜「决定今天吃什么」就能找到。