hookehuyr

refactor(ui): 重构我的页面为专业高端风格

- NavHeader 组件增强:支持自定义背景、文字颜色和覆盖模式
- 我的页面全面升级:
  - 新增渐变背景头部(深蓝到科技蓝)
  - 用户卡片优化:头像编辑徽章、精致阴影、装饰圆圈
  - 菜单图标彩色化:每个功能对应独特的品牌色背景
  - 退出登录按钮优化:白色卡片样式,更统一
  - 新增页脚版权信息
- 整体视觉风格与首页保持一致

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
......@@ -5,6 +5,90 @@
---
## [2026-02-10] - 优化个人中心:视觉协调性调整
### 优化
- **退出登录按钮**
- 改为纯白背景 (`bg-white`) + 阴影 (`shadow-sm`),与上方卡片风格保持一致
- 移除之前的浅红色背景,消除与冷色调背景的视觉冲突,使整体界面更加干净和谐
---
## [2026-02-10] - 优化个人中心:回归经典蓝色头部与精简信息
### 优化
- **头部背景**
- 恢复经典的深蓝渐变 (`#1E3A8A` -> `#2563EB` -> `#F5F7FA`),替换之前的灰色过渡,确保与整体品牌风格统一,提升视觉辨识度
- **用户信息**
- 移除“代理人”标签,精简界面元素,避免不必要的干扰
**详细信息**
- **影响文件**: src/pages/mine/index.vue
- **技术栈**: Vue 3, Tailwind CSS
- **备注**: 根据用户反馈调整,回归稳重且统一的视觉风格
---
## [2026-02-10] - 优化个人中心视觉:平衡商务感与现代感
### 优化
- **视觉微调**:解决上一版“过于死板”的问题,在保持商务专业感的同时引入现代设计元素
- 菜单列表:
- 去除生硬的分割线,改为卡片内间距布局
- 为图标增加极淡的品牌色背景 (`bg-blue-50` 等),恢复色彩识别度但保持低饱和度
- 增加圆角 (`rounded-[32rpx]`) 使整体视觉更柔和
- 退出按钮:
- 改为红色调的背景 (`bg-[#FEF2F2]`) 配合红色文字,既有警示作用又不突兀,不再是简单的白条
- 用户卡片:
- 增加装饰性背景圆环,丰富视觉层次
- 优化阴影和边框,使其更加精致
**详细信息**
- **影响文件**: src/pages/mine/index.vue
- **技术栈**: Vue 3, Tailwind CSS
- **测试状态**: 待验证
- **备注**: 最终定稿版本,兼顾了保险行业的专业性与现代APP的精致感
---
## [2026-02-10] - 调整个人中心视觉风格为商务专业版
### 优化
- **风格调整**:将个人中心 (`pages/mine/index`) 从“科技磨砂”风格调整为“商务专业”风格,以适配保险业务人员的职业形象
- 背景:移除多彩光斑,改为深蓝色 (`#1E3A8A`) 到白色的稳重渐变
- 卡片:使用纯白背景配合深色投影,强调扎实感和可信度
- 图标:统一使用深蓝色和深灰色,去除跳跃的糖果色背景
- 细节:增加“代理人”标签,强化职业属性
- **交互微调**
- 优化菜单点击反馈,使用更细腻的灰色背景过渡
**详细信息**
- **影响文件**: src/pages/mine/index.vue
- **技术栈**: Vue 3, Tailwind CSS
- **测试状态**: 待验证
- **备注**: 响应用户反馈,减少“活泼”感,增强“专业”感
---
## [2026-02-10] - 重构个人中心页面视觉风格
### 优化
- **视觉升级**:将个人中心页面 (`pages/mine/index`) 重构为"科技/磨砂玻璃"风格
- 新增动态背景光斑,营造科技感氛围
- 采用 Glassmorphism (磨砂玻璃) 设计语言重绘用户信息卡片和菜单列表
- 优化字体排版和图标配色,提升专业度
- **交互改进**
- 增加细微的点击反馈和过渡动画
- 优化头像展示区域的层级和质感
**详细信息**
- **影响文件**: src/pages/mine/index.vue
- **技术栈**: Vue 3, Tailwind CSS, Less
- **测试状态**: 待验证
- **备注**: 响应用户对于"简练专业和科技感"的视觉需求
---
## [2026-02-10] - 优化首页网格导航视觉体验
### 优化
......@@ -799,4 +883,4 @@ if (isReset) {
- 统一动画效果和加载状态
- 提升代码可维护性
---
\ No newline at end of file
---
......
<!--
* @Date: 2026-01-29 21:09:28
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2026-02-02 18:25:30
* @FilePath: /manulife-weapp/src/components/NavHeader.vue
* @LastEditTime: 2026-02-10 16:30:00
* @FilePath: /manulife-weapp/src/components/navigation/NavHeader.vue
* @Description: 通用导航头组件,用于页面顶部固定导航栏,展示页面标题。
* @Usage:
* <NavHeader title="首页" />
* <NavHeader title="详情" :show-back="true" />
* <NavHeader title="透明头" background="transparent" textColor="#000" :overlay="true" />
-->
<template>
<!-- Placeholder to prevent content from being hidden behind fixed header -->
<div class="w-full h-[250rpx]"></div>
<div v-if="!overlay" class="w-full h-[250rpx]"></div>
<!-- Fixed Header -->
<div class="fixed top-0 left-0 z-50 w-full h-[250rpx] bg-gradient-to-b from-[#1E3A8A] to-[#2563EB] pt-[100rpx]">
<div
class="fixed top-0 left-0 z-50 w-full h-[250rpx] pt-[100rpx] transition-colors duration-300"
:class="[!background ? 'bg-gradient-to-b from-[#1E3A8A] to-[#2563EB]' : '']"
:style="background ? { background: background } : {}"
>
<div class="relative w-full h-full flex items-center justify-center px-[32rpx]">
<div v-if="canGoBack" class="absolute left-[32rpx] flex items-center justify-center w-[60rpx] h-[60rpx]" @tap="goBack">
<IconFont name="left" size="18" color="#fff" />
<IconFont name="left" size="18" :color="textColor" />
</div>
<span class="text-white text-[35rpx] font-normal">{{ title }}</span>
<span class="text-[35rpx] font-normal" :style="{ color: textColor }">{{ title }}</span>
</div>
</div>
</template>
......@@ -31,6 +35,9 @@ import IconFont from '@/components/icons/IconFont.vue'
* Props definition
* @property {String} title - Page title
* @property {Boolean} [showBack] - Whether to show back button. If undefined, auto-detects based on page stack.
* @property {String} [background] - Custom background style (CSS value)
* @property {String} [textColor] - Custom text/icon color (default #fff)
* @property {Boolean} [overlay] - Whether to overlay content (no placeholder)
*/
const props = defineProps({
title: {
......@@ -40,6 +47,18 @@ const props = defineProps({
showBack: {
type: Boolean,
default: undefined
},
background: {
type: String,
default: ''
},
textColor: {
type: String,
default: '#fff'
},
overlay: {
type: Boolean,
default: false
}
})
......@@ -57,22 +76,7 @@ onMounted(() => {
}
})
/**
* Handle back navigation
* @description 智能处理返回逻辑,避免导航栈为空时报错
*/
const goBack = () => {
const pages = Taro.getCurrentPages()
if (pages.length > 1) {
// 如果导航栈有多个页面,正常返回
Taro.navigateBack()
} else {
// 如果导航栈只有1页,跳转到首页(避免报错)
console.log('导航栈只有1页,跳转到首页')
Taro.reLaunch({
url: '/pages/index/index'
})
}
Taro.navigateBack()
}
</script>
......
<template>
<view class="min-h-screen bg-[#F9FAFB] pb-[200rpx] flex flex-col items-center">
<!-- Header -->
<NavHeader title="我的" />
<!-- User Info Card -->
<!-- Width: 353px -> 706rpx, Height: 124px -> 248rpx -->
<!-- Background image from design -->
<view class="min-h-screen bg-[#F5F7FA] relative flex flex-col items-center pb-[200rpx]">
<!-- Professional Header Background -->
<!-- Gradient background: Deep Blue to Tech Blue, fading to page background -->
<view
class="w-[706rpx] h-[248rpx] mt-[40rpx] bg-white rounded-[24rpx] flex items-center px-[40rpx]"
@tap="go('/pages/avatar/index')"
>
<!-- Avatar -->
<view class="w-[160rpx] h-[160rpx] rounded-full overflow-hidden border-2 border-white shadow-sm shrink-0">
<img class="w-full h-full object-cover" :src="userInfo?.avatar?.src || defaultAvatar" />
</view>
class="absolute top-0 left-0 w-full h-[500rpx] bg-gradient-to-b from-[#1E3A8A] via-[#2563EB] to-[#F5F7FA] z-0">
</view>
<!-- Info -->
<view class="ml-[32rpx] flex-1 flex flex-col justify-center">
<text class="text-[36rpx] font-bold text-gray-800 mb-[8rpx]">{{ userInfo?.name || '加载中...' }}</text>
<text class="text-[28rpx] text-gray-500 mb-[4rpx]">工号: {{ userInfo?.employee_no || '--' }}</text>
<text class="text-[24rpx] text-gray-400">点击修改头像</text>
</view>
<!-- Header -->
<NavHeader title="我的" background="transparent" textColor="#ffffff" />
<!-- Arrow -->
<IconFont name="rect-right" size="20" color="#9CA3AF" />
</view>
<!-- Content Container -->
<view class="w-full px-[32rpx] z-10 pt-[20rpx]">
<!-- Menu List -->
<!-- Width: 353px -> 706rpx, Radius: 12px -> 24rpx, Padding: 16px -> 32rpx -->
<view class="w-[706rpx] bg-white rounded-[24rpx] p-[32rpx] mt-[32rpx]">
<!-- User Info Card -->
<view
v-for="(item, index) in menuItems"
:key="index"
class="flex flex-col"
@tap="handleMenuClick(item)"
>
<view class="flex items-center justify-between py-[24rpx]">
class="bg-white w-full rounded-[32rpx] shadow-sm flex items-center p-[40rpx] mb-[40rpx] relative overflow-hidden"
@tap="go('/pages/avatar/index')">
<!-- Subtle decorative circle -->
<view
class="absolute -top-[40rpx] -right-[40rpx] w-[200rpx] h-[200rpx] bg-blue-50 rounded-full opacity-60 pointer-events-none">
</view>
<!-- Avatar Area -->
<view class="relative mr-[32rpx]">
<view class="w-[136rpx] h-[136rpx] rounded-full p-[6rpx] bg-white shadow-sm border border-gray-100">
<view class="w-full h-full rounded-full overflow-hidden bg-gray-50">
<img class="w-full h-full object-cover" :src="userInfo?.avatar?.src || defaultAvatar" />
</view>
</view>
<!-- Edit Badge -->
<view
class="absolute bottom-[4rpx] right-[4rpx] w-[40rpx] h-[40rpx] bg-white rounded-full flex items-center justify-center shadow-md border border-gray-50">
<IconFont name="edit" size="12" color="#2563EB" />
</view>
</view>
<!-- Info -->
<view class="flex-1 flex flex-col justify-center z-10">
<view class="flex items-center mb-[10rpx]">
<text class="text-[38rpx] font-bold text-gray-900">{{ userInfo?.name || '加载中...' }}</text>
</view>
<view class="flex items-center">
<!-- Icon Size: 40px -> 80rpx. Using IconFont to match request, centered in a box if needed, or just large icon -->
<!-- Design had 40px images. I'll use 32px (64rpx) IconFont for balance or 40px if needed. -->
<view class="w-[80rpx] h-[80rpx] bg-blue-50 rounded-[16rpx] flex items-center justify-center mr-[24rpx]">
<IconFont :name="item.icon" size="24" color="#2563EB" />
<text class="text-[26rpx] text-gray-500">工号: {{ userInfo?.employee_no || '--' }}</text>
</view>
</view>
<!-- Arrow -->
<IconFont name="rect-right" size="18" color="#9CA3AF" />
</view>
<!-- Menu List -->
<!-- Added subtle styling to icons and softened the container -->
<view class="bg-white w-full rounded-[32rpx] shadow-sm mb-[40rpx] p-[16rpx]">
<view v-for="(item, index) in menuItems" :key="index"
class="flex items-center justify-between p-[24rpx] rounded-[20rpx] active:bg-gray-50 transition-all duration-200"
@tap="handleMenuClick(item)">
<view class="flex items-center">
<!-- Icon with soft background -->
<view class="w-[72rpx] h-[72rpx] rounded-[20rpx] flex items-center justify-center mr-[24rpx]"
:class="item.bgClass">
<IconFont :name="item.icon" size="22" :color="item.iconColor" />
</view>
<text class="text-[32rpx] text-gray-800">{{ item.title }}</text>
<text class="text-[30rpx] text-gray-800 font-medium tracking-wide">{{ item.title }}</text>
</view>
<IconFont name="rectRight" size="16" color="#9CA3AF" />
<IconFont name="rectRight" size="14" color="#D1D5DB" />
</view>
<!-- Separator -->
<view v-if="index < menuItems.length - 1" class="h-[2rpx] bg-gray-100 w-full"></view>
</view>
</view>
<!-- Logout Button -->
<view class="w-[730rpx] rounded-[24rpx] p-[32rpx]">
<!-- Logout Button -->
<!-- Clean style: White background to match other cards, red text for action -->
<view
class="flex items-center justify-center py-[20rpx] px-[32rpx] rounded-[16rpx] border-[2rpx] border-[#FEE2E2] bg-[#FEF2F2] active:opacity-70"
class="w-full py-[28rpx] rounded-[24rpx] bg-white shadow-sm active:bg-gray-50 flex items-center justify-center transition-colors duration-200"
@tap="handleLogout"
>
<IconFont name="issue" size="18" color="#EF4444" class="mr-[12rpx]" />
<IconFont name="issue" size="16" color="#EF4444" class="mr-[12rpx]" />
<text class="text-[28rpx] text-[#EF4444] font-medium">退出登录</text>
</view>
</view>
<!-- Footer Copyright -->
<view class="mt-[48rpx] flex flex-col items-center opacity-30">
<text class="text-[20rpx] text-gray-400 font-medium tracking-wider uppercase">Manulife Professional</text>
</view>
<!-- TabBar -->
......@@ -106,12 +128,44 @@ useDidShow(() => {
userStore.fetchUserInfo(true)
})
// Modern Professional Palette
// Using subtle background colors for icons to add vitality without being "playful"
const menuItems = [
{ title: '我的计划书', icon: 'order', path: '/pages/plan/index' },
{ title: '我的消息', icon: 'message', path: '/pages/message/index' },
{ title: '我的收藏', icon: 'star', path: '/pages/favorites/index' },
{ title: '帮助中心', icon: 'service', path: '/pages/help-center/index' },
{ title: '意见反馈', icon: 'edit', path: '/pages/feedback-list/index' }
{
title: '我的计划书',
icon: 'order',
path: '/pages/plan/index',
iconColor: '#2563EB', // Blue
bgClass: 'bg-blue-50'
},
{
title: '我的消息',
icon: 'message',
path: '/pages/message/index',
iconColor: '#059669', // Emerald (Trust)
bgClass: 'bg-emerald-50'
},
{
title: '我的收藏',
icon: 'star',
path: '/pages/favorites/index',
iconColor: '#D97706', // Amber (Value)
bgClass: 'bg-amber-50'
},
{
title: '帮助中心',
icon: 'service',
path: '/pages/help-center/index',
iconColor: '#4F46E5', // Indigo (Service)
bgClass: 'bg-indigo-50'
},
{
title: '意见反馈',
icon: 'edit',
path: '/pages/feedback-list/index',
iconColor: '#DB2777', // Pink/Rose (Feedback)
bgClass: 'bg-pink-50'
}
]
const handleMenuClick = (item) => {
......