保存本地对routes.ts的修改
Change-Id: I4f4dbd8069893d7363e251130791dc0594be44e1
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