ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CRMEB移动端代客下单实战:从需求到性能优化全记录

CRMEB移动端代客下单实战:从需求到性能优化全记录

做代客下单这个功能,最早是我在实体门店蹲了一周之后才下决心去改的。店里几个店员一天能收到十几句“姐你帮我下单吧”“这个我算不清楚”,要么是老年顾客不会用手机,要么是顾客自己都分不清要买哪个规格。站在柜台后面用电脑开单又跟不上节奏,顾客一多就手忙脚乱。CRMEB这套移动端的代客下单,就是给店员手上塞一个随身收银台,让“顾客动嘴、店员动手”这件事真正跑得通。下面就把我从需求调研到功能落地、从调试踩坑到性能优化的完整过程拆开讲。

1. 代客下单背后的核心需求与方案选型

1.1 为什么要做移动端代客下单

很多做CRMEB二开的项目组会把代客下单简单理解为“在后台加一个创建订单的入口”,这个理解在一开始就能省掉大量返工。我自己做下来最大的感触是:代客下单不是客服场景的“代下”,而是门店场景的“代录”,两者的操作节奏完全不同。

客服代下是顾客在线上沟通,客服慢慢查库存、找商品,时间压力小。移动端门店代客下单是顾客就站在你面前,有的还在犹豫要不要买,这时候店员端APP或者小程序不能加载太慢,不能来回跳转,不能出现那种“顾客问一个选项、店员要翻两层菜单才能找到”的体验。这决定了它的核心交互逻辑必须是:最少点击路径 + 所见即所得的订单确认 + 快速切换支付方式。

我当时的原始需求描述很短:“店员打开移动端,选客户、选商品、下单、收银。”但展开之后发现,真正的难点在三个地方:第一,代客下单的账号权限和顾客身份识别怎么处理;第二,下单前后的库存、优惠、积分怎么和原有的CRMEB订单流程无缝衔接;第三,移动端网络不稳或操作到一半被电话打断怎么办。所以后面的所有设计都是围绕这三个难点展开的。

1.2 方案选型:H5、小程序还是原生封装

同样是做移动端,CRMEB的部署形态直接影响技术选型。我接触过的项目里,有做微信公众号H5的,有做微信小程序+公众号双端的,也有用uni-app直接打包App的。单论代客下单这个模块,我的建议是优先跟随现有主端技术栈,不要为了一个子功能引入新的跨端框架。

原因很简单:代客下单要复用CRMEB现有的用户体系、商品浏览记录、购物车和订单支付回调用例。如果主端是uni-app,那么代客下单也用uni-app页面实现,能直接调用公共组件和接口;如果主端是独立App,考虑用web-view内嵌H5来实现,也不影响原生收银台能力。同时要留意CRMEB企业版在这块已经有相当完整的基础代码,二开时尽量沿用它的命名规范和接口约定,后面系统升级时能少很多冲突。

选型还牵涉到“店员端”和“用户端”是不是同一个容器。我的做法是同一套H5代码,通过登录态的角色标识区分操作入口。店员登录后进入代客模式,底部多一个“代客下单”的浮窗;普通用户登录从头到尾看不到这个入口。这样做的好处是整个前端资源不用分成两套,后端接口通过权限中间件过滤掉店员才能访问的代客专属接口。

1.3 权限模型与操作边界

代客下单最大的权限风险是店员能看顾客的隐私信息,比如手机号、历史订单、收货地址。权限模型如果设计得太宽,顾客在后太会闹出纠纷;设计得太窄,店员什么都做不了,功能就鸡肋了。我最后落地的是“角色-门店-操作范围”三级控制:

  • 角色:店长、店员、收银员,各自的代客下单权限独立配置。
  • 门店:当前登录账号绑定哪个门店,只能操作该门店的库存和订单。
  • 操作范围:允许代客选择哪些支付方式、最大单笔金额、是否需要二次短信验证。

在CRMEB现有的管理员权限节点上,我会单独挂一个delegate_order分支,子节点包括view、create、update_after_pay、refund等。这一步用CRMEB自带的后台菜单权限管理就能实现,不需要自己写RBAC,但要在员工登录的鉴权逻辑里额外判断shop_id是否匹配,防止有人跨店下单。

