一、背景
作为客服域访问量最大的页面之一,订单详情页在客服的日常工作中被用来查阅用户的订单信息,以此为进线的买卖家用户提供更好的购买服务,进而提升用户的满意度。无论是一二线客服还是客服管理者,都能在日常使用的系统中直接访问到详情页,因此客服订单详情页的入口也比较多,目前已经超过了10处。

随着得物业务的快速发展,客服订单详情页需要展示的信息越来越多,需要支持的操作也越来越多,在页面改版前,一个页面首屏就需要展示80条订单信息,具体数量会根据订单类型、交易状态、物流状态等因素而改变。一个页面最多情况会有200条信息、60个按钮以及20个订单标签(不含用户标签、商品标签),所以会出现一个现象,一个1920*1080分辨率的显示器(客服常用的分辨率),鼠标滚轮需要滚2次才能从页面的最上方滑到最下方,详情页信息截图如下所示。

另一方面,贸然调整反而会降低客服同学的工作效率。页面内容、交互变化太大对客服同学也存有不小的培训成本,因此秉持着变更影响最小化的原则,信息量一直保持着只增不减。
经过一段时间的沉淀与打磨,客服订单详情页无论是客服的使用体验,还是开发体验都得到了显著提升,订单相关的TS问题近半年一直保持清零状态。这期间做了很多尝试和渐进式优化,本文主要从以下三点具体聊聊对客服订单详情页体验升级做的一些思考和优化。
- 这么信息全的页面,几乎所有客服域平台都要能直接访问查阅,一个页面如何多个系统使用,在保障客服同学使用体验的同时,还能节省开发同学维护成本。
- 信息量大数据源多导致页面加载慢,客服同学经常反馈卡顿,如何对页面首屏进行秒开优化,进一步提升客服同学的使用体验。
- 简单的改动也需要投入资源,信息模块复用率低,如何建设信息自由编排、信息模块拔插的能力,最大程度解放产研运同学生产力。
二、多入口的页面复用
1、多实例iframe
最早订单详情页只是客服工单系统中的一个页面,使用的是Vue2、ElementUI的技术栈。客服工单系统的定位是后台管理系统,使用门槛较高,更适合管理者使用,所以需要一个面向一二线客服的平台,章鱼工作台就诞生了。章鱼工作台是基于qiankun微应用搭建的,其子应用最开始使用Vue3、Vite和Ant Design,那时,如果要在章鱼工作台中访问客服订单详情页属于跨应用、跨技术栈通信,使用iframe是成本最小,也是初期最合适的一种方式,这也是页面复用的第一个阶段:在子应用使用多个iframe容器嵌入工单系统中的订单详情页。

所有订单详情页的使用方只需要在本地创建iframe容器,然后在嵌入订单详情页的访问地址时传一些必要的参数如订单号、求购单号就能够正常访问了,十分便捷。还可以支持一些高级配置供使用方选用,如支持通过url query传参的方式控制页面样式,当用于外部嵌入时隐藏主应用的菜单和顶部tab栏等等。

这个阶段,初步解决了页面复用的问题。但大家都知道iframe的弊端,一二线客服同学的日常工作中会出现大量的页面切换,这样一来,iframe的内存占用高、加载缓慢的缺点就被放大开来,这个阶段一二线客服经常会反馈页面卡顿,所以迫切需要进一步优化。
2、单实例iframe搭配MF远程组件
对客服工单系统、章鱼工作台两个平台的用户特点、作业行为进行分析,发现章鱼工作台的用户对页面的体验要求更高,于是对详情页做了第一次优化,步入了第二个阶段:将订单详情页迁移至章鱼工单工作台,其构建方式也由Vite变更为Webpack5,子应用之间利用Webpack5的Module Federation特性通过远程组件的方式进行数据通信。另一方面,尽管iframe的缺点明显,但仍是跨技术栈应用间页面通信的不错选择,将iframe控制在单实例容器中可以最大程度限制其对内存的占用。

这样一来,详情页的入口虽然有10多个,但通信方式都收拢成了三种:远程组件、单实例iframe、本地组件。所有场景都能覆盖到,后续各个入口有复杂交互的变更或者自定义事件,都能够在页面主体做到监控和收口,不需要页面的使用方做额外开发。
3、技术实现
3.1、单实例iframe通信
内容提供方
- 详情接口响应后注册message事件。
- 监听iframe父级携带数据变化,更新本地页面数据。
- 本地页面交互事件被远端触发,发送当前的数据给远端做自定义交互。
/** Vue3 */
/** 1. 详情接口响应后注册message事件 */
onMounted(() => {
/** 请求详情接口 */
fetchOrderDetail(() => {
/** query上打上iframe标签,用于确定注册时机 */
route.query.iframeRoute && watchParentMessage()
})
})
/** 2. 监听iframe父级携带数据变化,更新本地页面数据 */
const watchParentMessage = () => {
window.addEventListener('message', event => {
const orderNo = event.data.data.orderNo
if (event.data.type === 'ORDER_CHANGE' && orderNo) {
/** 更新订单信息*/
initStream(orderNo)
}
})
}
/** 3. 本地页面交互事件被远端触发,发送当前的数据给远端 */
window.parent.postMessage(
/** payload: 携带的数据*/
{
type: 'workbenchRoute',
params: {
/** 跳转退货详情页 */
name: 'refundDetail',
query: {
// 携带数据
},
},
},
/** orgin: 如果想要传递给任意窗口,可以将这个参数设置为'*' ,为了安全起见,不建议设置为'*'*/
'*'
)
内容使用方
- 页面初始化时注册message事件。
- 监听本地订单单号变化,将新的数据传给远端。
- 监听远端交互和数据变化,根据交互类型做不同的本地处理。
/** Vue2 */
/** 1. 页面初始化时注册message事件*/
mounted() {
window.addEventListener('message', this.callBack, false)
},
/** 2. 监听本地订单单号变化,将新的数据传给远端*/
watch: {
orderNo(newOrderNo) {
/** 在iframe的contentWindow属性上挂载postMessage方法*/
detailIframeRef.contentWindow.postMessage(
/** payload: 携带的数据*/
{
type: 'ORDER_CHANGE',
data: {
orderNo:newOrderNo,
//其他

本文围绕客服订单详情页体验升级展开,介绍多入口页面复用,采用单实例iframe搭配MF远程组件,降低渲染时间和内存占用;首屏秒开优化通过新增快慢接口等,提升响应速度;建设信息编排和模版插拔能力,降低开发成本;还给出灰度和埋点方案,提升系统质量和体现优化价值。
最低0.47元/天 解锁文章
577

被折叠的 条评论
为什么被折叠?



