From 25df88d0ab9d7444ed1d162b9efa1259ac2f6f66 Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期一, 27 四月 2026 10:13:53 +0800
Subject: [PATCH] 小程序对接finish

---
 yuyueMiniProgram/src/pages/mine/index.vue |  150 ++++++++++++++++++++++++++++++-------------------
 1 files changed, 91 insertions(+), 59 deletions(-)

diff --git a/yuyueMiniProgram/src/pages/mine/index.vue b/yuyueMiniProgram/src/pages/mine/index.vue
index b4a44cf..2ef937c 100644
--- a/yuyueMiniProgram/src/pages/mine/index.vue
+++ b/yuyueMiniProgram/src/pages/mine/index.vue
@@ -1,5 +1,6 @@
 <script setup lang="ts">
-import { ref } from 'vue'
+import { logoutMini } from '@/api/auth'
+import { useMiniAuthStore } from '@/store/auth'
 
 definePage({
   name: 'mine',
@@ -9,114 +10,145 @@
   },
 })
 
+interface MenuItem {
+  title: string
+  icon: string
+  path: string
+  showFor: Array<'employee' | 'normal'>
+}
+
+const router = useRouter()
+const authStore = useMiniAuthStore()
 const sysInfo = uni.getSystemInfoSync()
 const statusBarHeight = sysInfo.statusBarHeight || 0
 const navBarHeight = 44
 
