Эх сурвалжийг харах

✨ feat(elderly-university): 实现老年大学列表页面

- 添加老年大学卡片组件,支持水墨风格设计和响应式布局
- 创建模拟数据和数据获取钩子,支持搜索和分页功能
- 实现老年大学列表页面,包含搜索、统计和学校列表展示功能
- 添加加载状态、错误状态和空状态处理
- 设计水墨风格色彩系统和字体样式,统一视觉风格

✨ feat(ui): 实现水墨风格UI组件库

- 定义水墨风格色彩配置,包括墨色、强调色和文本色
- 创建字体样式系统,区分标题、正文和说明文字
- 实现骨架屏组件,优化加载体验
- 添加过渡动画效果,提升交互体验

🔧 chore(data): 添加老年大学模拟数据

- 创建6所老年大学的详细模拟数据,包括学校信息、课程类型和联系方式
- 数据包含北京、上海、广州、杭州、成都和深圳等城市的老年大学信息
- 每所学校包含35-42门课程,覆盖书法、绘画、音乐、舞蹈等多种类型
yourname 7 сар өмнө
parent
commit
69b189fb8d

+ 190 - 0
src/client/mobile/components/ElderlyUniversityCard.tsx

@@ -0,0 +1,190 @@
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+import { HeartIcon, EyeIcon, MapPinIcon, PhoneIcon, UserIcon, BookOpenIcon } from '@heroicons/react/24/outline';
+import { ElderlyUniversity } from '@/server/modules/silver-users/elderly-university.entity';
+
+// 水墨风格色彩配置
+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-lg font-semibold',
+  body: 'font-sans text-sm',
+  caption: 'font-sans text-xs',
+};
+
+interface ElderlyUniversityCardProps {
+  university: ElderlyUniversity;
+  showDetails?: boolean;
+  onClick?: () => void;
+}
+
+const ElderlyUniversityCard: React.FC<ElderlyUniversityCardProps> = ({
+  university,
+  showDetails = false,
+  onClick
+}) => {
+  const navigate = useNavigate();
+
+  const handleCardClick = () => {
+    if (onClick) {
+      onClick();
+    } else {
+      navigate(`/elderly-university/${university.id}`);
+    }
+  };
+
+  const handleContactClick = (e: React.MouseEvent) => {
+    e.stopPropagation();
+    // 这里可以实现拨打电话或发送邮件的功能
+    console.log('联系学校:', university.contactPhone);
+  };
+
+  const courseTypes = university.courseTypes.split(',').slice(0, 3);
+
+  return (
+    <div 
+      className="rounded-xl p-4 shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer backdrop-blur-sm"
+      style={{
+        backgroundColor: 'rgba(255,255,255,0.8)',
+        border: `1px solid ${COLORS.ink.medium}`
+      }}
+      onClick={handleCardClick}
+    >
+      {/* 顶部标题栏 */}
+      <div className="flex justify-between items-start mb-3">
+        <h3 
+          className={`${FONT_STYLES.title} line-clamp-2`}
+          style={{ color: COLORS.text.primary }}
+        >
+          {university.schoolName}
+        </h3>
+        <div className="flex items-center space-x-2 text-xs">
+          <div className="flex items-center">
+            <HeartIcon className="w-4 h-4 mr-1" style={{ color: COLORS.accent.red }} />
+            <span style={{ color: COLORS.text.secondary }}>{university.favoriteCount}</span>
+          </div>
+          <div className="flex items-center">
+            <EyeIcon className="w-4 h-4 mr-1" style={{ color: COLORS.text.light }} />
+            <span style={{ color: COLORS.text.secondary }}>{university.viewCount}</span>
+          </div>
+        </div>
+      </div>
+
+      {/* 简介 */}
+      <p 
+        className={`${FONT_STYLES.body} line-clamp-2 mb-3`}
+        style={{ color: COLORS.text.secondary }}
+      >
+        {university.schoolIntroduction}
+      </p>
+
+      {/* 课程类型 */}
+      <div className="mb-3">
+        <div className="flex items-center mb-2">
+          <BookOpenIcon className="w-4 h-4 mr-1" style={{ color: COLORS.accent.blue }} />
+          <span className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+            热门课程
+          </span>
+        </div>
+        <div className="flex flex-wrap gap-1">
+          {courseTypes.map((course, index) => (
+            <span
+              key={index}
+              className="px-2 py-1 rounded-full text-xs"
+              style={{
+                backgroundColor: COLORS.ink.light,
+                color: COLORS.text.primary,
+                border: `1px solid ${COLORS.ink.medium}`
+              }}
+            >
+              {course}
+            </span>
+          ))}
+          {university.courseTypes.split(',').length > 3 && (
+            <span 
+              className="px-2 py-1 rounded-full text-xs"
+              style={{
+                backgroundColor: COLORS.ink.light,
+                color: COLORS.text.light
+              }}
+            >
+              +{university.courseTypes.split(',').length - 3}
+            </span>
+          )}
+        </div>
+      </div>
+
+      {/* 联系信息 */}
+      <div className="border-t" style={{ borderColor: COLORS.ink.medium }}>
+        <div className="flex justify-between items-center pt-3">
+          <div className="flex items-center space-x-4">
+            <div className="flex items-center">
+              <MapPinIcon className="w-4 h-4 mr-1" style={{ color: COLORS.accent.green }} />
+              <span className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+                {university.schoolAddress.substring(0, 8)}...
+              </span>
+            </div>
+            <div className="flex items-center">
+              <UserIcon className="w-4 h-4 mr-1" style={{ color: COLORS.accent.blue }} />
+              <span className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+                {university.contactTeacher}
+              </span>
+            </div>
+          </div>
+          <button
+            onClick={handleContactClick}
+            className="flex items-center px-3 py-1 rounded-full transition-all duration-300 hover:shadow-md"
+            style={{
+              backgroundColor: COLORS.accent.blue,
+              color: 'white'
+            }}
+          >
+            <PhoneIcon className="w-3 h-3 mr-1" />
+            <span className="text-xs">联系</span>
+          </button>
+        </div>
+      </div>
+
+      {/* 详细信息展示(可选) */}
+      {showDetails && (
+        <div className="mt-4 pt-3 border-t" style={{ borderColor: COLORS.ink.medium }}>
+          <div className="grid grid-cols-2 gap-4 text-sm">
+            <div>
+              <span className="block font-medium" style={{ color: COLORS.text.primary }}>
+                课程数量
+              </span>
+              <span style={{ color: COLORS.text.secondary }}>{university.courseCount}门</span>
+            </div>
+            <div>
+              <span className="block font-medium" style={{ color: COLORS.text.primary }}>
+                授课时间
+              </span>
+              <span style={{ color: COLORS.text.secondary }} className="line-clamp-2">
+                {university.classSchedule}
+              </span>
+            </div>
+          </div>
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default ElderlyUniversityCard;

+ 115 - 0
src/client/mobile/data/mockElderlyUniversityData.ts

@@ -0,0 +1,115 @@
+// 老年大学模拟数据
+import { ElderlyUniversity } from '@/server/modules/silver-users/elderly-university.entity';
+
+export const mockElderlyUniversities: ElderlyUniversity[] = [
+  {
+    id: 1,
+    schoolName: '北京市朝阳区老年大学',
+    schoolIntroduction: '北京市朝阳区老年大学成立于2005年,是一所致力于为银龄群体提供终身教育服务的公益性机构。学校秉承"老有所学、老有所乐、老有所为"的办学理念,开设书法、绘画、音乐、舞蹈、健康养生等多元化课程,现有在校学员1200余人。学校环境优美,设施齐全,配备现代化教学设备,聘请专业教师团队,为老年人打造温馨舒适的学习环境。',
+    teacherResources: '学校现有专职教师28人,兼职教师45人。其中教授级教师3人,副教授级教师8人,具有硕士以上学位教师15人。师资团队涵盖书法、绘画、音乐、舞蹈、计算机、健康养生等多个专业领域,所有教师均具有丰富的老年教育经验,能针对老年人学习特点提供专业指导。',
+    courseCount: 35,
+    courseTypes: '书法,绘画,声乐,舞蹈,摄影,计算机基础,智能手机应用,健康养生,太极,瑜伽,茶艺,花艺',
+    classSchedule: '周一至周五 上午9:00-11:30,下午14:00-16:30;周末班:周六、周日 上午9:00-11:30',
+    contactTeacher: '张老师',
+    contactPhone: '010-65432100',
+    schoolAddress: '北京市朝阳区建国路88号朝阳老年活动中心3楼',
+    favoriteCount: 256,
+    viewCount: 3456,
+    likeCount: 189,
+    isDeleted: 0,
+    createdAt: new Date('2024-01-15'),
+    updatedAt: new Date('2024-07-20')
+  },
+  {
+    id: 2,
+    schoolName: '上海市静安区老年大学',
+    schoolIntroduction: '上海市静安区老年大学是一所综合性老年教育机构,以"智慧养老、文化养老"为特色,为老年人打造学习交流的理想平台。学校设有现代化多媒体教室、艺术创作室、舞蹈排练厅等专业场所,开设课程涵盖文化艺术、技能提升、健康养生等多个领域,年培训学员达2000人次。',
+    teacherResources: '拥有专业师资队伍68人,其中正高级教师5人、副高级教师12人、中级教师28人。师资来源包括高校退休教授、专业艺术院校教师、行业专家等。开设名师工作室3个,定期邀请知名艺术家、专家学者举办讲座和工作坊。',
+    courseCount: 42,
+    courseTypes: '国画,油画,书法,篆刻,摄影,摄像,舞蹈,声乐,戏剧表演,文学创作,英语,理财知识,心理健康,中医养生,康复训练',
+    classSchedule: '周一至周日均有课程安排,上午班8:30-11:00,下午班14:00-16:30,晚上班19:00-21:00,学员可自由选择',
+    contactTeacher: '李老师',
+    contactPhone: '021-55558888',
+    schoolAddress: '上海市静安区南京西路1555号静安寺街道社区服务中心',
+    favoriteCount: 328,
+    viewCount: 4567,
+    likeCount: 234,
+    isDeleted: 0,
+    createdAt: new Date('2024-02-01'),
+    updatedAt: new Date('2024-07-22')
+  },
+  {
+    id: 3,
+    schoolName: '广州市天河区老年大学',
+    schoolIntroduction: '广州市天河区老年大学是一所现代化老年教育机构,以"科技赋能老年教育"为办学特色,将传统教学与现代信息技术相结合,为老年人提供与时俱进的学习体验。学校设有智慧教室、VR体验室、3D打印室等先进设施,开设智能手机应用、短视频制作、电商运营等新潮课程。',
+    teacherResources: '师资团队由55名专业教师组成,包括高校退休教授12人、企业技术专家15人、艺术院校教师18人、行业认证讲师10人。所有教师均通过专业培训,持有老年教育师资证书,具有丰富的教学经验和老年心理学知识。',
+    courseCount: 38,
+    courseTypes: '智能手机应用,微信使用,短视频制作,电商运营,直播带货,摄影,视频剪辑,音乐制作,舞蹈,瑜伽,太极,书法,绘画,茶艺,插花',
+    classSchedule: '周一至周五 上午9:00-11:30,下午14:00-16:30,晚上19:00-21:00;周六日 上午9:00-11:30,下午14:00-16:30',
+    contactTeacher: '王老师',
+    contactPhone: '020-85555123',
+    schoolAddress: '广州市天河区天河路123号天河区老龄办大楼',
+    favoriteCount: 198,
+    viewCount: 2890,
+    likeCount: 156,
+    isDeleted: 0,
+    createdAt: new Date('2024-01-20'),
+    updatedAt: new Date('2024-07-19')
+  },
+  {
+    id: 4,
+    schoolName: '杭州市西湖区老年大学',
+    schoolIntroduction: '杭州市西湖区老年大学依托西湖文化资源,以"诗意栖居、文化养老"为办学理念,将传统文化与现代生活相结合,打造独具特色的老年教育品牌。学校位于西湖风景区附近,环境优美,文化氛围浓厚,开设诗词鉴赏、国画写生、茶艺香道等传统文化课程。',
+    teacherResources: '师资队伍由48位专业教师组成,包括中国美术学院退休教授6人、著名书法家8人、画家10人、茶艺师5人、文化学者12人、艺术教育工作者7人。学校还定期邀请文化名人、艺术家担任客座教授,确保教学质量。',
+    courseCount: 29,
+    courseTypes: '诗词鉴赏,国画写生,书法,篆刻,茶艺,香道,花艺,古筝,二胡,太极,养生气功,摄影,旅游英语,杭州历史文化,西湖文化',
+    classSchedule: '周一至周六 上午9:00-11:30,下午14:00-16:30;周日休息。节假日安排特别课程和户外活动。',
+    contactTeacher: '陈老师',
+    contactPhone: '0571-88889999',
+    schoolAddress: '杭州市西湖区保俶路190号西湖区文化中心',
+    favoriteCount: 267,
+    viewCount: 3567,
+    likeCount: 198,
+    isDeleted: 0,
+    createdAt: new Date('2024-01-10'),
+    updatedAt: new Date('2024-07-21')
+  },
+  {
+    id: 5,
+    schoolName: '成都市武侯区老年大学',
+    schoolIntroduction: '成都市武侯区老年大学是一所具有巴蜀文化特色的老年教育机构,以"传承巴蜀文化、乐享幸福晚年"为办学宗旨。学校融合川剧文化、茶文化、蜀绣文化等本土文化元素,开设具有地方特色的课程,为老年人打造充满川味的生活美学体验。',
+    teacherResources: '师资团队由52名专业教师组成,包括川剧表演艺术家8人、蜀绣大师5人、茶艺专家6人、书画家12人、舞蹈教师10人、音乐教师8人、养生专家3人。学校与四川艺术职业学院、成都中医药大学等单位合作,共享优质师资资源。',
+    courseCount: 33,
+    courseTypes: '川剧表演,川剧唱腔,蜀绣技艺,茶艺,书法,国画,舞蹈,声乐,乐器,太极,健康养生,摄影,智能手机应用,成都历史文化,川味烹饪',
+    classSchedule: '周一至周五 上午9:00-11:30,下午14:00-16:30,晚上19:00-21:00;周六上午班9:00-11:30',
+    contactTeacher: '刘老师',
+    contactPhone: '028-66667777',
+    schoolAddress: '成都市武侯区武侯祠大街123号武侯区老年活动中心',
+    favoriteCount: 312,
+    viewCount: 4234,
+    likeCount: 267,
+    isDeleted: 0,
+    createdAt: new Date('2024-01-25'),
+    updatedAt: new Date('2024-07-18')
+  },
+  {
+    id: 6,
+    schoolName: '深圳市南山区老年大学',
+    schoolIntroduction: '深圳市南山区老年大学是一所现代化、国际化的老年教育机构,以"活力养老、智慧生活"为办学特色。学校充分利用深圳科技优势,将AI、大数据、云计算等前沿技术融入老年教育,开设人工智能基础、数字金融、智能设备使用等前沿课程。',
+    teacherResources: '拥有国际化师资队伍58人,包括海外留学归国教师15人、科技企业技术专家20人、高校退休教授12人、行业认证讲师11人。学校与腾讯、华为等科技企业合作,定期邀请企业技术专家授课,确保课程内容与时俱进。',
+    courseCount: 40,
+    courseTypes: '人工智能基础,数字金融,智能设备使用,无人机操作,3D打印,虚拟现实,区块链基础,摄影,视频剪辑,音乐制作,舞蹈,瑜伽,书法,绘画,投资理财,健康管理',
+    classSchedule: '周一至周日全天开课,上午8:30-11:00,下午14:00-16:30,晚上19:00-21:30,学员可自由选择时间段',
+    contactTeacher: '赵老师',
+    contactPhone: '0755-88887777',
+    schoolAddress: '深圳市南山区科技园南区虚拟大学园A栋',
+    favoriteCount: 445,
+    viewCount: 5678,
+    likeCount: 345,
+    isDeleted: 0,
+    createdAt: new Date('2024-02-05'),
+    updatedAt: new Date('2024-07-23')
+  }
+];
+
+export default mockElderlyUniversities;

+ 113 - 0
src/client/mobile/hooks/useElderlyUniversityData.ts

@@ -0,0 +1,113 @@
+import { useQuery } from '@tanstack/react-query';
+import { elderlyUniversityClient } from '@/client/api';
+import { mockElderlyUniversities } from '../data/mockElderlyUniversityData';
+import { ElderlyUniversity } from '@/server/modules/silver-users/elderly-university.entity';
+
+// 获取老年大学列表
+export const useElderlyUniversities = (params?: {
+  page?: number;
+  pageSize?: number;
+  keyword?: string;
+  filters?: any;
+}) => {
+  return useQuery({
+    queryKey: ['elderly-universities', params],
+    queryFn: async () => {
+      try {
+        // 在实际应用中,这里会调用真实API
+        // const response = await elderlyUniversityClient.$get({
+        //   query: {
+        //     page: params?.page || 1,
+        //     pageSize: params?.pageSize || 10,
+        //     keyword: params?.keyword || '',
+        //     filters: params?.filters ? JSON.stringify(params.filters) : undefined
+        //   }
+        // });
+        // return response.json();
+
+        // 使用模拟数据
+        let data = [...mockElderlyUniversities];
+        
+        // 关键词搜索
+        if (params?.keyword) {
+          const keyword = params.keyword.toLowerCase();
+          data = data.filter(
+            item =>
+              item.schoolName.toLowerCase().includes(keyword) ||
+              item.schoolIntroduction.toLowerCase().includes(keyword) ||
+              item.courseTypes.toLowerCase().includes(keyword) ||
+              item.schoolAddress.toLowerCase().includes(keyword)
+          );
+        }
+
+        // 排序:先按收藏数,再按浏览数
+        data.sort((a, b) => {
+          if (b.favoriteCount !== a.favoriteCount) {
+            return b.favoriteCount - a.favoriteCount;
+          }
+          return b.viewCount - a.viewCount;
+        });
+
+        const total = data.length;
+        const page = params?.page || 1;
+        const pageSize = params?.pageSize || 10;
+        const startIndex = (page - 1) * pageSize;
+        const endIndex = startIndex + pageSize;
+        
+        return {
+          data: data.slice(startIndex, endIndex),
+          pagination: {
+            total,
+            current: page,
+            pageSize
+          }
+        };
+      } catch (error) {
+        console.error('获取老年大学列表失败:', error);
+        throw error;
+      }
+    },
+    staleTime: 5 * 60 * 1000, // 5分钟
+    gcTime: 10 * 60 * 1000, // 10分钟
+  });
+};
+
+// 获取单个老年大学详情
+export const useElderlyUniversityDetail = (id: number) => {
+  return useQuery({
+    queryKey: ['elderly-university', id],
+    queryFn: async () => {
+      try {
+        // 在实际应用中,这里会调用真实API
+        // const response = await elderlyUniversityClient[':id'].$get({
+        //   param: { id: id.toString() }
+        // });
+        // return response.json();
+
+        // 使用模拟数据
+        const university = mockElderlyUniversities.find(item => item.id === id);
+        if (!university) {
+          throw new Error('老年大学不存在');
+        }
+        return { data: university };
+      } catch (error) {
+        console.error('获取老年大学详情失败:', error);
+        throw error;
+      }
+    },
+    enabled: !!id,
+    staleTime: 5 * 60 * 1000,
+    gcTime: 10 * 60 * 1000,
+  });
+};
+
+// 搜索老年大学
+export const useSearchElderlyUniversities = (keyword: string) => {
+  return useElderlyUniversities({
+    keyword,
+    page: 1,
+    pageSize: 20
+  });
+};
+
+export default useElderlyUniversities;

+ 379 - 7
src/client/mobile/pages/ElderlyUniversityPage.tsx

@@ -1,15 +1,387 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { useElderlyUniversities } from '../hooks/useElderlyUniversityData';
+import ElderlyUniversityCard from '../components/ElderlyUniversityCard';
+import { SkeletonLoader, ListItemSkeleton } from '../components/SkeletonLoader';
+import {
+  MagnifyingGlassIcon,
+  MapPinIcon,
+  BookOpenIcon,
+  HeartIcon,
+  EyeIcon,
+  ArrowPathIcon
+} from '@heroicons/react/24/outline';
+
+// 水墨风格色彩配置
+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',
+};
+
+// 创建QueryClient实例
+const queryClient = new QueryClient({
+  defaultOptions: {
+    queries: {
+      staleTime: 5 * 60 * 1000,
+      gcTime: 10 * 60 * 1000,
+      refetchOnWindowFocus: false,
+    },
+  },
+});
+
+// 老年大学列表页面组件
+const ElderlyUniversityList: React.FC = () => {
+  const navigate = useNavigate();
+  const [searchQuery, setSearchQuery] = useState('');
+  const [isSearching, setIsSearching] = useState(false);
+  const [refreshKey, setRefreshKey] = useState(0);
+
+  const {
+    data: universities,
+    isLoading,
+    isError,
+    error,
+    refetch
+  } = useElderlyUniversities({
+    keyword: searchQuery,
+    page: 1,
+    pageSize: 10
+  });
+
+  // 搜索功能
+  const handleSearch = () => {
+    if (searchQuery.trim()) {
+      setIsSearching(true);
+    } else {
+      setIsSearching(false);
+    }
+  };
+
+  const handleKeyPress = (e: React.KeyboardEvent) => {
+    if (e.key === 'Enter') {
+      handleSearch();
+    }
+  };
+
+  const handleRefresh = async () => {
+    setRefreshKey(prev => prev + 1);
+    await refetch();
+  };
+
+  const clearSearch = () => {
+    setSearchQuery('');
+    setIsSearching(false);
+  };
+
+  const handleUniversityClick = (id: number) => {
+    navigate(`/elderly-university/${id}`);
+  };
+
+  // 渲染头部统计信息
+  const renderStats = () => {
+    if (!universities?.data) return null;
+
+    const totalUniversities = universities.pagination.total;
+    const totalCourses = universities.data.reduce((sum, uni) => sum + uni.courseCount, 0);
+    const totalFavorites = universities.data.reduce((sum, uni) => sum + uni.favoriteCount, 0);
+
+    return (
+      <div className="grid grid-cols-3 gap-3 mb-6">
+        <div 
+          className="text-center p-3 rounded-xl backdrop-blur-sm"
+          style={{
+            backgroundColor: 'rgba(255,255,255,0.8)',
+            border: `1px solid ${COLORS.ink.medium}`
+          }}
+        >
+          <div 
+            className="text-2xl font-bold mb-1"
+            style={{ color: COLORS.accent.blue }}
+          >
+            {totalUniversities}
+          </div>
+          <div className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+            合作院校
+          </div>
+        </div>
+        <div 
+          className="text-center p-3 rounded-xl backdrop-blur-sm"
+          style={{
+            backgroundColor: 'rgba(255,255,255,0.8)',
+            border: `1px solid ${COLORS.ink.medium}`
+          }}
+        >
+          <div 
+            className="text-2xl font-bold mb-1"
+            style={{ color: COLORS.accent.green }}
+          >
+            {totalCourses}
+          </div>
+          <div className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+            精品课程
+          </div>
+        </div>
+        <div 
+          className="text-center p-3 rounded-xl backdrop-blur-sm"
+          style={{
+            backgroundColor: 'rgba(255,255,255,0.8)',
+            border: `1px solid ${COLORS.ink.medium}`
+          }}
+        >
+          <div 
+            className="text-2xl font-bold mb-1"
+            style={{ color: COLORS.accent.red }}
+          >
+            {totalFavorites}
+          </div>
+          <div className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+            学员关注
+          </div>
+        </div>
+      </div>
+    );
+  };
+
+  // 加载状态
+  if (isLoading) {
+    return (
+      <div className="min-h-screen" style={{ backgroundColor: COLORS.ink.light }}>
+        <HeaderSkeleton />
+        <div className="p-4 space-y-4">
+          <div className="px-4 py-3">
+            <div className="h-8 rounded" style={{ backgroundColor: COLORS.ink.medium, width: '8rem' }}></div>
+          </div>
+          <ListItemSkeleton count={5} />
+        </div>
+      </div>
+    );
+  }
+
+  // 错误状态
+  if (isError) {
+    return (
+      <div className="min-h-screen flex items-center justify-center" style={{ backgroundColor: COLORS.ink.light }}>
+        <div className="text-center p-8">
+          <div className="text-6xl mb-4">📚</div>
+          <h3 className={`${FONT_STYLES.sectionTitle} mb-2`} style={{ color: COLORS.text.primary }}>
+            加载失败
+          </h3>
+          <p className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+            {(error as Error)?.message || '获取老年大学信息失败,请稍后重试'}
+          </p>
+          <button
+            onClick={handleRefresh}
+            className="mt-4 px-4 py-2 rounded-full border transition-all duration-300 hover:shadow-md"
+            style={{
+              color: COLORS.text.primary,
+              borderColor: COLORS.ink.medium,
+              backgroundColor: 'transparent'
+            }}
+          >
+            重新加载
+          </button>
+        </div>
+      </div>
+    );
+  }
+
+  // 空状态
+  if (!universities?.data || universities.data.length === 0) {
+    return (
+      <div className="min-h-screen flex items-center justify-center" style={{ backgroundColor: COLORS.ink.light }}>
+        <div className="text-center p-8">
+          <div className="text-6xl mb-4">🏫</div>
+          <h3 className={`${FONT_STYLES.sectionTitle} mb-2`} style={{ color: COLORS.text.primary }}>
+            {isSearching ? '搜索无结果' : '暂无老年大学信息'}
+          </h3>
+          <p className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+            {isSearching 
+              ? '换个关键词试试,或查看全部老年大学' 
+              : '我们正在努力为您搜集更多优质老年大学资源'}
+          </p>
+          {isSearching && (
+            <button
+              onClick={clearSearch}
+              className="mt-4 px-4 py-2 rounded-full border transition-all duration-300 hover:shadow-md"
+              style={{
+                color: COLORS.text.primary,
+                borderColor: COLORS.ink.medium,
+                backgroundColor: 'transparent'
+              }}
+            >
+              查看全部
+            </button>
+          )}
+        </div>
+      </div>
+    );
+  }
 
-const ElderlyUniversityPage = () => {
   return (
-    <div className="min-h-screen bg-gray-50">
-      <header className="bg-blue-600 text-white p-4">
-        <h1 className="text-xl font-bold">老年大学</h1>
+    <div className="min-h-screen" style={{ backgroundColor: COLORS.ink.light }}>
+      {/* 头部导航栏 */}
+      <header 
+        className="shadow-sm sticky top-0 z-10 border-b border-opacity-20"
+        style={{ 
+          backgroundColor: COLORS.ink.light,
+          borderColor: COLORS.ink.medium 
+        }}
+      >
+        <div className="px-4 py-4">
+          <h1 
+            className={`${FONT_STYLES.title} mb-4`}
+            style={{ color: COLORS.text.primary }}
+          >
+            老年大学
+          </h1>
+
+          {/* 搜索栏 */}
+          <div className="flex items-center rounded-full px-4 py-3 shadow-sm border transition-all duration-300 focus-within:shadow-md"
+            style={{ 
+              backgroundColor: 'rgba(255,255,255,0.7)',
+              borderColor: COLORS.ink.medium 
+            }}
+          >
+            <MagnifyingGlassIcon 
+              className="w-5 h-5 mr-2" 
+              style={{ color: COLORS.ink.dark }} 
+            />
+            <input
+              type="text"
+              placeholder="搜索学校名称、课程或地址..."
+              value={searchQuery}
+              onChange={(e) => setSearchQuery(e.target.value)}
+              onKeyPress={handleKeyPress}
+              className={`flex-1 bg-transparent outline-none ${FONT_STYLES.body}`}
+              style={{ color: COLORS.text.primary, fontSize: '16px' }}
+            />
+            {searchQuery && (
+              <button
+                onClick={clearSearch}
+                className={`${FONT_STYLES.caption} px-2 py-1 ml-2`}
+                style={{ color: COLORS.text.light }}
+              >
+                清除
+              </button>
+            )}
+            <button
+              onClick={handleSearch}
+              className={`${FONT_STYLES.caption} px-3 py-1 rounded-full transition-colors`}
+              style={{ 
+                color: COLORS.text.primary,
+                backgroundColor: COLORS.ink.medium 
+              }}
+            >
+              搜索
+            </button>
+          </div>
+        </div>
       </header>
-      <div className="p-4">
-        <p className="text-center text-gray-500 py-8">老年大学页面开发中...</p>
+
+      {/* 主要内容 */}
+      <div className="pb-16">
+        <div className="p-4">
+          {/* 统计信息 */}
+          {renderStats()}
+
+          {/* 列表头部 */}
+          <div className="flex justify-between items-center mb-4">
+            <h2 
+              className={`${FONT_STYLES.sectionTitle}`}
+              style={{ color: COLORS.text.primary }}
+            >
+              {isSearching ? '搜索结果' : '推荐院校'}
+            </h2>
+            <button
+              onClick={handleRefresh}
+              className={`${FONT_STYLES.caption} px-3 py-1 rounded-full border transition-all duration-300 hover:shadow-md`}
+              style={{
+                color: COLORS.text.primary,
+                borderColor: COLORS.ink.medium,
+                backgroundColor: 'transparent'
+              }}
+            >
+              <ArrowPathIcon className="w-4 h-4" />
+            </button>
+          </div>
+
+          {/* 学校列表 */}
+          <div className="space-y-4">
+            {universities.data.map((university) => (
+              <ElderlyUniversityCard
+                key={university.id}
+                university={university}
+                onClick={() => handleUniversityClick(university.id)}
+              />
+            ))}
+          </div>
+
+          {/* 加载更多提示 */}
+          {universities.pagination.total > universities.data.length && (
+            <div className="text-center mt-6">
+              <p className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+                共 {universities.pagination.total} 所院校,已显示 {universities.data.length} 所
+              </p>
+            </div>
+          )}
+        </div>
       </div>
+
+      {/* 刷新按钮 */}
+      <button
+        onClick={handleRefresh}
+        className="fixed bottom-20 right-4 p-3 rounded-full shadow-lg transition-all duration-300 hover:shadow-xl"
+        style={{ 
+          backgroundColor: COLORS.ink.dark,
+          color: 'white'
+        }}
+      >
+        <ArrowPathIcon className="w-5 h-5" />
+      </button>
+    </div>
+  );
+};
+
+// 水墨风格骨架屏
+const HeaderSkeleton: React.FC = () => (
+  <div className="px-4 py-4" style={{ backgroundColor: COLORS.ink.light }}>
+    <div className="h-8 rounded mb-4" style={{ backgroundColor: COLORS.ink.medium, width: '10rem' }}></div>
+    <div className="flex items-center rounded-full px-4 py-3" style={{ backgroundColor: COLORS.ink.light, border: `1px solid ${COLORS.ink.medium}` }}>
+      <div className="w-5 h-5 rounded mr-2" style={{ backgroundColor: COLORS.ink.medium }}></div>
+      <div className="h-4 rounded flex-1" style={{ backgroundColor: COLORS.ink.medium }}></div>
     </div>
+  </div>
+);
+
+// 主页面组件包装
+const ElderlyUniversityPage: React.FC = () => {
+  return (
+    <QueryClientProvider client={queryClient}>
+      <ElderlyUniversityList />
+    </QueryClientProvider>
   );
 };