Parcourir la source

✨ feat(policy-news): 实现水墨风格政策资讯移动页面

- 新增政策资讯实现计划文档,包含完整开发方案
- 创建PolicyNewsCard组件,支持卡片和简化两种展示模式
- 添加6组政策资讯模拟数据,覆盖各类政策主题
- 实现usePolicyNewsData Hook,支持真实/模拟数据切换
- 重构PolicyNewsPage页面,整合搜索、筛选、下拉刷新功能
- 新增PolicyNewsDetailPage详情页面,支持图片轮播和内容展示
- 配置详情页路由,支持从列表跳转至详情
- 应用水墨风格设计,包含色彩、字体、动效规范
yourname il y a 7 mois
Parent
commit
67e04a8919

+ 228 - 0
policy-news-implementation-plan.md

@@ -0,0 +1,228 @@
+# 政策资讯移动前端页面实现计划
+
+## 项目概述
+基于现有银龄智慧移动端,为政策资讯实体创建符合水墨风格的展示页面。
+
+## 实体分析结果
+
+### PolicyNews实体字段
+- **id**: 资讯ID
+- **newsTitle**: 资讯标题
+- **newsContent**: 资讯内容
+- **publishTime**: 发布时间
+- **viewCount**: 阅读量
+- **images**: 图片URL(逗号分隔)
+- **summary**: 资讯摘要
+- **source**: 资讯来源
+- **category**: 资讯分类
+- **isFeatured**: 是否精选
+- **isDeleted**: 删除状态
+
+### 现有结构分析
+- ✅ 实体已定义:src/server/modules/silver-users/policy-news.entity.ts
+- ✅ 路由已配置:/policy-news
+- ✅ 首页已链接:NewHomePage.tsx第87-91行
+- ⚠️ 页面需增强:当前PolicyNewsPage.tsx过于简单
+- ❌ 模拟数据未创建
+- ❌ 详情页面未实现
+
+## 开发计划
+
+### 1. 文件结构
+```
+src/client/mobile/
+├── data/mockPolicyNewsData.ts      # 模拟数据
+├── hooks/usePolicyNewsData.ts      # 数据获取Hook
+├── components/PolicyNewsCard.tsx   # 资讯卡片组件
+├── pages/PolicyNewsPage.tsx        # 主列表页面
+└── pages/PolicyNewsDetailPage.tsx  # 详情页面
+```
+
+### 2. 模拟数据设计(6组)
+
+```typescript
+const mockPolicyNews = [
+  {
+    id: 1,
+    newsTitle: "2025年最新养老政策全面解读",
+    newsContent: "国务院办公厅近日印发《关于积极应对人口老龄化的实施意见》,提出了一系列支持银龄群体的新政策...",
+    publishTime: "2025-07-20T09:00:00Z",
+    viewCount: 1258,
+    images: "/images/policy1.jpg,/images/policy1-1.jpg",
+    summary: "2025年养老政策重大调整,涉及养老金、医疗保障、社区服务等多个方面",
+    source: "中国政府网",
+    category: "政策法规",
+    isFeatured: 1
+  },
+  {
+    id: 2,
+    newsTitle: "银龄就业促进法草案征求意见",
+    newsContent: "为充分发挥银龄人才资源优势,国家拟制定《银龄就业促进法》...",
+    publishTime: "2025-07-18T14:30:00Z",
+    viewCount: 892,
+    images: "/images/policy2.jpg",
+    summary: "银龄就业促进法草案公开征求意见,重点关注反年龄歧视和就业保障",
+    source: "人社部官网",
+    category: "就业政策",
+    isFeatured: 1
+  },
+  {
+    id: 3,
+    newsTitle: "社区养老服务设施新标准发布",
+    newsContent: "住建部发布《社区养老服务设施规划建设标准》,对社区养老服务设施的规划...",
+    publishTime: "2025-07-15T10:15:00Z",
+    viewCount: 567,
+    images: "/images/policy3.jpg,/images/policy3-1.jpg,/images/policy3-2.jpg",
+    summary: "社区养老服务设施建设有了新标准,要求每万人不少于200平方米",
+    source: "住建部官网",
+    category: "社区建设",
+    isFeatured: 0
+  },
+  {
+    id: 4,
+    newsTitle: "智慧养老产业发展三年行动计划",
+    newsContent: "工信部联合多部门印发《智慧养老产业发展三年行动计划(2025-2027年)》...",
+    publishTime: "2025-07-12T08:30:00Z",
+    viewCount: 743,
+    images: "/images/policy4.jpg",
+    summary: "智慧养老产业迎来政策红利期,重点支持AI、物联网等技术在养老领域应用",
+    source: "工信部官网",
+    category: "产业发展",
+    isFeatured: 1
+  },
+  {
+    id: 5,
+    newsTitle: "银龄健康管理体系建设指导意见",
+    newsContent: "国家卫健委发布《银龄健康管理体系建设指导意见》,提出建立覆盖城乡的...",
+    publishTime: "2025-07-10T15:45:00Z",
+    viewCount: 456,
+    images: "/images/policy5.jpg,/images/policy5-1.jpg",
+    summary: "构建覆盖全国的银龄健康管理体系,实现健康档案、慢病管理、紧急救助一体化",
+    source: "国家卫健委",
+    category: "健康政策",
+    isFeatured: 0
+  },
+  {
+    id: 6,
+    newsTitle: "老年教育促进条例正式施行",
+    newsContent: "《老年教育促进条例》于2025年7月1日起正式施行,条例明确了老年教育的...",
+    publishTime: "2025-07-01T09:00:00Z",
+    viewCount: 1203,
+    images: "/images/policy6.jpg",
+    summary: "老年教育促进条例正式施行,保障老年人受教育权利,推动终身学习体系建设",
+    source: "全国人大网",
+    category: "教育政策",
+    isFeatured: 1
+  }
+]
+```
+
+### 3. 页面组件设计
+
+#### PolicyNewsPage - 主列表页面
+- **布局**:顶部标题栏 + 资讯列表
+- **功能**:下拉刷新、上拉加载更多、搜索过滤
+- **样式**:水墨风格卡片,圆角设计
+- **交互**:点击进入详情
+
+#### PolicyNewsCard - 资讯卡片
+- **展示内容**:
+  - 资讯图片(首张或默认占位图)
+  - 标题
+  - 摘要(前50字)
+  - 发布时间
+  - 阅读量
+  - 分类标签
+  - 来源
+- **特色标识**:精选内容特殊标记
+
+#### PolicyNewsDetailPage - 详情页面
+- **布局**:顶部返回栏 + 内容区域
+- **功能**:分享、收藏、返回
+- **内容**:
+  - 标题
+  - 发布时间
+  - 阅读量
+  - 来源
+  - 完整内容
+  - 相关图片(轮播展示)
+
+### 4. 水墨风格实现要点
+
+#### 色彩应用
+- 背景:宣纸色 #f5f3f0
+- 卡片:半透明白色 rgba(255,255,255,0.8)
+- 文字:墨色 #2f1f0f
+- 强调:朱砂红 #a85c5c 或 花青蓝 #4a6b7c
+
+#### 字体层级
+- 标题:font-serif 24px bold
+- 内容:font-sans 16px normal
+- 辅助:font-sans 14px/12px secondary
+
+#### 交互动效
+- 卡片悬停:hover:shadow-lg 300ms ease-in-out
+- 图片加载:淡入动画
+- 下拉刷新:旋转图标
+
+### 5. 数据获取策略
+
+#### Hook设计
+```typescript
+const usePolicyNewsData = () => {
+  // 优先获取真实数据
+  const { data: realData, isLoading, error } = useQuery(...)
+  
+  // 真实数据为空时使用模拟数据
+  const displayData = realData?.length > 0 ? realData : mockPolicyNews
+  
+  return { data: displayData, isLoading, error }
+}
+```
+
+### 6. 路由配置
+
+#### 新增路由
+```typescript
+{
+  path: 'policy-news/:id',
+  element: <PolicyNewsDetailPage />
+}
+```
+
+### 7. 实现顺序
+
+1. 创建模拟数据文件
+2. 创建PolicyNewsCard组件
+3. 重构PolicyNewsPage页面
+4. 创建PolicyNewsDetailPage
+5. 创建usePolicyNewsData Hook
+6. 更新路由配置
+7. 测试首页跳转功能
+8. 样式优化和验证
+
+### 8. 验证检查清单
+
+- [ ] 首页点击"政策资讯"正确跳转
+- [ ] 6组模拟数据完整展示
+- [ ] 水墨风格样式正确应用
+- [ ] 真实数据优先,模拟数据兜底
+- [ ] 响应式布局适配移动端
+- [ ] 交互动效流畅自然
+- [ ] 页面加载性能良好
+
+## 注意事项
+
+1. **兼容性**:确保iOS 14+、Android 8+兼容
+2. **性能**:图片懒加载、虚拟滚动优化
+3. **可访问性**:支持系统字体缩放
+4. **网络**:弱网环境下的优雅降级
+5. **安全**:XSS防护、内容安全策略
+
+## 测试要点
+
+1. **功能测试**:数据加载、页面跳转、搜索过滤
+2. **样式测试**:不同屏幕尺寸适配
+3. **性能测试**:页面加载时间、滚动流畅度
+4. **兼容性测试**:主流浏览器、微信浏览器
+5. **用户测试**:银龄用户群体可用性测试

