这么信息全的页面,几乎所有客服域平台都要能直接访问查阅,一个页面如何多个系统使用,在保障客服同学使用体验的同时,还能节省开发同学维护成本。
信息量大数据源多导致页面加载慢,客服同学经常反馈卡顿,如何对页面首屏进行秒开优化,进一步提升客服同学的使用体验。
简单的改动也需要投入资源,信息模块复用率低,如何建设信息自由编排、信息模块拔插的能力,最大程度解放产研运同学生产力。
/** 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: 如果想要传递给任意窗口,可以将这个参数设置为'*' ,为了安全起见,不建议设置为'*'*/
'*'
)
/** 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,
//其他数据
},
},
/** orgin: 如果想要传递给任意窗口,可以将这个参数设置为'*' ,为了安全起见,不建议设置为'*'*/
'*',
)
},
},
/** 3. 监听远端交互和数据变化,根据交互类型做不同的本地处理 */
method: {
/** callBack: 远端事件被触发后,处理本地回调逻辑 */
callBack(event) {
try {
if (event.data.type === 'workbenchRoute') {
switch (event.data.params.name) {
case 'orderdetail':
//跳转订单详情的handler
break
case 'detail':
//跳转工单详情的handler
break
// 其他交互
default:
//兜底处理
}
}
} catch(error) {
//异常处理
}
}
3.2、远程组件通信
/** 配置webpack MF插件,将订单详情页exposes出去*/
new ModuleFederationPlugin({
filename: 'remoteEntry.js?[hash]',
library: { type: 'window', name: 'app_ticket' },
name: 'app_ticket',
shared: {
/** 需要共享的依赖 */
},
exposes: {
/** 提供订单详情远程组件*/
'./OrderDetail': './src/views/orderdetail/Index.tsx',
},
}),
内容使用方
/** 1.webpack配置远端应用 */
remotes: {
app_ticket: getRemoteUrl('app_ticket'),
},
/** 2. 使用defineAsyncComponent注册组件*/
'OrderDetail': defineAsyncComponent(() => import('app_ticket/OrderDetail')),
/** 3. 像本地组件一样使用远程组件*/
<OrderDetail orderNo={orderNo} {...props} />
/** 处理promise,保证promise.all使用时相互独立 */
export const handlerPromise = (api, params) => {
return new Promise(resolve => {
api(params)
.then(resolve)
.catch(() => resolve({ error: true }))
})
}
/** 详情页首屏请求函数 */
const fetchOrderDetail = (callback?) => {
/** 使用handlerPromise封装过的promise,保证有一个报错不干扰其他接口请求 */
Promise.all([quickDetail(), firstLevel1(), firstLevel2()])
.then(([quickDetailData, firstLevelData1, firstLevelData2]) => {
// 快详情接口
!quickDetailData?.error && quickDetailHandler(quickDetailData)
// 第一梯队接口调用:不依赖详情反参的首屏信息接口
!firstLevelData1?.error && firstLevelHandler1(firstLevelData1)
!firstLevelData2?.error && firstLevelHandler2(firstLevelData2)
// 执行回调
nextTick(callback)
})
.then(() => {
// 第二梯队接口调用:依赖详情反参的首屏信息接口、非首屏接口
secondLevelHandler1()
secondLevelHandler2()
})
// 执行慢接口
fetchSlowOrderDetail()
}
/** 慢详情接口请求 */
const fetchSlowOrderDetail = () => {
slowLoading.value = true
orderApi
.getDetail(params)
.then(slowData => {
/** 防止快速切换订单导致的数据串台问题 */
if (slowData?.topInfo?.orderNo === orderNo.value) {
orderDetail.value = slowData
}
slowLoading.value = false
})
.catch(() => {
slowLoading.value = false
})
}
接口协议由POST改为GET请求,GET的总耗时是POST的三分之二;Chrome下如果检测到GET请求的是静态资源,则会缓存,如果两次传输的数据相同,第二次以后耗费的时间将在10ms以内。另一方面也为后续工作台引入Service Worker技术打下基础。
新增快详情接口,将大接口中的响应耗时较高的字段整理出来,快接口不再包含这些字段。这些高耗时的字段新增字段级别的loading效果,为了避免快慢接口耗时差异较大,导致一些经验丰富的客服同学误以为快接口没返回数据的字段是空数据,但是这个loading数量不会超过3处,保持页面的整洁易读。
schemaData : [
{
label: '订单类型'
text:'普通现货'
children: [
{
id: 'orderTypeDetail'
text: '详情',
show: true,
toolType: 'linkBtn', /** linkBtn, primaryBtn, tag */
eventType: 'click', /** dbclick, hover*/
interactiveType: 'popover', /** modal, popover, message*/
children: [
//** popover弹出的内容 */
{ label: , text: '', children: //..}]
{ label: , text: ''}
]
},
{
text: '晚到必赔',
show: true
toolType: 'tag',
},
{
text: '退运服务',
show: true
toolType: 'tag',
},
]
},
{
id: 'tradeStatus'
label: '支付状态'
text:'已经支付'
children: [
{
text: '七天风控',
show: true
toolType: 'tag',
},
]
}
],
2.2、高级配置
/** 信息元素枚举*/
enum INFO_ElEMENT_MAP {
/** 订单类型详情按钮 */
ORDERTYPE_DETAIL: 'orderTypeDetail'
}
/** 信息元素*/
const infoElementMap = {
INFO_ElEMENT_MAP.ORDERTYPE_DETAIL: {
/** 绑定事件 */
onClick: () => {
orderTypeDetailClickHandler()
},
/** 绑定样式 */
className: [styles.marginLeft],
},
/** 其他需要添加复杂交互和样式*/
}
const SchemaRender = () => {
//TODO 健壮性代码
return (
<div>
{schemaData.length ? (
<Row>
{schemaTemplate.map(item => {
// 分隔符
if (item.key === TemplateKeyEnum.dividedLine) {
return <Divider />
}
return (
<Col span={12}>
<InfoItem
key={item.key}
label={item.label}
text={item.text}
infoList={item.children.map(child => {
return {
text: popoverRender(child),
hide: !child.show,
}
})}
/>
</Col>
)
})}
</Row>
) : (
<Skeleton title={false} active paragraph={{ rows: 3 }} />
)}
</div>
)
}
/** 获取来源区分IM、工单灰度组信息 */
watch(
() => props.platformCode,
code => {
try {
switch (code) {
case PLATFORM_TYPE.IM:
/** 一线灰度走一线灰度接口 */
isGray.value = true
break
case PLATFORM_TYPE.TICKET:
/** 二线灰度走二线灰度接口 */
isGray.value = true
break
default:
isGray.value = false
} catch {
isGray.value = false
}
},
{
immediate: true,
}
)
return () => isGray.value ? (
<>
<Button type="link" onClick={clickHandler} >
返回{isOld.value ? '新版' : '老版'}
</Button>
{isOld.value ? <OldDetail {...props} /> : <Detail {...props} />}
</>
) : <OldDetail {...props} />
/** 数据上报 */
const uplog = (current, last, constant, type) => {
/** b: 只用考虑上一个路由是订单页面的情况 */
if (constant === last) {
const nowTime = getNowTime()
const stayTime = nowTime - stayOrderDetailTime.currentTime
/** c: 小于3s,大于30min视为无效数据 */
if (stayTime > 3000 && stayTime < 1000 * 60 * 30) {
orderDuLog('ORDER_STAY_TIME', {
orderNo: orderNo.value,
stayTime,
type,
})
}
stayOrderDetailTime.currentTime = nowTime
}
/** d:如果最近的路由是订单页面,则重置时间*/
if (constant === current) {
stayOrderDetailTime.currentTime = getNowTime()
}
}
/** 监听路由 */
watch(
() => {
return { name: route.name, id: route.params?.id }
},
throttle(
(currentRoute, lastRoute) => {
/** 从工单出发:只用考虑上一个路由是订单页面的情况 */
uplog(currentRoute?.name, lastRoute?.name, `${globalConfig.backstageCode}_orderdetail`, 'routeChange')
},
100,
{ leading: true, trailing: false }
),
{
deep: true,
immediate: true,
}
)
*文/昌禾
关注得物技术,每周一、三、五更新技术干货
要是觉得文章对你有帮助的话,欢迎评论转发点赞~
未经得物技术许可严禁转载,否则依法追究法律责任。
“
扫码添加小助手微信
如有任何疑问,或想要了解更多技术资讯,请添加小助手微信:
线下活动推荐
主题:得物技术沙龙-中间件专场
时间:2023年8月27日(周日)14:00-18:00
地点:上海·杨浦区黄兴路221号互联宝地C2栋5楼培训教室(宁国路地铁站1号口)
活动亮点:本次中间件专场沙龙由得物技术出品,聚焦于行业最新的技术趋势和实践,将在上海(线上同步直播)为你带来四个令人期待的演讲话题:
1. 《得物蓝绿发布演进和落地》
2. 《基于istio的Service Mesh落地实践》
3. 《Apache Pulsar -- 金融级云原生消息平台》
4. 《得物DLB演进之路》
相信这些话题将对你的工作和学习有所帮助,我们期待着与你共同探讨这些令人兴奋的思考和实践。欢迎线下参与,如果没办法到现场,也可以锁定我们的“得物Tech”视频号哦~
快快点击下面图片报名吧~