瀏覽代碼

重新调整个人中心水墨UI 未成功

yourname 7 月之前
父節點
當前提交
39677a5091

+ 271 - 0
docs/mobile-profile-ui-refactor-plan.md

@@ -0,0 +1,271 @@
+# 移动端个人中心页面水墨风格重构计划
+
+## 项目概述
+将移动端个人中心页面的UI风格重构为与首页一致的中国传统水墨风格,营造优雅、文化感强的用户体验。
+
+## 设计原则
+
+### 1. 色彩系统
+基于中国传统水墨画色彩体系:
+
+| 颜色名称 | CSS变量 | 色值 | 用途 |
+|---------|---------|------|------|
+| 宣纸背景 | `--ink-light` | `#f5f3f0` | 页面主背景 |
+| 淡墨 | `--ink-medium` | `#d4c4a8` | 边框、分割线 |
+| 浓墨 | `--ink-dark` | `#8b7355` | 主要文字、图标 |
+| 焦墨 | `--ink-deep` | `#3a2f26` | 强调文字、标题 |
+| 朱砂 | `--accent-red` | `#a85c5c` | 警示、删除操作 |
+| 花青 | `--accent-blue` | `#4a6b7c` | 主要按钮、链接 |
+| 石绿 | `--accent-green` | `#5c7c5c` | 成功状态、认证标识 |
+
+### 2. 字体系统
+- **主标题**: `font-serif text-3xl font-bold` - 营造传统文化氛围
+- **副标题**: `font-serif text-2xl font-semibold` - 章节标题
+- **正文**: `font-sans text-base` - 清晰易读
+- **说明文字**: `font-sans text-sm` - 辅助信息
+- **标签文字**: `font-sans text-xs` - 小标签
+
+### 3. 视觉层次
+- **背景层**: 宣纸纹理质感
+- **卡片层**: 毛玻璃效果(backdrop-blur)
+- **内容层**: 清晰的信息架构
+- **交互层**: 悬停动效和反馈
+
+## 组件重构方案
+
+### 1. 主页面结构 (ProfilePage)
+```typescript
+// 新的主页面组件
+const ProfilePage: React.FC = () => {
+  return (
+    <div className="min-h-screen" style={{ backgroundColor: COLORS.ink.light }}>
+      {/* 顶部导航栏 */}
+      <header className="sticky top-0 z-10 shadow-sm">
+        <div className="px-4 py-4">
+          <h1 className="font-serif text-2xl font-bold text-center">
+            个人中心
+          </h1>
+        </div>
+      </header>
+
+      {/* 主内容区域 */}
+      <div className="px-4 py-4 space-y-6">
+        <UserHeader />
+        <StatsGrid />
+        <MenuList />
+      </div>
+    </div>
+  );
+};
+```
+
+### 2. 用户头部组件 (UserHeader)
+**当前问题**: 现代风格,与水墨风格不符
+**重构方案**:
+- 背景: 水墨渐变纹理
+- 卡片: 宣纸质感卡片
+- 头像: 圆形边框+水墨边框
+- 文字: 书法风格字体
+
+```typescript
+// 重构后的UserHeader
+const UserHeader: React.FC<UserHeaderProps> = ({ user, onEditProfile }) => {
+  return (
+    <div className="mb-6">
+      {/* 水墨背景装饰 */}
+      <div className="h-32 rounded-2xl relative overflow-hidden"
+           style={{ background: `linear-gradient(135deg, var(--ink-light) 0%, var(--ink-medium) 100%)` }}>
+        {/* 水墨纹理 */}
+        <div className="absolute inset-0 opacity-10"
+             style={{ backgroundImage: `url("data:image/svg+xml...水墨纹理SVG")` }} />
+      </div>
+
+      {/* 用户信息卡片 */}
+      <div className="relative -mt-16">
+        <div className="rounded-2xl p-6 backdrop-blur-sm mx-4"
+             style={{ backgroundColor: 'rgba(255,255,255,0.9)', border: `1px solid var(--ink-medium)` }}>
+          {/* 头像和用户信息 */}
+        </div>
+      </div>
+    </div>
+  );
+};
+```
+
+### 3. 数据统计网格 (StatsGrid)
+**当前问题**: 彩色图标,现代风格
+**重构方案**:
+- 图标: 单色水墨图标
+- 背景: 宣纸质感卡片
+- 数值: 书法字体
+- 布局: 2x2网格保持
+
+### 4. 菜单列表 (MenuList)
+**当前问题**: 彩色emoji,现代列表样式
+**重构方案**:
+- 图标: 水墨风格SVG图标
+- 背景: 宣纸卡片
+- 分割线: 淡墨线条
+- 悬停效果: 阴影变化
+
+## 图标替换方案
+
+### 当前图标 → 水墨图标
+- 👤 个人信息 → 用户轮廓图标(水墨线条)
+- 💎 积分中心 → 宝石图标(单色)
+- ✍️ 我的发布 → 毛笔图标
+- ⭐ 我的收藏 → 书签图标
+- 🛠️ 技能管理 → 工具图标
+- 🔤 字体设置 → 字体图标
+- 🚪 退出登录 → 门图标(红色强调)
+
+## 动效设计
+
+### 1. 页面加载动效
+- 淡入效果
+- 卡片依次出现
+- 水墨晕染背景
+
+### 2. 交互动效
+- 按钮悬停: 阴影加深
+- 卡片点击: 轻微缩放
+- 列表项: 滑动进入
+
+### 3. 滚动动效
+- 视差滚动背景
+- 粘性导航栏
+
+## 响应式设计
+
+### 断点设置
+- 小屏幕 (< 375px): 紧凑布局
+- 标准屏幕 (375-768px): 默认布局
+- 大屏幕 (> 768px): 平板适配
+
+### 适配策略
+- 字体大小动态调整
+- 卡片间距自适应
+- 图标大小优化
+
+## 技术实现
+
+### 1. CSS变量系统
+```css
+:root {
+  /* 水墨色彩 */
+  --ink-light: #f5f3f0;
+  --ink-medium: #d4c4a8;
+  --ink-dark: #8b7355;
+  --ink-deep: #3a2f26;
+  
+  /* 点缀色彩 */
+  --accent-red: #a85c5c;
+  --accent-blue: #4a6b7c;
+  --accent-green: #5c7c5c;
+}
+```
+
+### 2. 组件样式类
+```css
+/* 水墨卡片 */
+.ink-card {
+  background-color: rgba(255, 255, 255, 0.9);
+  border: 1px solid var(--ink-medium);
+  border-radius: 1rem;
+  backdrop-filter: blur(10px);
+  transition: all 0.3s ease;
+}
+
+.ink-card:hover {
+  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
+}
+
+/* 水墨按钮 */
+.ink-button {
+  font-family: var(--font-serif);
+  border-radius: 2rem;
+  transition: all 0.3s ease;
+  cursor: pointer;
+}
+```
+
+## 开发步骤
+
+### 第一阶段:基础框架
+1. [ ] 创建主页面结构
+2. [ ] 设置CSS变量系统
+3. [ ] 导入水墨风格字体
+
+### 第二阶段:组件重构
+1. [ ] 重构UserHeader组件
+2. [ ] 重构StatsGrid组件
+3. [ ] 重构MenuList组件
+4. [ ] 创建水墨图标库
+
+### 第三阶段:动效优化
+1. [ ] 添加页面加载动效
+2. [ ] 实现交互反馈
+3. [ ] 优化滚动体验
+
+### 第四阶段:测试验证
+1. [ ] 跨设备测试
+2. [ ] 性能优化
+3. [ ] 用户体验测试
+
+## 文件结构
+
+```
+src/client/mobile/pages/ProfilePage/
+├── index.tsx                 # 主页面组件
+├── components/
+│   ├── UserHeader.tsx       # 用户头部组件(重构)
+│   ├── StatsGrid.tsx        # 数据统计组件(重构)
+│   ├── MenuList.tsx         # 菜单列表组件(重构)
+│   └── InkIcons.tsx         # 水墨图标组件
+├── styles/
+│   └── profile-ink.css      # 个人中心水墨样式
+└── utils/
+    └── animations.ts        # 动效工具
+```
+
+## 质量保证
+
+### 1. 设计一致性
+- 与首页风格100%匹配
+- 色彩系统统一
+- 字体规范一致
+
+### 2. 用户体验
+- 加载速度<2秒
+- 交互延迟<100ms
+- 无障碍支持
+
+### 3. 代码质量
+- TypeScript类型安全
+- 组件可复用性
+- 样式模块化
+
+## 风险与对策
+
+| 风险 | 影响 | 对策 |
+|------|------|------|
+| 性能问题 | 加载缓慢 | 图片优化、懒加载 |
+| 兼容性问题 | 显示异常 | 浏览器测试、降级方案 |
+| 用户体验差异 | 学习成本 | 渐进式更新、用户引导 |
+
+## 验收标准
+
+### 功能验收
+- [ ] 所有功能正常运行
+- [ ] 响应式布局适配
+- [ ] 动效流畅自然
+
+### 设计验收
+- [ ] 与首页风格一致
+- [ ] 水墨元素完整
+- [ ] 传统文化氛围浓厚
+
+### 技术验收
+- [ ] 代码规范符合项目标准
+- [ ] 性能指标达标
+- [ ] 测试覆盖率>80%

