
嗨,我是范米花儿,换新头像了,大家别不认识我~
最近我用AI 编程 ,独自为公司内部从0到1做了一个小程序 ,主要用来解决一件事:员工外勤填报 。 核心能力是「语音一句话」快速生成外勤记录,同时也支持手工填报、全员记录查看、客户与成员管理、考勤填报定时提醒推送等。

真实数据信息 已脱敏 ,录屏内所有内容(员工/记录/客户)为 虚拟数据 。
借助 AI 编程,从 2/24 到03/02 ,我独自完成 该外勤小程序从 0 到 1 的 全链路开发与上线 :
包括小程序注册与配置、产品与体验规划、前端页面开发、后台管理端搭建、接口与数据库实现、腾讯云语音识别与大模型结构化解析接入,以及微信体验版上线前检测、部署与真机联调等全流程落地。

- 定义前台功能 :先明确用户角色与最高频动作,写可迭代 PRD
- 方案先结构后细节 :用 AI 产出多套方案,并用 ASCII图 先画清页面层级、模块关系与关键状态,再进入 UI 与代码实现。
- 三段式前端落地 :React 快速探索 → Uniapp 迁移适配 → 小程序真机联调校正。
- 根据前台内容,确定管理后台 :前台流程跑顺后,再补后台最小集合(记录/客户/成员/配置)与权限边界,再进行后台界面开发。
- 接口与数据库后收口 :先稳定实体关系与字段,再固化接口与表结构。
- 最后接入语音与模型 :在字段与提交规则明确后,转为接入腾讯云语音识别与结构化解析
- 上线校验与部署 :提交前做敏感词与业务校验,完成微信检测、部署与上线准备。
全部梳理的话,内容太多啦~
其中:语音是整个小程序的重点,包含很多设计思考和功能开发的技术点,所以整理这部分给大家~
- 外勤填报天然发生在移动场景里,用户很多时候不适合长时间手动填报;
- 这类记录也不是简单备注,而是至少包含日期、时间、客户、类型和事项等结构化内容;
- 如果完全依赖手填,流程会很重,员工填写意愿和完成率都会受到影响;
所以我希望把它做成: 一句话开始 → 系统理解 → 用户确认 → 合规提交 。
如果把这套语音填报当成一个完整模块来看,它可以拆成五个连续阶段,分别承担 “引导、输入、理解、修正、校验“职责

- 首页引导: 告诉用户从哪里开始,以及一句话应该怎么说
- 录音交互: 把开始录音、取消录音、结束录音做成清晰可感知的过程
- 系统解析: 把语音先转成文本,再转成结构化字段
- 确认页: 让用户在提交前重录整段语音或逐项修正
- 正式提交: 完成敏感词检测,并把内容写入正式业务记录
1. 入口位置
是整个小程序页面架构里最关键的一环 :它决定了用户的第一步往哪走、最高频任务触达路径有多长、以及首页到底是“总览页”还是“任务起点”。
所以在首页引导这一部分,我做了2种方案:
方案一
这个最开始是同事提的想法:首页上方放“外勤填报”等主入口,下方展示全员记录;

这个结构对 “ 管理员视角”是友好的:打开首页就能顺手看全员数据与概览,入口也清晰,整体很像一个标准业务工作台,并且它的列表天然适合做成 全员瀑布流 ——记录承载量很强。
但在前端demo开发出来之后,我发现它有两个不匹配:
- 录入链路偏长:语音快填是“点入口 → 跳到语音页 → 长按 → 确认页”,开始说话前就多一次点击和一次切页。
- 任务优先级不匹配: 首页把“浏览全员记录”和“发起填报”放在同一层,默认更像一个总览页。
同时,根据公司实际情况,管理员本身也是员工且外勤频率更高。所以, 无论哪个角色,进入前台后的第一目标其实非常明确,就是先完成自己的填报。尤其是基于语音能力,首页的最高频任务进一步向“快速发起填报”集中。
方案二
于是在一天夜里,我决定推翻诉求并进行重构...

