Jelajahi Sumber

polish: 打磨登录页面,完善交互状态与视觉细节

- 背景改用 var(--color-sec) 替代纯白
- 增加品牌名、隐私提示、错误状态展示
- 按钮增加 loading/disabled/press 三态交互
- 登录失败时显示可重试的错误提示
- 移除 any 类型,规范 TypeScript 类型

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 1 hari lalu
induk
melakukan
e50bc9c9da
1 mengubah file dengan 108 tambahan dan 32 penghapusan
  1. 108 32
      charge-front/src/pages/login/login.vue

+ 108 - 32
charge-front/src/pages/login/login.vue

@@ -1,21 +1,36 @@
 <template>
-  <view class="login-container">
-    <view class="login-content">
-      <image
-        class="logo"
-        src="/static/images/map-logo.png"
-        mode="aspectFit"
-      />
-      <view class="title fs-36 fw-600 mt-40">欢迎使用充电桩</view>
-      <view class="subtitle fs-28 color-666 mt-16">登录后可享受更多功能</view>
-      <view class="btn-area mt-60">
+  <view class="login-page">
+    <view class="login-card">
+      <view class="brand">
+        <image
+          class="logo"
+          src="/static/images/map-logo.png"
+          mode="aspectFit"
+        />
+        <text class="brand-name">充电桩</text>
+      </view>
+
+      <view class="welcome mt-48">
+        <text class="heading">授权登录</text>
+        <text class="desc mt-12">使用微信手机号一键登录,即可开始充电</text>
+      </view>
+
+      <view class="actions mt-56">
         <button
           class="login-btn"
           open-type="getPhoneNumber"
+          hover-class="login-btn-press"
+          :loading="submitting"
+          :disabled="submitting"
           @getphonenumber="handleLogin"
         >
-          微信手机号一键登录
+          {{ submitting ? '登录中...' : '微信手机号一键登录' }}
         </button>
+        <text class="notice mt-20">授权仅用于账号注册,不会泄露隐私信息</text>
+      </view>
+
+      <view v-if="errorMsg" class="error mt-28">
+        <text>{{ errorMsg }}</text>
       </view>
     </view>
   </view>
@@ -28,8 +43,10 @@ import { onLoad } from "@dcloudio/uni-app";
 import { ref } from "vue";
 
 const redirect = ref("");
+const submitting = ref(false);
+const errorMsg = ref("");
 
-onLoad((query: any) => {
+onLoad((query: Record<string, string | undefined>) => {
   if (isAuthenticated()) {
     performRedirect(query?.redirect || "");
     return;
@@ -39,19 +56,28 @@ onLoad((query: any) => {
   }
 });
 
-const handleLogin = (e: any) => {
+const handleLogin = (e: WechatMiniprogram.ButtonGetPhoneNumber) => {
+  if (submitting.value) {
+    return;
+  }
+  errorMsg.value = "";
+  submitting.value = true;
+
   login(e)
     .then(() => {
       uni.showToast({
         title: "登录成功",
         icon: "success",
-        duration: 1000,
+        duration: 800,
       });
       setTimeout(() => {
         performRedirect(redirect.value);
-      }, 1000);
+      }, 800);
     })
-    .catch(() => {});
+    .catch(() => {
+      submitting.value = false;
+      errorMsg.value = "登录失败,请检查网络后重试";
+    });
 };
 
 const performRedirect = (url: string) => {
@@ -81,51 +107,101 @@ const performRedirect = (url: string) => {
 </script>
 
 <style lang="scss" scoped>
-.login-container {
+.login-page {
   min-height: 100vh;
   display: flex;
-  flex-direction: column;
   align-items: center;
   justify-content: center;
-  background: #fff;
-  padding: 0 60rpx;
+  background: var(--color-sec);
+  padding: 48rpx;
 }
 
-.login-content {
+.login-card {
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.brand {
   display: flex;
   flex-direction: column;
   align-items: center;
 }
 
 .logo {
-  width: 180rpx;
-  height: 180rpx;
+  width: 140rpx;
+  height: 140rpx;
+}
+
+.brand-name {
+  font-size: 36rpx;
+  font-weight: 600;
+  color: var(--color-primary);
+  margin-top: 16rpx;
+  letter-spacing: 8rpx;
 }
 
-.title {
-  color: #000;
+.welcome {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
 }
 
-.subtitle {
-  color: #999;
+.heading {
+  font-size: 40rpx;
+  font-weight: 700;
+  color: rgba(0, 0, 0, 0.85);
+  line-height: 1.3;
 }
 
-.btn-area {
+.desc {
+  font-size: 26rpx;
+  color: rgba(0, 0, 0, 0.45);
+  line-height: 1.5;
+}
+
+.actions {
   width: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
 }
 
 .login-btn {
   width: 100%;
-  height: 88rpx;
+  height: 96rpx;
   background: var(--color-primary);
   color: #fff;
-  font-size: 32rpx;
-  border-radius: 44rpx;
-  line-height: 88rpx;
+  font-size: 30rpx;
+  font-weight: 600;
+  border-radius: 48rpx;
+  line-height: 96rpx;
   border: none;
+  transition: opacity 0.2s;
 }
 
 .login-btn::after {
   border: none;
 }
+
+.login-btn-press {
+  opacity: 0.85;
+}
+
+.notice {
+  font-size: 22rpx;
+  color: rgba(0, 0, 0, 0.25);
+  text-align: center;
+}
+
+.error {
+  width: 100%;
+  text-align: center;
+}
+
+.error text {
+  font-size: 24rpx;
+  color: var(--color-warning);
+}
 </style>