+ 35 - 0
src/client/mobile/hooks/useUserProfile.ts

@@ -0,0 +1,35 @@
+import { useQuery } from '@tanstack/react-query';
+import { silverUsersClient } from '@/client/api';
+import { User } from '@/server/modules/users/user.entity';
+
+// 获取用户个人信息
+export const useUserProfile = () => {
+  return useQuery({
+    queryKey: ['userProfile'],
+    queryFn: async () => {
+      const response = await silverUsersClient.profiles.$get();
+      if (response.status !== 200) {
+        throw new Error('获取用户信息失败');
+      }
+      return response.json();
+    },
+    staleTime: 5 * 60 * 1000, // 5分钟
+    gcTime: 10 * 60 * 1000, // 10分钟
+  });
+};
+
+// 获取用户统计数据
+export const useUserStats = () => {
+  return useQuery({
+    queryKey: ['userStats'],
+    queryFn: async () => {
+      const response = await silverUsersClient.points.stats.$get();
+      if (response.status !== 200) {
+        throw new Error('获取统计数据失败');
+      }
+      return response.json();
+    },
+    staleTime: 5 * 60 * 1000,
+    gcTime: 10 * 60 * 1000,
+  });
+};

+ 101 - 0
src/client/mobile/pages/ProfilePage/components/InkIcons.tsx

