Преглед изворни кода

feat: 预约充电确认页重设计——倒计时升级为时/分/秒数字块主卡(含预计开始时间与等待开始标签),取消预约收入卡片底部,费用行与余额卡token化加按压反馈,页面底色统一#F4F7F6并加卡片入场动效

skyline пре 2 недеља
родитељ
комит
a048a8078c
1 измењених фајлова са 184 додато и 63 уклоњено
  1. 184 63
      charge-front/src/pages-charge/appointment/appointment.vue

+ 184 - 63
charge-front/src/pages-charge/appointment/appointment.vue

@@ -1,7 +1,7 @@
 <template>
   <view :class="['page']">
     <view v-if="station && priceInfo">
-      <view class="block">
+      <view class="block anim-fade-up">
         <view class="station">
           <ChargeMachine
               :title="'NO.' + equipment.shortId"
@@ -21,49 +21,49 @@
       </view>
       <!--      <view class="mt-40 ml-30 color-999 fs-32 fw-500">费用说明</view>-->
       <view
-          class="mt-20 block height-96 flex-align-center pl-30 pr-30"
+          class="mt-20 block height-96 flex-align-center pl-30 pr-30 pressable anim-fade-up"
+          style="animation-delay: 0.04s"
+          hover-class="pressed"
           @click="openPriceDesc"
       >
-        <view class="fs-28 color-000">充电费用</view>
-        <view class="ml-64 fs-26 color-333"
+        <view class="fs-28 color-333 fw-500">充电费用</view>
+        <view class="ml-auto fs-26 color-666 mr-8"
         >{{ priceInfo.minPrice }}~{{ priceInfo.maxPrice }}元/度
         </view
         >
-        <view class="ml-auto">
-          <uni-icons type="right" size="16" color="rgba(28,43,41,0.4)"></uni-icons>
-        </view>
+        <uni-icons type="right" size="16" color="rgba(28,43,41,0.4)"></uni-icons>
       </view>
       <template v-if="appointmentData">
-        <view class="mt-40 color-999 fs-32 fw-500">已预约充电</view>
-        <view class="mt-20 block flex-align-center" style="height: 180rpx">
-          <image
-              src="../static/icon-alarm.png"
-              mode="widthFix"
-              style="width: 32rpx; display: block"
-          ></image>
-          <view class="ml-24">
-            <view class="flex" v-if="appointmentCountDown">
-              <view class="fs-28 color-000">将在</view>
-              <view class="fs-44 lh-36 color-primary ml-8 mr-8">{{
-                  appointmentCountDown
-                }}
-              </view>
-              <view class="fs-28 color-000">后开始充电</view>
+        <view class="mt-20 block hero anim-fade-up" style="animation-delay: 0.08s">
+          <view class="flex-align-center pl-30 pr-30 pt-30">
+            <view class="hero-icon flex-center anim-breathe">
+              <uni-icons type="notification-filled" size="22" color="#2d9e95"></uni-icons>
             </view>
-            <view class="fs-24 color-999 mt-8"
-            >注意:启动充电前请勿拔插充电枪!
-            </view
-            >
+            <view class="ml-16 fs-30 fw-600 color-333">已预约充电</view>
+            <view class="hero-tag ml-auto">等待开始</view>
+          </view>
+          <view class="mt-28 fs-24 color-999 text-center">距开始充电</view>
+          <view class="mt-16 flex-center">
+            <view v-for="(part, i) in countdownParts" :key="i" class="hero-cell">
+              <view class="hero-num">{{ part }}</view>
+              <view class="hero-unit">{{ ["时", "分", "秒"][i] }}</view>
+            </view>
+          </view>
+          <view class="mt-20 fs-24 color-999 text-center" v-if="appointmentStartText"
+          >预计 {{ appointmentStartText }} 开始充电
+          </view>
+          <view class="hero-tip flex-align-center ml-30 mr-30 mt-24">
+            <uni-icons type="info" size="14" color="#2d9e95"></uni-icons>
+            <view class="ml-8 fs-24 color-666">启动充电前请勿拔插充电枪</view>
+          </view>
+          <view class="mt-30 hero-divider"></view>
+          <view class="flex-center pt-20 pb-24">
+            <view
+                class="hero-cancel pressable flex-center"
+                hover-class="pressed"
+                @click="cancelAppointment"
+            >取消预约</view>
           </view>
