longz
2026-04-27 25df88d0ab9d7444ed1d162b9efa1259ac2f6f66
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;