把首页当作更明确的任务起点——上方承接个人视角的信息(今日记录、日期、说法引导),核心动作从内容区独立出来,作为右下角热区直接长按发起;全员记录独立成单独页面/菜单,“我的”承接个人管理。
当时我也考虑过一个现实问题: 方案二把列表放在上方可视区域,如果列表很多,确实不适合像全员瀑布流那样无限滚动 ,所占区域高度会过小。
但这里在于:方案二首页展示的不是全员列表,而是 当日的个人记录 。在我们的业务里,一个人当天最多也就去一两个地方, 记录量非常有限,甚至为空 ,几乎不存在需要长列表滚动的情况。也正因为这个前提成立,首页才可以采用“个人记录 + 主动作入口”的结构:
核心价值:
- 目标更一致 :管理员也是高频填报者,首页优先服务“我的内容 + 快速录入”更符合真实使用顺序。
- 启动更短 :从“点击 + 跳页 + 长按”缩短为“打开就能长按”,对高频任务更关键。
- 操作更顺手 :完成触达、长按、松手这一整套连续操作,放在单手热区更稳定。
补充,一些开发细节(设计师友好版):
- 触控热区要做足,降低误触失败率;
- 长按期间拦截页面滚动与触摸穿透,避免手指滑动导致页面滚动/录音中断。
2. 示例引导与自动收起

只有入口还不够,用户即使看到了长按按钮,也不一定知道一句话应该怎么组织。
所以首页里还增加了一块 “一句话填报指引” 。这块指引的目标不是解释规则,而是降低开口门槛。
它直接给用户一个可以模仿的示例句,并把这句话里隐含的结构拆成更容易理解的 槽位信息 ,比如日期、时间段、客户和事项。
这个思路的灵感来自于我之前一直在做的 ChatBI 项目。
后来我又补了一步很轻的交互处理:点击 “知道了” 后,这块指引会自动收起。因为它本质上是一个 新手辅助模块 ,而不是首页里的永久说明区。
新用户需要它来建立表达预期,熟练用户则更需要一个更干净、更直接的首页入口环境。自动收起这一步的价值,不在于多了一个按钮,而在于它让首页引导具备了“可退场”的能力。
一些开发细节(设计师友好版):
用本地存储/用户态记录 “已读” ,做到第一次使用之后,默认收起,不需要手动折叠(同时保留展开指引)
用户真正开始使用后,第二个关键点就是录音过程本身够不够顺:

1. 录入方式
常见的语音录入方式一般分为两种:
- 按钮型入口 :通常采用「按住说话、松手发送、上滑取消」的交互,适合高频、短路径、强调快速完成的场景,录音结果往往会直接发送或进入下一步。
- 输入框型入口 :通常嵌在文本框内部,更像是文字输入的补充。常见做法是「点击开始、点击结束」,再将识别结果回填到输入框中,方便用户二次修正。
本项目里其实有两个语音入口:一个在 首页主入口 ,另一个在 确认页的输入框区域 。但我最终没有让它们分别走这两套行业常见模式,而是将两个入口 统一为同一套长按录音逻辑 。
原因在于:这两个入口虽然位置不同,但本质上都属于 同一条语音填报链路 。尤其在确认页,语音并不只是“补充输入框”的能力,它还承担了 整段长按重录 和 单个外勤事项补录 的作用。
因此我把它们统一到底层同一套长按逻辑上:
- 在首页,语音以 主按钮 形式出现,突出“快速开始”
- 在确认页,语音嵌入 输入区域 ,服务于“补充与修正”
入口位置不同,但 触发方式、页面反馈、结果流转 保持一致
统一之后,用户感知到的是: 同一条语音填报路径在不同位置提供的两个入口 ,而不是两套交互规则不同的录音功能。
但是,首页的主按钮位置稳定、热区完整,而确认页和填报页里的语音入口往往嵌在输入框或底部操作区里,位置会跟着表单结构、滚动状态和机型高度一起变化。也就是说,交互规则虽然统一了,承接这套规则的物理环境并不统一。

