完成主页, 作品页,作品编辑页
> 未对接后端接口
Change-Id: I5d62663602656da4940707e00f76bfe09d824c2c
diff --git a/src/feature/home/Home.tsx b/src/feature/home/Home.tsx
index 80e44eb..953af8a 100644
--- a/src/feature/home/Home.tsx
+++ b/src/feature/home/Home.tsx
@@ -1,116 +1,223 @@
-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万' },
-];
+import React, { useEffect, useMemo } from 'react';
+import { useDispatch } from 'react-redux';
+import { Input, Spin, Alert } from 'antd';
+import { SearchOutlined } from '@ant-design/icons';
+import type { Section, Artwork } from './types';
+import { initializeArtworks, selectFilteredArtworks, selectSearchTerm, selectWorkListError, selectWorkListLoading, setSearchTerm } from './workListSlice';
+import { useAppSelector } from '../../store/hooks';
+import { selectSections, selectCategoryLoading, selectCategoryError, initializeSections } from './categorySlice';
+import Category from './Category';
-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 },
- ];
+const Home: React.FC = () => {
+ const dispatch = useDispatch();
- 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>
+ // 从Redux store获取状态
+ const sections = useAppSelector(selectSections);
+ const filteredArtworks = useAppSelector(selectFilteredArtworks);
+ const searchTerm = useAppSelector(selectSearchTerm);
+ const workListLoading = useAppSelector(selectWorkListLoading);
+ const workListError = useAppSelector(selectWorkListError);
+ const categoryLoading = useAppSelector(selectCategoryLoading);
+ const categoryError = useAppSelector(selectCategoryError);
- {/* 分区 + 排行榜 容器,改为 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)' }}
- />
+ // 综合加载状态和错误状态
+ const loading = workListLoading || categoryLoading;
+ const error = workListError || categoryError;
- {/* 渐变遮罩层 - 增强文字可读性 */}
- <div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent z-10"></div>
+ // 示例数据
+ const sampleSections: Section[] = [
+ {
+ id: 1,
+ childrenid: [1, 2, 3],
+ name: "数字艺术"
+ },
+ {
+ id: 2,
+ childrenid: [4, 5],
+ name: "传统绘画"
+ }
+ ];
- {/* 文字内容 */}
- <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>
+ const sampleArtworks: Artwork[] = [
+ {
+ id: 1,
+ title: "未来城市概念设计",
+ author: "视觉设计师张三",
+ views: 1247,
+ category: {
+ id: 1,
+ name: "数字艺术",
+ children: ["概念设计", "建筑设计"]
+ },
+ description: "一个关于2050年智慧城市的概念设计作品,融合了可持续发展、人工智能和绿色科技的理念",
+ createTime: "2024-01-15T10:30:00Z",
+ cover: "https://picsum.photos/300/200?random=1"
+ },
+ {
+ id: 2,
+ title: "移动应用界面设计套件",
+ author: "UI设计师李四",
+ views: 856,
+ category: {
+ id: 2,
+ name: "界面设计",
+ children: ["UI/UX设计", "移动端设计"]
+ },
+ description: "一套完整的移动端UI设计规范和组件库,包含100+个精美界面和500+个设计组件",
+ createTime: "2024-02-20T14:15:00Z",
+ cover: "https://picsum.photos/300/200?random=2"
+ },
+ {
+ id: 3,
+ title: "React组件库开发指南",
+ author: "刘松林",
+ views: 432,
+ category: {
+ id: 3,
+ name: "程序开发",
+ children: ["前端开发", "React技术"]
+ },
+ description: "一套完整的企业级React组件库开发教程和源码,包含从设计到发布的完整流程",
+ createTime: "2024-03-10T09:45:00Z",
+ cover: "https://picsum.photos/300/200?random=3"
+ },
+ {
+ id: 4,
+ title: "机械战士3D模型",
+ author: "3D艺术家王五",
+ views: 789,
+ category: {
+ id: 1,
+ name: "数字艺术",
+ children: ["3D建模", "科幻设计"]
+ },
+ description: "一个高精度的科幻机械战士3D模型,包含完整的材质贴图和动画骨骼系统",
+ createTime: "2024-01-25T16:20:00Z",
+ cover: "https://picsum.photos/300/200?random=4"
+ },
+ {
+ id: 5,
+ title: "城市夜景摄影集",
+ author: "摄影师赵六",
+ views: 1123,
+ category: {
+ id: 4,
+ name: "摄影艺术",
+ children: ["摄影作品", "城市风光"]
+ },
+ description: "一组精美的城市夜景摄影作品,捕捉了都市夜晚的璀璨光影",
+ createTime: "2024-02-14T11:30:00Z",
+ cover: "https://picsum.photos/300/200?random=5"
+ },
+ {
+ id: 6,
+ title: "奇幻世界插画系列",
+ author: "插画师孙七",
+ views: 945,
+ category: {
+ id: 5,
+ name: "插画艺术",
+ children: ["插画艺术", "奇幻风格"]
+ },
+ description: "一套充满想象力的奇幻题材插画作品,包含角色设计、场景概念图和完整插图",
+ createTime: "2024-03-05T13:20:00Z",
+ cover: "https://picsum.photos/300/200?random=6"
+ }
+ ];
- {/* 描述文本 - 悬停显示 */}
- <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>
+ // 初始化数据
+ useEffect(() => {
+ dispatch(initializeArtworks(sampleArtworks));
+ dispatch(initializeSections(sampleSections));
+ }, [dispatch]);
+
+ // 处理搜索输入
+ const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ dispatch(setSearchTerm(e.target.value));
+ };
+
+ // 根据分区ID获取对应的作品
+ const getArtworksBySection = useMemo(() => {
+ return (childrenIds: number[]): Artwork[] => {
+ return filteredArtworks.filter(artwork => childrenIds.includes(artwork.id));
+ };
+ }, [filteredArtworks]);
+
+ // 渲染加载状态
+ if (loading) {
+ return (
+ <div style={{
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ height: '100vh'
+ }}>
+ <Spin size="large" tip="加载中..." />
+ </div>
+ );
+ }
+
+ // 渲染错误状态
+ if (error) {
+ return (
+ <div style={{ padding: '24px' }}>
+ <Alert
+ message="加载失败"
+ description={error}
+ type="error"
+ showIcon
+ />
+ </div>
+ );
+ }
+
+ return (
+ <div style={{
+ backgroundColor: '#f5f5f5',
+ minHeight: '100vh',
+ padding: '24px'
+ }}>
+ <div style={{ maxWidth: 1200, margin: '0 auto' }}>
+ {/* 搜索栏 */}
+ <div style={{ marginBottom: '32px' }}>
+ <Input
+ size="large"
+ placeholder="搜索作品标题、作者、分类..."
+ prefix={<SearchOutlined />}
+ value={searchTerm}
+ onChange={handleSearchChange}
+ style={{ maxWidth: 600, width: '100%' }}
+ allowClear
+ />
</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>
- );
-}
+ {/* 分区展示 */}
+ {sections.map((section) => {
+ const sectionArtworks = getArtworksBySection(section.childrenid);
-export default Home;
\ No newline at end of file
+ return (
+ <Category
+ key={section.id}
+ section={section}
+ artworks={sectionArtworks}
+ />
+ );
+ })}
+
+ {/* 无搜索结果提示 */}
+ {searchTerm && filteredArtworks.length === 0 && (
+ <div style={{
+ textAlign: 'center',
+ padding: '48px 0',
+ color: '#999'
+ }}>
+ <p style={{ fontSize: 16 }}>未找到相关作品</p>
+ <p>尝试使用其他关键词搜索</p>
+ </div>
+ )}
+ </div>
+ </div>
+ );
+};
+
+export default Home;