feat: 优化订单结束动效
Co-Authored-By: 卢春龙 <lucl@xiaopeng.com>
| | |
| | | } |
| | | } |
| | | |
| | | // 结束态公里数「渐显」:轻微上移并淡入,配合卡片升起分层呈现 |
| | | @keyframes finished-distance-fade { |
| | | from { |
| | | transform: translateY(16px); |
| | | opacity: 0; |
| | | } |
| | | |
| | | to { |
| | | transform: translateY(0); |
| | | opacity: 1; |
| | | } |
| | | } |
| | | |
| | | .calling-car { |
| | | position: relative; |
| | | padding: 148px 0px 0px 0px; |
| | |
| | | will-change: transform; |
| | | } |
| | | // 「行程结束」入场:仅在真实 live 跃迁进入结束态时(父层 playFinishedEnter 上升沿)加此类, |
| | | // 承载背景卡升起与里程渐显动画;恢复态不加此类,直接显示最终态、不弹起。 |
| | | // 承载背景卡与里程「一起升起」动画;恢复态不加此类,直接显示最终态、不弹起。 |
| | | // |
| | | // 入场时序:礼花先播放(见 trip-finished-fireworks),延迟 @finished-enter-delay 后卡片与里程 |
| | | // 才开始升起——让礼花播到中段时卡片才登场,避免二者同时抢镜(延迟解耦,不与礼花播放硬关联)。 |
| | | @finished-enter-delay: 700ms; |
| | | .calling-car--finished-enter { |
| | | .calling-car-bg.finished-bg { |
| | | // 背景卡(背景图)缓缓升起:进入结束态时随类挂载触发,时长 1s |
| | | animation: finished-bg-rise 1s cubic-bezier(0.22, 0.61, 0.36, 1) both; |
| | | // 背景卡(背景图)缓缓升起:延迟至礼花中段后触发,时长 1s |
| | | animation: finished-bg-rise 1s cubic-bezier(0.22, 0.61, 0.36, 1) @finished-enter-delay both; |
| | | } |
| | | .trip-finished-header-distance { |
| | | // 公里数在卡片升起后渐显出现 |
| | | animation: finished-distance-fade 700ms ease-out 450ms both; |
| | | // 里程简化:与背景卡「同延迟、同时长、同曲线」纯位移升起(复用 finished-bg-rise), |
| | | // 与背景卡锁步移动,视觉上如同印在卡面上一起升起;不再做淡入淡出。 |
| | | // 整块头部(到达目的地 + 里程)一起动,避免只动里程导致标题脱节。 |
| | | .trip-finished-header { |
| | | animation: finished-bg-rise 1s cubic-bezier(0.22, 0.61, 0.36, 1) @finished-enter-delay both; |
| | | } |
| | | } |
| | | // 派单成功转场期间:蓝牙卡 / 车控卡 / 底部操作栏隐藏但保留占位(opacity),逻辑另在各组件延迟执行; |
| | |
| | | * |
| | | * ## 职责 |
| | | * - 监听 tripStatus 变化,检测「送驾中(6) → 行程结束(8)」上升沿 |
| | | * - 延迟约 180ms 后发射一簇礼花(与背景卡片升起动画同步呈现) |
| | | * - 进入结束态后尽快发射一簇礼花(礼花先行播放),卡片/里程延迟约 700ms 才升起 |
| | | * - 仅发射一次,prevStatus 去重防重复播放 |
| | | * - tripStatus 非 TripFinished 时卸载 canvas(条件渲染) |
| | | */ |
| | |
| | | if (tripStatus !== TripStatus.TripFinished || prevStatus === TripStatus.TripFinished) { |
| | | return; |
| | | } |
| | | // 略微延迟,等待 canvas 挂载与背景卡片升起动画启动,礼花随卡片一同呈现 |
| | | // 礼花先行:进入结束态后尽快发射(仅留极短延迟等 canvas 挂载),卡片随后延迟升起 |
| | | const timer = setTimeout(() => { |
| | | // 仅发射一簇(single burst),避免连发造成「播放多次」的观感 |
| | | fireworksRef.current?.shoot({ |
| | | origin: { x: 0.5, y: 0.4 }, |
| | | angle: 90, |
| | | particleCount: 260, |
| | | particleCount: 180, |
| | | spread: 360, |
| | | startVelocity: 42, |
| | | gravity: 0.9, |
| | | gravity: 1.1, |
| | | scalar: 0.9, |
| | | ticks: 180, |
| | | // ticks 控制粒子存活帧数(≈ticks/60 秒)。卡片动效约 1.7s 收尾, |
| | | // 礼花缩短到约 1.5s(ticks 90)先行结束,避免动效结束后礼花还在飘。 |
| | | ticks: 90, |
| | | colors: ['#FFD666', '#F9A76A', '#FFF1B8', '#7FE6F2', '#95CF29'], |
| | | }); |
| | | }, 60); |
| | |
| | | // 调试面板:模拟完整行程流转(仅 dev 构建可见) |
| | | // import DebugOrderSimulatorPanel from './components/debug-order-simulator-panel'; |
| | | // 转场动效调试面板:呼叫中→派单成功、送驾中→行程结束(仅 dev 构建可见) |
| | | // import DebugTransitionPanel from './components/debug-transition-panel'; |
| | | import DebugTransitionPanel from './components/debug-transition-panel'; |
| | | // 到达结束态全屏礼花动效 |
| | | import TripFinishedFireworks from './components/trip-finished-fireworks'; |
| | | // 弹窗状态管理 |
| | |
| | | |
| | | useEffect(() => { |
| | | if (tripStatus === TripStatus.TripFinished) { |
| | | void handleCreditPayTripFinished(orderId); |
| | | // 等行程结束动效(礼花 + 卡片/里程升起,约 700ms 延迟 + 1s 升起 ≈ 1.7s)播完再调起免密支付, |
| | | // 避免「扣款结果查询中」Toast/遮罩在动效期间弹出打断观感。 |
| | | const payTimer = setTimeout(() => { |
| | | void handleCreditPayTripFinished(orderId); |
| | | }, 2100); |
| | | return () => { |
| | | clearTimeout(payTimer); |
| | | clearCreditPayFallbackRuntime(); |
| | | }; |
| | | } else { |
| | |
| | | onConfirm={handleConfirmCreditPayPopup} |
| | | /> |
| | | <TripFinishedFireworks tripStatus={tripStatus} /> |
| | | {/* 转场动效调试面板 — 固定在地图上方,始终可见 */} |
| | | {/* <DebugTransitionPanel |
| | | {/* 转场动效调试面板 — 固定在地图上方,始终可见(临时开启,调试完成后请重新注释) */} |
| | | <DebugTransitionPanel |
| | | orderId={orderId} |
| | | setOrderId={setOrderId} |
| | | setTripStatus={setTripStatus} |
| | | bindSocketListeners={bindSocketListeners} |
| | | /> */} |
| | | /> |
| | | {/* 模拟器入口已关闭,如需本地调试可取消下方注释 |
| | | <DebugOrderSimulatorPanel |
| | | orderId={orderId} |