所以后面我实际上又做了一些补充:
开发细节(设计师友好版):
- 物理分区: 语音按钮虽然看起来嵌在输入框里,但不能真的压在 `textarea` 上方,否则长按会同时触发输入框和录音两套行为。最终我把输入区拆成“上半部分负责文字输入,下半部分负责清空和录音按钮”,保留视觉一体感,但把命中区域真正拆开。
- 长按保护: 小程序里长按启动录音时,遮罩挂载、组件切换和原生触摸事件会互相影响,容易在刚进入录音态时收到异常 `touchcancel`。所以我加了一小段保护窗口,让按钮视觉上立即进入录音态,但短暂忽略异常取消事件,等状态稳定后再恢复正常的松手结束和上滑取消。
- 动态锚点 :填报页和确认页里的录音按钮位置不固定,所以遮罩、提示文案和波形不能写死在某个屏幕高度,而是要根据按钮真实位置去生成整块录音反馈层。另外,长按按钮放在表单最后,本身就规避了两个风险:一是它不会像中上部控件那样滚动到页面最顶部,超出热区的问题;二是如果在最底部超出,用户也必须先滚动到输入框位置才能看到并操作它,所以它也不会落在当前视口之外、只剩一部分可按,天然保证它既不会超出顶部热区,也不会因为太靠下而被裁掉可操作区域。
- 录音能力抽成统一组件 :首页与确认页只是不同容器/不同样式复用,同一套事件与状态机。
2. 状态语言与过程反馈
语音交互里有一个常见分岔点: 录音过程中是否实时回填识别文本 。主要为以下2种:
- 边录边预览 :录音时持续返回中间结果,页面同步展示,录音与修正几乎同时发生,更像即时转写工具。
- 一句话录完再处理 :先完成一次录音,再进入识别、解析与确认流程,更强调“提交一段完整输入”的确定性,也更容易与确认页、提交动作形成闭环。
本项目最终选择的是后者。核心原因在于: 我们做的是填报类语音 。填报天然不是“说完就结束”,而是需要落到 确认页的表单结构 里:字段要对齐、事项要拆分、内容要可编辑、最终要提交。既然确认页本身就是必须存在的一步,我们就不需要在录音过程中实时回填中间识别结果。相反,先把一段语音完整录完,再进入识别、结构化解析与确认,链路更清晰,也更符合用户预期:先完成输入 → 再看结果 → 再做修正 → 再提交 。
一些开发细节(设计师友好版):
把录音过程做成明确的状态机:录音态 / 取消态 / 结束态,首页和确认页完全复用同一套状态语言。

下面的过程反馈,可以收敛为三段: 开始切换 → 过程保障 → 可感知听写 。

开始切换:从“浏览态”进入“录音态”

用户长按开始录音后,页面不会只让按钮变一下,而是 整体切到录音态 :遮罩出现、背景降权、主按钮激活、提示文案明确下一步操作。
目的只有一个:让“录音开始”这件事 被明确感知 。 只有当用户确信系统已经进入录音状态,后续的长按、上滑取消才有信任基础。
一些开发细节(设计师友好版):
进入录音态后展示遮罩,降权其他内容,拦截触摸穿透,避免误触页面导致录音中断或跳转。
过程保障:时长、取消区、音量

