Переглянути джерело

优化用户端小程序动画性能

skyline 3 тижнів тому
батько
коміт
dea62b6aae

+ 21 - 13
haha-mp/src/App.vue

@@ -6,11 +6,12 @@ import { logger } from './utils/logger';
 
 /**
  * 应用启动
+ * 登录状态检查采用非阻塞模式,避免网络延迟拖慢启动速度
  */
 onLaunch((options: any) => {
   logger.log("App Launch, options:", JSON.stringify(options));
-  checkLoginStatus(options);
   checkBindingCode(options);
+  checkLoginStatus(options);
 });
 
 /**
@@ -76,7 +77,8 @@ const LOGIN_WHITE_LIST = [
 
 /**
  * 验证token是否有效
- * 调用后端用户信息接口校验token,返回true/false
+ * 调用后端用户信息接口校验token,最多等待3秒,
+ * 超时则假定token有效(由后续API请求的401拦截兜底)
  */
 const verifyToken = (): Promise<boolean> => {
   return new Promise((resolve) => {
@@ -86,6 +88,14 @@ const verifyToken = (): Promise<boolean> => {
       return;
     }
 
+    let settled = false;
+    const done = (result: boolean) => {
+      if (!settled) {
+        settled = true;
+        resolve(result);
+      }
+    };
+
     const url = `${API_CONFIG.baseUrl}/login/user-info`;
     uni.request({
       url,
@@ -94,34 +104,32 @@ const verifyToken = (): Promise<boolean> => {
         'Content-Type': 'application/json',
         'accessToken': token
       },
-      timeout: 10000,
+      timeout: 5000,
       success: (res: any) => {
         if (res.statusCode === 200) {
           const data = res.data;
           if (data && (data.code === 200 || data.code === 0)) {
-            // token有效
-            resolve(true);
+            done(true);
           } else if (data && data.code === 401) {
-            // token无效或已过期
             logger.log('[App] token无效:', data.message);
-            resolve(false);
+            done(false);
           } else {
-            // 其他业务错误,保守起见仍视为token有效
             logger.warn('[App] 验证token返回异常状态:', data?.code, data?.message);
-            resolve(true);
+            done(true);
           }
         } else {
-          // 网络或服务异常,不阻断用户使用,保守视为token有效
           logger.warn('[App] 验证token网络异常, statusCode:', res.statusCode);
-          resolve(true);
+          done(true);
         }
       },
       fail: (err: any) => {
-        // 网络请求失败,保守视为token有效,不阻断用户使用
         logger.warn('[App] 验证token请求失败:', err.errMsg);
-        resolve(true);
+        done(true);
       }
     });
+
+    // 竞速兜底:最多等3秒,超时假定token有效
+    setTimeout(() => done(true), 3000);
   });
 };
 

+ 7 - 7
haha-mp/src/pages/coupons/coupons.vue