2. 移动端代客下单的核心功能设计与表单交互

2.1 代客下单页面结构:从“选客户”到“收款完成”

整个流程我拆成五个步骤:选客户、选商品、确认订单、支付收银、完成小票。移动端的页面结构按这个顺序做单列瀑布流,不采用桌面端的表格多列布局。

第一步“选客户”是代客下单和普通下单最大的差异点。普通用户是自己登录账号下单,代客下单的店员必须手动指定订单归属。这里直接用CRMEB的用户列表接口,支持手机号精确搜索和用户名模糊搜索。我额外加了一个“无主订单”兜底:顾客不愿意留手机号时,可以选择游客模式,订单挂在门店的公共客户下,不影响后续提货和售后的订单追溯。

第二步“选商品”跟正常商城的搜索/分类页共用一套接口,但做了两个改动:一是商品卡片上直接显示门店库存,不是总库存,避免店员下完单才发现门店没货;二是支持连续加购,选中一个规格后停留当前页面,自动把商品加入底部购物车栏,方便同一顾客一次买多件。

“确认订单”页是整单信息集中展示的地方。我把会员等级折扣、优惠券、积分抵扣、运费四部分都放在同一屏内,店员可以逐个展开查看明细,所有金额变化实时计算。这一步对接口性能要求最高,因为优惠计算涉及会员价、商品促销、限时折扣等多个模块,CRMEB默认走购物车计算接口,但建议在移动端做一个防抖:用户改动数量或优惠时,等500毫秒停顿后再发起重新计算,避免店员连续点加减号瞬间打一堆请求。

2.2 表单必填项与校验规则:少弹窗、多引导

热词里有“移动端表单必填项”,这恰恰是代客下单做得最细的地方。桌面端表单可以靠红星星号提示,移动端空间有限,弹窗一多店员就烦。我的处理原则是:能默认就不让填,能选择就不让输,输错了也要能当场反应过来。

实际落地的校验规则整理成了表格:

字段是否必填处理方式异常提示
客户手机号二选一游客模式下自动填充虚拟号无
收货人姓名是文本输入,限制20字红色边框+文字提示,不弹窗
收货地址是省市区级联选择+详细地址未选完时提交按钮置灰
商品SKU是默认选中第一个有库存规格无该规格库存时禁止加入
发票抬头否折叠面板无
备注否多行输入,限制100字超出时计数变红

比较反直觉的一点:支付方式也是必填项。店员代客下单时经常出现“顾客先说你帮我付了,回头又掏出来现金”,如果支付方式在提交时没有显式锁定,后面结算会乱。我在确认订单页顶部用两个大按钮二选一:线上支付/收银台支付。线上支付走CRMEB的支付回调,收银台支付则直接登记“已收款”,订单状态改为待发货,不走线上支付通道。

2.3 商品搜索与SKU选择的移动端优化

CRMEB默认的商品 SKU 选择方式是弹出层,一行行列规格。这在手机屏幕上问题很大:规格多的时候弹窗高度超过一屏,店员手指一滑就容易误触。我改成了半屏抽屉+顶部已选内容钉住的做法,每次只展示当前规格分组,选完一组自动滚到下一组。这个过程就像密码锁“拨一位锁一位”,不会出现选到一半忘记前面选了啥。

另外,搜索关键词联想在移动端一定要做实时搜索。店员输入“可乐”两个字等搜索结果的时候,顾客可能已经说“算了不要了”。我直接复用CRMEB的全局搜索接口,做了300毫秒防抖,并把“最近搜过”和“门店高频购买TOP10”展示在搜索空态页。这样店员不用打字也能快速点到常说的高频商品,实测一个30个SKU的小超市,从打开页面到商品入单平均能控制在15秒内。

3. 订单提交流程与后端交互的实战实现

3.1 代客下单的订单生成逻辑

代客下单在后端不是一个完全独立的创建订单接口,而是把CRMEB原本的用户下单流程包了一层。它的特殊之处在于用户身份是店员指定的,因此生成订单时必须注入两个额外的身份标识:代客店员ID(staff_id)和所属门店ID(shop_id),这两个字段会跟着订单进入结算、发货和分佣链路。