录音态建立后,系统还要持续告诉用户“录音仍然有效”,并且让结果可预期。录音过程中页面同步做三件事:
- 时长记录 :确保达到有效提交门槛,减少误触/空录被带进后续识别流程。
- 取消区监听 :当手指进入取消区,立即切换提示与视觉状态,让“松手发送 / 松手取消”有明确分界。
- 音量采样 :为波形提供真实驱动,让反馈不是装饰,而是“系统正在听”的证据。
这三类反馈分别解决三个风险: 不确定是否录上了|不确定松手会怎样|不确定系统有没有听到 。
可感知听写
波形动画我把它当成“听写可信度”的核心反馈,因此做了三层处理:
① 真实驱动
这里的波形是“真音量驱动”的:录音会产生 原始声音数据 ( PCM ,可以理解为最原始的声音采样点),我会用 RMS (可以理解为“把这一小段声音的强弱做一个平均”)算出 当前音量 ,再把它映射到 0~1 的范围,用来驱动波形高度,也就是说话越大声,波形越高;停顿或变小声,波形就会跟着变弱。
② 可读性增强
如果直接用瞬时音量去驱动柱子的高度,波形会抖得很硬,用户也很难从中判断“系统到底有没有听到”,所以要做到2点:
- 先做平滑过渡 :不是每一帧都立刻跳到最新音量,而是让当前波形逐步靠近目标音量,减少突兀的抖动,让视觉反馈更稳定。
- 提升轻声区的可见性 :现实里用户经常不会一直大声说话,如果必须大声波形才有变化,反馈就不可信。所以对音量做了一个“非线性放大”。
③ 听感连续
录音时用户会自然停顿、换气。如果波形在停顿的一瞬间完全静止,很容易让人误以为录音中断了。所以要给“静音/停顿”留了一层很轻的 呼吸基底。
另外,波形本身也不是所有柱子一起等高变化。每一根柱子的高度还会叠加时间偏移、中心包络和取消态颜色切换,所以最终看到的效果更接近 连续起伏的声浪 ,而不是一排机械同步跳动的柱状条。进入取消区后,颜色也会跟着从正常录音色切到 取消态颜色 ,让视觉反馈和操作结果保持一致。
这整套持续反馈最终回答的是三个问题: 现在是否真的在录、系统有没有正常接收到声音、此刻松手到底会发送还是取消。 只有这三个问题始终清楚,用户才会把这条语音路径当成可靠的输入方式,而不是一次不太确定的尝试。
在录音结束到结果落入确认页之间,我又补了一层 轻量的处理中遮罩 。因为这中间实际还要经过上传、转写和结构化解析,如果没有过渡反馈,用户会误以为操作没有生效,容易重复触发录音或打断当前流程。
如果说「系统解析」负责把一句话变成草稿字段,那么「确认页」负责把草稿变成可提交的正式记录 。这一步看起来它其实承担了三个关键任务: 接住不确定性、提供修正手段、把链路收口到可控提交 。

1. 为什么确认页是“必需的一层”?
语音输入天然不确定,主要来自三类问题:
- 听写误差 :ASR 可能把客户简称/全称听错
- 表达缺失 :用户一句话里可能缺日期、缺客户、缺时间段
- 结构拆分偏差 :客户和事项混写、顺序变化、语义省略,导致字段被拆错或拆不全
如果没有确认页,链路会更短,但业务会变得不可控:错误会直接进入正式记录,后续只能靠人工回改,长期成本更高。 所以确认页的定位是「 半自动填写 」:系统先生成结构化草稿,用户再确认与修正。
2. 确认页接的是什么?
确认页承接的不是一段自由文本,而是一份 结构化草稿 。它的特点是:
- 字段已经被拆成“可填表”的结构(例如:类型、客户、日期、时间段、事项列表等);
- 用户在确认页的操作是“校对与编辑字段”,而不是“重写一句话”;
- 草稿可以带缺失/异常状态(比如缺客户、缺时间段、事项为空),确认页据此提示用户补齐后再提交。
一些开发细节(设计师相对友好版):
这份草稿( draft )是由服务端的 transcribe 流程产出的。这里的 transcribe 你可以把它理解为“ 把音频转成可填表的草稿 ”这一整步:先把语音 转写成文字 ,再把文字 解析成结构化字段 ,最终把结果交给确认页。
具体它分两层解析,且都在服务端完成:

- 腾讯云语音识别( ASR )|音频 → rawText: 服务端先调用腾讯云的语音识别能力(ASR,简单理解就是“语音转文字”),做“一句话识别”,把音频转成一段 rawText (就是“原始识别文本”)。
- 结构化解析|rawText → draft: 拿到 rawText 后,transcribe 会继续做“把一句话拆成表单字段”的解析,输出结构化草稿 draft (draft 就是“可编辑的草稿字段”,解决“这句话怎么填表”),字段通常包括:类型、客户、日期、时间段、事项列表等。
在结构化解析阶段,我采用「 规则解析 + 大模型解析 」组合:
- 规则解析更擅长稳定明确的结构化信息(日期、时间、类型等),也作为兜底;
- 大模型解析更擅长处理不规整自然语言(客户与事项混写、描述顺序变化、语义省略、口语表达等)。