-        </view>
-        <view class="mt-40 flex-center">
-          <view
-              class="flex-center height-68 br-68 fs-26 color-666"
-              style="width: 184rpx; border: 1px solid #c9d4d2"
-              @click="cancelAppointment"
-          >取消预约
-          </view
-          >
         </view>
       </template>
       <template v-else>
@@ -175,39 +175,40 @@
       </template>
       <!-- 当前余额 + 低余额提醒,点击去充值(充值后返回本页) -->
       <view
-          class="mt-20 block flex-align-center pl-30 pr-30 pt-30 pb-30"
-          :style="isLowBalance ? 'background-color: #fff5f5; border: 1rpx solid rgba(244, 54, 54, 0.25);' : ''"
+          class="mt-20 block flex-align-center pl-30 pr-30 pt-30 pb-30 pressable anim-fade-up"
+          :class="{ 'balance-low': isLowBalance }"
+          style="animation-delay: 0.12s"
+          hover-class="pressed"
           @click="to('/pages-user/wallet-recharge/wallet-recharge?back=1')"
       >
-        <view class="flex-column">
-          <view class="flex-align-center">
-            <uni-icons type="wallet-filled" size="16" :color="isLowBalance ? '#f43636' : '#999'"></uni-icons>
-            <view class="fs-26 ml-8 color-333">当前余额</view>
-          </view>
-          <view class="mt-8">
-            <view class="fs-40 fw-600" :style="{ color: isLowBalance ? '#f43636' : '#333' }">{{ balanceText }}</view>
+        <view class="balance-icon flex-center flex-shrink">
+          <uni-icons
+              type="wallet-filled"
+              size="18"
+              :color="isLowBalance ? '#f43636' : '#2d9e95'"
+          ></uni-icons>
+        </view>
+        <view class="ml-20">
+          <view class="fs-24 color-999">当前余额</view>
+          <view class="flex-align-baseline mt-6">
+            <text class="fs-24 fw-500 color-666">¥</text>
+            <text
+                class="fs-44 fw-600 ml-4 lh-44"
+                :style="{ color: isLowBalance ? 'var(--color-error)' : 'var(--text-1)' }"
+            >{{ balanceValue }}
+            </text>
           </view>
           <view
               v-if="isLowBalance"
-              class="fs-24 mt-8 lh-30"
-              style="color: #f43636"
-          >余额仅 {{ balanceText }},可能无法完成本次充电
-          </view
-          >
-        </view>
-        <view class="ml-auto">
-          <view
-              class="flex-center fs-24 fw-500"
-              :style="isLowBalance
-                  ? 'height: 56rpx; border-radius: 56rpx; background-color: var(--color-error); color: #fff; padding: 0 28rpx;'
-                  : 'height: 56rpx; border-radius: 56rpx; border: 1rpx solid #c9d4d2; color: #666; padding: 0 28rpx;'"
-          >去充值
-          </view
-          >
+              class="fs-22 mt-4 lh-30"
+              style="color: var(--color-error)"
+          >余额较低,可能无法完成本次充电
+          </view>
         </view>
+        <view class="ml-auto recharge-pill flex-center fs-24 fw-500 flex-shrink">去充值</view>
       </view>
       <view class="pt-60 pb-80"></view>
-      <style-bottom-view>
+      <style-bottom-view :shadow="true">
         <view class="pt-20 pl-40 pr-40 pb-20 bg-fff flex">
           <template v-if="appointmentData">
             <view class="mr-10" style="width: 50%">
@@ -375,7 +376,7 @@ const LOW_BALANCE_THRESHOLD = 30;
 const isLowBalance = computed(
     () => Number(balance.value) > 0 && Number(balance.value) < LOW_BALANCE_THRESHOLD
 );
