From be4e2d7c2b330c3b8991a0286ea16cc1285b9ec0 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Fri, 08 May 2026 17:47:32 +0800
Subject: [PATCH] feat: 微信小程序支持上传头像

---
 src/pages/login/index.vue |  269 +++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 229 insertions(+), 40 deletions(-)

diff --git a/src/pages/login/index.vue b/src/pages/login/index.vue
index 9f75363..75d4a89 100644
--- a/src/pages/login/index.vue
+++ b/src/pages/login/index.vue
@@ -1,48 +1,95 @@
 <!-- 登录页 -->
 <template>
-  <view>
-    <view class="login-form-wrap">
-      <view class="title"> 掌控智飞</view>
-      <input
-        v-model="loginForm.username"
-        class="u-border-bottom"
-        placeholder="请输入用户名"
-      />
+  <view class="login-form-wrap">
+    <image class="logo" :src="logoSvg" />
+    <div class="title">掌控智飞</div>
+    <div class="user-name">
+      <image :src="usernameSvg" />
+      <input v-model="loginForm.username" placeholder="请输入用户名" />
+    </div>
+    <div class="pass-word">
+      <image :src="passwordSvg" />
       <input
         v-model="loginForm.password"
-        class="u-border-bottom"
         type="password"
         placeholder="请输入密码"
       />
-      <button class="login-btn" :style="[inputStyle]" @tap="submit">
-        登录
-        <text class="i-mdi-login" />
-      </button>
-    </view>
+    </div>
+    <div class="remember-password">
+      <label>
+        <checkbox-group @change="toggleRemember">
+          <checkbox
+            :checked="rememberPassword"
+            color="#1D6FE9"
+            style="transform: scale(0.7)"
+          />
+        </checkbox-group>
+        记住密码
+      </label>
+    </div>
+
+    <button class="login-btn" :style="[inputStyle]" @tap="submit">登录</button>
+    <image class="lowerRightCorner" :src="droneSvg" />
+
+    <!-- #ifdef MP-WEIXIN -->
+    <GetPrivacy ref="privacyComponent" position="center" @allowPrivacy="allowPrivacy"/>
+    <!-- #endif -->
   </view>
 </template>
 
 <script setup>
+import { getAssetsImage } from "@/utils/index.js";
 import md5 from "js-md5";
 import { loginByUsername } from "@/api/user/index.js";
 import { useUserStore } from "@/store/index.js";
+// #ifdef MP-WEIXIN
+import GetPrivacy from '@/components/GetPrivacy.vue'
+// #endif
 import { HOME_PATH, LOGIN_PATH, removeQueryString } from "@/router";
+import { onMounted } from "vue";
+
+const droneSvg = getAssetsImage("/images/login/droneSvg.png");
+const usernameSvg = getAssetsImage("/images/login/username.png");
+const passwordSvg = getAssetsImage("/images/login/password.png");
+const logoSvg = getAssetsImage("/images/login/logo.png");
+
 const userStore = useUserStore();
 const loginForm = ref({
-  username: "cpz3",
-  password: "cpz3@2025",
+  username: "",
+  password: "",
 });
+const rememberPassword = ref(false);
 const inputStyle = computed(() => {
   const style = {};
   if (loginForm.value.username && loginForm.value.password) {
     style.color = "#fff";
-    style.backgroundColor = uni.$u.color.warning;
+    style.backgroundColor = "#1D6FE9";
   }
   return style;
 });
 let redirect = HOME_PATH;
