49 lines
3.5 KiB
Vue
49 lines
3.5 KiB
Vue
<template>
|
|
<view class="page-shell profile-page">
|
|
<view class="profile-hero"><view class="profile-seal">{{ profile.name ? profile.name.slice(0, 1) : '谱' }}</view><view class="profile-copy"><text class="profile-name">{{ profile.name || '家谱用户' }}</text><text class="profile-meta">{{ profile.phone || '资料加载中' }} · {{ profile.role || '家谱成员' }}</text></view><text class="profile-edit" @click="showSoon">资料</text></view>
|
|
<text v-if="loadError" class="error-copy">{{ loadError }}</text>
|
|
<view class="todo-card paper-card" @click="toNotifications"><view><text class="todo-title">待你处理</text><text class="todo-copy">家谱相关提醒与审核通知</text></view><text class="todo-count">{{ unreadCount }}</text></view>
|
|
<view class="menu-group paper-card"><view v-for="item in accountItems" :key="item" class="menu-row" @click="showSoon"><text>{{ item }}</text><text>查看</text></view></view>
|
|
<view class="menu-group paper-card"><view v-for="item in serviceItems" :key="item" class="menu-row" @click="showSoon"><text>{{ item }}</text><text>查看</text></view></view>
|
|
<AppTabbar active="profile" />
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, onMounted, ref } from 'vue'
|
|
import AppTabbar from '@/components/AppTabbar.vue'
|
|
import { appApi } from '@/utils/api.js'
|
|
import { notifications } from '@/data/mock.js'
|
|
|
|
const profile = ref({})
|
|
const loadError = ref('')
|
|
const unreadCount = computed(() => notifications.filter((item) => item.unread).length)
|
|
const accountItems = ['我的资料', '我的加入申请', '账号与安全']
|
|
const serviceItems = ['帮助中心', '意见反馈', 'VIP 服务']
|
|
|
|
onMounted(async () => {
|
|
try { profile.value = await appApi.getProfile() } catch (error) { loadError.value = error.message || '个人资料加载失败。' }
|
|
})
|
|
const toNotifications = () => uni.navigateTo({ url: '/pages/notification/index' })
|
|
const showSoon = () => uni.showToast({ title: '该服务将按计划逐步开放', icon: 'none' })
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.profile-page { padding-bottom: 178rpx; }
|
|
.profile-hero { display: flex; align-items: center; gap: 22rpx; padding: 48rpx 30rpx; background: $navy; }
|
|
.profile-seal { display: flex; width: 88rpx; height: 88rpx; align-items: center; justify-content: center; border: 3rpx solid #e0bd77; border-radius: 50%; color: #f4daa1; font-family: serif; font-size: 43rpx; }
|
|
.profile-copy { min-width: 0; flex: 1; }
|
|
.profile-name { display: block; color: #fff8ec; font-family: serif; font-size: 43rpx; font-weight: 700; }
|
|
.profile-meta { display: block; margin-top: 10rpx; color: #dfc590; font-size: 21rpx; }
|
|
.profile-edit { color: #f4dca8; font-size: 24rpx; }
|
|
.error-copy { display: block; margin: 18rpx 28rpx 0; color: $brand-red; font-size: 23rpx; }
|
|
.todo-card { display: flex; align-items: center; justify-content: space-between; margin: -14rpx 28rpx 0; padding: 28rpx; background: #fff8ea; }
|
|
.todo-title { display: block; color: $ink; font-size: 30rpx; font-weight: 700; }
|
|
.todo-copy { display: block; margin-top: 8rpx; color: $ink-muted; font-size: 22rpx; }
|
|
.todo-count { display: flex; width: 52rpx; height: 52rpx; align-items: center; justify-content: center; border-radius: 50%; background: $brand-red; color: #fff8ec; font-size: 26rpx; }
|
|
.menu-group { margin: 28rpx 28rpx 0; padding: 0 28rpx; }
|
|
.menu-row { display: flex; align-items: center; justify-content: space-between; min-height: 102rpx; border-bottom: 1rpx solid #eadfc9; color: $ink; font-size: 29rpx; }
|
|
.menu-row:last-child { border-bottom: 0; }
|
|
.menu-row text:last-child { color: $brand-red; font-size: 23rpx; }
|
|
</style>
|