-const balanceText = computed(() => `${Number(balance.value).toFixed(2)}元`);
+const balanceValue = computed(() => Number(balance.value).toFixed(2));
 
 
 const refreshUserBalance = () => {
@@ -691,6 +692,25 @@ const formatAppointmentCountDown = (time: string) => {
   }:${secondTime < 10 ? "0" + secondTime : secondTime}`;
 };
 
+/** 倒计时分段:["01", "20", "52"] 对应 时/分/秒 */
+const countdownParts = computed(() => {
+  const cd = appointmentCountDown.value;
+  return cd ? String(cd).split(":") : ["--", "--", "--"];
+});
+
+/** 预约开始时间的展示文案:今天/明天 M月d日 HH:mm */
+const appointmentStartText = computed(() => {
+  if (!appointmentData.value?.startTime) {
+    return "";
+  }
+  const ts = parseDate(appointmentData.value.startTime).getTime();
+  const dayDiff = Math.round(
+      (new Date(ts).setHours(0, 0, 0, 0) - new Date().setHours(0, 0, 0, 0)) / DAY
+  );
+  const dayText = dayDiff <= 0 ? "今天" : dayDiff === 1 ? "明天" : format("M月d日", ts);
+  return `${dayText} ${format("h:m", ts)}`;
+});
+
 const submit = () => {
   if (
       chargeType.value === 0 &&
@@ -946,8 +966,8 @@ onUnload(() => {
 .page {
   min-height: 100vh;
   width: 100%;
-  padding: 20rpx;
-  background-color: #f6f7fa;
+  padding: 24rpx 30rpx 0;
+  background-color: var(--bg-page);
 }
 
 .block {
@@ -960,6 +980,107 @@ onUnload(() => {
   border-bottom: 1rpx solid var(--divider);
 }
 
+/* ============ 预约状态主卡 ============ */
+.hero-icon {
+  width: 72rpx;
+  height: 72rpx;
+  border-radius: 50%;
+  background: var(--color-primary-tint-strong);
+  flex-shrink: 0;
+}
+
+.hero-tag {
+  display: flex;
+  align-items: center;
+  height: 44rpx;
+  padding: 0 20rpx;
+  border-radius: 12rpx;
+  background: var(--color-primary-tint);
+  color: var(--color-primary);
+  font-size: 24rpx;
+  font-weight: 500;
+  flex-shrink: 0;
+}
+
+.hero-cell {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  width: 128rpx;
+  padding: 20rpx 0 14rpx;
+  border-radius: 12rpx;
+  background: var(--color-primary-tint);
+}
+
+.hero-cell + .hero-cell {
+  margin-left: 16rpx;
+}
+
+.hero-num {
+  font-size: 52rpx;
+  line-height: 56rpx;
+  font-weight: 600;
+  color: var(--color-primary);
+  font-variant-numeric: tabular-nums;
+}
+
+.hero-unit {
+  margin-top: 4rpx;
+  font-size: 20rpx;
+  color: var(--text-3);
+}
+
+.hero-tip {
+  height: 64rpx;
+  border-radius: 12rpx;
+  background: var(--color-sec);
+}
+
+.hero-divider {
+  border-top: 1rpx solid var(--divider);
+}
+
+.hero-cancel {
+  min-width: 240rpx;
+  height: 64rpx;
+  padding: 0 48rpx;
+  border: 1rpx solid var(--divider);
+  border-radius: 32rpx;
+  background: #fff;
+  font-size: 26rpx;
+  color: var(--text-2);
+}
+
+/* ============ 余额卡 ============ */
+.balance-icon {
+  width: 72rpx;
+  height: 72rpx;
+  border-radius: 50%;
+  background: var(--color-primary-tint-strong);
+}
+
+.balance-low {
+  background-color: rgba(244, 54, 54, 0.04);
+  border: 1rpx solid rgba(244, 54, 54, 0.25);
+}
+
+.balance-low .balance-icon {
+  background: rgba(244, 54, 54, 0.08);
+}
+
+.recharge-pill {
+  height: 56rpx;
+  padding: 0 28rpx;
+  border-radius: 28rpx;
+  background: var(--color-primary-tint);
+  color: var(--color-primary);
+}
+
+.balance-low .recharge-pill {
+  background: var(--color-error);
+  color: #fff;
+}
+
 /* ============ 时间选择器 ============ */
 .time-picker {
   background-color: #fff;