Browse Source

获取用户昵称和头像

macmini 1 week ago
parent
commit
2693919137
2 changed files with 187 additions and 64 deletions
  1. 174 60
      src/pages/me/me.vue
  2. 13 4
      src/store/user.ts

+ 174 - 60
src/pages/me/me.vue

@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 import { useRequest } from 'alova/client'
 import { storeToRefs } from 'pinia'
-import { ref } from 'vue'
+import { computed, ref } from 'vue'
 import { getCouponSituation } from '@/api/home'
 import { getCouponIssuerApplyById } from '@/api/me'
 import { LOGIN_PAGE } from '@/router/config'
@@ -9,10 +9,10 @@ import { useUserStore } from '@/store'
 import { useTokenStore } from '@/store/token'
 
 definePage({
-  style: {
-    navigationBarTitleText: '我的',
-    navigationStyle: 'custom',
-  },
+    style: {
+        navigationBarTitleText: '我的',
+        navigationStyle: 'custom',
+    },
 })
 
 const userStore = useUserStore()
@@ -30,9 +30,19 @@ const { send: getCouponSituationRequest, data: couponSituationData } = useReques
 const { send: getCouponIssuerApplyByIdRequest, data: couponIssuerApplyByIdData } = useRequest(getCouponIssuerApplyById, {
     immediate: false,
 })