@@ -322,7 +322,7 @@ onMounted(() => {
 .ticket-amount {
   display: flex;
   align-items: baseline;
-  animation: scaleIn 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55) 0.2s both;
+  animation: scaleIn 0.3s ease 0.1s both;
 }
 
 .ticket-currency {
@@ -485,13 +485,13 @@ onMounted(() => {
   justify-content: center;
   min-height: 55vh;
   padding: 40rpx;
-  animation: fadeIn 0.6s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: fadeIn 0.3s ease;
 }
 
 .empty-visual {
   margin-bottom: 40rpx;
   position: relative;
-  animation: bounce 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55) 0.2s both;
+  animation: bounce 0.3s ease 0.1s both;
 }
 
 .empty-ticket-shadow {
@@ -574,15 +574,15 @@ onMounted(() => {
   color: #999999;
   font-weight: 600;
   margin-bottom: 36rpx;
-  animation: slideUp 0.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.3s both;
+  animation: slideUp 0.3s ease 0.1s both;
 }
 
 .empty-cta {
   padding: 18rpx 64rpx;
   background: #1A1A1A;
   border-radius: 44rpx;
-  animation: slideUp 0.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.4s both;
-  transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideUp 0.3s ease 0.15s both;
+  transition: transform 0.3s ease;
   
   &:active {
     transform: scale(0.95);
@@ -629,7 +629,7 @@ onMounted(() => {
   padding: 20rpx 64rpx 56rpx;
   display: flex;
   justify-content: center;
-  animation: slideUp 0.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.3s both;
+  animation: slideUp 0.3s ease 0.1s both;
 }
 
 .bottom-btn {

+ 4 - 7
haha-mp/src/pages/index/index.vue

@@ -232,21 +232,18 @@ const doOpenDoor = async (deviceId: string) => {
 };
 
 const goToMy = () => {
-  uni.vibrateShort({ type: 'light' })
   uni.navigateTo({
     url: '/pages/my/my'
   })
 }
 
 const goToOrders = () => {
-  uni.vibrateShort({ type: 'light' })
   uni.navigateTo({
     url: '/pages/orders/orders'
   })
 }
 
 const goToCouponCenter = () => {
-  uni.vibrateShort({ type: 'light' })
   uni.navigateTo({
     url: '/pages/couponCenter/couponCenter'
   })
@@ -274,7 +271,7 @@ const onContactSuccess = () => {
 .brand-section {
   text-align: center;
   padding: $spacing-xxl 0 $spacing-xl;
-  animation: slideUp 0.6s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideUp 0.3s ease;
   will-change: transform, opacity;
   transform: translateZ(0);
 
@@ -300,7 +297,7 @@ const onContactSuccess = () => {
   justify-content: center;
   align-items: center;
   padding: $spacing-xl 0;
-  animation: scaleIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55) 0.2s both;
+  animation: scaleIn 0.3s ease 0.1s both;
   will-change: transform, opacity;
   transform: translateZ(0);
 }
@@ -378,7 +375,7 @@ const onContactSuccess = () => {
   align-items: center;
   gap: $spacing-xl;
   margin: $spacing-xxl 0;
-  animation: slideUp 1s cubic-bezier(0.25, 0.1, 0.25, 1) 0.4s both;
+  animation: slideUp 0.35s ease 0.15s both;
   will-change: transform, opacity;
   transform: translateZ(0);
 
@@ -437,7 +434,7 @@ const onContactSuccess = () => {
   border-radius: $radius-lg;
   padding: $spacing-lg;
   box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
-  animation: slideUp 1.2s cubic-bezier(0.25, 0.1, 0.25, 1) 0.6s both;
+  animation: slideUp 0.35s ease 0.2s both;
   margin-top: auto;
   width: 100%;
   box-sizing: border-box;

+ 3 - 3
haha-mp/src/pages/login/login.vue

@@ -315,7 +315,7 @@ const goToPrivacyPolicy = () => {
   align-items: center;
   padding-top: 160rpx;
   padding-bottom: 80rpx;
-  animation: slideDown 0.8s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideDown 0.3s ease;
 }
 
 .logo-wrapper {
@@ -440,7 +440,7 @@ const goToPrivacyPolicy = () => {
     0 16rpx 48rpx rgba(0, 0, 0, 0.06),
     inset 0 1rpx 0 rgba(255, 255, 255, 0.8);
   border: 1rpx solid rgba(255, 215, 0, 0.15);
-  animation: slideUp 0.8s cubic-bezier(0.25, 0.1, 0.25, 1) 0.3s both;
+  animation: slideUp 0.3s ease 0.1s both;
   will-change: transform, opacity;
   transform: translateZ(0);
 }
@@ -531,7 +531,7 @@ const goToPrivacyPolicy = () => {
 
 /* ========== 用户协议 ========== */
 .agreement-section {
-  animation: fadeIn 1s cubic-bezier(0.25, 0.1, 0.25, 1) 0.6s both;
+  animation: fadeIn 0.35s ease 0.15s both;
 }
 
 .agreement-card {

+ 5 - 8
haha-mp/src/pages/my/my.vue

@@ -162,21 +162,18 @@ const goBack = () => {
 };
 
 const goToOrders = () => {
-  uni.vibrateShort({ type: 'light' });
   uni.navigateTo({
     url: '/pages/orders/orders'
   });
 };
 
 const goToCoupons = () => {
-  uni.vibrateShort({ type: 'light' });
   uni.navigateTo({
     url: '/pages/coupons/coupons'
   });
 };
 
 const goToCouponCenter = () => {
-  uni.vibrateShort({ type: 'light' });
   uni.navigateTo({
     url: '/pages/couponCenter/couponCenter'
   });
@@ -274,7 +271,7 @@ const handleLogout = () => {
   padding-bottom: $spacing-md;
   display: flex;
   align-items: center;
-  animation: slideDown 0.6s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideDown 0.3s ease;
   
   .user-avatar {
     width: 88rpx;
@@ -335,7 +332,7 @@ const handleLogout = () => {
 /* ========== 菜单分组 ========== */
 .menu-section {
   margin-top: $spacing-lg;
-  animation: slideUp 0.8s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideUp 0.3s ease;
   
   .section-title {
     font-size: 24rpx;
@@ -409,7 +406,7 @@ const handleLogout = () => {
     border-radius: 16rpx;
     padding: 0 8rpx;
     margin-right: $spacing-sm;
-    animation: bounce 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+    animation: bounce 0.3s ease;
   }
   
   .service-phone {
@@ -425,7 +422,7 @@ const handleLogout = () => {
   padding: $spacing-xxl $spacing-lg $spacing-lg;
   display: flex;
   justify-content: center;
-  animation: fadeIn 1s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: fadeIn 0.35s ease;
   
   .logout-btn {
     width: 60%;
@@ -458,6 +455,6 @@ const handleLogout = () => {
   font-size: 22rpx;
   color: $color-text-tertiary;
   padding: $spacing-lg 0;
-  animation: fadeIn 1.2s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: fadeIn 0.4s ease;
 }
 </style>

+ 14 - 18
haha-mp/src/pages/orderDetail/orderDetail.vue

@@ -27,7 +27,7 @@
         <!-- 商品列表 -->
         <view v-for="(product, index) in order.products" :key="index" class="product-item">
           <view class="product-image">
-            <image v-if="product.image" :src="product.image" mode="aspectFill"></image>
+            <image v-if="product.image" :src="product.image" mode="aspectFill" lazy-load></image>
             <view v-else class="image-placeholder"></view>
           </view>
           <view class="product-info">
@@ -141,7 +141,7 @@ import { checkAuth } from '../../utils/auth';
 import { getStatusText, canRefund } from '../../utils/order';
 
 const order = ref<OrderInfo | null>(null);
-const loading = ref(false);
+const loading = ref(true);
 const orderId = ref<string | null>(null);
 
 /**
@@ -217,8 +217,7 @@ const loadOrderDetail = async () => {
 
   try {
     uni.showLoading({
-      title: '加载中...',
-      mask: true
+      title: '加载中...'
     });
 
     // 调用真实接口获取订单详情
@@ -339,7 +338,7 @@ const viewVideo = (url: string) => {
   min-height: 400rpx;
   font-size: 28rpx;
   color: #999;
-  animation: fadeIn 0.4s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: fadeIn 0.2s ease;
 }
 
 /* 通用卡片样式 */
@@ -348,8 +347,8 @@ const viewVideo = (url: string) => {
   border-radius: 24rpx;
   padding: 32rpx;
   margin-bottom: 24rpx;
-  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04), 0 2rpx 8rpx rgba(0, 0, 0, 0.02);
-  animation: slideUp 0.5s cubic-bezier(0.25, 0.1, 0.25, 1) both;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+  animation: slideUp 0.25s ease both;
 }
 
 /* 订单状态卡片 */
@@ -357,7 +356,6 @@ const viewVideo = (url: string) => {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  animation-delay: 0.1s;
 }
 
 .status-left {
@@ -375,7 +373,7 @@ const viewVideo = (url: string) => {
   justify-content: center;
   margin-right: 20rpx;
   box-shadow: 0 4rpx 12rpx rgba(0, 204, 102, 0.3);
-  animation: scaleIn 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) 0.3s both;
+  animation: scaleIn 0.3s ease 0.1s both;
 }
 
 .status-icon-wrapper.status-success {
@@ -417,7 +415,6 @@ const viewVideo = (url: string) => {
 .detail-card {
   padding: 0;
   overflow: hidden;
-  animation-delay: 0.2s;
 }
 
 .card-header {
@@ -435,7 +432,7 @@ const viewVideo = (url: string) => {
   display: flex;
   padding: 32rpx;
   align-items: flex-start;
-  transition: background 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
+  transition: background 0.2s ease;
   
   &:active {
     background: #FAFAFA;
@@ -559,7 +556,7 @@ const viewVideo = (url: string) => {
   margin: 0;
   padding: 16rpx 32rpx;
   line-height: 1;
-  transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
+  transition: all 0.2s ease;
   
   &:active {
     transform: scale(0.95);
@@ -581,7 +578,7 @@ const viewVideo = (url: string) => {
   line-height: 1;
   font-weight: 600;
   box-shadow: 0 4rpx 12rpx rgba(255, 193, 7, 0.25);
-  transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
+  transition: all 0.2s ease;
   
   &:active {
     transform: scale(0.95);
@@ -596,7 +593,6 @@ const viewVideo = (url: string) => {
 /* 订单信息卡片 */
 .info-card {
   padding: 0;
-  animation-delay: 0.3s;
 }
 
 .info-list {
@@ -609,7 +605,7 @@ const viewVideo = (url: string) => {
   align-items: center;
   padding: 28rpx 0;
   border-bottom: 1rpx solid #F5F5F5;
-  transition: background 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
+  transition: background 0.2s ease;
   
   &:active {
     background: #FAFAFA;
@@ -639,7 +635,7 @@ const viewVideo = (url: string) => {
 .copy-btn {
   margin-left: 12rpx;
   padding: 8rpx;
-  transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
+  transition: transform 0.2s ease;
   
   &:active {
     transform: scale(0.9);
@@ -669,7 +665,7 @@ const viewVideo = (url: string) => {
 .info-link {
   display: flex;
   align-items: center;
-  transition: opacity 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
+  transition: opacity 0.2s ease;
   
   &:active {
     opacity: 0.6;
@@ -692,7 +688,7 @@ const viewVideo = (url: string) => {
 .footer-note {
   text-align: center;
   padding: 60rpx 0 40rpx;
-  animation: fadeIn 0.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.5s both;
+  animation: fadeIn 0.3s ease 0.15s both;
 }
 
 .footer-note text {

+ 3 - 4
haha-mp/src/pages/orders/orders.vue

@@ -83,8 +83,7 @@ const loadOrders = async () => {
   
   try {
     uni.showLoading({
-      title: '加载中...',
-      mask: true
+      title: '加载中...'
     });
     
     // 调用真实接口获取订单列表
@@ -158,7 +157,7 @@ const viewOrderDetail = (order: OrderInfo) => {
   justify-content: center;
   min-height: 80vh;
   padding: 40rpx;
-  animation: fadeIn 0.6s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: fadeIn 0.3s ease;
   will-change: transform, opacity;
   transform: translateZ(0);
 }
@@ -167,7 +166,7 @@ const viewOrderDetail = (order: OrderInfo) => {
   width: 300rpx;
   height: 300rpx;
   margin-bottom: 40rpx;
-  animation: fadeIn 0.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.2s both;
+  animation: fadeIn 0.3s ease 0.1s both;
   will-change: transform, opacity;
   transform: translateZ(0);
 }

+ 3 - 3
haha-mp/src/pages/replenish/bind.vue

@@ -223,7 +223,7 @@ const handleBind = async () => {
   flex-direction: column;
   align-items: center;
   padding: 80rpx 0 48rpx;
-  animation: slideDown 0.6s $ease-out;
+  animation: slideDown 0.3s $ease-out;
 
   .brand-icon {
     width: 120rpx;
@@ -264,7 +264,7 @@ const handleBind = async () => {
   width: 100%;
   max-width: 600rpx;
   padding: 0 32rpx;
-  animation: slideUp 0.6s $ease-out 0.2s both;
+  animation: slideUp 0.3s $ease-out 0.1s both;
 }
 
 /* 绑定码展示 */
@@ -469,7 +469,7 @@ const handleBind = async () => {
     align-items: center;
     justify-content: center;
     margin-bottom: 32rpx;
-    animation: bounceIn 0.6s $bounce;
+    animation: bounceIn 0.3s $ease-out;
 
     .success-check {
       font-size: 72rpx;

+ 9 - 16
haha-mp/src/pages/shopping/shopping.vue

@@ -290,7 +290,6 @@ const startStatusPolling = async () => {
 };
 
 const showProblem = () => {
-  uni.vibrateShort({ type: 'light' });
   uni.showActionSheet({
     itemList: ['辅助远程开门', '报修'],
     success: function (res) {
@@ -311,15 +310,12 @@ const showProblem = () => {
 };
 
 const goToOrderDetail = () => {
-  uni.vibrateShort({ type: 'light' });
-  // 跳转到订单详情页
   uni.navigateTo({
     url: `/pages/orderDetail/orderDetail?orderNo=${currentOrderNo.value}`
   });
 };
 
 const goHome = () => {
-  uni.vibrateShort({ type: 'light' });
   uni.reLaunch({
     url: '/pages/index/index'
   });
@@ -355,7 +351,7 @@ const goHome = () => {
   width: 200rpx;
   height: 200rpx;
   margin-bottom: $spacing-xl;
-  animation: scaleIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+  animation: scaleIn 0.3s ease;
 }
 
 .status-icon {
@@ -368,11 +364,11 @@ const goHome = () => {
   }
   
   &.door-open {
-    animation: doorOpen 1s $ease-out;
+    animation: doorOpen 0.5s ease;
   }
   
   &.success {
-    animation: successPop 0.6s $bounce;
+    animation: successPop 0.35s ease;
   }
   
   &.error {
@@ -407,12 +403,9 @@ const goHome = () => {
 
 @keyframes successPop {
   0% {
-    transform: scale(0);
+    transform: scale(0.8);
     opacity: 0;
   }
-  50% {
-    transform: scale(1.1);
-  }
   100% {
     transform: scale(1);
     opacity: 1;
@@ -425,20 +418,20 @@ const goHome = () => {
   font-weight: 600;
   margin-bottom: $spacing-sm;
   color: $color-text-primary;
-  animation: slideUp 0.8s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideUp 0.3s ease;
 }
 
 .status-tip {
   font-size: 30rpx;
   color: $color-text-secondary;
   margin-bottom: $spacing-xl;
-  animation: slideUp 0.9s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideUp 0.3s ease 0.05s both;
 }
 
 /* ========== 倒计时 ========== */
 .countdown-wrapper {
   margin-bottom: $spacing-xl;
-  animation: scaleIn 1s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+  animation: scaleIn 0.35s ease 0.1s both;
 }
 
 .countdown {
@@ -488,7 +481,7 @@ const goHome = () => {
   color: $color-primary-dark;
   text-decoration: underline;
   margin-top: $spacing-lg;
-  animation: fadeIn 1.2s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: fadeIn 0.4s ease 0.2s both;
 }
 
 /* ========== 商品列表 ========== */
@@ -499,7 +492,7 @@ const goHome = () => {
   padding: $spacing-lg;
   margin: $spacing-xl 0;
   box-shadow: $shadow-sm;
-  animation: slideUp 1s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideUp 0.35s ease 0.15s both;
 }
 
 .product-item {

+ 0 - 214
haha-mp/src/static/animations.css

@@ -1,214 +0,0 @@
-/**
- * haha-mp 全局动画样式
- * 使用纯CSS动画类,避免SCSS mixins的导入问题
- */
-
-/* ========== 淡入淡出 ========== */
-@keyframes fadeIn {
-  from { opacity: 0; }
-  to { opacity: 1; }
-}
-
-@keyframes fadeOut {
-  from { opacity: 1; }
-  to { opacity: 0; }
-}
-
-/* ========== 滑入效果 ========== */
-@keyframes slideUp {
-  from {
-    opacity: 0;
-    transform: translateY(40rpx);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-
-@keyframes slideDown {
-  from {
-    opacity: 0;
-    transform: translateY(-40rpx);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-
-@keyframes slideLeft {
-  from {
-    opacity: 0;
-    transform: translateX(40rpx);
-  }
-  to {
-    opacity: 1;
-    transform: translateX(0);
-  }
-}
-
-@keyframes slideRight {
-  from {
-    opacity: 0;
-    transform: translateX(-40rpx);
-  }
-  to {
-    opacity: 1;
-    transform: translateX(0);
-  }
-}
-
-/* ========== 缩放效果 ========== */
-@keyframes scaleIn {
-  from {
-    opacity: 0;
-    transform: scale(0.9);
-  }
-  to {
-    opacity: 1;
-    transform: scale(1);
-  }
-}
-
-@keyframes scaleOut {
-  from {
-    opacity: 1;
-    transform: scale(1);
-  }
-  to {
-    opacity: 0;
-    transform: scale(0.9);
-  }
-}
-
-/* ========== 脉冲动画 ========== */
-@keyframes pulse {
-  0%, 100% { 
-    transform: scale(1);
-    opacity: 0.3;
-  }
-  50% { 
-    transform: scale(1.05);
-    opacity: 0.5;
-  }
-}
-
-/* ========== 呼吸动画 ========== */
-@keyframes breathe {
-  0%, 100% { 
-    transform: scale(1);
-  }
-  50% { 
-    transform: scale(1.02);
-  }
-}
-
-/* ========== 骨架屏闪烁 ========== */
-@keyframes skeleton {
-  0%, 100% { 
-    background-color: #F5F5F5; 
-  }
-  50% { 
-    background-color: #EEEEEE; 
-  }
-}
-
-/* ========== 旋转加载 ========== */
-@keyframes spin {
-  to { 
-    transform: rotate(360deg); 
-  }
-}
-
-/* ========== 抖动效果 ========== */
-@keyframes shake {
-  0%, 100% { transform: translateX(0); }
-  10%, 30%, 50%, 70%, 90% { transform: translateX(-8rpx); }
-  20%, 40%, 60%, 80% { transform: translateX(8rpx); }
-}
-
-/* ========== 弹跳效果 ========== */
-@keyframes bounce {
-  0% {
-    transform: scale(0);
-    opacity: 0;
-  }
-  50% {
-    transform: scale(1.1);
-  }
-  100% {
-    transform: scale(1);
-    opacity: 1;
-  }
-}
-
-/* ========== 通用动画类 ========== */
-.animate-fade-in {
-  animation: fadeIn 300ms cubic-bezier(0.25, 0.1, 0.25, 1);
-}
-
-.animate-fade-out {
-  animation: fadeOut 300ms cubic-bezier(0.25, 0.1, 0.25, 1);
-}
-
-.animate-slide-up {
-  animation: slideUp 300ms cubic-bezier(0.25, 0.1, 0.25, 1);
-}
-
-.animate-slide-down {
-  animation: slideDown 300ms cubic-bezier(0.25, 0.1, 0.25, 1);
-}
-
-.animate-slide-left {
-  animation: slideLeft 300ms cubic-bezier(0.25, 0.1, 0.25, 1);
-}
-
-.animate-slide-right {
-  animation: slideRight 300ms cubic-bezier(0.25, 0.1, 0.25, 1);
-}
-
-.animate-scale-in {
-  animation: scaleIn 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
-}
-
-.animate-scale-out {
-  animation: scaleOut 300ms cubic-bezier(0.25, 0.1, 0.25, 1);
-}
-
-.animate-pulse {
-  animation: pulse 2s cubic-bezier(0.42, 0, 0.58, 1) infinite;
-}
-
-.animate-breathe {
-  animation: breathe 3s cubic-bezier(0.42, 0, 0.58, 1) infinite;
-}
-
-.animate-skeleton {
-  animation: skeleton 1.5s cubic-bezier(0.42, 0, 0.58, 1) infinite;
-}
-
-.animate-spin {
-  animation: spin 0.8s linear infinite;
-}
-
-.animate-shake {
-  animation: shake 0.5s cubic-bezier(0.42, 0, 0.58, 1);
-}
-
-.animate-bounce {
-  animation: bounce 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
-}
-
-/* ========== 延迟动画类 ========== */
-.delay-100 { animation-delay: 100ms; }
-.delay-200 { animation-delay: 200ms; }
-.delay-300 { animation-delay: 300ms; }
-.delay-400 { animation-delay: 400ms; }
-.delay-500 { animation-delay: 500ms; }
-
-/* ========== GPU加速 ========== */
-.gpu-accelerated {
-  transform: translateZ(0);
-  will-change: transform, opacity;
-}

+ 0 - 332
haha-mp/src/styles/animations.scss

@@ -1,332 +0,0 @@
-/**
- * haha-mp 全局动画库
- * 极简留白风格 · 优雅动效 · 微交互体验
- */
-
-/* ========================================
- * 动画 Mixins
- * ======================================== */
-
-// 淡入效果
-@mixin fade-in($duration: $duration-normal) {
-  animation: fadeIn $duration $ease-out;
-}
-
-@keyframes fadeIn {
-  from { 
-    opacity: 0; 
-  }
-  to { 
-    opacity: 1; 
-  }
-}
-
-// 淡出效果
-@mixin fade-out($duration: $duration-normal) {
-  animation: fadeOut $duration $ease-out;
-}
-
-@keyframes fadeOut {
-  from { 
-    opacity: 1; 
-  }
-  to { 
-    opacity: 0; 
-  }
-}
-
-// 向上滑入
-@mixin slide-up($duration: $duration-normal, $distance: 40rpx) {
-  animation: slideUp $duration $ease-out;
-}
-
-@keyframes slideUp {
-  from {
-    opacity: 0;
-    transform: translateY(40rpx);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-
-// 向下滑入
-@mixin slide-down($duration: $duration-normal) {
-  animation: slideDown $duration $ease-out;
-}
-
-@keyframes slideDown {
-  from {
-    opacity: 0;
-    transform: translateY(-40rpx);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-
-// 向左滑入
-@mixin slide-left($duration: $duration-normal) {
-  animation: slideLeft $duration $ease-out;
-}
-
-@keyframes slideLeft {
-  from {
-    opacity: 0;
-    transform: translateX(40rpx);
-  }
-  to {
-    opacity: 1;
-    transform: translateX(0);
-  }
-}
-
-// 向右滑入
-@mixin slide-right($duration: $duration-normal) {
-  animation: slideRight $duration $ease-out;
-}
-
-@keyframes slideRight {
-  from {
-    opacity: 0;
-    transform: translateX(-40rpx);
-  }
-  to {
-    opacity: 1;
-    transform: translateX(0);
-  }
-}
-
-// 缩放进入
-@mixin scale-in($duration: $duration-normal) {
-  animation: scaleIn $duration $bounce;
-}
-
-@keyframes scaleIn {
-  from {
-    opacity: 0;
-    transform: scale(0.9);
-  }
-  to {
-    opacity: 1;
-    transform: scale(1);
-  }
-}
-
-// 缩放退出
-@mixin scale-out($duration: $duration-normal) {
-  animation: scaleOut $duration $ease-out;
-}
-
-@keyframes scaleOut {
-  from {
-    opacity: 1;
-    transform: scale(1);
-  }
-  to {
-    opacity: 0;
-    transform: scale(0.9);
-  }
-}
-
-// 脉冲动画
-@mixin pulse($duration: 2s) {
-  animation: pulse $duration $ease-in-out infinite;
-}
-
-@keyframes pulse {
-  0%, 100% { 
-    transform: scale(1);
-    opacity: 0.3;
-  }
-  50% { 
-    transform: scale(1.05);
-    opacity: 0.5;
-  }
-}
-
-// 呼吸动画
-@mixin breathe($duration: 3s) {
-  animation: breathe $duration $ease-in-out infinite;
-}
-
-@keyframes breathe {
-  0%, 100% { 
-    transform: scale(1);
-  }
-  50% { 
-    transform: scale(1.02);
-  }
-}
-
-// 骨架屏闪烁
-@mixin skeleton-loading {
-  animation: skeleton 1.5s $ease-in-out infinite;
-}
-
-@keyframes skeleton {
-  0%, 100% { 
-    background-color: #F5F5F5; 
-  }
-  50% { 
-    background-color: #EEEEEE; 
-  }
-}
-
-// 旋转加载
-@mixin spin($duration: 0.8s) {
-  animation: spin $duration linear infinite;
-}
-
-@keyframes spin {
-  to { 
-    transform: rotate(360deg); 
-  }
-}
-
-// 抖动效果
-@mixin shake($duration: 0.5s) {
-  animation: shake $duration $ease-in-out;
-}
-
-@keyframes shake {
-  0%, 100% { transform: translateX(0); }
-  10%, 30%, 50%, 70%, 90% { transform: translateX(-8rpx); }
-  20%, 40%, 60%, 80% { transform: translateX(8rpx); }
-}
-
-// 弹跳效果
-@mixin bounce($duration: 0.6s) {
-  animation: bounce $duration $bounce;
-}
-
-@keyframes bounce {
-  0% {
-    transform: scale(0);
-    opacity: 0;
-  }
-  50% {
-    transform: scale(1.1);
-  }
-  100% {
-    transform: scale(1);
-    opacity: 1;
-  }
-}
-
-// 翻转效果
-@mixin flip($duration: 0.6s) {
-  animation: flip $duration $ease-in-out;
-}
-
-@keyframes flip {
-  0% {
-    transform: perspective(400px) rotateY(0);
-  }
-  100% {
-    transform: perspective(400px) rotateY(360deg);
-  }
-}
-
-/* ========================================
- * 通用动画类
- * ======================================== */
-
-// 渐入类
-.animate-fade-in {
-  @include fade-in;
-}
-
-// 滑入类
-.animate-slide-up {
-  @include slide-up;
-}
-
-.animate-slide-down {
-  @include slide-down;
-}
-
-.animate-slide-left {
-  @include slide-left;
-}
-
-.animate-slide-right {
-  @include slide-right;
-}
-
-// 缩放类
-.animate-scale-in {
-  @include scale-in;
-}
-
-// 脉冲类
-.animate-pulse {
-  @include pulse;
-}
-
-// 呼吸类
-.animate-breathe {
-  @include breathe;
-}
-
-// 加载旋转类
-.animate-spin {
-  @include spin;
-}
-
-// 抖动类
-.animate-shake {
-  @include shake;
-}
-
-// 弹跳类
-.animate-bounce {
-  @include bounce;
-}
-
-/* ========================================
- * 延迟动画类
- * ======================================== */
-
-.delay-100 {
-  animation-delay: 100ms;
-}
-
-.delay-200 {
-  animation-delay: 200ms;
-}
-
-.delay-300 {
-  animation-delay: 300ms;
-}
-
-.delay-400 {
-  animation-delay: 400ms;
-}
-
-.delay-500 {
-  animation-delay: 500ms;
-}
-
-/* ========================================
- * 性能优化
- * ======================================== */
-
-// GPU加速类
-.gpu-accelerated {
-  transform: translateZ(0);
-  will-change: transform, opacity;
-}
-
-// 减少动画类(用户偏好减少动画时)
-@media (prefers-reduced-motion: reduce) {
-  *,
-  *::before,
-  *::after {
-    animation-duration: 0.01ms !important;
-    animation-iteration-count: 1 !important;
-    transition-duration: 0.01ms !important;
-  }
-}

+ 41 - 5
haha-mp/src/utils/config.ts

@@ -6,6 +6,12 @@
 // @ts-ignore
 const isDevelopment = import.meta.env.DEV || false;
 
+/** 客服电话 */
+export const CUSTOMER_SERVICE_PHONE = '400-0755-315';
+
+/** 应用版本号(与 package.json 同步) */
+export const APP_VERSION = 'v1.62.11';
+
 export const API_CONFIG = {
   // 后端API基础URL
   // 注意:上线生产环境时需替换为正式域名
@@ -22,20 +28,50 @@ export const API_CONFIG = {
 
 /**
  * API接口路径
+ * 各 API 文件从此处引用路径常量,避免硬编码
  */
 export const API_PATHS = {
   // 用户相关
-  login: '/user/login',
-  getUserInfo: '/user/info',
+  loginMiniappPhone: '/login/miniapp-phone',
+  getUserInfo: '/login/user-info',
+  logout: '/login/logout',
   
   // 设备相关
-  scanDoor: '/device/scan',
+  scanDoor: '/device/scan-open',
   checkDeviceStatus: '/device/status',
+  getDeviceProducts: (deviceId: string) => `/device/products/${deviceId}`,
   
   // 订单相关
   getOrders: '/order/list',
   getOrderDetail: '/order/detail',
+  cancelOrder: '/order/cancel',
+  
+  // 支付分相关
+  checkPayscoreEnable: '/payscore/check-enable',
+  enablePayscore: '/payscore/enable',
+  createPayscoreOrder: '/payscore/create',
+  confirmEnablePayscore: '/payscore/confirm-enable',
+  
+  // 优惠券相关
+  getMyCoupons: '/coupon/my',
+  getCouponDetail: (id: string) => `/coupon/${id}`,
+  receiveCoupon: (templateId: string) => `/coupon/receive/${templateId}`,
+  getCouponCount: '/coupon/count',
+  getAvailableCoupons: '/coupon/available',
+  getUsableCoupons: '/coupon/usable',
+  
+  // 状态轮询相关
+  pollDeviceStatus: '/status/device',
+  pollRecognizeResult: '/status/recognize',
+  pollOrderInfo: '/status/order',
+  pollAllStatus: '/status/all',
+  
+  // 公告相关
+  getAnnouncementList: '/announcement/list',
+  getAnnouncementDetail: '/announcement/detail',
   
-  // 商品相关
-  getProducts: '/goods/list'
+  // 补货员相关
+  replenisherWechatLogin: '/replenisher/login/wechat',
+  replenisherBind: '/replenisher/login/bind',
+  replenisherMyInfo: '/replenisher/my-info'
 };