+ 218 - 0
src/client/mobile/components/PolicyNewsCard.tsx

@@ -0,0 +1,218 @@
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+import { CalendarDaysIcon, EyeIcon } from '@heroicons/react/24/outline';
+import type { PolicyNewsItem } from '@/client/mobile/hooks/usePolicyNewsData';
+
+// 水墨风格颜色配置
+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',
+  }
+};
+
+interface PolicyNewsCardProps {
+  news: PolicyNewsItem;
+  onClick?: () => void;
+}
+
+const PolicyNewsCard: React.FC<PolicyNewsCardProps> = ({ news, onClick }) => {
+  const navigate = useNavigate();
+
+  const handleClick = () => {
+    if (onClick) {
+      onClick();
+    } else {
+      navigate(`/policy-news/${news.id}`);
+    }
+  };
+
+  const getFirstImage = () => {
+    if (news.images) {
+      return news.images.split(',')[0];
+    }
+    return '/images/placeholder-banner.jpg';
+  };
+
+  const formatDate = (date: string | Date) => {
+    return new Date(date).toLocaleDateString('zh-CN', {
+      year: 'numeric',
+      month: '2-digit',
+      day: '2-digit'
+    });
+  };
+
+  const truncateSummary = (text: string, maxLength: number = 60) => {
+    if (text.length <= maxLength) return text;
+    return text.substring(0, maxLength) + '...';
+  };
+
+  return (
+    <div 
+      className="bg-white bg-opacity-80 backdrop-blur-sm rounded-xl shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer overflow-hidden border border-opacity-20"
+      style={{ borderColor: COLORS.ink.medium }}
+      onClick={handleClick}
+    >
+      {/* 图片区域 */}
+      <div className="relative">
+        <img
+          src={getFirstImage()}
+          alt={news.newsTitle}
+          className="w-full h-40 object-cover"
+          onError={(e) => {
+            (e.target as HTMLImageElement).src = '/images/placeholder-banner.jpg';
+          }}
+        />
+        
+        {/* 精选标记 */}
+        {news.isFeatured === 1 && (
+          <div 
+            className="absolute top-2 left-2 px-2 py-1 rounded-full text-xs font-medium"
+            style={{ 
+              backgroundColor: COLORS.accent.red,
+              color: 'white'
+            }}
+          >
+            精选
+          </div>
+        )}
+        
+        {/* 分类标签 */}
+        <div 
+          className="absolute top-2 right-2 px-2 py-1 rounded-full text-xs font-medium"
+          style={{ 
+            backgroundColor: COLORS.accent.blue,
+            color: 'white'
+          }}
+        >
+          {news.category || '政策资讯'}
+        </div>
+      </div>
+
+      {/* 内容区域 */}
+      <div className="p-4">
+        {/* 标题 */}
+        <h3 
+          className="font-serif text-lg font-semibold mb-2 line-clamp-2"
+          style={{ color: COLORS.text.primary }}
+        >
+          {news.newsTitle}
+        </h3>
+
+        {/* 摘要 */}
+        <p 
+          className="text-sm mb-3 line-clamp-2"
+          style={{ color: COLORS.text.secondary }}
+        >
+          {news.summary || truncateSummary(news.newsContent)}
+        </p>
+
+        {/* 元信息 */}
+        <div className="flex items-center justify-between text-xs">
+          {/* 来源 */}
+          <span 
+            className="font-medium"
+            style={{ color: COLORS.text.light }}
+          >
+            {news.source || '官方发布'}
+          </span>
+
+          {/* 时间 */}
+          <div className="flex items-center space-x-1">
+            <CalendarDaysIcon 
+              className="w-3 h-3" 
+              style={{ color: COLORS.text.light }}
+            />
+            <span style={{ color: COLORS.text.light }}>
+              {formatDate(news.publishTime)}
+            </span>
+          </div>
+
+          {/* 阅读量 */}
+          <div className="flex items-center space-x-1">
+            <EyeIcon 
+              className="w-3 h-3" 
+              style={{ color: COLORS.text.light }}
+            />
+            <span style={{ color: COLORS.text.light }}>
+              {news.viewCount}
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+// 简化版卡片(用于首页展示)
+export const PolicyNewsCardSimple: React.FC<PolicyNewsCardProps> = ({ news, onClick }) => {
+  const navigate = useNavigate();
+
+  const handleClick = () => {
+    if (onClick) {
+      onClick();
+    } else {
+      navigate(`/policy-news/${news.id}`);
+    }
+  };
+
+  const formatDate = (date: Date) => {
+    return new Date(date).toLocaleDateString('zh-CN', {
+      month: '2-digit',
+      day: '2-digit'
+    });
+  };
+
+  return (
+    <div 
+      className="bg-white bg-opacity-70 backdrop-blur-sm rounded-lg p-3 shadow-sm hover:shadow-md transition-all duration-300 cursor-pointer border border-opacity-20"
+      style={{ borderColor: COLORS.ink.medium }}
+      onClick={handleClick}
+    >
+      <div className="flex items-start space-x-3">
+        {/* 图片缩略图 */}
+        <img
+          src={news.images ? news.images.split(',')[0] : '/images/placeholder-banner.jpg'}
+          alt={news.newsTitle}
+          className="w-16 h-16 rounded-md object-cover flex-shrink-0"
+          onError={(e) => {
+            (e.target as HTMLImageElement).src = '/images/placeholder-banner.jpg';
+          }}
+        />
+        
+        {/* 内容 */}
+        <div className="flex-1 min-w-0">
+          <h4 
+            className="font-medium text-sm line-clamp-2 mb-1"
+            style={{ color: COLORS.text.primary }}
+          >
+            {news.newsTitle}
+          </h4>
+          
+          <div className="flex items-center justify-between text-xs">
+            <span style={{ color: COLORS.text.secondary }}>
+              {news.source || '官方'}
+            </span>
+            <span style={{ color: COLORS.text.light }}>
+              {formatDate(news.publishTime)}
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default PolicyNewsCard;

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

@@ -0,0 +1,115 @@
+import { PolicyNews } from '@/server/modules/silver-users/policy-news.entity';
+
+// 政策资讯模拟数据(6组)
+export const mockPolicyNews: PolicyNews[] = [
+  {
+    id: 1,
+    newsTitle: "2025年最新养老政策全面解读",
+    newsContent: "国务院办公厅近日印发《关于积极应对人口老龄化的实施意见》,提出了一系列支持银龄群体的新政策。文件明确,到2025年,基本建成覆盖城乡、功能完善、规模适度、医养结合的养老服务体系。具体包括:提高基础养老金标准,完善长期护理保险制度,推进智慧养老服务平台建设,鼓励社会力量参与养老服务供给。同时,支持银龄人才再就业,建立灵活就业机制,为低龄健康老年人提供更多就业机会。",
+    publishTime: new Date("2025-07-20T09:00:00Z"),
+    viewCount: 1258,
+    images: "/images/policy1.jpg,/images/policy1-1.jpg",
+    summary: "2025年养老政策重大调整,涉及养老金、医疗保障、社区服务等多个方面",
+    source: "中国政府网",
+    category: "政策法规",
+    isFeatured: 1,
+    isDeleted: 0,
+    createdAt: new Date("2025-07-20T08:30:00Z"),
+    updatedAt: new Date("2025-07-20T09:00:00Z")
+  },
+  {
+    id: 2,
+    newsTitle: "银龄就业促进法草案征求意见",
+    newsContent: "为充分发挥银龄人才资源优势,国家拟制定《银龄就业促进法》。草案明确禁止年龄歧视,要求用人单位不得设置不合理的年龄限制。建立银龄人才信息库,推动人才与企业精准对接。鼓励企业设立银龄岗位,给予税收优惠。完善银龄劳动者权益保护,包括工伤保险、职业培训等配套措施。同时建立银龄创业支持体系,提供创业指导、资金支持和场地保障。",
+    publishTime: new Date("2025-07-18T14:30:00Z"),
+    viewCount: 892,
+    images: "/images/policy2.jpg",
+    summary: "银龄就业促进法草案公开征求意见,重点关注反年龄歧视和就业保障",
+    source: "人社部官网",
+    category: "就业政策",
+    isFeatured: 1,
+    isDeleted: 0,
+    createdAt: new Date("2025-07-18T14:00:00Z"),
+    updatedAt: new Date("2025-07-18T14:30:00Z")
+  },
+  {
+    id: 3,
+    newsTitle: "社区养老服务设施新标准发布",
+    newsContent: "住建部发布《社区养老服务设施规划建设标准》,对社区养老服务设施的规划、建设、运营提出明确要求。新标准规定:新建小区按每万人不少于200平方米配建养老服务设施;老旧小区通过改造补充设施缺口;设施应包括日间照料、助餐服务、康复护理、文化娱乐等功能;鼓励采用智能化设备提升服务质量;建立设施运营评估机制,确保服务质量达标。",
+    publishTime: new Date("2025-07-15T10:15:00Z"),
+    viewCount: 567,
+    images: "/images/policy3.jpg,/images/policy3-1.jpg,/images/policy3-2.jpg",
+    summary: "社区养老服务设施建设有了新标准,要求每万人不少于200平方米",
+    source: "住建部官网",
+    category: "社区建设",
+    isFeatured: 0,
+    isDeleted: 0,
+    createdAt: new Date("2025-07-15T09:45:00Z"),
+    updatedAt: new Date("2025-07-15T10:15:00Z")
+  },
+  {
+    id: 4,
+    newsTitle: "智慧养老产业发展三年行动计划",
+    newsContent: "工信部联合多部门印发《智慧养老产业发展三年行动计划(2025-2027年)》,提出到2027年,智慧养老产业规模突破5万亿元。重点任务包括:开发适老化智能产品,建立智慧养老服务平台,推进AI、物联网、5G等技术在养老领域的应用;建设智慧养老示范区;完善智慧养老标准体系;支持企业加大研发投入,对符合条件的智慧养老产品给予税收优惠。",
+    publishTime: new Date("2025-07-12T08:30:00Z"),
+    viewCount: 743,
+    images: "/images/policy4.jpg",
+    summary: "智慧养老产业迎来政策红利期,重点支持AI、物联网等技术在养老领域应用",
+    source: "工信部官网",
+    category: "产业发展",
+    isFeatured: 1,
+    isDeleted: 0,
+    createdAt: new Date("2025-07-12T08:00:00Z"),
+    updatedAt: new Date("2025-07-12T08:30:00Z")
+  },
+  {
+    id: 5,
+    newsTitle: "银龄健康管理体系建设指导意见",
+    newsContent: "国家卫健委发布《银龄健康管理体系建设指导意见》,提出建立覆盖城乡的银龄健康管理体系。主要内容包括:为65岁以上老年人建立健康档案,提供年度免费体检;开展慢性病筛查和干预;建立家庭医生签约服务制度;推进医养结合机构建设;完善老年人紧急医疗救助网络;支持社会力量举办老年病医院、康复医院、护理院等医疗机构。",
+    publishTime: new Date("2025-07-10T15:45:00Z"),
+    viewCount: 456,
+    images: "/images/policy5.jpg,/images/policy5-1.jpg",
+    summary: "构建覆盖全国的银龄健康管理体系,实现健康档案、慢病管理、紧急救助一体化",
+    source: "国家卫健委",
+    category: "健康政策",
+    isFeatured: 0,
+    isDeleted: 0,
+    createdAt: new Date("2025-07-10T15:15:00Z"),
+    updatedAt: new Date("2025-07-10T15:45:00Z")
+  },
+  {
+    id: 6,
+    newsTitle: "老年教育促进条例正式施行",
+    newsContent: "《老年教育促进条例》于2025年7月1日起正式施行,条例明确了老年教育的地位、政府职责、保障措施等内容。条例规定:县级以上人民政府应当加强老年教育工作统筹规划;鼓励普通高等学校、职业院校开设老年教育专业;支持社会力量举办老年教育机构;建立老年教育师资培训体系;将老年教育经费列入财政预算;推动优质老年教育资源向基层延伸。",
+    publishTime: new Date("2025-07-01T09:00:00Z"),
+    viewCount: 1203,
+    images: "/images/policy6.jpg",
+    summary: "老年教育促进条例正式施行,保障老年人受教育权利,推动终身学习体系建设",
+    source: "全国人大网",
+    category: "教育政策",
+    isFeatured: 1,
+    isDeleted: 0,
+    createdAt: new Date("2025-07-01T08:30:00Z"),
+    updatedAt: new Date("2025-07-01T09:00:00Z")
+  }
+];
+
+// 获取精选政策资讯
+export const getFeaturedPolicyNews = () => {
+  return mockPolicyNews.filter(news => news.isFeatured === 1);
+};
+
+// 按分类获取政策资讯
+export const getPolicyNewsByCategory = (category: string) => {
+  return mockPolicyNews.filter(news => news.category === category);
+};
+
+// 按阅读量排序
+export const getPolicyNewsByViews = () => {
+  return [...mockPolicyNews].sort((a, b) => b.viewCount - a.viewCount);
+};
+
+// 按时间排序(最新优先)
+export const getPolicyNewsByDate = () => {
+  return [...mockPolicyNews].sort((a, b) => b.publishTime.getTime() - a.publishTime.getTime());
+};

+ 153 - 0
src/client/mobile/hooks/usePolicyNewsData.ts

@@ -0,0 +1,153 @@
+import { useQuery } from '@tanstack/react-query';
+import { policyNewsClient } from '@/client/api';
+import { mockPolicyNews } from '@/client/mobile/data/mockPolicyNewsData';
+
+// 简化的数据类型
+interface PolicyNewsItem {
+  id: number;
+  newsTitle: string;
+  newsContent: string;
+  publishTime: string | Date;
+  viewCount: number;
+  images: string | null;
+  summary: string | null;
+  source: string | null;
+  category: string | null;
+  isFeatured: number;
+  isDeleted: number;
+  createdAt: string | Date;
+  updatedAt: string | Date;
+}
+
+interface PolicyNewsResponse {
+  data: PolicyNewsItem[];
+  pagination: {
+    total: number;
+    current: number;
+    pageSize: number;
+  };
+}
+
+// 转换日期类型
+const transformDates = (item: PolicyNewsItem): PolicyNewsItem => ({
+  ...item,
+  publishTime: new Date(item.publishTime),
+  createdAt: new Date(item.createdAt),
+  updatedAt: new Date(item.updatedAt),
+});
+
+// 获取政策资讯列表
+export const usePolicyNewsData = (page: number = 1, pageSize: number = 10) => {
+  return useQuery({
+    queryKey: ['policy-news', page, pageSize],
+    queryFn: async (): Promise<PolicyNewsResponse> => {
+      try {
+        // 尝试获取真实数据
+        const response = await policyNewsClient.$get({
+          query: { page, pageSize }
+        });
+        
+        if (!response.ok) {
+          throw new Error('Failed to fetch policy news');
+        }
+        
+        const data = await response.json();
+        return data as PolicyNewsResponse;
+      } catch (error) {
+        // 出错时使用模拟数据
+        console.warn('Using mock data due to API error:', error);
+        const startIndex = (page - 1) * pageSize;
+        const endIndex = startIndex + pageSize;
+        
+        return {
+          data: mockPolicyNews.slice(startIndex, endIndex).map(transformDates),
+          pagination: {
+            total: mockPolicyNews.length,
+            current: page,
+            pageSize
+          }
+        };
+      }
+    },
+    staleTime: 5 * 60 * 1000,
+    gcTime: 10 * 60 * 1000,
+    refetchOnWindowFocus: false,
+  });
+};
+
+// 获取单个政策资讯详情
+export const usePolicyNewsDetail = (id: number) => {
+  return useQuery({
+    queryKey: ['policy-news', id],
+    queryFn: async (): Promise<PolicyNewsItem> => {
+      try {
+        // 尝试获取真实数据 - 使用动态路由
+        const response = await policyNewsClient.$get({
+          query: { id }
+        });
+        
+        if (!response.ok) {
+          throw new Error('Failed to fetch policy news detail');
+        }
+        
+        const data = await response.json();
+        
+        // 查找具体的政策资讯
+        const items = (data as any).data || [];
+        const item = items.find((i: any) => i.id === id);
+        
+        if (item) {
+          return transformDates(item);
+        }
+        
+        throw new Error('Policy news not found');
+      } catch (error) {
+        // 出错时使用模拟数据
+        console.warn('Using mock detail data due to API error:', error);
+        const detail = mockPolicyNews.find(item => item.id === id);
+        if (!detail) {
+          throw new Error('Policy news not found');
+        }
+        return transformDates(detail);
+      }
+    },
+    staleTime: 10 * 60 * 1000,
+    gcTime: 30 * 60 * 1000,
+    refetchOnWindowFocus: false,
+  });
+};
+
+// 获取精选政策资讯
+export const useFeaturedPolicyNews = () => {
+  return useQuery({
+    queryKey: ['policy-news', 'featured'],
+    queryFn: async (): Promise<PolicyNewsItem[]> => {
+      try {
+        const response = await policyNewsClient.$get({
+          query: { 
+            filters: JSON.stringify({ isFeatured: 1 }),
+            pageSize: 6 
+          }
+        });
+        
+        if (!response.ok) {
+          throw new Error('Failed to fetch featured policy news');
+        }
+        
+        const data = await response.json();
+        return (data as PolicyNewsResponse).data.map(transformDates);
+      } catch (error) {
+        console.warn('Using mock featured data due to API error:', error);
+        return mockPolicyNews
+          .filter(item => item.isFeatured === 1)
+          .map(transformDates);
+      }
+    },
+    staleTime: 10 * 60 * 1000,
+    gcTime: 30 * 60 * 1000,
+    refetchOnWindowFocus: false,
+  });
+};
+
+// 导出类型供组件使用
+export type { PolicyNewsItem };

+ 325 - 0
src/client/mobile/pages/PolicyNewsDetailPage.tsx

@@ -0,0 +1,325 @@
+import React from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
+import { useQueryClient } from '@tanstack/react-query';
+import { usePolicyNewsDetail } from '../hooks/usePolicyNewsData';
+import { SkeletonLoader } from '../components/SkeletonLoader';
+import {
+  ArrowLeftIcon,
+  CalendarDaysIcon,
+  EyeIcon,
+  ShareIcon,
+  HeartIcon
+} 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-2xl font-bold tracking-wide',
+  body: 'font-sans text-base leading-relaxed',
+  caption: 'font-sans text-sm',
+  small: 'font-sans text-xs',
+};
+
+const PolicyNewsDetailPage: React.FC = () => {
+  const { id } = useParams<{ id: string }>();
+  const navigate = useNavigate();
+  const queryClient = useQueryClient();
+
+  const {
+    data: news,
+    isLoading,
+    isError,
+    error,
+  } = usePolicyNewsDetail(Number(id));
+
+  if (isLoading) {
+    return (
+      <div className="min-h-screen" style={{ backgroundColor: COLORS.ink.light }}>
+        <header 
+          className="sticky top-0 z-10 shadow-sm border-b border-opacity-20"
+          style={{ 
+            backgroundColor: COLORS.ink.light,
+            borderColor: COLORS.ink.medium 
+          }}
+        >
+          <div className="px-4 py-4 flex items-center">
+            <button
+              onClick={() => navigate('/policy-news')}
+              className="p-2 rounded-full transition-all duration-300 hover:shadow-md mr-4"
+              style={{
+                backgroundColor: 'rgba(255,255,255,0.7)',
+                color: COLORS.text.primary
+              }}
+            >
+              <ArrowLeftIcon className="w-5 h-5" />
+            </button>
+            <h1 className={FONT_STYLES.title} style={{ color: COLORS.text.primary }}>
+              政策详情
+            </h1>
+          </div>
+        </header>
+        
+        <div className="p-4">
+          <SkeletonLoader />
+        </div>
+      </div>
+    );
+  }
+
+  if (isError || !news) {
+    return (
+      <div 
+        className="min-h-screen flex items-center justify-center"
+        style={{ backgroundColor: COLORS.ink.light }}
+      >
+        <div className="text-center">
+          <h3 className={FONT_STYLES.title} style={{ color: COLORS.text.primary }}>
+            资讯不存在
+          </h3>
+          <button
+            onClick={() => navigate('/policy-news')}
+            className="mt-4 px-4 py-2 rounded-full transition-all duration-300 hover:shadow-md"
+            style={{
+              backgroundColor: COLORS.ink.dark,
+              color: 'white'
+            }}
+          >
+            返回列表
+          </button>
+        </div>
+      </div>
+    );
+  }
+
+  const formatDate = (date: string | Date) => {
+    return new Date(date).toLocaleDateString('zh-CN', {
+      year: 'numeric',
+      month: 'long',
+      day: 'numeric',
+      hour: '2-digit',
+      minute: '2-digit'
+    });
+  };
+
+  const getImages = () => {
+    if (!news.images) return [];
+    return news.images.split(',').filter(img => img.trim());
+  };
+
+  const images = getImages();
+
+  return (
+    <div className="min-h-screen pb-16" style={{ backgroundColor: COLORS.ink.light }}>
+      {/* 头部导航 */}
+      <header 
+        className="sticky top-0 z-10 shadow-sm border-b border-opacity-20"
+        style={{ 
+          backgroundColor: COLORS.ink.light,
+          borderColor: COLORS.ink.medium 
+        }}
+      >
+        <div className="px-4 py-4 flex items-center justify-between">
+          <button
+            onClick={() => navigate('/policy-news')}
+            className="p-2 rounded-full transition-all duration-300 hover:shadow-md"
+            style={{
+              backgroundColor: 'rgba(255,255,255,0.7)',
+              color: COLORS.text.primary
+            }}
+          >
+            <ArrowLeftIcon className="w-5 h-5" />
+          </button>
+          <h1 className={`${FONT_STYLES.title} text-lg`} style={{ color: COLORS.text.primary }}>
+            政策详情
+          </h1>
+          <div className="flex items-center space-x-2">
+            <button
+              className="p-2 rounded-full transition-all duration-300 hover:shadow-md"
+              style={{
+                backgroundColor: 'rgba(255,255,255,0.7)',
+                color: COLORS.text.primary
+              }}
+            >
+              <ShareIcon className="w-5 h-5" />
+            </button>
+            <button
+              className="p-2 rounded-full transition-all duration-300 hover:shadow-md"
+              style={{
+                backgroundColor: 'rgba(255,255,255,0.7)',
+                color: COLORS.text.primary
+              }}
+            >
+              <HeartIcon className="w-5 h-5" />
+            </button>
+          </div>
+        </div>
+      </header>
+
+      {/* 内容区域 */}
+      <div className="p-4 space-y-6">
+        {/* 标题区域 */}
+        <div className="bg-white bg-opacity-80 backdrop-blur-sm rounded-xl p-6 shadow-sm border border-opacity-20"
+             style={{ borderColor: COLORS.ink.medium }}>
+          <h1 className={FONT_STYLES.title} style={{ color: COLORS.text.primary }}>
+            {news.newsTitle}
+          </h1>
+          
+          <div className="flex items-center justify-between mt-4 text-sm"
+               style={{ color: COLORS.text.secondary }}>
+            <div className="flex items-center space-x-4">
+              <span className="font-medium">{news.source || '官方发布'}</span>
+              <div className="flex items-center space-x-1">
+                <CalendarDaysIcon className="w-4 h-4" />
+                <span>{formatDate(news.publishTime)}</span>
+              </div>
+              <div className="flex items-center space-x-1">
+                <EyeIcon className="w-4 h-4" />
+                <span>{news.viewCount} 阅读</span>
+              </div>
+            </div>
+            <span 
+              className="px-3 py-1 rounded-full text-xs"
+              style={{
+                backgroundColor: COLORS.accent.blue,
+                color: 'white'
+              }}
+            >
+              {news.category || '政策资讯'}
+            </span>
+          </div>
+        </div>
+
+        {/* 图片展示 */}
+        {images.length > 0 && (
+          <div className="grid grid-cols-1 gap-4">
+            {images.map((image, index) => (
+              <img
+                key={index}
+                src={image.trim()}
+                alt={`政策资讯图片 ${index + 1}`}
+                className="w-full h-64 object-cover rounded-xl"
+                onError={(e) => {
+                  (e.target as HTMLImageElement).src = '/images/placeholder-banner.jpg';
+                }}
+              />
+            ))}
+          </div>
+        )}
+
+        {/* 摘要 */}
+        {news.summary && (
+          <div className="bg-white bg-opacity-80 backdrop-blur-sm rounded-xl p-6 shadow-sm border border-opacity-20"
+               style={{ borderColor: COLORS.ink.medium }}>
+            <h3 className={`${FONT_STYLES.body} font-semibold mb-3`} 
+                style={{ color: COLORS.text.primary }}>
+              摘要
+            </h3>
+            <p className={FONT_STYLES.body} style={{ color: COLORS.text.secondary }}>
+              {news.summary}
+            </p>
+          </div>
+        )}
+
+        {/* 主要内容 */}
+        <div className="bg-white bg-opacity-80 backdrop-blur-sm rounded-xl p-6 shadow-sm border border-opacity-20"
+             style={{ borderColor: COLORS.ink.medium }}>
+          <h3 className={`${FONT_STYLES.body} font-semibold mb-3`} 
+              style={{ color: COLORS.text.primary }}>
+            详细内容
+          </h3>
+          <div 
+            className={FONT_STYLES.body} 
+            style={{ color: COLORS.text.secondary }}
+            dangerouslySetInnerHTML={{
+              __html: news.newsContent.replace(/\n/g, '<br/>')
+            }}
+          />
+        </div>
+
+        {/* 元信息 */}
+        <div className="bg-white bg-opacity-80 backdrop-blur-sm rounded-xl p-4 shadow-sm border border-opacity-20"
+             style={{ borderColor: COLORS.ink.medium }}>
+          <div className="grid grid-cols-2 gap-4 text-sm">
+            <div>
+              <span className="font-medium" style={{ color: COLORS.text.primary }}>发布时间:</span>
+              <span style={{ color: COLORS.text.secondary }}>{formatDate(news.publishTime)}</span>
+            </div>
+            <div>
+              <span className="font-medium" style={{ color: COLORS.text.primary }}>信息来源:</span>
+              <span style={{ color: COLORS.text.secondary }}>{news.source || '官方发布'}</span>
+            </div>
+            <div>
+              <span className="font-medium" style={{ color: COLORS.text.primary }}>分类:</span>
+              <span style={{ color: COLORS.text.secondary }}>{news.category || '其他'}</span>
+            </div>
+            <div>
+              <span className="font-medium" style={{ color: COLORS.text.primary }}>阅读量:</span>
+              <span style={{ color: COLORS.text.secondary }}>{news.viewCount}</span>
+            </div>
+          </div>
+        </div>
+
+        {/* 相关推荐 */}
+        <div className="bg-white bg-opacity-80 backdrop-blur-sm rounded-xl p-6 shadow-sm border border-opacity-20"
+             style={{ borderColor: COLORS.ink.medium }}>
+          <h3 className={`${FONT_STYLES.body} font-semibold mb-4`} 
+              style={{ color: COLORS.text.primary }}>
+            相关推荐
+          </h3>
+          <div className="text-center">
+            <p className={FONT_STYLES.caption} style={{ color: COLORS.text.secondary }}>
+              暂无相关推荐
+            </p>
+          </div>
+        </div>
+      </div>
+
+      {/* 底部操作栏 */}
+      <div className="fixed bottom-0 left-0 right-0 border-t border-opacity-20 px-4 py-3 flex items-center justify-between"
+           style={{ 
+             backgroundColor: COLORS.ink.light,
+             borderColor: COLORS.ink.medium
+           }}>
+        <button
+          onClick={() => navigate('/policy-news')}
+          className="flex-1 py-2 rounded-full transition-all duration-300 hover:shadow-md mr-2"
+          style={{
+            backgroundColor: COLORS.ink.medium,
+            color: COLORS.text.primary
+          }}
+        >
+          返回列表
+        </button>
+        <button
+          className="flex-1 py-2 rounded-full transition-all duration-300 hover:shadow-md ml-2"
+          style={{
+            backgroundColor: COLORS.accent.blue,
+            color: 'white'
+          }}
+        >
+          分享资讯
+        </button>
+      </div>
+    </div>
+  );
+};
+
+export default PolicyNewsDetailPage;

+ 336 - 22
src/client/mobile/pages/PolicyNewsPage.tsx

@@ -1,32 +1,346 @@
-import React from 'react';
+import React, { useState, useRef } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useQueryClient } from '@tanstack/react-query';
+import { usePolicyNewsData, type PolicyNewsItem } from '../hooks/usePolicyNewsData';
+import PolicyNewsCard from '../components/PolicyNewsCard';
+import { SkeletonLoader } from '../components/SkeletonLoader';
+import {
+  CalendarDaysIcon,
+  EyeIcon,
+  ArrowPathIcon,
+  FunnelIcon,
+  MagnifyingGlassIcon
+} 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',
+};
+
+// 骨架屏组件
+const PolicyNewsSkeleton: React.FC = () => (
+  <div className="p-4 space-y-4">
+    {[1, 2, 3].map((i) => (
+      <div key={i} className="bg-white bg-opacity-80 rounded-xl p-4 shadow-sm">
+        <div className="flex space-x-4">
+          <div className="w-32 h-32 bg-gray-200 rounded-lg flex-shrink-0"></div>
+          <div className="flex-1 space-y-2">
+            <div className="h-4 bg-gray-200 rounded w-3/4"></div>
+            <div className="h-3 bg-gray-200 rounded w-1/2"></div>
+            <div className="h-3 bg-gray-200 rounded w-full"></div>
+            <div className="h-3 bg-gray-200 rounded w-2/3"></div>
+            <div className="flex space-x-4">
+              <div className="h-3 bg-gray-200 rounded w-16"></div>
+              <div className="h-3 bg-gray-200 rounded w-20"></div>
+              <div className="h-3 bg-gray-200 rounded w-12"></div>
+            </div>
+          </div>
+        </div>
+      </div>
+    ))}
+  </div>
+);
 
 const PolicyNewsPage: React.FC = () => {
-  return (
-    <div className="min-h-screen bg-gray-50 p-4">
-      <div className="text-center">
-        <h1 className="text-2xl font-bold text-gray-900 mb-4">政策资讯</h1>
-        <p className="text-gray-600">最新政策解读和资讯推送</p>
-        
-        <div className="mt-8 space-y-4">
-          <div className="bg-white p-6 rounded-lg shadow">
-            <h3 className="text-lg font-semibold mb-2">养老政策解读</h3>
-            <p className="text-gray-600 mb-2">2025年最新养老政策全面解读</p>
-            <span className="text-sm text-gray-500">2025-07-15</span>
+  const navigate = useNavigate();
+  const queryClient = useQueryClient();
+  
+  const [searchQuery, setSearchQuery] = useState('');
+  const [filterCategory, setFilterCategory] = useState('');
+  const [showFilters, setShowFilters] = useState(false);
+  const [isRefreshing, setIsRefreshing] = useState(false);
+  
+  const {
+    data: policyNewsData,
+    isLoading,
+    isError,
+    error,
+  } = usePolicyNewsData(1, 20);
+
+  const categories = [
+    { value: '', label: '全部' },
+    { value: '政策法规', label: '政策法规' },
+    { value: '就业政策', label: '就业政策' },
+    { value: '社区建设', label: '社区建设' },
+    { value: '产业发展', label: '产业发展' },
+    { value: '健康政策', label: '健康政策' },
+    { value: '教育政策', label: '教育政策' },
+  ];
+
+  // 下拉刷新
+  const handleRefresh = async () => {
+    setIsRefreshing(true);
+    await queryClient.invalidateQueries({ queryKey: ['policy-news'] });
+    setIsRefreshing(false);
+  };
+
+  // 搜索和过滤逻辑
+  const filteredNews = policyNewsData?.data.filter(news => {
+    const matchesSearch = searchQuery === '' || 
+      news.newsTitle.toLowerCase().includes(searchQuery.toLowerCase()) ||
+      news.summary?.toLowerCase().includes(searchQuery.toLowerCase());
+    
+    const matchesCategory = filterCategory === '' || 
+      news.category === filterCategory;
+    
+    return matchesSearch && matchesCategory;
+  });
+
+  // 处理搜索
+  const handleSearch = (e: React.FormEvent) => {
+    e.preventDefault();
+  };
+
+  // 清除搜索
+  const clearSearch = () => {
+    setSearchQuery('');
+  };
+
+  if (isLoading) {
+    return (
+      <div className="min-h-screen" style={{ backgroundColor: COLORS.ink.light }}>
+        {/* 头部骨架屏 */}
+        <div className="sticky top-0 z-10 shadow-sm" style={{ backgroundColor: COLORS.ink.light }}>
+          <div className="px-4 py-4">
+            <div className="h-8 bg-gray-200 rounded w-32 mb-4"></div>
+            <div className="h-10 bg-gray-200 rounded-full"></div>
           </div>
-          
-          <div className="bg-white p-6 rounded-lg shadow">
-            <h3 className="text-lg font-semibold mb-2">银龄就业新政</h3>
-            <p className="text-gray-600 mb-2">支持银龄群体再就业的新政策</p>
-            <span className="text-sm text-gray-500">2025-07-10</span>
+        </div>
+        <PolicyNewsSkeleton />
+      </div>
+    );
+  }
+
+  if (isError) {
+    return (
+      <div 
+        className="min-h-screen flex items-center justify-center"
+        style={{ backgroundColor: COLORS.ink.light }}
+      >
+        <div className="text-center">
+          <div 
+            className="text-6xl mb-4"
+            style={{ color: COLORS.text.light }}
+          >
+            📰
           </div>
-          
-          <div className="bg-white p-6 rounded-lg shadow">
-            <h3 className="text-lg font-semibold mb-2">社区服务动态</h3>
-            <p className="text-gray-600 mb-2">社区银龄服务最新动态</p>
-            <span className="text-sm text-gray-500">2025-07-08</span>
+          <h3 
+            className={`${FONT_STYLES.sectionTitle} mb-2`}
+            style={{ color: COLORS.text.primary }}
+          >
+            加载失败
+          </h3>
+          <p 
+            className={FONT_STYLES.caption}
+            style={{ color: COLORS.text.secondary }}
+          >
+            {error instanceof Error ? error.message : '获取政策资讯失败'}
+          </p>
+          <button
+            onClick={handleRefresh}
+            className="mt-4 px-4 py-2 rounded-full transition-all duration-300 hover:shadow-md"
+            style={{
+              backgroundColor: COLORS.ink.dark,
+              color: 'white'
+            }}
+          >
+            重试
+          </button>
+        </div>
+      </div>
+    );
+  }
+
+  return (
+    <div className="min-h-screen pb-16" style={{ backgroundColor: COLORS.ink.light }}>
+      {/* 头部导航 */}
+      <header 
+        className="sticky top-0 z-10 shadow-sm border-b border-opacity-20"
+        style={{ 
+          backgroundColor: COLORS.ink.light,
+          borderColor: COLORS.ink.medium 
+        }}
+      >
+        <div className="px-4 py-4">
+          <div className="flex items-center justify-between mb-3">
+            <h1 
+              className={FONT_STYLES.title}
+              style={{ color: COLORS.text.primary }}
+            >
+              政策资讯
+            </h1>
+            <button
+              onClick={handleRefresh}
+              disabled={isRefreshing}
+              className="p-2 rounded-full transition-all duration-300 hover:shadow-md"
+              style={{ 
+                backgroundColor: 'rgba(255,255,255,0.7)',
+                color: COLORS.text.primary
+              }}
+            >
+              <ArrowPathIcon 
+                className={`w-5 h-5 ${isRefreshing ? 'animate-spin' : ''}`} 
+              />
+            </button>
           </div>
+
+          {/* 搜索栏 */}
+          <form onSubmit={handleSearch} className="mb-3">
+            <div className="flex items-center space-x-2">
+              <div className="flex-1 relative">
+                <MagnifyingGlassIcon
+                  className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4"
+                  style={{ color: COLORS.text.light }}
+                />
+                <input
+                  type="text"
+                  placeholder="搜索政策资讯..."
+                  value={searchQuery}
+                  onChange={(e) => setSearchQuery(e.target.value)}
+                  className="w-full pl-10 pr-4 py-2 rounded-full border transition-all duration-300 focus:shadow-md"
+                  style={{
+                    backgroundColor: 'rgba(255,255,255,0.7)',
+                    borderColor: COLORS.ink.medium,
+                    color: COLORS.text.primary
+                  }}
+                />
+              </div>
+              
+              <button
+                type="button"
+                onClick={() => setShowFilters(!showFilters)}
+                className="p-2 rounded-full transition-all duration-300 hover:shadow-md"
+                style={{
+                  backgroundColor: 'rgba(255,255,255,0.7)',
+                  color: COLORS.text.primary
+                }}
+              >
+                <FunnelIcon className="w-5 h-5" />
+              </button>
+            </div>
+          </form>
+
+          {/* 分类过滤器 */}
+          {showFilters && (
+            <div className="grid grid-cols-3 gap-2 mt-3">
+              {categories.map((category) => (
+                <button
+                  key={category.value}
+                  onClick={() => setFilterCategory(category.value)}
+                  className={`px-3 py-2 rounded-full text-sm transition-all duration-300 ${
+                    filterCategory === category.value
+                      ? 'shadow-md'
+                      : 'hover:shadow-md'
+                  }`}
+                  style={{
+                    backgroundColor: filterCategory === category.value 
+                      ? COLORS.accent.blue 
+                      : 'rgba(255,255,255,0.7)',
+                    color: filterCategory === category.value ? 'white' : COLORS.text.primary,
+                    borderColor: COLORS.ink.medium
+                  }}
+                >
+                  {category.label}
+                </button>
+              ))}
+            </div>
+          )}
+
+          {/* 清除搜索/过滤 */}
+          {(searchQuery || filterCategory) && (
+            <button
+              onClick={() => {
+                setSearchQuery('');
+                setFilterCategory('');
+              }}
+              className="mt-3 text-sm"
+              style={{ color: COLORS.accent.red }}
+            >
+              清除筛选
+            </button>
+          )}
+        </div>
+      </header>
+
+      {/* 内容区域 */}
+      <div className="p-4">
+        {/* 统计信息 */}
+        <div className="mb-4 text-sm" style={{ color: COLORS.text.secondary }}>
+          共找到 {filteredNews?.length || 0} 条政策资讯
+        </div>
+
+        {/* 资讯列表 */}
+        <div className="space-y-4">
+          {filteredNews?.map((news) => (
+            <PolicyNewsCard
+              key={news.id}
+              news={news}
+              onClick={() => navigate(`/policy-news/${news.id}`)}
+            />
+          ))}
         </div>
+
+        {/* 空状态 */}
+        {filteredNews?.length === 0 && (
+          <div className="text-center py-8">
+            <div 
+              className="text-6xl mb-4"
+              style={{ color: COLORS.text.light }}
+            >
+              📋
+            </div>
+            <h3 
+              className={`${FONT_STYLES.sectionTitle} mb-2`}
+              style={{ color: COLORS.text.primary }}
+            >
+              暂无政策资讯
+            </h3>
+            <p 
+              className={FONT_STYLES.caption}
+              style={{ color: COLORS.text.secondary }}
+            >
+              {searchQuery || filterCategory 
+                ? '请尝试调整搜索条件或清除筛选'
+                : '暂无政策资讯内容,敬请期待'}
+            </p>
+          </div>
+        )}
       </div>
+
+      {/* 回到顶部按钮 */}
+      <button
+        onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
+        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'
+        }}
+      >
+        ↑
+      </button>
     </div>
   );
 };

+ 5 - 0
src/client/mobile/routes.tsx

@@ -15,6 +15,7 @@ import SilverWisdomPage from './pages/SilverWisdomPage';
 import ElderlyUniversityPage from './pages/ElderlyUniversityPage';
 import TimeBankPage from './pages/TimeBankPage';
 import PolicyNewsPage from './pages/PolicyNewsPage';
+import PolicyNewsDetailPage from './pages/PolicyNewsDetailPage';
 import PublishPage from './pages/PublishPage';
 import ProfilePage from './pages/ProfilePage';
 import ProfileEditPage from './pages/ProfileEditPage';
@@ -62,6 +63,10 @@ export const router = createBrowserRouter([
         path: 'policy-news',
         element: <PolicyNewsPage />
       },
+      {
+        path: 'policy-news/:id',
+        element: <PolicyNewsDetailPage />
+      },
       {
         path: 'publish',
         element: (