+function toggleRemember(e) {
+  rememberPassword.value = e.detail.value.length > 0;
+}
 
 async function submit() {
+  if (!loginForm.value.username.trim()) {
+    uni.showToast({
+      title: "请输入用户名",
+      icon: "none",
+      duration: 2000,
+    });
+    return;
+  }
+
+  if (!loginForm.value.password.trim()) {
+    uni.showToast({
+      title: "请输入密码",
+      icon: "none",
+      duration: 2000,
+    });
+    return;
+  }
   let userInfo = {
     tenantId: "000000",
     deptId: "",
@@ -53,36 +100,177 @@
     code: "",
     key: "",
   };
-  loginByUsername(
-    userInfo.tenantId,
-    userInfo.deptId,
-    userInfo.roleId,
-    userInfo.username,
-    md5(userInfo.password),
-    userInfo.type,
-    userInfo.key,
-    userInfo.code
-  ).then((res) => {
-    userStore.setUserInfo(res.data);
-    uni.switchTab({
-      url: "/pages/user/index",
+
+  if (rememberPassword.value) {
+    uni.setStorageSync("rememberedUser", {
+      username: loginForm.value.username,
+      password: loginForm.value.password,
     });
-  });
+  } else {
+    uni.removeStorageSync("rememberedUser");
+  }
+
+  try {
+    const res = await loginByUsername(
+      userInfo.tenantId,
+      userInfo.deptId,
+      userInfo.roleId,
+      userInfo.username,
+      md5(userInfo.password),
+      userInfo.type,
+      userInfo.key,
+      userInfo.code
+    );
+    userStore.setUserInfo(res.data);
+    uni.reLaunch({
+      url: "/pages/map/index",
+    });
+  } catch (error) {
+    const errorMsg =
+      error.data?.error_description !== "Bad credentials"
+        ? error.data?.error_description
+        : "登录失败,请重试";
+    uni.showToast({
+      title: errorMsg,
+      icon: "none",
+      duration: 2000,
+    });
+  }
 }
 
+// 从本地存储加载记住的密码
+onMounted(() => {
+  const savedUserInfo = uni.getStorageSync("rememberedUser");
+  console.log("记住密码", savedUserInfo);
+  if (savedUserInfo) {
+    loginForm.value.username = savedUserInfo.username;
+    loginForm.value.password = savedUserInfo.password;
+    rememberPassword.value = true;
+  }
+});
 onLoad((options) => {
   if (options.redirect && removeQueryString(options.redirect) !== LOGIN_PATH) {
     redirect = decodeURIComponent(options.redirect);
   }
 });
+
+// #ifdef MP-WEIXIN
+const allowPrivacy = () =>{
+
+  // 同意隐私协议触发事件,有些接口需要同意授权后才能执行,比如获取手机号授权接口,可以在同意隐私协议后,再执行授权获取手机号接口,如果不需要可以不添加该方法
+  console.log('同意隐私授权')
+}
+const privacyComponent =ref(null)
+// onShow(() =>{
+//   wx.getPrivacySetting({
+//     success: res => {
+//       console.log(res)
+//       if (!res.needAuthorization) {
+//         privacyComponent?.value?.closePrivacy()
+//         // 查询授权,针对有tab切换的页面,可以在onshow中查询隐私授权状态,判断在tab切换后是否需要关闭授权弹框
+//         console.log('已经同意隐私授权,不需要再次授权')
+//       }
+//     },
+//     fail: () => {},
+//     complete: () => {}
+//   })
+// })
+// #endif
 </script>
 
 <style lang="scss" scoped>
 .login-form-wrap {
-  @apply mt-80rpx mx-auto mb-0 w-600rpx;
+  position: relative;
+  text-align: center;
+  height: 100%;
+  width: 100%;
+
+  .logo {
+    width: 127px;
+    height: 51px;
+    margin: 0 auto;
+    margin-top: 104px;
+    margin-bottom: 16px;
+  }
+
+  .lowerRightCorner {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    width: 425.61rpx;
+    height: 316.46rpx;
+  }
 
   .title {
-    @apply mb-100rpx text-60rpx text-left font-500;
+    font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
+    font-weight: 400;
+    font-size: 84rpx;
+    line-height: 82rpx;
+    letter-spacing: 1px;
+    text-shadow: 0px 8px 8px rgba(0, 0, 0, 0.18);
+    text-align: center;
+    font-style: normal;
+    text-transform: none;
+    color: #1452d3;
+    text-align: center;
+    margin-bottom: 168rpx;
+  }
+
+  .user-name,
+  .pass-word {
+    display: flex;
+    //justify-content: center;
+    align-items: center;
+    margin-left: 62rpx;
+    margin-right: 58rpx;
+    height: 118rpx;
+    border-bottom: 2rpx solid #e3e3e3;
+
+    image {
+      width: 40rpx;
+      height: 40rpx;
+      margin-right: 12rpx;
+    }
+
+    :deep(uni-input) {
+      height: 40rpx;
+      line-height: 40rpx;
+      width: 80%;
+      margin-top: 20rpx;
+      padding: 0 !important;
+    }
+
+    :deep(input) {
+      height: 40rpx;
+      line-height: 40rpx;
+      width: 80%;
+      margin-top: 20rpx;
+      padding: 0 !important;
+      margin: 0 !important;
+    }
+
+    :deep(.uni-input-placeholder) {
+      font-size: 32rpx;
+      color: #e3e3e3;
+      font-weight: 500;
+    }
+  }
+
+  .remember-password {
+    display: flex;
+    justify-content: flex-end;
+    align-items: center;
+    margin-left: 62rpx;
+    margin-right: 58rpx;
+    margin-top: 20rpx;
+
+    color: #666;
+    font-size: 28rpx;
+
+    label {
+      display: flex;
+      align-items: center;
+    }
   }
 
   input {
@@ -91,14 +279,18 @@
 
   .tips {
     @apply mt-8rpx mb-60rpx;
-
     color: $u-info;
   }
 
   .login-btn {
-    @apply flex items-center justify-center py-12rpx px-0 text-30rpx bg-#fdf3d0 border-none;
-
-    color: $u-tips-color;
+    z-index: 1;
+    @apply flex items-center justify-center py-12rpx px-0 text-30rpx border-none;
+    background: #1d6fe9;
+    color: white;
+    width: 590rpx;
+    height: 76rpx;
+    border-radius: 40rpx 40rpx 40rpx 40rpx;
+    margin-top: 100rpx;
 
     &::after {
       @apply border-none;
@@ -107,7 +299,6 @@
 
   .alternative {
     @apply flex justify-between mt-30rpx;
-
     color: $u-tips-color;
   }
 }
@@ -117,14 +308,12 @@
 
   .item {
     @apply flex items-center flex-col text-28rpx;
-
     color: $u-content-color;
   }
 }
 
 .hint {
   @apply px-40rpx py-20rpx text-24rpx;
-
   color: $u-tips-color;
 
   .link {

--
Gitblit v1.9.3