Vue.js冷库的入库单,我改到第四版才有人在现场真的用。前三版都栽在同一个地方:录一条入库要两秒以上,仓管嫌慢,干脆记在纸上,晚上一起补。数据晚一天进系统,等于没有。
这页的核心控件就一个:选货位。听着简单,做起来全是取舍。下面写的是我怎么把这个选择器从「能选」改到「愿意选」的。
三级联动下拉是第一个坑
货位是三层:仓库 → 库区(冷冻、冷藏、预冷)→ 货位。第一版用的是级联选择器,标准的三级懒加载,选完一层请求下一层。逻辑没错,问题出在冷库里的网络。
冷库墙厚,里面信号本来就差,仓管站在库门口操作,切一层等一次请求,中间只要有一次慢,界面就停在「加载中」。他等不及,退回去重新点,上一层的响应回来又把当前选择覆盖掉,最后选中的库区和手里拿的货对不上。
第二版换了做法:进页面时一次把当前农场的货位树整个拉下来,本地建索引,切换层级只在内存里过滤,不再发请求。我们最大的一个客户有十一个仓库、一千二百多个货位,一次拉完的 JSON 两百多 KB,首屏多花三百来毫秒,之后每次切换都是即时的。
这个改动的前提是货位树不常变。货位是会新增的,但一天也就几条,所以我又加了一个版本号:接口返回树的版本,跟本地存的不一致时才重新拉。现在这页打开基本不卡,切换没有任何等待。
常用货位置顶
选得快不快,取决于列表里第一屏是不是他要的那个。冷库的实际情况是,一个人长期只进出那几个货位,剩下几百个一年碰不到几次。
所以选择器打开时,先把「这个人最近用过的五个货位」排在最前面,数据存在本地,不上服务端。看着很土,但仓管的第一反应就是直接点第一个,不用往下翻。这个功能上线后,入库单的平均填写时间从两分钟降到四十秒左右。
代价是换人用同一台平板时,置顶的还是上一个人的习惯。我们没做多用户区分,因为现场就是一台平板挂在墙上,谁用谁拿,做了反而更乱。
扫码枪不是「输入设备」,是键盘
冷库里的货位都贴了码,扫码枪是标配。我一开始把它当成普通的输入框:点开货位选择,让输入框拿到焦点,扫一下就把编码填进去。
实际用起来才发现扫码枪在系统眼里就是一个打字极快的键盘,它只负责按键,不负责告诉你「这一串是扫码来的」。仓管扫完码,如果焦点没落在我们指定的输入框上,那串编码就打到别的地方去了------我遇到过最离谱的一次,编码被打进了备注框,货位反而是空的,单子照样能提交。
后来的处理是全局监听按键:连续的快速输入(几十毫秒一个字符)加回车结尾,认定是一次扫码,不管焦点在哪,都把值拦下来解析成货位。同时把被误写的那个输入框恢复原值。
这里有个细节,扫码枪的回车默认会触发表单提交。我在捕获阶段拦掉这个回车,否则扫一次码就提交一次单,重复入库比不录还麻烦。
一个货位放多批货,界面怎么表达
货位选完,紧接着是选批次。同一格冷库位置,今天放九月的苹果,明天补货又放十月的,这是常态,不允许多批次反而是浪费库容。
界面上这一块我改了三次。第一版做成下拉选批次,仓管要记住哪个批次在哪一格,反人类。第二版是把该货位的批次全列出来,让他自己挑,结果他永远挑最新那批------因为看着顺眼,先进先出就废了。
现在是倒序展示,但把「建议出库」的批次标在第一位,并且写明入库日期和剩余件数,默认选中它。仓管可以改,但改的时候会看到一行提示,说这批货已经压了多少天。让他看见代价,而不是堵住他的手。
盘点差异不给改数字
这条不是前端的事,但界面得配合。库存数在页面上是只读的,盘出差异只能提交差异单,走审批。
一开始产品同学不同意,说这样操作步骤多。我的理由是:允许直接改数字,差异的来路就永远查不清,下个月还会差。现在这页上库存数字是灰的,旁边一个「报差异」按钮,点了要选原因。仓管抱怨过,但三个月后差异率确实降下来了。
前端只做提示,扣减以后端为准
库存这种数,前端算出来的任何结果都不能当依据。我做过一次很蠢的实现:页面上显示剩余件数,出库时前端先减掉,看着很跟手,结果两个人同时出库同一格,页面各自显示扣完的数,实际库存被扣了两次。
现在前端只做两件事:提交前把「这一格还剩多少」的实时值拿一次,如果不够就提示;提交后等后端返回权威数值再刷新。中间的几百毫秒里,按钮是转圈状态,不允许重复点。
弱网这块也做了点处理:冷库里断网是常事,提交失败的单子不丢,进本地队列,回到有信号的地方自动重发。重发带一个客户端生成的单据号,后端按它去重,避免网络抖动造成重复入库。
一点边界
这套东西解决的是「有人愿意录」的问题,不是「录得对」的问题。货位贴错、批次号抄错,系统拦不住,只能靠盘点和复核。
另外,货位树一次拉全量这个方案,在货位上万、多农场共用的场景下会撑不住。真到那个量级,得回到分段加载,或者让后端直接给「这个品类常去的货位」的候选集。我们现在这套,是给几十个品类、一两千个货位的冷库写的,再大就得重新想。