@@ -0,0 +1,101 @@
+import React from 'react';
+import { 
+  UserIcon, 
+  CurrencyDollarIcon, 
+  PencilSquareIcon, 
+  BookmarkIcon, 
+  WrenchScrewdriverIcon, 
+  AdjustmentsHorizontalIcon,
+  ArrowRightOnRectangleIcon,
+  TrophyIcon,
+  ClockIcon
+} from '@heroicons/react/24/outline';
+
+// 水墨风格图标配置
+const inkIconProps = {
+  strokeWidth: 1.5,
+  className: "w-6 h-6"
+};
+
+// 统一的图标样式
+const iconContainerClass = "w-10 h-10 rounded-full flex items-center justify-center transition-transform duration-300 hover:scale-110";
+
+// 色彩系统
+const COLORS = {
+  accent: {
+    red: '#a85c5c',
+    blue: '#4a6b7c',
+    green: '#5c7c5c',
+    orange: '#b8860b',
+  },
+  ink: {
+    dark: '#8b7355',
+  }
+};
+
+// 图标包装组件
+export const InkIconWrapper: React.FC<{
+  icon: React.ElementType;
+  color: string;
+  className?: string;
+}> = ({ icon: Icon, color, className }) => (
+  <div 
+    className={`${iconContainerClass} ${className}`}
+    style={{ 
+      backgroundColor: `${color}15`,
+      color: color
+    }}
+  >
+    <Icon {...inkIconProps} />
+  </div>
+);
+
+// 具体图标组件
+export const UserProfileIcon = () => (
+  <InkIconWrapper icon={UserIcon} color={COLORS.accent.blue} />
+);
+
+export const PointsIcon = () => (
+  <InkIconWrapper icon={CurrencyDollarIcon} color={COLORS.accent.green} />
+);
+
+export const PostsIcon = () => (
+  <InkIconWrapper icon={PencilSquareIcon} color={COLORS.accent.blue} />
+);
+
+export const FavoritesIcon = () => (
+  <InkIconWrapper icon={BookmarkIcon} color={COLORS.ink.dark} />
+);
+
+export const SkillsIcon = () => (
+  <InkIconWrapper icon={WrenchScrewdriverIcon} color={COLORS.accent.green} />
+);
+
+export const SettingsIcon = () => (
+  <InkIconWrapper icon={AdjustmentsHorizontalIcon} color={COLORS.accent.blue} />
+);
+
+export const LogoutIcon = () => (
+  <InkIconWrapper icon={ArrowRightOnRectangleIcon} color={COLORS.accent.red} />
+);
+
+export const TrophyStatsIcon = () => (
+  <InkIconWrapper icon={TrophyIcon} color={COLORS.accent.orange} />
+);
+
+export const ClockStatsIcon = () => (
+  <InkIconWrapper icon={ClockIcon} color={COLORS.accent.green} />
+);
+
+// 导出所有图标供使用
+export {
+  UserIcon,
+  CurrencyDollarIcon,
+  PencilSquareIcon,
+  BookmarkIcon,
+  WrenchScrewdriverIcon,
+  AdjustmentsHorizontalIcon,
+  ArrowRightOnRectangleIcon,
+  TrophyIcon,
+  ClockIcon
+};

+ 219 - 0
src/client/mobile/pages/ProfilePage/components/MenuList.tsx

@@ -0,0 +1,219 @@
+import React from 'react';
+import { FontSizeType } from '@/server/modules/silver-users/user-preference.entity';
+import { 
+  UserIcon, 
+  CurrencyDollarIcon, 
+  PencilSquareIcon, 
+  BookmarkIcon, 
+  WrenchScrewdriverIcon, 
+  AdjustmentsHorizontalIcon,
+  ArrowRightOnRectangleIcon,
+  ChevronRightIcon
+} from '@heroicons/react/24/outline';
+
+interface MenuListProps {
+  onNavigate: (path: string) => void;
+  onLogout: () => void;
+  onFontSizeChange?: (size: FontSizeType) => void;
+  currentFontSize?: FontSizeType;
+  fontSizeOptions?: { value: FontSizeType; label: string }[];
+  loading?: boolean;
+}
+
+// 水墨风格色彩系统
+const COLORS = {
+  ink: {
+    light: '#f5f3f0',
+    medium: '#d4c4a8',
+    dark: '#8b7355',
+    deep: '#3a2f26',
+  },
+  accent: {
+    red: '#a85c5c',
+    blue: '#4a6b7c',
+    green: '#5c7c5c',
+  },
+  text: {
+    primary: '#2f1f0f',
+    secondary: '#5d4e3b',
+    light: '#8b7355',
+  }
+};
+
+const MenuList: React.FC<MenuListProps> = ({
+  onNavigate,
+  onLogout,
+  onFontSizeChange,
+  currentFontSize,
+  fontSizeOptions = [],
+  loading = false
+}) => {
+  const menuItems = [
+    {
+      title: '个人信息',
+      icon: UserIcon,
+      path: '/profile/edit',
+      description: '完善个人资料',
+      color: COLORS.accent.blue
+    },
+    {
+      title: '积分中心',
+      icon: CurrencyDollarIcon,
+      path: '/profile/points',
+      description: '查看积分明细',
+      color: COLORS.accent.green
+    },
+    {
+      title: '我的发布',
+      icon: PencilSquareIcon,
+      path: '/profile/posts',
+      description: '管理发布内容',
+      color: COLORS.accent.blue
+    },
+    {
+      title: '我的收藏',
+      icon: BookmarkIcon,
+      path: '/profile/favorites',
+      description: '查看收藏内容',
+      color: COLORS.ink.dark
+    },
+    {
+      title: '技能管理',
+      icon: WrenchScrewdriverIcon,
+      path: '/profile/skills',
+      description: '管理专业技能',
+      color: COLORS.accent.green
+    },
+    {
+      title: '字体设置',
+      icon: AdjustmentsHorizontalIcon,
+      path: '/profile/font-settings',
+      description: '调整字体大小',
+      color: COLORS.accent.blue
+    }
+  ];
+
+  return (
+    <div>
+      <h3 
+        className="font-serif text-xl font-semibold mb-4 tracking-wide"
+        style={{ color: COLORS.text.primary }}
+      >
+        功能菜单
+      </h3>
+      
+      <div 
+        className="rounded-2xl overflow-hidden"
+        style={{
+          backgroundColor: 'rgba(255, 255, 255, 0.9)',
+          border: `1px solid ${COLORS.ink.medium}`,
+          boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)'
+        }}
+      >
+        {menuItems.map((item, index) => (
+          <div key={index}>
+            <button
+              onClick={() => onNavigate(item.path)}
+              className="w-full flex items-center p-4 transition-all duration-300 hover:shadow-md hover:bg-opacity-5"
+              style={{
+                backgroundColor: 'transparent',
+                border: 'none',
+                cursor: loading ? 'not-allowed' : 'pointer',
+                opacity: loading ? 0.6 : 1
+              }}
+              disabled={loading}
+              aria-label={`${item.title} - ${item.description}`}
+            >
+              <div className="flex items-center flex-1">
+                {/* 图标 */}
+                <div 
+                  className="w-10 h-10 rounded-full flex items-center justify-center mr-4 transition-transform duration-300 hover:scale-110"
+                  style={{ 
+                    backgroundColor: `${item.color}15`,
+                    color: item.color
+                  }}
+                >
+                  <item.icon className="w-5 h-5" />
+                </div>
+                
+                {/* 文字内容 */}
+                <div className="text-left">
+                  <div className="font-sans text-base font-medium" style={{ color: COLORS.text.primary }}>
+                    {item.title}
+                  </div>
+                  <div className="font-sans text-sm" style={{ color: COLORS.text.secondary }}>
+                    {item.description}
+                  </div>
+                </div>
+              </div>
+              
+              {/* 箭头图标 */}
+              <ChevronRightIcon 
+                className="w-5 h-5 transition-transform duration-300" 
+                style={{ color: COLORS.text.light }}
+              />
+            </button>
+            
+            {/* 分隔线 */}
+            {index < menuItems.length - 1 && (
+              <div 
+                className="mx-4"
+                style={{ 
+                  height: '1px', 
+                  backgroundColor: `${COLORS.ink.medium}40`
+                }}
+              />
+            )}
+          </div>
+        ))}
+        
+        {/* 退出登录按钮 */}
+        <button
+          onClick={onLogout}
+          disabled={loading}
+          className="w-full flex items-center p-4 transition-all duration-300 hover:shadow-md hover:bg-opacity-5"
+          style={{
+            backgroundColor: 'transparent',
+            border: 'none',
+            cursor: loading ? 'not-allowed' : 'pointer',
+            opacity: loading ? 0.6 : 1
+          }}
+          aria-label="退出登录"
+        >
+          <div className="flex items-center flex-1">
+            <div 
+              className="w-10 h-10 rounded-full flex items-center justify-center mr-4 transition-transform duration-300 hover:scale-110"
+              style={{ 
+                backgroundColor: `${COLORS.accent.red}15`,
+                color: COLORS.accent.red
+              }}
+            >
+              <ArrowRightOnRectangleIcon className="w-5 h-5" />
+            </div>
+            <div className="text-left">
+              <div 
+                className="font-sans text-base font-medium"
+                style={{ color: COLORS.accent.red }}
+              >
+                退出登录
+              </div>
+              <div 
+                className="font-sans text-sm"
+                style={{ color: COLORS.text.secondary }}
+              >
+                安全退出当前账号
+              </div>
+            </div>
+          </div>
+          
+          <ChevronRightIcon 
+            className="w-5 h-5" 
+            style={{ color: COLORS.accent.red }}
+          />
+        </button>
+      </div>
+    </div>
+  );
+};
+
+export default MenuList;

