<script setup lang="ts">
|
import { logoutMini } from '@/api/auth'
|
import { fetchSystemSettings } from '@/api/systemSettings'
|
import { useMiniAuthStore } from '@/store/auth'
|
|
definePage({
|
name: 'mine',
|
layout: 'tabbar',
|
style: {
|
navigationStyle: 'custom',
|
},
|
})
|
|
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 profile = computed(() => authStore.profile)
|
const isLoggedIn = computed(() => authStore.isLoggedIn)
|
const aboutUsEnabled = ref(true)
|
const userRole = computed<'employee' | 'normal'>(() => profile.value?.userType === 'EMPLOYEE' ? 'employee' : 'normal')
|
const roleLabel = computed(() => {
|
if (userRole.value === 'employee') {
|
return '员工'
|
}
|
return '普通访客'
|
})
|
const secondaryText = computed(() => {
|
if (!profile.value) {
|
return ''
|
}
|
if (userRole.value === 'employee') {
|
return profile.value.deptName || ''
|
}
|
return profile.value.companyName || ''
|
})
|
const maskedMobile = computed(() => {
|
const mobile = profile.value?.mobile?.trim() || ''
|
if (!mobile) {
|
return '未绑定手机号'
|
}
|
if (mobile.length < 7) {
|
return mobile
|
}
|
return `${mobile.slice(0, 3)}****${mobile.slice(-4)}`
|
})
|
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'] },
|
])
|
const visibleMenus = computed(() => menuList.value.filter((item) => {
|
if (!item.showFor.includes(userRole.value)) {
|
return false
|
}
|
if (item.title === '关于我们') {
|
return aboutUsEnabled.value
|
}
|
return true
|
}))
|
|
async function loadContentSettings() {
|
try {
|
const settings = await fetchSystemSettings('CONTENT_ABOUT_US_ENABLED')
|
const value = settings?.CONTENT_ABOUT_US_ENABLED
|
aboutUsEnabled.value = value !== '0' && value !== 'false' && value !== 'FALSE'
|
}
|
catch (error) {
|
console.warn('load content settings failed', error)
|
aboutUsEnabled.value = true
|
}
|
}
|
|
function handleEditProfile() {
|
if (!isLoggedIn.value) {
|
authStore.showLoginPrompt('您还未登录,请先登录')
|
return
|
}
|
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: 'home' })
|
}
|
}
|
|
function handleMenuClick(item: MenuItem) {
|
if (!isLoggedIn.value) {
|
authStore.showLoginPrompt('您还未登录,请先登录')
|
return
|
}
|
if (item.title === '退出登录') {
|
void handleLogout()
|
return
|
}
|
|
if (item.path) {
|
uni.navigateTo({ url: item.path })
|
}
|
}
|
|
onShow(() => {
|
authStore.restoreSession()
|
void loadContentSettings()
|
})
|
</script>
|
|
<template>
|
<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>
|
|
<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 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="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>
|
</view>
|
|
<view
|
class="relative z-10 mt-[32rpx] flex items-center px-[48rpx] shrink-0"
|
:class="userRole === 'normal' ? 'active:opacity-90 transition-opacity' : ''"
|
@click="userRole === 'normal' ? handleEditProfile() : undefined"
|
>
|
<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="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="ml-[12rpx] mt-[2rpx] h-[40rpx] w-[40rpx]" mode="aspectFit" />
|
</view>
|
|
<template v-if="userRole === 'normal'">
|
<text class="text-[28rpx] text-[#666666]">{{ maskedMobile }}</text>
|
<text v-if="secondaryText" class="mt-[8rpx] text-[28rpx] text-[#666666]">{{ secondaryText }}</text>
|
</template>
|
<template v-else>
|
<text v-if="secondaryText" class="mb-[8rpx] text-[28rpx] text-[#666666]">{{ secondaryText }}</text>
|
<text class="text-[28rpx] text-[#666666]">{{ maskedMobile }}</text>
|
</template>
|
</view>
|
</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 !== visibleMenus.length - 1 ? 'border-b1' : ''"
|
@click="handleMenuClick(item)"
|
>
|
<view class="flex items-center">
|
<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;
|
}
|
</style>
|
|
<style scoped>
|
.border-b1 {
|
border-bottom: 1rpx solid #F5F5F5;
|
}
|
</style>
|