-const userRole = ref('employee') // 'employee' 或 'normal'
-
-const menuList = ref([
+const profile = computed(() => authStore.profile)
+const userRole = computed<'employee' | 'normal'>(() => profile.value?.userType === 'EMPLOYEE' ? 'employee' : 'normal')
+const roleLabel = computed(() => {
+  if (userRole.value === 'employee') {
+    return profile.value?.deptLeaderFlag ? '部门领导' : '员工'
+  }
+  return '普通访客'
+})
+const secondaryText = computed(() => {
+  if (!profile.value) {
+    return ''
+  }
+  if (userRole.value === 'employee') {
+    return profile.value.deptName || ''
+  }
+  return profile.value.companyName || ''
+})
+const menuList = ref<MenuItem[]>([
   { title: '预约审核', icon: '/static/mine/review.png', path: '/pages/reviewList/index', showFor: ['employee'] },
   { title: '来访记录', icon: '/static/mine/record.png', path: '/pages/visitRecord/index', showFor: ['employee'] },
   { title: '关于我们', icon: '/static/mine/aboutUs.png', path: '/pages/aboutUs/index', showFor: ['employee', 'normal'] },
   { title: '退出登录', icon: '/static/mine/logout.png', path: '', showFor: ['employee', 'normal'] },
 ])
-
-function handleMenuClick(item: any) {
-  if (item.path) {
-    uni.navigateTo({ url: item.path })
-  } else if (item.title === '退出登录') {
-    uni.showToast({ title: '已退出登录', icon: 'none' })
-  }
-}
+const visibleMenus = computed(() => menuList.value.filter(item => item.showFor.includes(userRole.value)))
 
 function handleEditProfile() {
   uni.navigateTo({ url: '/pages/profile/index' })
 }
+
+async function handleLogout() {
+  try {
+    await logoutMini()
+  }
+  catch (error) {
+    console.warn('mini logout failed', error)
+  }
+  finally {
+    authStore.clearSession()
+    router.replaceAll({ name: 'login' })
+  }
+}
+
+function handleMenuClick(item: MenuItem) {
+  if (item.title === '退出登录') {
+    void handleLogout()
+    return
+  }
+
+  if (item.path) {
+    uni.navigateTo({ url: item.path })
+  }
+}
+
+onShow(() => {
+  authStore.restoreSession()
+})
 </script>
 
 <template>
-  <view class="h-screen w-full relative box-border flex flex-col overflow-hidden m-0 p-0">
-    <!-- 顶部背景图 (被覆盖层) 整个页面的背景 -->
-    <view class="absolute left-0 top-0 z-0 h-full w-full pointer-events-none">
-      <image src="/static/mine/bg.png" class="w-full h-full" mode="scaleToFill" />
+  <view class="relative m-0 h-screen w-full box-border flex flex-col overflow-hidden p-0">
+    <view class="pointer-events-none absolute left-0 top-0 z-0 h-full w-full">
+      <image src="/static/mine/bg.png" class="h-full w-full" mode="scaleToFill" />
     </view>
 
-    <!-- 整体内容背景图 (bgmask覆盖在上面约202rpx处) -->
-    <view class="absolute left-0 top-[330rpx] w-full z-0 pointer-events-none" style="height: calc(100% - 330rpx);">
-      <image src="/static/mine/bgmask.png" class="w-full h-full" mode="scaleToFill" />
+    <view class="pointer-events-none absolute left-0 top-[330rpx] z-0 w-full" style="height: calc(100% - 330rpx);">
+      <image src="/static/mine/bgmask.png" class="h-full w-full" mode="scaleToFill" />
     </view>
 
-    <!-- 自定义导航栏 -->
     <view class="relative z-50 w-full shrink-0" :style="{ height: (statusBarHeight + navBarHeight) + 'px' }">
-      <view class="fixed left-0 top-0 w-full z-50" :style="{ height: (statusBarHeight + navBarHeight) + 'px' }">
-        <view class="flex items-center justify-between w-full absolute left-0 z-10"
+      <view class="fixed left-0 top-0 z-50 w-full" :style="{ height: (statusBarHeight + navBarHeight) + 'px' }">
+        <view class="absolute left-0 z-10 flex w-full items-center justify-between"
           :style="{ top: statusBarHeight + 'px', height: navBarHeight + 'px' }">
-          <view class="flex h-full w-[88rpx] items-center justify-center relative z-10">
-            <!-- 占位,tabbar 页面不需要返回按钮 -->
-          </view>
-          <view class="absolute left-0 w-full text-center text-[34rpx] font-medium text-white z-0">
+          <view class="relative z-10 flex h-full w-[88rpx] items-center justify-center" />
+          <view class="absolute left-0 z-0 w-full text-center text-[34rpx] font-medium text-white">
             预约小程序
           </view>
-          <view class="w-[88rpx]"></view>
+          <view class="w-[88rpx]" />
         </view>
       </view>
     </view>
 
-    <!-- 用户信息区 -->
-    <view class="relative z-10 px-[48rpx] mt-[32rpx] flex items-center shrink-0">
-      <view class="relative w-[122rpx] h-[122rpx] rounded-full border-[2rpx] border-solid border-[#0068ff] box-border shrink-0">
-        <image src="/static/mine/header.png" class="w-full h-full rounded-full" mode="aspectFill" />
-        <!-- 带有 #0068FF 边框的外圈 -->
-        <view v-if="userRole === 'employee'" class="absolute bottom-[-4rpx] right-[4rpx] w-[32rpx] h-[32rpx] bg-white border-[2rpx] border-solid border-[#0068FF] box-border rounded-full z-10 flex items-center justify-center">
-          <image src="/static/mine/change.png" class="w-[20rpx] h-[20rpx]" mode="aspectFit" />
+    <view class="relative z-10 mt-[32rpx] flex items-center px-[48rpx] shrink-0">
+      <view class="relative h-[122rpx] w-[122rpx] shrink-0 rounded-full border-[2rpx] border-solid border-[#0068ff] box-border">
+        <image :src="profile?.avatarUrl || '/static/mine/header.png'" class="h-full w-full rounded-full" mode="aspectFill" />
+        <view v-if="userRole === 'employee'" class="absolute bottom-[-4rpx] right-[4rpx] z-10 h-[32rpx] w-[32rpx] flex items-center justify-center rounded-full border-[2rpx] border-solid border-[#0068FF] bg-white box-border">
+          <image src="/static/mine/change.png" class="h-[20rpx] w-[20rpx]" mode="aspectFit" />
         </view>
       </view>
-      
+
       <view class="ml-[32rpx] flex flex-col justify-center">
-        <view class="flex items-center mb-[12rpx]">
-          <text class="text-[32rpx] text-[#333333] font-[500]">王明</text>
-          
-          <!-- 员工角色标签 -->
-          <view v-if="userRole === 'employee'" class="ml-[16rpx] w-[96rpx] h-[32rpx] rounded-[18rpx] flex items-center justify-center box-border border-[1rpx] border-solid border-[#FFFFFF]" style="background: linear-gradient(90deg, #68A5FF 0%, #0068FF 107%, rgba(255, 255, 255, 0) 107%);">
-            <text class="text-white text-[16rpx]">部门领导</text>
+        <view class="mb-[12rpx] flex items-center">
+          <text class="text-[32rpx] text-[#333333] font-[500]">{{ profile?.displayName || '用户' }}</text>
+
+          <view v-if="userRole === 'employee'" class="ml-[16rpx] flex h-[32rpx] min-w-[96rpx] items-center justify-center rounded-[18rpx] border-[1rpx] border-solid border-[#FFFFFF] px-[12rpx] box-border" style="background: linear-gradient(90deg, #68A5FF 0%, #0068FF 107%, rgba(255, 255, 255, 0) 107%);">
+            <text class="text-[16rpx] text-white">{{ roleLabel }}</text>
           </view>
-          <!-- 普通用户角色标签 -->
-          <image v-else src="/static/mine/edit.png" class="w-[32rpx] mt-[4rpx] h-[32rpx] ml-[10rpx]" mode="aspectFit" @click="handleEditProfile" />
+          <image v-else src="/static/mine/edit.png" class="ml-[10rpx] mt-[4rpx] h-[32rpx] w-[32rpx]" mode="aspectFit" @click="handleEditProfile" />
         </view>
-        
-        <text v-if="userRole === 'employee'" class="text-[28rpx] text-[#666666]">综合管理部</text>
-        <view v-if="userRole === 'normal'" class="flex flex-col">
-          <text class="text-[28rpx] text-[#666666] mb-[8rpx]">186****4567</text>
-          <text class="text-[28rpx] text-[#666666]">成都xxxxx公司</text>
-        </view>
+
+        <text v-if="secondaryText" class="mb-[8rpx] text-[28rpx] text-[#666666]">{{ secondaryText }}</text>
+        <text class="text-[28rpx] text-[#666666]">{{ profile?.mobile || '未绑定手机号' }}</text>
+        <text v-if="userRole === 'normal'" class="mt-[8rpx] text-[28rpx] text-[#666666]">{{ roleLabel }}</text>
       </view>
     </view>
 
-    <!-- 菜单选项卡片 -->
-    <view class="relative z-10 px-[32rpx] mt-[80rpx] shrink-0">
-      <view class="bg-white rounded-[16rpx] py-[24rpx] w-full" style="box-shadow: 0px 4rpx 8rpx 0px rgba(6, 47, 108, 0.1608);">
-        <template v-for="(item, index) in menuList.filter(m => m.showFor.includes(userRole))" :key="index">
-          <view 
+    <view class="relative z-10 mt-[80rpx] px-[32rpx] shrink-0">
+      <view class="w-full rounded-[16rpx] bg-white py-[24rpx]" style="box-shadow: 0px 4rpx 8rpx 0px rgba(6, 47, 108, 0.1608);">
+        <template v-for="(item, index) in visibleMenus" :key="item.title">
+          <view
             class="flex items-center justify-between px-[40rpx] py-[20rpx] active:bg-gray-50 transition-colors"
-            :class="index !== menuList.filter(m => m.showFor.includes(userRole)).length - 1 ? 'border-b1' : ''"
+            :class="index !== visibleMenus.length - 1 ? 'border-b1' : ''"
             @click="handleMenuClick(item)"
           >
             <view class="flex items-center">
-              <image :src="item.icon" class="w-[56rpx] h-[56rpx] shrink-0" mode="aspectFit" />
-              <text class="ml-[16rpx] text-[#000000] text-[28rpx] font-normal">{{ item.title }}</text>
+              <image :src="item.icon" class="h-[56rpx] w-[56rpx] shrink-0" mode="aspectFit" />
+              <text class="ml-[16rpx] text-[28rpx] text-[#000000] font-normal">{{ item.title }}</text>
             </view>
             <wd-icon name="arrow-right" size="28rpx" color="#000000" />
           </view>
         </template>
       </view>
     </view>
-
   </view>
 </template>
 
 <style>
-/* 针对整个页面的样式重置,强制隐藏原生滚动条并固定页面 */
 page {
   height: 100%;
   overflow: hidden;

--
Gitblit v1.7.1