我在订单表的扩展信息里新增了delegate_info JSON字段,内容包含operator_uid、shop_id、customer_uid。重点说明一下customer_uid,这个字段决定订单的会员等级和赠品归属,是代客下单能不能触发优惠的关键。很多二开项目没注意这点,导致店员用游客模式代下单后,顾客原本该享受的会员价没生效,最后只能手动改价,非常容易漏。

订单号生成也做了调整。CRMEB原本的订单号规则是前缀+时间戳+随机数,为了代客对账方便,我在中间插入门店编号。比如A10003 + 20240115 + 6位随机数。这样以后从后台导订单表,只要扫一眼订单号前缀就能知道是哪个门店的业绩。

3.2 防重提交与库存锁定的几个关键点

移动端最怕的一件事就是店员手快点了两次“提交订单”,生成两笔一模一样的代客订单。我做了三层防重:

  • 前端:点击提交按钮后立即置灰,并在按钮文案上显示“提交中...”,同时用一个本地布尔值和sessionStorage双重锁,防止页面在极端情况下重复触发。
  • 接口层:代客下单接口要求客户端上传一个uuid参数,后端查redis,键不存在才允许继续,同时把失效时间设为5分钟。同一店员在5分钟内用同一个uuid调用两次接口直接返回“重复提交”。
  • 库存层:下单时预占库存,但不是锁死,而是在订单超时未支付时自动回滚。CRMEB的库存扣减逻辑默认是支付后扣减,代客场景我改成了“确认订单即冻结库存”,否则十来个顾客同时看中同一件衣服,店员一个个下单,最后一个顾客可能就没货了。

冻结库存的实现不建议在原有的库存表上直接加减字段,而是增加库存流水表,记录每条订单对每个SKU的冻结与解冻操作。这样从后台查库存变动,能看到是“下单扣减-未支付解冻”还是“支付扣减-退款回补”,对账和排查异常订单都清晰。

3.3 移动端支付收银:线上回调与线下收银台

代客下单的支付环节,我见过不少项目直接沿用原有支付流程,导致店员手机上弹出一个用户支付页面,但顾客的微信或支付宝已经绑定了其它支付环境,钱就付岔了。代客支付的正确做法是分两条路:

线上支付场景,店员帮顾客发起支付时,通过CRMEB现有的预支付接口生成支付参数。这里有个细节:要把支付结果回调的附加参数里带上代客订单号,否则支付成功之后无法自动完成订单状态更新。我在notify_url的回调逻辑里增加了delegate_order_no的解析分支,回调成功则把订单状态从“待付款”改为“待发货”,并且记录支付方式来自代客。

线下收银台场景,店员在移动端点击“确认收款”,后端走完订单确认后,直接把订单状态改成“已付款”,但有个前提条件:当前店员账号配置了收银权限,并且该门店开启了线下收银的开关。这能防止店员手动把订单改成已付款然后私吞货款,我在管理后台还加了一个“收银宝典”开关的分支逻辑:开启后,收银员每天收款金额超过设定的阈值,第二天必须店长二次确认,否则账号会被停用代客权限。

3.4 接口异常与超时处理:移动端的自我保护

代客下单在门店的弱网环境容易出问题。Wi-Fi不稳定、4G信号满格但速度慢的场景我都实际碰过。前端有两个必须做的兜底:

一是提交订单的接口超时时间要比普通接口长,建议设为10秒以上,不能沿用默认的5秒。因为下单接口的响应链路包含了库存预占、优惠计算、订单生成等多个环节,移动端经常在无线网络下往返时间偏长,超时太短会造成“服务器已下单、前端却报失败”的问题。

二是提交失败时的恢复按钮不能是简单的“重试”,而是“查看订单状态”。因为网络超时的时候,后端不一定真的没建单。我给提交接口加了一个幂等查询接口,提交失败后店员点“查看订单状态”,前端拿uuid去查服务端日志,如果订单存在就把前端状态拉回来,显示“订单已生成,是否继续支付”。这样哪怕店员以为下单失败又重新下了一单,也能及时发现并删除多余订单,不会出现“顾客被收了两次钱”的尴尬。