+ 138 - 0
src/client/mobile/pages/ProfilePage/components/StatsGrid.tsx

@@ -0,0 +1,138 @@
+import React from 'react';
+import { 
+  TrophyIcon, 
+  ClockIcon, 
+  PencilIcon, 
+  BookmarkIcon 
+} from '@heroicons/react/24/outline';
+
+interface UserStats {
+  pointBalance: number;
+  timeBankHours: number;
+  publishedCount: number;
+  favoriteCount: number;
+}
+
+interface StatsGridProps {
+  stats: UserStats;
+}
+
+// 水墨风格色彩系统
+const COLORS = {
+  ink: {
+    light: '#f5f3f0',
+    medium: '#d4c4a8',
+    dark: '#8b7355',
+    deep: '#3a2f26',
+  },
+  accent: {
+    red: '#a85c5c',
+    blue: '#4a6b7c',
+    green: '#5c7c5c',
+    orange: '#b8860b',
+  },
+  text: {
+    primary: '#2f1f0f',
+    secondary: '#5d4e3b',
+  }
+};
+
+const StatsGrid: React.FC<StatsGridProps> = ({ stats }) => {
+  const statsData = [
+    {
+      title: '积分余额',
+      value: stats.pointBalance,
+      icon: TrophyIcon,
+      color: COLORS.accent.orange,
+      unit: '分',
+      description: '当前可用积分'
+    },
+    {
+      title: '时间银行',
+      value: stats.timeBankHours,
+      icon: ClockIcon,
+      color: COLORS.accent.green,
+      unit: '小时',
+      description: '志愿服务时长'
+    },
+    {
+      title: '知识分享',
+      value: stats.publishedCount,
+      icon: PencilIcon,
+      color: COLORS.accent.blue,
+      unit: '篇',
+      description: '已发布内容'
+    },
+    {
+      title: '我的收藏',
+      value: stats.favoriteCount,
+      icon: BookmarkIcon,
+      color: COLORS.accent.red,
+      unit: '个',
+      description: '已收藏内容'
+    }
+  ];
+
+  return (
+    <div className="mb-6">
+      <h3 
+        className="font-serif text-xl font-semibold mb-4 tracking-wide"
+        style={{ color: COLORS.text.primary }}
+      >
+        我的数据
+      </h3>
+      
+      <div className="grid grid-cols-2 gap-4">
+        {statsData.map((stat, index) => (
+          <div
+            key={index}
+            className="rounded-xl p-4 transition-all duration-300 hover:shadow-lg cursor-pointer backdrop-blur-sm hover:scale-105"
+            style={{
+              backgroundColor: 'rgba(255, 255, 255, 0.8)',
+              border: `1px solid ${COLORS.ink.medium}`,
+            }}
+          >
+            <div className="text-center">
+              {/* 图标 */}
+              <div 
+                className="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-2 transition-transform duration-300 hover:rotate-12"
+                style={{ 
+                  backgroundColor: `${stat.color}20`,
+                  color: stat.color
+                }}
+              >
+                <stat.icon className="w-6 h-6" />
+              </div>
+              
+              {/* 数值 */}
+              <div 
+                className="font-serif text-2xl font-bold mb-1"
+                style={{ color: COLORS.text.primary }}
+              >
+                {stat.value}
+              </div>
+              
+              {/* 标题 */}
+              <div 
+                className="font-sans text-sm font-medium mb-1"
+                style={{ color: COLORS.text.secondary }}
+              >
+                {stat.title}
+              </div>
+              
+              {/* 单位 */}
+              <div 
+                className="font-sans text-xs"
+                style={{ color: COLORS.ink.dark }}
+              >
+                {stat.unit}
+              </div>
+            </div>
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+};
+
+export default StatsGrid;

+ 137 - 0
src/client/mobile/pages/ProfilePage/components/UserHeader.tsx

@@ -0,0 +1,137 @@
+import React from 'react';
+import { User } from '@/server/modules/users/user.entity';
+
+interface UserHeaderProps {
+  user: User;
+  profile?: any;
+  onEditProfile: () => void;
+}
+
+// 水墨风格色彩系统
+const COLORS = {
+  ink: {
+    light: '#f5f3f0',
+    medium: '#d4c4a8',
+    dark: '#8b7355',
+    deep: '#3a2f26',
+  },
+  accent: {
+    green: '#5c7c5c',
+    blue: '#4a6b7c',
+  },
+  text: {
+    primary: '#2f1f0f',
+    secondary: '#5d4e3b',
+  }
+};
+
+const UserHeader: React.FC<UserHeaderProps> = ({ user, profile, onEditProfile }) => {
+  return (
+    <div className="mb-6">
+      {/* 水墨背景装饰 */}
+      <div 
+        className="h-32 rounded-2xl mb-4 relative overflow-hidden"
+        style={{
+          background: `linear-gradient(135deg, ${COLORS.ink.light} 0%, ${COLORS.ink.medium} 50%, ${COLORS.ink.dark} 100%)`
+        }}
+      >
+        {/* 水墨纹理装饰 */}
+        <div 
+          className="absolute inset-0 opacity-10"
+          style={{
+            backgroundImage: `url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23000' fill-opacity='0.1'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z'/%3E%3C/g%3E%3C/svg%3E")`
+          }}
+        />
+      </div>
+
+      {/* 用户信息卡片 */}
+      <div className="relative -mt-16">
+        <div 
+          className="rounded-2xl p-6 backdrop-blur-sm mx-4 transition-all duration-300 hover:shadow-lg"
+          style={{
+            backgroundColor: 'rgba(255, 255, 255, 0.9)',
+            border: `1px solid ${COLORS.ink.medium}`,
+            boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)'
+          }}
+        >
+          <div className="flex items-center">
+            {/* 头像 */}
+            <div 
+              className="w-24 h-24 rounded-full flex items-center justify-center text-3xl font-bold border-4 transition-all duration-300 hover:scale-105"
+              style={{
+                backgroundColor: COLORS.ink.dark,
+                color: 'white',
+                borderColor: COLORS.ink.light,
+                boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'
+              }}
+            >
+              {user.username?.charAt(0)?.toUpperCase() || '用'}
+            </div>
+            
+            {/* 用户信息 */}
+            <div className="ml-4 flex-1">
+              <h2 className="font-serif text-2xl font-bold mb-1" style={{ color: COLORS.text.primary }}>
+                {user.username}
+              </h2>
+              <p className="font-sans text-sm mb-2" style={{ color: COLORS.text.secondary }}>
+                {user.email}
+              </p>
+              <div className="flex items-center">
+                <span 
+                  className="inline-block w-2 h-2 rounded-full mr-1"
+                  style={{ backgroundColor: COLORS.accent.green }}
+                />
+                <span className="font-sans text-xs" style={{ color: COLORS.accent.green }}>
+                  {profile?.certificationStatus === 'CERTIFIED' ? '已认证用户' : '普通用户'}
+                </span>
+              </div>
+            </div>
+            
+            {/* 编辑按钮 */}
+            <button
+              onClick={onEditProfile}
+              className="p-3 rounded-full transition-all duration-300 hover:shadow-md hover:scale-110"
+              style={{
+                backgroundColor: COLORS.ink.medium,
+                color: COLORS.text.primary
+              }}
+              aria-label="编辑个人信息"
+            >
+              <svg 
+                className="w-5 h-5" 
+                fill="none" 
+                stroke="currentColor" 
+                viewBox="0 0 24 24"
+              >
+                <path 
+                  strokeLinecap="round" 
+                  strokeLinejoin="round" 
+                  strokeWidth={2} 
+                  d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" 
+                />
+              </svg>
+            </button>
+          </div>
+
+          {/* 额外信息 */}
+          {profile?.phone && (
+            <div className="mt-4 pt-4 border-t" style={{ borderColor: `${COLORS.ink.medium}40` }}>
+              <div className="flex items-center justify-between">
+                <span className="font-sans text-sm" style={{ color: COLORS.text.secondary }}>
+                  手机号: {profile.phone}
+                </span>
+                {profile?.city && (
+                  <span className="font-sans text-sm" style={{ color: COLORS.text.secondary }}>
+                    城市: {profile.city}
+                  </span>
+                )}
+              </div>
+            </div>
+          )}
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default UserHeader;

+ 123 - 0
src/client/mobile/pages/ProfilePage/index.tsx

@@ -0,0 +1,123 @@
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useAuth } from '../../hooks/AuthProvider';
+import UserHeader from './components/UserHeader';
+import StatsGrid from './components/StatsGrid';
+import MenuList from './components/MenuList';
+import { FontSizeType } from '@/server/modules/silver-users/user-preference.entity';
+import { useUserProfile } from '../../hooks/useUserProfile';
+import { useUserStats } from '../../hooks/useUserStats';
+
+// 中国水墨风格色彩系统
+const COLORS = {
+  ink: {
+    light: '#f5f3f0',    // 宣纸背景色
+    medium: '#d4c4a8',   // 淡墨
+    dark: '#8b7355',     // 浓墨
+    deep: '#3a2f26',     // 焦墨
+  },
+  accent: {
+    red: '#a85c5c',      // 朱砂
+    blue: '#4a6b7c',     // 花青
+    green: '#5c7c5c',    // 石绿
+  },
+  text: {
+    primary: '#2f1f0f',  // 墨色文字
+    secondary: '#5d4e3b', // 淡墨文字
+    light: '#8b7355',    // 极淡文字
+  }
+};
+
+// 字体样式
+const FONT_STYLES = {
+  title: 'font-serif text-3xl font-bold tracking-wide',
+  sectionTitle: 'font-serif text-2xl font-semibold tracking-wide',
+  body: 'font-sans text-base leading-relaxed',
+  caption: 'font-sans text-sm',
+  small: 'font-sans text-xs',
+};
+
+const ProfilePage: React.FC = () => {
+  const navigate = useNavigate();
+  const { user, logout } = useAuth();
+  const { data: profile } = useUserProfile();
+  const { data: stats } = useUserStats();
+
+  const handleNavigate = (path: string) => {
+    navigate(path);
+  };
+
+  const handleLogout = () => {
+    logout();
+    navigate('/login');
+  };
+
+  const handleFontSizeChange = (size: FontSizeType) => {
+    console.log('Font size changed to:', size);
+  };
+
+  if (!user) {
+    navigate('/login');
+    return null;
+  }
+
+  return (
+    <div className="min-h-screen" style={{ backgroundColor: COLORS.ink.light }}>
+      {/* 顶部导航栏 */}
+      <header 
+        className="sticky top-0 z-10 shadow-sm border-b"
+        style={{ 
+          backgroundColor: COLORS.ink.light,
+          borderColor: 'rgba(212, 196, 168, 0.3)'
+        }}
+      >
+        <div className="px-4 py-4">
+          <h1 
+            className={FONT_STYLES.title}
+            style={{ color: COLORS.text.primary }}
+          >
+            个人中心
+          </h1>
+        </div>
+      </header>
+
+      {/* 主内容区域 */}
+      <div className="px-4 py-6 space-y-6">
+        {/* 用户信息头部 */}
+        <UserHeader 
+          user={user} 
+          profile={profile}
+          onEditProfile={() => handleNavigate('/profile/edit')}
+        />
+
+        {/* 数据统计 */}
+        <StatsGrid 
+          stats={{
+            pointBalance: stats?.pointBalance || 0,
+            timeBankHours: stats?.timeBankHours || 0,
+            publishedCount: stats?.publishedCount || 0,
+            favoriteCount: stats?.favoriteCount || 0,
+          }}
+        />
+
+        {/* 功能菜单 */}
+        <MenuList
+          onNavigate={handleNavigate}
+          onLogout={handleLogout}
+          onFontSizeChange={handleFontSizeChange}
+          currentFontSize="normal"
+          fontSizeOptions={[
+            { value: 'small', label: '小号' },
+            { value: 'normal', label: '中号' },
+            { value: 'large', label: '大号' },
+          ]}
+        />
+      </div>
+
+      {/* 底部装饰 */}
+      <div className="h-20"></div>
+    </div>
+  );
+};
+
+export default ProfilePage;

+ 233 - 0
src/client/mobile/pages/ProfilePage/styles/profile-ink.css

@@ -0,0 +1,233 @@
+/* 个人中心水墨风格样式 */
+
+/* 水墨色彩系统 */
+:root {
+  --profile-ink-light: #f5f3f0;
+  --profile-ink-medium: #d4c4a8;
+  --profile-ink-dark: #8b7355;
+  --profile-ink-deep: #3a2f26;
+  
+  --profile-accent-red: #a85c5c;
+  --profile-accent-blue: #4a6b7c;
+  --profile-accent-green: #5c7c5c;
+  --profile-accent-orange: #b8860b;
+  
+  --profile-text-primary: #2f1f0f;
+  --profile-text-secondary: #5d4e3b;
+  --profile-text-light: #8b7355;
+}
+
+/* 全局水墨样式 */
+.profile-ink-container {
+  background-color: var(--profile-ink-light);
+  min-height: 100vh;
+}
+
+.profile-ink-card {
+  background-color: rgba(255, 255, 255, 0.9);
+  border: 1px solid var(--profile-ink-medium);
+  border-radius: 1rem;
+  backdrop-filter: blur(10px);
+  transition: all 0.3s ease;
+}
+
+.profile-ink-card:hover {
+  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
+  transform: translateY(-2px);
+}
+
+/* 水墨按钮样式 */
+.profile-ink-button {
+  font-family: 'Noto Serif SC', serif;
+  border-radius: 2rem;
+  transition: all 0.3s ease;
+  cursor: pointer;
+  border: none;
+  outline: none;
+  padding: 0.75rem 1.5rem;
+}
+
+.profile-ink-button-primary {
+  background-color: var(--profile-ink-dark);
+  color: white;
+}
+
+.profile-ink-button-primary:hover {
+  background-color: var(--profile-ink-deep);
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+.profile-ink-button-secondary {
+  background-color: transparent;
+  color: var(--profile-text-primary);
+  border: 1px solid var(--profile-ink-medium);
+}
+
+.profile-ink-button-secondary:hover {
+  background-color: var(--profile-ink-medium);
+  color: white;
+}
+
+/* 水墨头像样式 */
+.profile-ink-avatar {
+  background-color: var(--profile-ink-dark);
+  color: white;
+  border: 4px solid var(--profile-ink-light);
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  transition: all 0.3s ease;
+}
+
+.profile-ink-avatar:hover {
+  transform: scale(1.05);
+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
+}
+
+/* 水墨背景装饰 */
+.profile-ink-background {
+  background: linear-gradient(135deg, var(--profile-ink-light) 0%, var(--profile-ink-medium) 100%);
+  position: relative;
+  overflow: hidden;
+}
+
+.profile-ink-background::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23000' fill-opacity='0.05'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7z'/%3E%3Cpath d='M59 43c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7z'/%3E%3Cpath d='M52 36c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3z'/%3E%3Cpath d='M82 67c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3z'/%3E%3C/g%3E%3C/svg%3E");
+  pointer-events: none;
+}
+
+/* 水墨列表项样式 */
+.profile-ink-list-item {
+  transition: all 0.3s ease;
+  border-bottom: 1px solid var(--profile-ink-medium);
+}
+
+.profile-ink-list-item:last-child {
+  border-bottom: none;
+}
+
+.profile-ink-list-item:hover {
+  background-color: rgba(255, 255, 255, 0.5);
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.profile-ink-list-item:active {
+  transform: scale(0.98);
+}
+
+/* 水墨图标容器 */
+.profile-ink-icon-container {
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  transition: all 0.3s ease;
+}
+
+.profile-ink-icon-container:hover {
+  transform: scale(1.1) rotate(5deg);
+}
+
+/* 水墨文字样式 */
+.profile-ink-title {
+  font-family: 'Noto Serif SC', serif;
+  font-weight: 600;
+  letter-spacing: 0.05em;
+}
+
+.profile-ink-subtitle {
+  font-family: 'PingFang SC', sans-serif;
+  font-weight: 400;
+  opacity: 0.8;
+}
+
+/* 响应式字体大小 */
+@media (max-width: 375px) {
+  .profile-ink-title {
+    font-size: 1.125rem;
+  }
+  
+  .profile-ink-subtitle {
+    font-size: 0.875rem;
+  }
+}
+
+@media (min-width: 376px) {
+  .profile-ink-title {
+    font-size: 1.25rem;
+  }
+  
+  .profile-ink-subtitle {
+    font-size: 0.875rem;
+  }
+}
+
+/* 动效类 */
+.profile-ink-fade-in {
+  animation: fadeIn 0.5s ease-in-out;
+}
+
+.profile-ink-slide-up {
+  animation: slideUp 0.4s ease-out;
+}
+
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+
+@keyframes slideUp {
+  from {
+    opacity: 0;
+    transform: translateY(20px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* 老年用户优化 */
+.elderly-friendly {
+  font-size: 1.125rem;
+  line-height: 1.8;
+}
+
+.elderly-friendly .profile-ink-card {
+  padding: 1.5rem;
+}
+
+.elderly-friendly .profile-ink-button {
+  padding: 1rem 2rem;
+  font-size: 1.125rem;
+}
+
+/* 触摸优化 */
+.touch-optimized {
+  min-height: 44px;
+  min-width: 44px;
+}
+
+/* 水墨分隔线 */
+.profile-ink-divider {
+  height: 1px;
+  background: linear-gradient(90deg, transparent, var(--profile-ink-medium), transparent);
+  margin: 0.5rem 0;
+}
+
+/* 水墨阴影效果 */
+.profile-ink-shadow {
+  box-shadow: 0 2px 8px rgba(139, 115, 85, 0.1);
+}
+
+.profile-ink-shadow-hover:hover {
+  box-shadow: 0 4px 16px rgba(139, 115, 85, 0.2);
+}

+ 151 - 0
src/client/mobile/styles/ink-style.css

@@ -0,0 +1,151 @@
+/* 银龄智慧水墨风格样式变量 */
+:root {
+  /* 水墨色彩系统 */
+  --ink-light: #f5f3f0;     /* 宣纸背景色 */
+  --ink-medium: #d4c4a8;    /* 淡墨 */
+  --ink-dark: #8b7355;      /* 浓墨 */
+  --ink-deep: #3a2f26;      /* 焦墨 */
+  
+  /* 点缀色彩 */
+  --accent-red: #a85c5c;    /* 朱砂 */
+  --accent-blue: #4a6b7c;   /* 花青 */
+  --accent-green: #5c7c5c;  /* 石绿 */
+  
+  /* 文字色彩 */
+  --text-primary: #2f1f0f;   /* 墨色文字 */
+  --text-secondary: #5d4e3b; /* 淡墨文字 */
+  --text-light: #8b7355;     /* 极淡文字 */
+  
+  /* 字体定义 */
+  --font-serif: 'Noto Serif SC', 'Songti SC', serif;
+  --font-sans: 'PingFang SC', 'Helvetica Neue', sans-serif;
+  
+  /* 间距系统 */
+  --spacing-xs: 4px;
+  --spacing-sm: 8px;
+  --spacing-md: 16px;
+  --spacing-lg: 24px;
+  --spacing-xl: 32px;
+  
+  /* 圆角系统 */
+  --radius-sm: 6px;
+  --radius-md: 12px;
+  --radius-lg: 16px;
+  --radius-xl: 24px;
+  
+  /* 阴影系统 */
+  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
+  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
+  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
+}
+
+/* 全局样式重置 */
+* {
+  box-sizing: border-box;
+}
+
+body {
+  font-family: var(--font-sans);
+  background-color: var(--ink-light);
+  color: var(--text-primary);
+  line-height: 1.6;
+}
+
+/* 水墨风格按钮 */
+.ink-button {
+  font-family: var(--font-sans);
+  border-radius: var(--radius-xl);
+  transition: all 0.3s ease;
+  cursor: pointer;
+  border: none;
+  outline: none;
+}
+
+.ink-button-primary {
+  background-color: var(--ink-dark);
+  color: white;
+}
+
+.ink-button-primary:hover {
+  background-color: var(--ink-deep);
+  box-shadow: var(--shadow-md);
+}
+
+.ink-button-secondary {
+  background-color: transparent;
+  color: var(--text-primary);
+  border: 1px solid var(--ink-medium);
+}
+
+.ink-button-secondary:hover {
+  background-color: var(--ink-medium);
+  color: white;
+}
+
+/* 水墨风格卡片 */
+.ink-card {
+  background-color: rgba(255, 255, 255, 0.9);
+  border: 1px solid var(--ink-medium);
+  border-radius: var(--radius-lg);
+  backdrop-filter: blur(10px);
+  transition: all 0.3s ease;
+}
+
+.ink-card:hover {
+  box-shadow: var(--shadow-lg);
+}
+
+/* 水墨风格输入框 */
+.ink-input {
+  background-color: rgba(255, 255, 255, 0.7);
+  border: 1px solid var(--ink-medium);
+  border-radius: var(--radius-xl);
+  font-family: var(--font-sans);
+  transition: all 0.3s ease;
+}
+
+.ink-input:focus {
+  outline: none;
+  border-color: var(--ink-dark);
+  box-shadow: 0 0 0 2px rgba(139, 115, 85, 0.2);
+}
+
+/* 水墨风格分隔线 */
+.ink-divider {
+  height: 1px;
+  background-color: var(--ink-medium);
+  opacity: 0.5;
+}
+
+/* 动效类 */
+.ink-transition {
+  transition: all 0.3s ease;
+}
+
+.ink-hover-shadow:hover {
+  box-shadow: var(--shadow-md);
+}
+
+/* 响应式字体大小 */
+@media (max-width: 375px) {
+  :root {
+    --font-size-base: 14px;
+  }
+}
+
+@media (min-width: 376px) {
+  :root {
+    --font-size-base: 16px;
+  }
+}
+
+/* 银龄用户优化 */
+.elderly-friendly {
+  font-size: 18px;
+  line-height: 1.8;
+}
+
+.touch-friendly {
+  min-height: 44px;
+  min-width: 44px;
+}

+ 156 - 0
src/client/mobile/styles/variables.css

@@ -0,0 +1,156 @@
+/* 中国水墨风格CSS变量定义 */
+:root {
+  /* 水墨色彩系统 */
+  --ink-light: #f5f3f0;     /* 宣纸背景色 */
+  --ink-medium: #d4c4a8;    /* 淡墨 */
+  --ink-dark: #8b7355;      /* 浓墨 */
+  --ink-deep: #3a2f26;      /* 焦墨 */
+  
+  /* 点缀色彩 */
+  --accent-red: #a85c5c;    /* 朱砂 */
+  --accent-blue: #4a6b7c;   /* 花青 */
+  --accent-green: #5c7c5c;  /* 石绿 */
+  
+  /* 文字色彩 */
+  --text-primary: #2f1f0f;   /* 墨色文字 */
+  --text-secondary: #5d4e3b; /* 淡墨文字 */
+  --text-light: #8b7355;     /* 极淡文字 */
+  
+  /* 间距系统 */
+  --spacing-xs: 4px;
+  --spacing-sm: 8px;
+  --spacing-md: 16px;
+  --spacing-lg: 24px;
+  --spacing-xl: 32px;
+  
+  /* 字体大小 */
+  --font-size-small: 14px;
+  --font-size-base: 16px;
+  --font-size-large: 18px;
+  --font-size-xl: 20px;
+  --font-size-2xl: 24px;
+  --font-size-3xl: 28px;
+  
+  /* 圆角系统 */
+  --radius-sm: 4px;
+  --radius-md: 8px;
+  --radius-lg: 12px;
+  --radius-xl: 16px;
+  --radius-full: 9999px;
+  
+  /* 阴影系统 */
+  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
+  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
+  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
+  
+  /* 动画时长 */
+  --duration-fast: 150ms;
+  --duration-normal: 300ms;
+  --duration-slow: 500ms;
+}
+
+/* 响应式字体大小 */
+@media (max-width: 375px) {
+  :root {
+    --font-size-base: 15px;
+    --font-size-large: 17px;
+  }
+}
+
+/* 高对比度模式支持 */
+@media (prefers-contrast: high) {
+  :root {
+    --text-primary: #000000;
+    --text-secondary: #333333;
+    --text-light: #666666;
+  }
+}
+
+/* 减少动画模式支持 */
+@media (prefers-reduced-motion: reduce) {
+  * {
+    animation-duration: 0.01ms !important;
+    animation-iteration-count: 1 !important;
+    transition-duration: 0.01ms !important;
+  }
+}
+
+/* 全局样式重置 */
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+body {
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+    sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  background-color: var(--ink-light);
+  color: var(--text-primary);
+  line-height: 1.6;
+}
+
+/* 移动端适配 */
+html {
+  -webkit-text-size-adjust: 100%;
+  -webkit-tap-highlight-color: transparent;
+}
+
+/* 触摸目标最小尺寸 */
+button, a, [role="button"] {
+  min-height: 44px;
+  min-width: 44px;
+}
+
+/* 滚动条样式 */
+::-webkit-scrollbar {
+  width: 4px;
+  height: 4px;
+}
+
+::-webkit-scrollbar-track {
+  background: var(--ink-light);
+}
+
+::-webkit-scrollbar-thumb {
+  background: var(--ink-medium);
+  border-radius: var(--radius-sm);
+}
+
+/* 加载动画 */
+@keyframes pulse {
+  0%, 100% {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0.5;
+  }
+}
+
+.animate-pulse {
+  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
+}
+
+/* 水墨纹理背景 */
+.ink-texture {
+  background-image: 
+    radial-gradient(circle at 20% 80%, rgba(139, 115, 85, 0.1) 0%, transparent 50%),
+    radial-gradient(circle at 80% 20%, rgba(212, 196, 168, 0.1) 0%, transparent 50%),
+    radial-gradient(circle at 40% 40%, rgba(47, 31, 15, 0.05) 0%, transparent 50%);
+}
+
+/* 内容区域基础样式 */
+.content-area {
+  padding: var(--spacing-md);
+  padding-bottom: calc(env(safe-area-inset-bottom) + 80px);
+}
+
+/* 安全区域适配 */
+@supports (padding-top: env(safe-area-inset-top)) {
+  .content-area {
+    padding-top: calc(env(safe-area-inset-top) + var(--spacing-md));
+  }
+}