ai-coding
2026-08-14 d3db99e6ca9b1b3c4a7ee5e28b9446bbc08dab5e
feat: 优化订单结束动效

Co-Authored-By: 卢春龙 <lucl@xiaopeng.com>
3个文件已修改
58 ■■■■■ 已修改文件
src/robotaxi/pages/begin-route/components/css-folder/calling-car.less 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/trip-finished-fireworks/index.tsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/index.tsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/begin-route/components/css-folder/calling-car.less
@@ -23,19 +23,6 @@
  }
}
// 结束态公里数「渐显」:轻微上移并淡入,配合卡片升起分层呈现
@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;
@@ -189,15 +176,21 @@
  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),逻辑另在各组件延迟执行;
src/robotaxi/pages/begin-route/components/trip-finished-fireworks/index.tsx
@@ -12,7 +12,7 @@
 *
 * ## 职责
 * - 监听 tripStatus 变化,检测「送驾中(6) → 行程结束(8)」上升沿
 * - 延迟约 180ms 后发射一簇礼花(与背景卡片升起动画同步呈现)
 * - 进入结束态后尽快发射一簇礼花(礼花先行播放),卡片/里程延迟约 700ms 才升起
 * - 仅发射一次,prevStatus 去重防重复播放
 * - tripStatus 非 TripFinished 时卸载 canvas(条件渲染)
 */
@@ -27,18 +27,20 @@
    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);
src/robotaxi/pages/begin-route/index.tsx
@@ -11,7 +11,7 @@
// 调试面板:模拟完整行程流转(仅 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';
// 弹窗状态管理
@@ -1674,8 +1674,13 @@
  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 {
@@ -2655,13 +2660,13 @@
        onConfirm={handleConfirmCreditPayPopup}
      />
      <TripFinishedFireworks tripStatus={tripStatus} />
      {/* 转场动效调试面板 — 固定在地图上方,始终可见 */}
      {/* <DebugTransitionPanel
      {/* 转场动效调试面板 — 固定在地图上方,始终可见(临时开启,调试完成后请重新注释) */}
      <DebugTransitionPanel
        orderId={orderId}
        setOrderId={setOrderId}
        setTripStatus={setTripStatus}
        bindSocketListeners={bindSocketListeners}
      /> */}
      />
      {/* 模拟器入口已关闭,如需本地调试可取消下方注释
      <DebugOrderSimulatorPanel
        orderId={orderId}