4. 移动端性能优化与多端适配的实操记录

4.1 首屏加载与接口合并

热词里有一条“移动端性能优化”,在代客下单模块我花了最多力气。首屏打开代客下单页面时,原本要串行请求用户信息、门店库存、会员等级、营销活动、首页聚合数据五个接口,在门店弱网环境下首屏耗时超过3.5秒。后来我把这五个接口合并为一个聚合接口,返回一个一次性赋值给前端状态的JSON结构,首屏时间压到1.2秒内。

优化细节是后端不再是一层层同步调用,而是把五个子数据源的取数逻辑并行化,用Go/PHP的并发方式同时拉取,都返回后组装成统一响应。这样数据库查询的压力没有增加,但网络开销从5次降到1次,移动端体验提升非常明显。实测在4G网络下,原本要转三四个圈才能进去的代客下单页,现在基本是点开就有内容。

4.2 列表渲染与内存占用

门店商品列表在CRMEB的场景里经常是几十上百个SKU,如果一口气全渲染,低端手机会掉帧甚至白屏。我的做法是分页+虚拟列表。分页按每页20个商品来,上拉加载下一页;虚拟列表则只渲染可视区域附近的三屏DOM,其他的用占位符,滑动时再补充。这两个方案组合下来,一个300个SKU的超市门店,移动端内存占用比原来少了将近40%。

另外,商品图片的处理也很关键。CRMEB的商品图经常是原图直出,一张图两三MB,店员在店里网络一般时加载起来会卡到怀疑人生。我把移动端代客下单的商品图全部走独立图片域名,并且按需裁剪——列表页用200x200缩略图,详情页用800x800,购物车栏用100x100。裁剪参数可以复用服务端上传时自动生成的缩略图规则,前端只要拼URL参数即可,不用额外开发一套图片处理服务。

4.3 中低端安卓机的适配心得

虽然热词里“移动端CPU天梯”“移动端PC CPU天梯”看起来和功能开发无关,但这提醒我一个真实问题:门店店员用的手机配置通常很一般,很多是几百块钱的安卓机,CPU和内存都相当紧张。代客下单不能只在iPhone和旗舰机上流畅,低端机上的体验同样决定门店会不会真正用它。

我发现的几个低端机适配坑:

  • CSS动画尽量不要用px做位移,用transform和opacity,避免触发大量重排。
  • 长时间在页面停留后,代客下单页偶尔出现白屏,排查后是WebView的内存回收导致。我在页面生命周期里加了状态恢复逻辑,通过判断sessionStorage里的订单草稿,重新渲染已选商品,不要求店员重新从头选一遍。
  • 大尺寸商品图在低端机解码时容易崩溃,我在前端加了一个异常容错:图片加载失败时显示固定的灰色占位图,并自动尝试一次小尺寸图,避免整页白屏。

4.4 改动表单必填项时要注意的联动

表单必填项的“必填”不是静态的。比如店员选择“线下收银台支付”时,线上支付时的“支付方式”就不再需要选择了,但需要新增“实收金额”的必填校验,用来核对实际收的钱和订单金额是否一致。我在表单校验引擎里做成了条件依赖:支付方式字段切换时,动态调整下一步表单区域的必填项集合,并用一次重新计算校验函数完成联动。

如果用的CRMEB企业版,你可以直接在已有的表单验证规则上扩展,不必重写引擎。要注意的是,新增必填项一定要在前后端同时维护,后端接口也要校验,否则就会被人跳过前端直接调接口,绕过权限和金额校验。

4.5 移动端调试与HTTPS证书安装

提到性能调优和接口联调,绕不开移动端抓包。门店现场的移动端接口问题最能暴露问题,但CSS布局、请求参数这些必须看真机才能定位。我日常用的是Charles,在手机上抓HTTPS请求时需要先安装并信任证书。这个过程在iOS和Android上不太一样:

iOS上证书装好后,还要在“设置-通用-关于本机-证书信任设置”里打开完全信任开关,否则抓包时只能看到密文,解析不了请求内容。Android上则是把证书文件导入系统证书目录,或者在App内单独配置信任用户证书,否则部分App默认不信任用户安装的证书。这个坑没人提醒的话,光一个证书信任来回就能折腾大半天。