几类字段的解析方案:
- 类型字段: 先让 混元模型 在 onsite / remote / unknown 这几个有限枚举里输出结果,再用规则层做归一化和兜底。这样像“在客户单位处理现场问题”这类没有直接说“客户现场”的表达,也能通过场景语义被落到外出类型。
- 客户字段: 客户不做开放生成,而是基于 现有客户池做约束匹配 。解析时将客户 简称+全称 作为候选上下文提供给模型,优先让模型在已有名单中选择;若模型未能稳定命中,再用 原文文本包含匹配 做一次兜底补抓,避免“识别对了但落成不存在的新名字”。
- 日期字段: 日期是做 相对时间理解 。像“今天”“明天”“后天”“下周一”这类表达,解析时会先注入当前日期上下文,再把相对时间换算成具体日期。
- 时间字段: 时间拆成两类处理。一类是“9点到12点”“下午3点到5点”这种明确区间,直接标准化成开始和结束时间;另一类是“上午”“下午”“全天”这种模糊时间段,按 预设映射表 补成标准时间范围。比如下午默认映射14:00-18:00;
- 事项字段: 事项不是原文直出,而是做一次 信息剥离 。日期、时间、客户、类型这些结构化信息被抽走之后,再保留真正需要沉淀到记录里的工作内容。这样确认页里的事项更短、更聚焦,也更适合后续检索和统计。
整体上,这几类字段不是由单一方法完成,而是按“模型理解语义,规则校正结果”的思路分别处理,最后拼成一份可校对、可修正的确认页草稿。两种修正方式

整段重录
整段重录适合整体表达有问题的情况:比如说错了、漏了很多关键信息、识别偏差比较大、事项拆分明显不对等。 重置路径: 重新说一遍 → 系统重新识别与解析 → 生成新的结构化草稿 。
单项修正
单项修正支持两类实现:
- 纯字段编辑: 可以直接修改类型、客户、日期、时间段这些结构化字段,也可以手动补正文案内容。
- 单条事项语音录入: 事项字段因为是长文本,在保留手动修改的同时,支持重新录入,并识别并回填到当前输入框,同时可以清空旧内容。

确认页点击提交之后,系统也不会直接入库,而是先经过一层正式业务校验。

常见的敏感词通常可以分成两类:
- 基础合规类 :政治、违法违规等,一旦命中直接拦截
- 业务定制类 :公司内部表述、组织信息、特定业务风险词等
这两类词都支持在后台配置和维护。这样做的好处是,系统既能满足基础合规要求,也能随着公司的业务变化,动态调整自己的内容校验规则。
如果从模块职责上看,这套语音填报大致分成四层:页面层、交互层、语音业务层和正式记录层。

- 页面层 :承接用户流程(首页、语音页、确认页)
- 交互层 :录音按钮能力(启动录音、时长控制、取消手势、波形反馈)
- 语音业务层 :上传音频、调用 ASR、结构化解析
- 正式记录层 :敏感词检测、业务校验与最终入库
篇幅有限,文中没有把所有小程序细节都展开写完,除此之外:

一句题外话:以前从来没想过可以自己独立做出一个小程序,但经过半年的不断尝试,从最开始的界面还原,到静态网页,到即图figma插件,到奶爸知道小程序协作,再到前段时间开源的个人建站工具。
随着跨界链路越来越长,尝试的胆子越来越大,好像把一个想法推进成真实可用的产品,也没那么遥不可及了。
拜,今天就到这里啦~ 我们下个项目见(coming soon(very soon))。
复制本文链接 文章为作者独立观点不代表优设网立场,未经允许不得转载。




发评论!每天赢奖品
点击 登录 后,在评论区留言,系统会随机派送奖品
2012年成立至今,是国内备受欢迎的设计师平台,提供奖品赞助 联系我们
AI辅助海报设计101例
已累计诞生 781 位幸运星
发表评论 为下方 3 条评论点赞,解锁好运彩蛋
↓ 下方为您推荐了一些精彩有趣的文章热评 ↓