+// 昵称输入值
+const nicknameInput = ref('')
 onShow(() => {
     // 登录后查询收益数据
     if (hasLogin) {
+        // 获取用户信息
+        userStore.fetchUserInfo().then((data) => {
+            // #ifdef MP-WEIXIN
+            // 初始化昵称输入框
+            console.log('用户信息:', data)
+            nicknameInput.value = data?.userInfo.nickname || ''
+            // #endif
+        })
         getCouponSituationRequest()
         getCouponIssuerApplyByIdRequest()
         if (couponIssuerApplyByIdData.value) {
@@ -44,66 +54,128 @@ onShow(() => {
 
 // 微信小程序下登录
 async function handleLogin() {
-  // #ifdef MP-WEIXIN
-  // 微信登录
-  await tokenStore.wxLogin()
-
-  // #endif
-  // #ifndef MP-WEIXIN
-  uni.navigateTo({
-    url: `${LOGIN_PAGE}`,
-  })
-  // #endif
+    // #ifdef MP-WEIXIN
+    // 微信登录
+    await tokenStore.wxLogin()
+
+    // #endif
+    // #ifndef MP-WEIXIN
+    uni.navigateTo({
+        url: `${LOGIN_PAGE}`,
+    })
+    // #endif
 }
 
 function handleLogout() {
-  uni.showModal({
-    title: '提示',
-    content: '确定要退出登录吗?',
-    success: (res) => {
-      if (res.confirm) {
-        // 清空用户信息
-        useTokenStore().logout()
-        // 执行退出登录逻辑
-        uni.showToast({
-          title: '退出登录成功',
-          icon: 'success',
-        })
-        // #ifdef MP-WEIXIN
-        // 微信小程序,去首页
-        // uni.reLaunch({ url: '/pages/index/index' })
-        // #endif
-        // #ifndef MP-WEIXIN
-        // 非微信小程序,去登录页
-        // uni.navigateTo({ url: LOGIN_PAGE })
-        // #endif
-      }
-    },
-  })
+    uni.showModal({
+        title: '提示',
+        content: '确定要退出登录吗?',
+        success: (res) => {
+            if (res.confirm) {
+                // 清空用户信息
+                useTokenStore().logout()
+                // 执行退出登录逻辑
+                uni.showToast({
+                    title: '退出登录成功',
+                    icon: 'success',
+                })
+                // #ifdef MP-WEIXIN
+                // 微信小程序,去首页
+                // uni.reLaunch({ url: '/pages/index/index' })
+                // #endif
+                // #ifndef MP-WEIXIN
+                // 非微信小程序,去登录页
+                // uni.navigateTo({ url: LOGIN_PAGE })
+                // #endif
+            }
+        },
+    })
 }
 
 // 顶部导航栏高度,设置banner位置
 const navigationBarHeight = ref(0)
+// 头像默认图片
+const defaultAvatar = '../../static/images/me/me-bg.png'
+// 计算头像显示
+const avatarDisplay = computed(() => {
+    return userInfo.value?.avatar || defaultAvatar
+})
 // #ifdef MP-WEIXIN
 function getNavigationBarHeight() {
-  uni.getSystemInfo({
-    success: (res) => {
-      const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
-      console.log('顶部导航栏高度:', res.statusBarHeight, menuButtonInfo)
-      // 顶部导航栏高度 = 状态栏高度 + 胶囊的高度
-      navigationBarHeight.value = res.statusBarHeight + menuButtonInfo.height + 12
-    },
-  })
+    uni.getSystemInfo({
+        success: (res) => {
+            const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
+            console.log('顶部导航栏高度:', res.statusBarHeight, menuButtonInfo)
+            // 顶部导航栏高度 = 状态栏高度 + 胶囊的高度
+            navigationBarHeight.value = res.statusBarHeight + menuButtonInfo.height + 12
+        },
+    })
 }
 getNavigationBarHeight()
+
+// 处理点击头像获取用户头像
+async function handleGetAvatar(e) {
+    const { avatarUrl } = e.detail
+    if (avatarUrl) {
+        userStore.setUserAvatar(avatarUrl)
+        uni.showToast({
+            title: '头像获取成功',
+            icon: 'success',
+        })
+        // 验证本地存储是否已更新
+        const updatedUser = uni.getStorageSync('user')
+        console.log('验证本地存储头像更新:', updatedUser?.avatar)
+    }
+}
+
+// 保存昵称
+function saveNickname(e: any) {
+    console.log('保存昵称:', e.detail)
+    // 直接使用nicknameInput.value,因为input已经通过v-model绑定
+    const nickname = nicknameInput.value.trim()
+    if (nickname) {
+        try {
+            // 更新用户信息到store
+            userStore.setUserInfo({
+                ...userInfo.value,
+                nickname,
+            })
+
+            uni.showToast({
+                title: '昵称保存成功',
+                icon: 'success',
+                duration: 1500,
+            })
+
+            // 验证本地存储是否已更新
+            const updatedUser = uni.getStorageSync('user')
+            console.log('本地存储昵称已更新:', updatedUser?.nickname)
+        }
+        catch (error) {
+            console.error('保存昵称失败:', error)
+            uni.showToast({
+                title: '保存失败,请重试',
+                icon: 'error',
+                duration: 1500,
+            })
+        }
+    }
+    else {
+        uni.showToast({
+            title: '昵称不能为空',
+            icon: 'none',
+            duration: 1500,
+        })
+    }
+}
 // #endif
 
 const show = ref(false)
 function close() {
-  show.value = false
+    show.value = false
 }
 function open() {
-  show.value = true
+    show.value = true
 }
 function menuClick(page) {
     if (couponIssuerApplyByIdData.value?.status === '0') {
@@ -119,14 +191,26 @@ function menuClick(page) {
 <template>
     <view class="profile-container">
         <!-- 顶部区域 -->
-        <view class="me-header" style="background: url('../../static/images/me/me-bg.png') no-repeat center center; background-size: cover;">
+        <view
+            class="me-header"
+            style="background: url('../../static/images/me/me-bg.png') no-repeat center center; background-size: cover;"
+        >
             <view class="me-header-avatar-info" :style="{ paddingTop: `${navigationBarHeight}px` }">
-                <view class="me-header-avatar">
-                    <image src="https://picsum.photos/200/200" mode="" />
-                </view>
+                <button class="me-header-avatar" open-type="chooseAvatar" @click="handleGetAvatar">
+                    <image :src="avatarDisplay" mode="aspectFill" />
+                </button>
                 <view class="me-header-info">
                     <view class="me-header-name">
-                        {{ userInfo.value?.nickName || '用户' }}
+                        <!-- #ifdef MP-WEIXIN -->
+                        <input
+                            v-model="nicknameInput" type="nickname" placeholder="用户昵称"
+                            placeholder-style="color: #fff; opacity: 0.7;" class="nickname-input"
+                            @confirm="saveNickname" @blur="saveNickname"
+                        >
+                        <!-- #endif -->
+                        <!-- #ifndef MP-WEIXIN -->
+                        {{ userInfo.value?.nickname || '用户' }}
+                        <!-- #endif -->
                     </view>
                 </view>
             </view>
@@ -161,7 +245,7 @@ function menuClick(page) {
         <view class="me-header-menu">
             <view class="me-header-menu-item" @click="menuClick('applyForm')">
                 <view class="me-header-menu-icon">
-                    <image src="@/static/images/me/coupon-need.png" mode="" />
+                    <image src="@/static/images/me/coupon-need.png" mode="aspectFill" />
                     <view class="me-header-menu-text">
                         发券人申请
                     </view>
@@ -172,7 +256,7 @@ function menuClick(page) {
             </view>
             <view class="me-header-menu-item" @click="handleLogout">
                 <view class="me-header-menu-icon">
-                    <image src="@/static/images/me/loginOut.png" mode="" />
+                    <image src="@/static/images/me/loginOut.png" mode="aspectFill" />
                     <view class="me-header-menu-text">
                         退出登录
                     </view>
@@ -183,11 +267,7 @@ function menuClick(page) {
             </view>
         </view>
         <!-- 申请中的提示框 -->
-        <up-modal
-            content="您已提交申请,请耐心等待!"
-            title="提示"
-            :show="show"
-        >
+        <up-modal content="您已提交申请,请耐心等待!" title="提示" :show="show">
             <template #confirmButton>
                 <view class="rounded" style="margin-top: 20rpx;" @click="show = false">
                     我知道了
@@ -204,6 +284,7 @@ function menuClick(page) {
   //   height: 376rpx !important;
   border-radius: 20rpx !important;
 }
+
 ::v-deep .u-modal__title {
   font-weight: 500 !important;
   font-size: 34rpx !important;
@@ -211,18 +292,21 @@ function menuClick(page) {
   padding-top: 29rpx !important;
   padding-bottom: 28rpx !important;
 }
+
 ::v-deep .u-modal__content {
   border-top: 1px solid #eeeeee;
   border-bottom: 1px solid #eeeeee;
   padding-top: 82rpx !important;
   padding-bottom: 64rpx !important;
 }
+
 ::v-deep .u-modal__content__text {
   font-weight: 500 !important;
   font-size: 32rpx !important;
   color: #333333 !important;
   text-align: center !important;
 }
+
 .rounded {
   width: 300rpx;
   line-height: 69rpx;
@@ -234,27 +318,33 @@ function menuClick(page) {
   text-align: center;
   margin: 0 auto;
 }
+
 .profile-container {
   font-family: Alibaba PuHuiTi;
+
   .me-header {
     height: 575rpx;
+
     .me-header-avatar-info {
       display: flex;
       flex-direction: column;
       justify-content: center;
       align-items: center;
       gap: 24rpx;
+
       .me-header-avatar {
         width: 128rpx;
         height: 128rpx;
         border-radius: 50%;
         overflow: hidden;
+
         image {
           width: 100%;
           height: 100%;
           object-fit: cover;
         }
       }
+
       .me-header-info {
         .me-header-name {
           font-weight: 500;
@@ -263,9 +353,11 @@ function menuClick(page) {
         }
       }
     }
+
     .me-header-tips {
       display: flex;
       margin-top: 49rpx;
+
       .me-header-tips-item {
         flex: 1;
         display: flex;
@@ -277,9 +369,11 @@ function menuClick(page) {
         font-size: 34rpx;
         color: #ffffff;
         line-height: 1;
+
         .me-header-tips-item-num {
           font-weight: bold;
         }
+
         .me-header-tips-item-des {
           font-weight: 400;
           font-size: 24rpx;
@@ -288,38 +382,58 @@ function menuClick(page) {
       }
     }
   }
+
   .me-header-menu {
     background: #ffffff;
     border-radius: 10rpx 10rpx 0rpx 0rpx;
     margin: -50rpx 24rpx 0;
     padding: 0 20rpx;
+
     .me-header-menu-item {
       height: 88rpx;
       display: flex;
       justify-content: space-between;
       align-items: center;
       border-bottom: 1px solid #eeeeee;
+
       &:last-child {
         border-bottom: none;
       }
+
       .me-header-menu-icon {
         display: flex;
         justify-content: center;
         align-items: center;
         gap: 13rpx;
+
         image {
           width: 40rpx;
           height: 40rpx;
         }
+
         .me-header-menu-text {
           font-weight: 400;
           font-size: 26rpx;
           color: #333333;
         }
       }
+
       .me-header-menu-left {
       }
     }
   }
 }
+
+/* 昵称输入框样式 */
+.nickname-input {
+  width: 100%;
+  height: 100%;
+  font-weight: 500;
+  font-size: 30rpx;
+  color: #ffffff;
+  background: transparent;
+  border: none;
+  outline: none;
+  text-align: center;
+}
 </style>

+ 13 - 4
src/store/user.ts

@@ -26,11 +26,21 @@ export const useUserStore = defineStore(
                 val.avatar = userInfoState.avatar
             }
             userInfo.value = val
+            // 直接更新本地存储(无论本地是否已有用户信息)
+            const currentUser = uni.getStorageSync('user')
+            const updatedUser = currentUser ? { ...currentUser, ...val } : val
+            uni.setStorageSync('user', updatedUser)
+            console.log('本地存储用户信息已更新', updatedUser)
         }
         const setUserAvatar = (avatar: string) => {
             userInfo.value.avatar = avatar
             console.log('设置用户头像', avatar)
             console.log('userInfo', userInfo.value)
+            // 直接更新本地存储(无论本地是否已有用户信息)
+            const currentUser = uni.getStorageSync('user')
+            const updatedUser = currentUser ? { ...currentUser, avatar } : { ...userInfo.value }
+            uni.setStorageSync('user', updatedUser)
+            console.log('本地存储用户头像已更新', updatedUser)
         }
         // 删除用户信息
         const clearUserInfo = () => {
@@ -39,11 +49,10 @@ export const useUserStore = defineStore(
         }
 
         /**
-             * 获取用户信息
-             */
+                                 * 获取用户信息
+                                 */
         const fetchUserInfo = async () => {
-            const res = await getUserInfo()
-            setUserInfo(res)
+            const res = JSON.parse(uni.getStorageSync('user'))
             return res
         }