5. 常见问题与排查技巧实录

5.1 问题速查表

实际运营两个月之后,我把门店反馈最多的代客下单问题整理成了一张速查表,方便后续维护人员一眼定位:

问题现象可能原因排查顺序
店员下单后顾客没收到短信用户手机号填写错误或虚拟号占位查订单customer_uid是否真实
会员价没生效游客模式被选成默认客户查delegate_info.customer_uid
库存显示有货但下单失败冻结库存已超卖查库存流水表的冻结阶段
线下收银台支付后订单还是待付款当前账号没有收银权限查店员角色和门店开关
重复提交生成了两笔订单前端防重锁被绕过查uuid是否唯一
提交订单超时但订单已生成网络抖动导致前端不知道结果调幂等查询接口核对uid

5.2 一片式排查技巧实录

有一个特别经典的问题,店员反馈“代客下单后顾客的积分没涨”。我排查了大半天,最后发现是订单的会员积分是在支付完成前按订单金额预估的,而代客线下收银台支付的订单默认不走线上支付回调,积分回调不触发。这个问题在CRMEB标准流程里不会暴露,因为标准流程的积分发放挂在支付成功回调里。

解决思路是给线下收银台支付增加一个显式的支付成功事件,手动触发积分发放逻辑。如果你们项目里还有分销佣金、推广人奖励这类依赖支付回调的模块,也要一并检查,不能在“代客收银台支付”这个分支里漏掉这些后置动作。我最后写了一个扩展钩子,在收银台确认收款成功后,统一调用订单后置处理服务,和线上支付回调走同一个逻辑函数。

5.3 踩过的坑:不要把代客下单做成“客服代下”

再提醒一个方向性错误。有次同事图省事,直接复用PC后台的客服代下功能,把它搬到移动端,结果门店反馈很难用。原因是客服代下的设计目标是“客服仔细核对订单信息”,每个步骤都要求完整确认,页面流程比较长。而门店代客是“快速录单”,店员恨不得三个手指点完整个流程。两者的交互思路完全不同。

如果你在接代客下单需求时发现对方说“参考一下客服代下”,最好先和需求方确认清楚他们的使用场景:是前台店员对着顾客快速开单,还是售后客服在电话里慢慢代客下单。这两个场景在页面上体现为“能少一步就少一步”和“每一步都要严谨”,实现细节差异非常大。

5.4 环境问题排查:门店Wi-Fi与DNS

门店网络环境很容易出一些“本地复现不了、后台日志正常”的玄学问题。比如有个门店反馈代客下单偶尔能开、偶尔打不开,排查了半天,发现是门店Wi-Fi的DNS设置有问题,导致部分HTTPS请求解析到旧IP。CRMEB的接口域名一旦切换节点,门店路由器里缓存的DNS不刷新,就会出现时好时坏的情况。

后续我在代客下单模块的接口请求层面加了一层域名解析监测:请求失败时捕获域名解析耗时和IP信息,自动上报到后端监控日志。这不算复杂,但排查效率提升非常多,不用再为了一个门店问题跑去现场看路由器。

6. 后续扩展方向与个人体会

如果你也正在做CRMEB的移动端代客下单,有几个扩展方向值得在项目初期就预留接口:

  • 导购分销绑定:代客下单的业绩经常需要归到导购头上,可以预留staff_id到分销佣金表的映射关系。
  • 电子小票与售后联动:移动端支付完成后展示一个二维码小票,顾客扫码直接进入售后申请页,能降低门店的售后咨询量。
  • 多门店切换:一个店员可能会在多个门店间轮岗,可设计成员工账号关联多个门店,但每次只能选一个作为当前操作门店,这样库存和业绩归属才不乱。

我有一次在门店看到店员用这个功能帮一位老人下单,老人又说不太清楚收货地址,店员就半蹲在柜台前,一边问一边填,最后把确认订单页转过去给老人看,总共不到两分钟。那个瞬间我就觉得,这种从真实场景里长出来的功能,比做一个“功能齐全但没人用”的后台订单模块有意义得多。希望这篇实操笔记能让你少走我踩过的那些弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进