保存本地对routes.ts的修改

Change-Id: I4f4dbd8069893d7363e251130791dc0594be44e1
diff --git a/src/feature/categories/GameCategory.tsx b/src/feature/categories/GameCategory.tsx
new file mode 100644
index 0000000..3f5c78d
--- /dev/null
+++ b/src/feature/categories/GameCategory.tsx
@@ -0,0 +1,173 @@
+import React, { useState, useEffect } from 'react';
+import { Card, List, message, Spin, Input, Tag, Typography} from 'antd';
+import { SearchOutlined, PlayCircleOutlined } from '@ant-design/icons';
+import CategoryAPI from '../../api/categoryApi';
+import type { GameResource } from '../../api/categoryTypes';
+import { useNavigate } from 'react-router';
+
+const { Text } = Typography;
+const { Search } = Input;
+
+const GameCategory: React.FC = () => {
+  const [games, setGames] = useState<GameResource[]>([]);
+  const [filteredGames, setFilteredGames] = useState<GameResource[]>([]);
+  const [isLoading, setIsLoading] = useState(true);
+  const [searchQuery, setSearchQuery] = useState('');
+  
+  // 加载数据
+useEffect(() => {
+  const loadGames = async () => {
+    try {
+      const response = await CategoryAPI.getWorksByCategory(3);
+      
+      // 类型转换或断言
+      const gameResources = response.content.map((work: any) => ({
+        ...work,
+        developer: (work as any).developer || '未知开发商',
+        publisher: (work as any).publisher || '未知发行商',
+        platform: (work as any).platform || 'PC',
+        releaseDate: (work as any).releaseDate || '未知日期'
+      })) as unknown as GameResource[];
+      
+      setGames(gameResources);
+      setFilteredGames(gameResources);
+    } catch (error) {
+      message.error('加载游戏资源失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+  
+  loadGames();
+}, []);
+
+  // 筛选逻辑
+  useEffect(() => {
+    if (!searchQuery) {
+      setFilteredGames(games);
+      return;
+    }
+    
+    const filtered = games.filter(game => 
+      game.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
+      game.developer.toLowerCase().includes(searchQuery.toLowerCase())
+    );
+    
+    setFilteredGames(filtered);
+  }, [searchQuery, games]);
+
+
+  // // 在加载数据部分添加虚拟数据
+  // useEffect(() => {
+  //   const loadGames = async () => {
+  //     try {
+  //       // 模拟API请求
+  //       const mockGames: GameResource[] = [
+  //         {
+  //           id: 5,
+  //           title: '赛博朋克2077',
+  //           developer: 'CD Projekt Red',
+  //           publisher: 'CD Projekt',
+  //           categoryId: 3,
+  //           categoryName: '角色扮演',
+  //           platform: 'PC',
+  //           releaseDate: '2020-12-10',
+  //           seeders: 156,
+  //           leechers: 34,
+  //           uploadDate: '2023-06-01',
+  //           uploader: 'gameLover',
+  //           downloadCount: 2876,
+  //           hash: 'm3n4o5p6q7r8',
+  //           size: '123Mb'
+  //         },
+  //         {
+  //           id: 6,
+  //           title: '艾尔登法环',
+  //           developer: 'FromSoftware',
+  //           publisher: '万代南梦宫',
+  //           categoryId: 3,
+  //           categoryName: '动作冒险',
+  //           releaseDate: '2022-02-25',
+  //           seeders: 201,
+  //           leechers: 45,
+  //           uploadDate: '2023-05-20',
+  //           uploader: 'hardcoreGamer',
+  //           downloadCount: 3542,
+  //           hash: 's9t0u1v2w3x4',
+  //           platform: 'PC',
+  //           size: '234Mb'
+  //         }
+  //       ];
+
+  //       setGames(mockGames);
+  //       setFilteredGames(mockGames);
+  //     } catch (error) {
+  //       message.error('加载游戏资源失败');
+  //     } finally {
+  //       setIsLoading(false);
+  //     }
+  //   };
+    
+  //   loadGames();
+  // }, []);
+  
+  return (
+    <div className="game-category-container">
+      <div className="category-header">
+        <h1><PlayCircleOutlined /> 游戏资源分区</h1>
+        <p>PC、主机游戏资源分享</p>
+      </div>
+      
+      <Search
+        placeholder="搜索游戏名称或开发商"
+        allowClear
+        enterButton={<SearchOutlined />}
+        value={searchQuery}
+        onChange={e => setSearchQuery(e.target.value)}
+        className="search-bar"
+      />
+      
+      {isLoading ? (
+        <Spin tip="加载游戏资源..." size="large" />
+      ) : (
+        <List
+          grid={{ gutter: 16, column: 1 }}
+          dataSource={filteredGames}
+          renderItem={game => (
+            <List.Item>
+              <GameCard game={game} />
+            </List.Item>
+          )}
+        />
+      )}
+    </div>
+  );
+};
+
+const GameCard: React.FC<{ game: GameResource }> = ({ game }) => {
+  const navigate = useNavigate();
+  
+  const handleClick = () => {
+    navigate(`/works/${game.id}`);
+  };
+
+  return (
+    <Card className="game-card" onClick={handleClick} hoverable>
+      <div className="card-content">
+        <div className="card-header">
+          <Text strong className="resource-title">{game.title}</Text>
+          <Text type="secondary" className="resource-developer">开发商: {game.developer}</Text>
+        </div>
+        
+        <div className="card-meta">
+          <Tag color="blue">{game.platform}</Tag>
+          <Tag color="geekblue">{game.categoryName}</Tag>
+          <Tag color="green">{game.seeders} 做种</Tag>
+          <Tag color="orange">{game.leechers} 下载</Tag>
+        </div>
+      </div>
+    </Card>
+  );
+};
+
+export default GameCategory;
\ No newline at end of file
diff --git a/src/feature/categories/MovieCategory.tsx b/src/feature/categories/MovieCategory.tsx
new file mode 100644
index 0000000..262ebd4
--- /dev/null
+++ b/src/feature/categories/MovieCategory.tsx
@@ -0,0 +1,172 @@
+import React, { useState, useEffect } from 'react';
+import { Card, List, message, Spin, Input, Tag, Typography} from 'antd';
+import { SearchOutlined, VideoCameraOutlined } from '@ant-design/icons';
+import CategoryAPI from '../../api/categoryApi';
+import type { MovieResource } from '../../api/categoryTypes';
+import { useNavigate } from 'react-router';
+
+const { Text } = Typography;
+const { Search } = Input;
+
+const MovieCategory: React.FC = () => {
+  const [movies, setMovies] = useState<MovieResource[]>([]);
+  const [filteredMovies, setFilteredMovies] = useState<MovieResource[]>([]);
+  const [isLoading, setIsLoading] = useState(true);
+  const [searchQuery, setSearchQuery] = useState('');
+  
+  // 加载数据
+useEffect(() => {
+  const loadMovies = async () => {
+    try {
+      const response = await CategoryAPI.getWorksByCategory(2);
+      // 添加类型断言或转换
+      const movies = response.content.map((work: any) => ({
+        ...work,
+        director: (work as any).director || '未知导演',
+        actors: (work as any).actors || [],
+        resolution: (work as any).resolution || '1080p',
+        duration: (work as any).duration || '0分钟'
+      })) as unknown as MovieResource[];
+      
+      setMovies(movies);
+      setFilteredMovies(movies);
+    } catch (error) {
+      message.error('加载影视资源失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+  
+  loadMovies();
+}, []);
+
+  // 筛选逻辑
+  useEffect(() => {
+    if (!searchQuery) {
+      setFilteredMovies(movies);
+      return;
+    }
+    
+    const filtered = movies.filter(movie => 
+      movie.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
+      movie.director.toLowerCase().includes(searchQuery.toLowerCase())
+    );
+    
+    setFilteredMovies(filtered);
+  }, [searchQuery, movies]);
+
+
+//   // 在加载数据部分添加虚拟数据
+// useEffect(() => {
+//   const loadMovies = async () => {
+//     try {
+//       // 模拟API请求
+//       const mockMovies: MovieResource[] = [
+//         {
+//           id: 3,
+//           title: '盗梦空间',
+//           director: '克里斯托弗·诺兰',
+//           categoryId: 2,
+//           categoryName: '科幻电影',
+//           resolution: '1080p',
+//           duration: '148分钟',
+//           actors: ['莱昂纳多·迪卡普里奥', '约瑟夫·高登-莱维特'],
+//           seeders: 215,
+//           leechers: 42,
+//           uploadDate: '2023-06-10',
+//           uploader: 'movieFan',
+//           downloadCount: 3256,
+//           hash: 'a1b2c3d4e5f6',
+//           size: '234Mb'
+//         },
+//         {
+//           id: 4,
+//           title: '肖申克的救赎',
+//           director: '弗兰克·德拉邦特',
+//           categoryId: 2,
+//           categoryName: '剧情片',
+//           resolution: '4K',
+//           duration: '142分钟',
+//           actors: ['蒂姆·罗宾斯', '摩根·弗里曼'],
+//           seeders: 189,
+//           leechers: 28,
+//           uploadDate: '2023-05-15',
+//           uploader: 'classicMovie',
+//           downloadCount: 4123,
+//           hash: 'g7h8i9j0k1l2',
+//           size: '123Mb'
+//         }
+//       ];
+
+//       setMovies(mockMovies);
+//       setFilteredMovies(mockMovies);
+//     } catch (error) {
+//       message.error('加载影视资源失败');
+//     } finally {
+//       setIsLoading(false);
+//     }
+//   };
+  
+//   loadMovies();
+// }, []);
+
+  return (
+    <div className="movie-category-container">
+      <div className="category-header">
+        <h1><VideoCameraOutlined /> 影视资源分区</h1>
+        <p>高清电影、电视剧、纪录片资源分享</p>
+      </div>
+      
+      <Search
+        placeholder="搜索电影或导演"
+        allowClear
+        enterButton={<SearchOutlined />}
+        value={searchQuery}
+        onChange={e => setSearchQuery(e.target.value)}
+        className="search-bar"
+      />
+      
+      {isLoading ? (
+        <Spin tip="加载影视资源..." size="large" />
+      ) : (
+        <List
+          grid={{ gutter: 16, column: 1 }}
+          dataSource={filteredMovies}
+          renderItem={movie => (
+            <List.Item>
+              <MovieCard movie={movie} />
+            </List.Item>
+          )}
+        />
+      )}
+    </div>
+  );
+};
+
+const MovieCard: React.FC<{ movie: MovieResource }> = ({ movie }) => {
+  const navigate = useNavigate();
+  
+  const handleClick = () => {
+    navigate(`/works/${movie.id}`);
+  };
+
+  return (
+    <Card className="movie-card" onClick={handleClick} hoverable>
+      <div className="card-content">
+        <div className="card-header">
+          <Text strong className="resource-title">{movie.title}</Text>
+          <Text type="secondary" className="resource-director">导演: {movie.director}</Text>
+        </div>
+        
+        <div className="card-meta">
+          <Tag color="blue">{movie.resolution}</Tag>
+          <Tag color="geekblue">{movie.categoryName}</Tag>
+          <Tag color="green">{movie.seeders} 做种</Tag>
+          <Tag color="orange">{movie.leechers} 下载</Tag>
+        </div>
+      </div>
+    </Card>
+  );
+};
+
+export default MovieCategory;
\ No newline at end of file
diff --git a/src/feature/categories/MusicCategory.tsx b/src/feature/categories/MusicCategory.tsx
new file mode 100644
index 0000000..f9057ee
--- /dev/null
+++ b/src/feature/categories/MusicCategory.tsx
@@ -0,0 +1,191 @@
+import React, { useState, useEffect } from 'react';
+import { 
+  Card, Button, List, Tag, Typography, 
+  message, Spin, 
+  Input} from 'antd';
+import { 
+  SearchOutlined
+} from '@ant-design/icons';
+import CategoryAPI from '../../api/categoryApi';
+import type { CategoryDTO, MusicResource } from '../../api/categoryTypes';
+import { useNavigate } from 'react-router';
+
+const { Search } = Input;
+const { Text } = Typography;
+
+const MusicCategory: React.FC = () => {
+  const [categories, setCategories] = useState<CategoryDTO[]>([]);
+  const [resources, setResources] = useState<MusicResource[]>([]);
+  const [filteredResources, setFilteredResources] = useState<MusicResource[]>([]);
+  const [isLoading, setIsLoading] = useState(true);
+  const [selectedCategory, setSelectedCategory] = useState<number | null>(null);
+  
+  // 筛选状态
+  const [searchQuery, setSearchQuery] = useState('');
+  const [qualityFilter, setQualityFilter] = useState<string>('all');
+
+  // 加载分类数据
+  useEffect(() => {
+    const loadData = async () => {
+      try {
+        const [categoryData, resourceData] = await Promise.all([
+          CategoryAPI.getCategoryTree(),
+          CategoryAPI.getWorksByCategory(1)
+        ]);
+        
+        // 确保 parentId 不包含 null
+        const normalizedCategories = categoryData.map(cat => ({
+          ...cat,
+          parentId: cat.parentId === null ? undefined : cat.parentId
+        })) as CategoryDTO[];
+        
+        // 音乐资源类型转换
+        const musicResources = resourceData.content.map(work => ({
+          ...work,
+          artist: work.artist || '未知艺术家',
+          quality: work.quality || 'MP3 320k',
+          genre: work.genre || ['未知流派'],
+          categoryName: work.categoryName || '未知分类',
+          size: work.size || '0MB'
+        })) as unknown as MusicResource[];
+        
+        setCategories(normalizedCategories);
+        setResources(musicResources);
+        setFilteredResources(musicResources);
+      } catch (error) {
+        message.error('加载数据失败');
+      } finally {
+        setIsLoading(false);
+      }
+    };
+    
+    loadData();
+  }, []);
+
+  // 筛选逻辑
+  useEffect(() => {
+    let filtered = resources;
+    
+    // 搜索筛选
+    if (searchQuery) {
+      filtered = filtered.filter(resource => 
+        resource.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
+        resource.artist.toLowerCase().includes(searchQuery.toLowerCase())
+      );
+    }
+    
+    // 音质筛选
+    if (qualityFilter !== 'all') {
+      filtered = filtered.filter(resource => resource.quality === qualityFilter);
+    }
+    
+    // 分类筛选
+    if (selectedCategory) {
+      filtered = filtered.filter(resource => resource.categoryId === selectedCategory);
+    }
+    
+    setFilteredResources(filtered);
+  }, [searchQuery, qualityFilter, selectedCategory, resources]);
+
+  // 分类选择处理
+  const handleCategorySelect = (categoryId: number) => {
+    setSelectedCategory(prev => prev === categoryId ? null : categoryId);
+  };
+
+  return (
+    <div className="music-category-container">
+      {/* 头部区域 */}
+      <div className="category-header">
+        <h1>音乐资源分区</h1>
+        <p>高质量音乐资源共享,保持分享率,共建良好PT环境</p>
+      </div>
+      
+      {/* 搜索和筛选 */}
+      <div className="filter-section">
+        <Search
+          placeholder="搜索音乐名称或艺术家"
+          allowClear
+          enterButton={<SearchOutlined />}
+          value={searchQuery}
+          onChange={e => setSearchQuery(e.target.value)}
+          className="search-bar"
+        />
+        
+        <div className="quality-filter">
+          <span>音质筛选:</span>
+          <Button.Group>
+            {['all', 'FLAC', 'Hi-Res', 'MP3 320k'].map(quality => (
+              <Button 
+                key={quality}
+                type={qualityFilter === quality ? 'primary' : 'default'}
+                onClick={() => setQualityFilter(quality)}
+              >
+                {quality === 'all' ? '全部' : quality}
+              </Button>
+            ))}
+          </Button.Group>
+        </div>
+      </div>
+      
+      {/* 分类导航 */}
+      <div className="category-navigation">
+        {categories.map(category => (
+          <Tag 
+            key={category.id}
+            color={selectedCategory === category.id ? 'blue' : undefined}
+            onClick={() => handleCategorySelect(category.id)}
+            className="category-tag"
+          >
+            {category.name} ({category.workCount || 0})
+          </Tag>
+        ))}
+      </div>
+      
+      {/* 内容展示 */}
+      {isLoading ? (
+        <Spin tip="加载中..." size="large" />
+      ) : (
+        <div className="resource-list">
+          <List
+            grid={{ gutter: 16, column: 1 }}
+            dataSource={filteredResources}
+            renderItem={resource => (
+              <List.Item>
+                <ResourceCard resource={resource} />
+              </List.Item>
+            )}
+          />
+        </div>
+      )}
+    </div>
+  );
+};
+
+// 资源卡片组件
+const ResourceCard: React.FC<{ resource: MusicResource }> = ({ resource }) => {
+  const navigate = useNavigate();
+  
+  const handleClick = () => {
+    navigate(`/works/${resource.id}`);
+  };
+
+  return (
+    <Card className="resource-card" onClick={handleClick} hoverable>
+      <div className="card-content">
+        <div className="card-header">
+          <Text strong className="resource-title">{resource.title}</Text>
+          <Text type="secondary" className="resource-artist">{resource.artist}</Text>
+        </div>
+        
+        <div className="card-meta">
+          <Tag color="blue">{resource.quality}</Tag>
+          <Tag color="geekblue">{resource.categoryName}</Tag>
+          <Tag color="green">{resource.seeders} 做种</Tag>
+          <Tag color="orange">{resource.leechers} 下载</Tag>
+        </div>
+      </div>
+    </Card>
+  );
+};
+
+export default MusicCategory;
\ No newline at end of file
diff --git a/src/feature/categories/OtherCategory.tsx b/src/feature/categories/OtherCategory.tsx
new file mode 100644
index 0000000..6c3318a
--- /dev/null
+++ b/src/feature/categories/OtherCategory.tsx
@@ -0,0 +1,178 @@
+import React, { useState, useEffect } from 'react';
+import { Card, List, message, Spin, Input, Tag, Typography} from 'antd';
+import { SearchOutlined, AppstoreOutlined } from '@ant-design/icons';
+import CategoryAPI from '../../api/categoryApi';
+import type { MovieResource, OtherResource } from '../../api/categoryTypes';
+import { useNavigate } from 'react-router';
+
+const { Text } = Typography;
+const { Search } = Input;
+
+const OtherCategory: React.FC = () => {
+  const [resources, setResources] = useState<OtherResource[]>([]);
+  const [filteredResources, setFilteredResources] = useState<OtherResource[]>([]);
+  const [isLoading, setIsLoading] = useState(true);
+  const [searchQuery, setSearchQuery] = useState('');
+  
+  // 加载数据
+useEffect(() => {
+  const loadResources = async () => {
+    try {
+      const response = await CategoryAPI.getWorksByCategory(4);
+      
+      // 其他资源类型转换
+      const otherResources = response.content.map(work => ({
+        ...work,
+        description: (work as any).description || '暂无描述',
+        fileType: (work as any).fileType || '未知类型'
+      })) as unknown as OtherResource[];
+      
+      setResources(otherResources);
+      setFilteredResources(otherResources);
+    } catch (error) {
+      message.error('加载资源失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+  
+  loadResources();
+}, []);
+
+  // 筛选逻辑
+  useEffect(() => {
+    if (!searchQuery) {
+      setFilteredResources(resources);
+      return;
+    }
+    
+    const filtered = resources.filter(resource => 
+      resource.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
+      resource.description.toLowerCase().includes(searchQuery.toLowerCase())
+    );
+    
+    setFilteredResources(filtered);
+  }, [searchQuery, resources]);
+
+    // 在加载数据部分添加虚拟数据
+  useEffect(() => {
+    const loadMovies = async () => {
+      try {
+        // 模拟API请求
+        const mockMovies: MovieResource[] = [
+          {
+            id: 3,
+            title: '盗梦空间',
+            director: '克里斯托弗·诺兰',
+            categoryId: 2,
+            categoryName: '科幻电影',
+            resolution: '1080p',
+            duration: '148分钟',
+            actors: ['莱昂纳多·迪卡普里奥', '约瑟夫·高登-莱维特'],
+            seeders: 215,
+            leechers: 42,
+            uploadDate: '2023-06-10',
+            uploader: 'movieFan',
+            downloadCount: 3256,
+            hash: 'a1b2c3d4e5f6',
+            size: '123Mb'
+          },
+          {
+            id: 4,
+            title: '肖申克的救赎',
+            director: '弗兰克·德拉邦特',
+            categoryId: 2,
+            categoryName: '剧情片',
+            resolution: '4K',
+            duration: '142分钟',
+            actors: ['蒂姆·罗宾斯', '摩根·弗里曼'],
+            seeders: 189,
+            leechers: 28,
+            uploadDate: '2023-05-15',
+            uploader: 'classicMovie',
+            downloadCount: 4123,
+            hash: 'g7h8i9j0k1l2',
+            size: '123Mb'
+          }
+        ];
+
+        setMovies(mockMovies);
+        setFilteredMovies(mockMovies);
+      } catch (error) {
+        message.error('加载影视资源失败');
+      } finally {
+        setIsLoading(false);
+      }
+    };
+    
+    loadMovies();
+  }, []);
+
+  return (
+    <div className="other-category-container">
+      <div className="category-header">
+        <h1><AppstoreOutlined /> 其他资源分区</h1>
+        <p>软件、电子书等其他类型资源</p>
+      </div>
+      
+      <Search
+        placeholder="搜索资源名称或描述"
+        allowClear
+        enterButton={<SearchOutlined />}
+        value={searchQuery}
+        onChange={e => setSearchQuery(e.target.value)}
+        className="search-bar"
+      />
+      
+      {isLoading ? (
+        <Spin tip="加载资源..." size="large" />
+      ) : (
+        <List
+          grid={{ gutter: 16, column: 1 }}
+          dataSource={filteredResources}
+          renderItem={resource => (
+            <List.Item>
+              <OtherResourceCard resource={resource} />
+            </List.Item>
+          )}
+        />
+      )}
+    </div>
+  );
+};
+
+const OtherResourceCard: React.FC<{ resource: OtherResource }> = ({ resource }) => {
+  const navigate = useNavigate();
+  
+  const handleClick = () => {
+    navigate(`/works/${resource.id}`);
+  };
+
+  return (
+    <Card className="other-resource-card" onClick={handleClick} hoverable>
+      <div className="card-content">
+        <div className="card-header">
+          <Text strong className="resource-title">{resource.title}</Text>
+          <Text type="secondary" className="resource-type">类型: {resource.fileType}</Text>
+        </div>
+        
+        <div className="card-meta">
+          <Tag color="geekblue">{resource.categoryName}</Tag>
+          <Tag color="green">{resource.seeders} 做种</Tag>
+          <Tag color="orange">{resource.leechers} 下载</Tag>
+        </div>
+      </div>
+    </Card>
+  );
+};
+
+export default OtherCategory;
+
+function setMovies(_mockMovies: MovieResource[]) {
+  throw new Error('Function not implemented.');
+}
+
+
+function setFilteredMovies(_mockMovies: MovieResource[]) {
+  throw new Error('Function not implemented.');
+}
diff --git a/src/feature/home/Home.tsx b/src/feature/home/Home.tsx
index fc2c982..80e44eb 100644
--- a/src/feature/home/Home.tsx
+++ b/src/feature/home/Home.tsx
@@ -1,12 +1,116 @@
+import { NavLink } from 'react-router';
+import filmImg from '../../assets/categories/film.jpg';
+import musicImg from '../../assets/categories/music.jpg';
+import gameImg from '../../assets/categories/game.jpg';
+import otherImg from '../../assets/categories/other.jpg';
+// 假设你有排行榜数据,这里模拟一下,实际根据接口等替换
+const filmRankList = [
+  { id: 1, name: '影视作品1', view: '1.2万' },
+  { id: 2, name: '影视作品2', view: '1.1万' },
+  { id: 3, name: '影视作品3', view: '1.0万' },
+];
+const musicRankList = [
+  { id: 1, name: '音乐作品1', view: '1.5万' },
+  { id: 2, name: '音乐作品2', view: '1.3万' },
+  { id: 3, name: '音乐作品3', view: '1.2万' },
+];
+const gameRankList = [
+  { id: 1, name: '游戏作品1', view: '2.0万' },
+  { id: 2, name: '游戏作品2', view: '1.8万' },
+  { id: 3, name: '游戏作品3', view: '1.6万' },
+];
+const otherRankList = [
+  { id: 1, name: '其他作品1', view: '0.8万' },
+  { id: 2, name: '其他作品2', view: '0.7万' },
+  { id: 3, name: '其他作品3', view: '0.6万' },
+];
+
 function Home() {
+  const categories = [
+    { id: 'film', name: '影视', image: filmImg, rankList: filmRankList },
+    { id: 'music', name: '音乐', image: musicImg, rankList: musicRankList },
+    { id: 'game', name: '游戏', image: gameImg, rankList: gameRankList },
+    { id: 'other', name: '其他', image: otherImg, rankList: otherRankList },
+  ];
 
   return (
-    <>
-      主页
-    </>
-  )
+    <div className="max-w-7xl mx-auto px-4 py-16 flex flex-col items-center">
+      {/* 页面标题 */}
+      <h1 className="text-[clamp(2rem,5vw,3.5rem)] font-bold text-center mb-12 text-gray-800 tracking-tight">
+        欢迎访问创意协作平台
+      </h1>
+
+      {/* 分区 + 排行榜 容器,改为 flex 布局 */}
+      <div className="w-full flex max-w-6xl mx-auto">
+        {/* 分区卡片容器 - 响应式网格布局 */}
+        <div className="grid grid-cols-4 gap-6 w-3/4">
+          {categories.map((category) => (
+            <div 
+              key={category.id}
+              className="group relative overflow-hidden rounded-xl shadow-lg transition-all duration-300 hover:-translate-y-2 hover:shadow-xl"
+            >
+              <NavLink to={`/categories/${category.id}`} className="block">
+                {/* 图片容器 */}
+                <div className="aspect-[4/3] relative overflow-hidden">
+                  {/* 背景图片 - 带模糊和亮度调整 */}
+                  <img 
+                    src={category.image}
+                    alt={category.name}
+                    className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
+                    style={{ filter: 'blur(1px) brightness(0.85)' }}
+                  />
+
+                  {/* 渐变遮罩层 - 增强文字可读性 */}
+                  <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent z-10"></div>
+
+                  {/* 文字内容 */}
+                  <div className="absolute inset-0 flex flex-col items-center justify-center p-4 z-20">
+                    {/* 分类标题 - 艺术字体 */}
+                    <h2 className="text-[clamp(1.8rem,4vw,2.5rem)] font-bold text-white text-center mb-2" style={{
+                      fontFamily: '"Playfair Display", serif',
+                      textShadow: '0 4px 12px rgba(0,0,0,0.8)',
+                      transform: 'translateY(10px)',
+                      transition: 'transform 0.3s ease-out',
+                      letterSpacing: '2px',
+                      borderBottom: '2px solid rgba(255,255,255,0.6)',
+                      paddingBottom: '4px'
+                    }}>
+                      {category.name}
+                    </h2>
+
+                    {/* 描述文本 - 悬停显示 */}
+                    <p className="text-indigo-100 text-center opacity-0 transform translate-y-4 transition-all duration-300 group-hover:opacity-100 group-hover:translate-y-0 mt-2" style={{
+                      fontFamily: '"Merriweather", serif',
+                      textShadow: '0 2px 6px rgba(0,0,0,0.6)'
+                    }}>
+                      探索{category.name}创意项目
+                    </p>
+                  </div>
+                </div>
+              </NavLink>
+            </div>
+          ))}
+        </div>
+
+        {/* 排行榜区域 - 右侧 */}
+        <div className="w-1/4 pl-6">
+          {categories.map((category) => (
+            <div key={category.id} className="mb-8">
+              <h3 className="text-xl font-bold text-gray-800 mb-4">{category.name}排行榜</h3>
+              <ul>
+                {category.rankList.map((item) => (
+                  <li key={item.id} className="flex justify-between items-center mb-2">
+                    <span>{item.name}</span>
+                    <span className="text-gray-600">{item.view}</span>
+                  </li>
+                ))}
+              </ul>
+            </div>
+          ))}
+        </div>
+      </div>
+    </div>
+  );
 }
 
-
-
-export default Home
+export default Home;
\ No newline at end of file
diff --git a/src/feature/work/WorkPage.css b/src/feature/work/WorkPage.css
new file mode 100644
index 0000000..14b815a
--- /dev/null
+++ b/src/feature/work/WorkPage.css
@@ -0,0 +1,155 @@
+/* 作品页面容器 */
+.work-page-container {
+  max-width: 1200px;
+  margin: 0 auto;
+  padding: 20px;
+}
+
+/* 返回按钮 */
+.back-button {
+  margin-bottom: 20px;
+}
+
+/* 作品头部 */
+.work-header {
+  margin-bottom: 20px;
+}
+
+.work-header .ant-typography {
+  margin-bottom: 8px;
+}
+
+.work-meta {
+  margin: 16px 0;
+}
+
+.like-button {
+  margin-top: 10px;
+}
+
+/* 内容区域 */
+.work-content {
+  padding: 20px;
+  background: #f9f9f9;
+  border-radius: 4px;
+}
+
+/* Bug反馈区域 */
+.bug-report-section {
+  margin-top: 20px;
+}
+
+.bug-item {
+  width: 100%;
+  padding: 15px;
+  border: 1px solid #f0f0f0;
+  border-radius: 4px;
+  margin-bottom: 10px;
+}
+
+.bug-header {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 8px;
+}
+
+.bug-content {
+  margin: 10px 0;
+}
+
+/* 讨论区 */
+.discussion-section {
+  margin-top: 20px;
+}
+
+.discussion-container {
+  display: flex;
+  gap: 20px;
+}
+
+.discussion-list {
+  width: 300px;
+  border-right: 1px solid #f0f0f0;
+  padding-right: 20px;
+}
+
+.discussion-detail {
+  flex: 1;
+}
+
+.discussion-item {
+  padding: 15px;
+  cursor: pointer;
+  border-radius: 4px;
+  margin-bottom: 10px;
+  transition: all 0.3s;
+}
+
+.discussion-item:hover {
+  background: #f5f5f5;
+}
+
+.discussion-item.active {
+  background: #e6f7ff;
+  border-left: 3px solid #1890ff;
+}
+
+.discussion-detail-content {
+  padding: 20px;
+  background: #f9f9f9;
+  border-radius: 4px;
+  margin-bottom: 20px;
+}
+
+.discussion-title {
+  font-size: 18px;
+  display: block;
+  margin-bottom: 10px;
+}
+
+.discussion-meta {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 15px;
+}
+
+.discussion-body {
+  margin-bottom: 20px;
+}
+
+.comment-item {
+  padding: 15px 0;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.comment-header {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 10px;
+}
+
+.comment-actions {
+  margin-top: 10px;
+}
+
+.new-discussion-btn {
+  margin-bottom: 20px;
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+  .discussion-container {
+    flex-direction: column;
+  }
+  
+  .discussion-list {
+    width: 100%;
+    border-right: none;
+    padding-right: 0;
+    border-bottom: 1px solid #f0f0f0;
+    padding-bottom: 20px;
+    margin-bottom: 20px;
+  }
+}
\ No newline at end of file
diff --git a/src/feature/work/WorkPage.tsx b/src/feature/work/WorkPage.tsx
new file mode 100644
index 0000000..3a108a7
--- /dev/null
+++ b/src/feature/work/WorkPage.tsx
@@ -0,0 +1,131 @@
+import React, { useState, useEffect } from 'react';
+import { useParams, useNavigate } from 'react-router';
+import { Button, Tabs, message, Spin, Tag, Typography, Space, Divider } from 'antd';
+import { ArrowLeftOutlined, LikeOutlined, BugOutlined, CommentOutlined } from '@ant-design/icons';
+import WorkAPI from '../../api/workApi';
+import BugReportSection from '../../components/BugReportSection';
+import DiscussionSection from '../../components/DiscussionSection';
+import type { Work } from '../../api/otherType';
+
+const { Title, Text, Paragraph } = Typography;
+const { TabPane } = Tabs;
+
+const WorkPage: React.FC = () => {
+  const { id } = useParams<{ id: string }>();
+  const navigate = useNavigate();
+  const [work, setWork] = useState<Work | null>(null);
+  const [loading, setLoading] = useState(true);
+  const [activeTab, setActiveTab] = useState('details');
+
+  // 加载作品数据
+  useEffect(() => {
+    const loadWork = async () => {
+      try {
+        const workData = await WorkAPI.getWorkById(Number(id));
+        setWork(workData);
+      } catch (error) {
+        message.error('加载作品失败');
+        navigate('/');
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    loadWork();
+  }, [id, navigate]);
+
+  // 点赞处理
+  const handleLike = async () => {
+    try {
+      await WorkAPI.likeWork(Number(id));
+      setWork(prev => prev ? { ...prev, likes: prev.likes + 1 } : null);
+      message.success('点赞成功');
+    } catch (error) {
+      message.error('点赞失败');
+    }
+  };
+
+  if (loading) {
+    return <Spin size="large" className="center-spinner" />;
+  }
+
+  if (!work) {
+    return <div>作品不存在</div>;
+  }
+
+  return (
+    <div className="work-page-container">
+      <Button 
+        type="text" 
+        icon={<ArrowLeftOutlined />} 
+        onClick={() => navigate(-1)}
+        className="back-button"
+      >
+        返回
+      </Button>
+
+      <div className="work-header">
+        <Title level={2}>{work.title}</Title>
+        <Text type="secondary">作者: {work.author}</Text>
+        
+        <div className="work-meta">
+          <Space size="middle">
+            <Tag color="blue">{work.categoryName}</Tag>
+            <Text>浏览: {work.views}</Text>
+            <Text>点赞: {work.likes}</Text>
+            <Text>上传时间: {new Date(work.createTime).toLocaleDateString()}</Text>
+          </Space>
+        </div>
+
+        <Button 
+          type="primary" 
+          icon={<LikeOutlined />} 
+          onClick={handleLike}
+          className="like-button"
+        >
+          点赞
+        </Button>
+      </div>
+
+      <Divider />
+
+      <Tabs activeKey={activeTab} onChange={setActiveTab}>
+        <TabPane tab="作品详情" key="details">
+          <div className="work-content">
+            <Title level={4}>作品描述</Title>
+            <Paragraph>{work.description}</Paragraph>
+            
+            <Title level={4}>作品内容</Title>
+            <div className="content-container">
+              {work.content}
+            </div>
+          </div>
+        </TabPane>
+
+        <TabPane 
+          tab={
+            <span>
+              <BugOutlined /> Bug反馈
+            </span>
+          } 
+          key="bugs"
+        >
+          <BugReportSection workId={work.id} />
+        </TabPane>
+
+        <TabPane 
+          tab={
+            <span>
+              <CommentOutlined /> 交流区
+            </span>
+          } 
+          key="discussions"
+        >
+          <DiscussionSection workId={work.id} />
+        </TabPane>
+      </Tabs>
+    </div>
+  );
+};
+
+export default WorkPage;
\ No newline at end of file