完成Work组件的界面和一些小修改
> 1. 修改优化路由守卫
> 2. 去除拦截器中的调试信息
> 3. 修改头部导航条下拉菜单的样式增加图标。
> 4. work组件现在使用mock数据

Change-Id: Ic602a35bb02e645a0d5253c5cbd12a68d70bfb33
diff --git a/src/feature/work/EditWork.tsx b/src/feature/work/EditWork.tsx
new file mode 100644
index 0000000..f56d42a
--- /dev/null
+++ b/src/feature/work/EditWork.tsx
@@ -0,0 +1,753 @@
+import React, { useState, useCallback } from 'react';
+import {
+    Modal, Form, Input, Upload, Button, message, Space, Card,
+    Typography, Alert, List, Tag, Popconfirm, Row, Col,
+    type FormInstance
+} from 'antd';
+import {
+    EditOutlined, DeleteOutlined, PlusOutlined, InboxOutlined,
+    SaveOutlined, FileTextOutlined, UserOutlined
+} from '@ant-design/icons';
+import ReactMarkdown from 'react-markdown';
+import type {
+    UploadFile, UploadProps, UploadChangeParam, RcFile,
+} from 'antd/es/upload';
+import type {
+    ArtworkData, VersionFormData, Comment,
+} from './types';
+
+const { TextArea } = Input;
+const { Dragger } = Upload;
+const { Text } = Typography;
+
+// ==================== 工具函数 ====================
+const getBase64 = (file: RcFile): Promise<string> =>
+    new Promise((resolve, reject) => {
+        const reader = new FileReader();
+        reader.readAsDataURL(file);
+        reader.onload = (): void => resolve(reader.result as string);
+        reader.onerror = (error): void => reject(error);
+    });
+
+// ==================== 类型定义 ====================
+interface EditCoverProps {
+    visible: boolean;
+    currentCover: string;
+    onCancel: () => void;
+    onSave: (coverUrl: string) => Promise<void>;
+}
+
+interface EditDescriptionProps {
+    visible: boolean;
+    currentDescription: string;
+    onCancel: () => void;
+    onSave: (description: string) => Promise<void>;
+}
+
+interface EditVersionsProps {
+    visible: boolean;
+    versions: VersionFormData[];
+    onCancel: () => void;
+    onSave: (versions: VersionFormData[]) => Promise<void>;
+}
+
+interface CommentItemProps {
+    comment: Comment;
+    isAuthor: boolean;
+    onDelete: (commentId: string) => Promise<void>;
+    level?: number;
+}
+
+interface EditWorkControlsProps {
+    artwork: ArtworkData;
+    isAuthor: boolean;
+    onUpdate: (updatedArtwork: Partial<ArtworkData>) => Promise<void>;
+    onDeleteComment: (commentId: string) => Promise<void>;
+}
+
+interface VersionItemProps {
+    version: VersionFormData;
+    index: number;
+    onEdit: (index: number) => void;
+    onDelete: (index: number) => void;
+}
+
+interface VersionEditFormProps {
+    form: FormInstance<VersionFormData>;
+    version: VersionFormData;
+    onSave: () => void;
+    onCancel: () => void;
+    onFileChange: (file: UploadFile | undefined) => void;
+}
+
+// ==================== 封面编辑组件 ====================
+export const EditWorkCover: React.FC<EditCoverProps> = ({
+    visible,
+    currentCover,
+    onCancel,
+    onSave
+}) => {
+    const [fileList, setFileList] = useState<UploadFile[]>([]);
+    const [previewImage, setPreviewImage] = useState<string>('');
+    const [previewOpen, setPreviewOpen] = useState<boolean>(false);
+    const [uploading, setUploading] = useState<boolean>(false);
+
+    const handleChange: UploadProps['onChange'] = useCallback((info: UploadChangeParam<UploadFile>): void => {
+        setFileList(info.fileList);
+    }, []);
+
+    const handlePreview = useCallback(async (file: UploadFile): Promise<void> => {
+        if (!file.url && !file.preview) {
+            file.preview = await getBase64(file.originFileObj as RcFile);
+        }
+        setPreviewImage(file.url || (file.preview as string));
+        setPreviewOpen(true);
+    }, []);
+
+    const beforeUpload = useCallback((file: RcFile): boolean => {
+        const isImage = file.type.startsWith('image/');
+        if (!isImage) {
+            message.error('只能上传图片文件!');
+            return false;
+        }
+        const isLt5M = file.size / 1024 / 1024 < 5;
+        if (!isLt5M) {
+            message.error('图片大小不能超过 5MB!');
+            return false;
+        }
+        return false; // 阻止自动上传
+    }, []);
+
+    const handleSave = useCallback(async (): Promise<void> => {
+        if (fileList.length === 0) {
+            message.error('请选择要上传的封面图片');
+            return;
+        }
+
+        setUploading(true);
+        try {
+            // 模拟上传过程
+            const file = fileList[0];
+            const coverUrl = file.preview || URL.createObjectURL(file.originFileObj as RcFile);
+
+            await onSave(coverUrl);
+            message.success('封面更新成功!');
+            onCancel();
+        } catch {
+            message.error('封面更新失败,请重试');
+        } finally {
+            setUploading(false);
+        }
+    }, [fileList, onSave, onCancel]);
+
+    return (
+        <>
+            <Modal
+                title="编辑作品封面"
+                open={visible}
+                onCancel={onCancel}
+                footer={[
+                    <Button key="cancel" onClick={onCancel}>
+                        取消
+                    </Button>,
+                    <Button
+                        key="save"
+                        type="primary"
+                        loading={uploading}
+                        onClick={handleSave}
+                        icon={<SaveOutlined />}
+                    >
+                        保存
+                    </Button>,
+                ]}
+                width={600}
+            >
+                <div style={{ marginBottom: 16 }}>
+                    <Text strong>当前封面:</Text>
+                    <div style={{ marginTop: 8 }}>
+                        <img
+                            src={currentCover}
+                            alt="当前封面"
+                            style={{ maxWidth: '100%', maxHeight: 200, objectFit: 'cover' }}
+                        />
+                    </div>
+                </div>
+
+                <Alert
+                    message="新封面要求"
+                    description="图片格式:JPG、PNG、GIF;大小不超过 5MB;建议尺寸:宽高比 3:4"
+                    type="info"
+                    showIcon
+                    style={{ marginBottom: 16 }}
+                />
+
+                <Upload
+                    listType="picture-card"
+                    fileList={fileList}
+                    onChange={handleChange}
+                    onPreview={handlePreview}
+                    beforeUpload={beforeUpload}
+                    maxCount={1}
+                    accept="image/*"
+                >
+                    {fileList.length === 0 && (
+                        <div>
+                            <PlusOutlined />
+                            <div style={{ marginTop: 8 }}>选择新封面</div>
+                        </div>
+                    )}
+                </Upload>
+            </Modal>
+
+            <Modal
+                open={previewOpen}
+                title="图片预览"
+                footer={null}
+                onCancel={(): void => setPreviewOpen(false)}
+            >
+                <img alt="预览" style={{ width: '100%' }} src={previewImage} />
+            </Modal>
+        </>
+    );
+};
+
+// ==================== 作品描述编辑组件 ====================
+export const EditWorkDescription: React.FC<EditDescriptionProps> = ({
+    visible,
+    currentDescription,
+    onCancel,
+    onSave
+}) => {
+    const [form] = Form.useForm<{ description: string }>();
+    const [previewMode, setPreviewMode] = useState<boolean>(false);
+    const [saving, setSaving] = useState<boolean>(false);
+
+    const handleSave = useCallback(async (): Promise<void> => {
+        try {
+            const values = await form.validateFields();
+            setSaving(true);
+            await onSave(values.description);
+            message.success('作品描述更新成功!');
+            onCancel();
+        } catch (error) {
+            if (error && typeof error === 'object' && 'errorFields' in error) {
+                message.error('请检查输入内容');
+            } else {
+                message.error('更新失败,请重试');
+            }
+        } finally {
+            setSaving(false);
+        }
+    }, [form, onSave, onCancel]);
+
+    const handlePreview = useCallback((): void => {
+        form.validateFields().then(() => {
+            setPreviewMode(true);
+        }).catch(() => {
+            message.error('请先填写完整信息');
+        });
+    }, [form]);
+
+    return (
+        <>
+            <Modal
+                title="编辑作品描述"
+                open={visible}
+                onCancel={onCancel}
+                footer={[
+                    <Button key="preview" onClick={handlePreview}>
+                        预览
+                    </Button>,
+                    <Button key="cancel" onClick={onCancel}>
+                        取消
+                    </Button>,
+                    <Button
+                        key="save"
+                        type="primary"
+                        loading={saving}
+                        onClick={handleSave}
+                        icon={<SaveOutlined />}
+                    >
+                        保存
+                    </Button>,
+                ]}
+                width={800}
+            >
+                <Form
+                    form={form}
+                    layout="vertical"
+                    initialValues={{ description: currentDescription }}
+                >
+                    <Form.Item
+                        label="作品描述"
+                        name="description"
+                        rules={[
+                            { required: true, message: '请输入作品描述' },
+                            { min: 20, message: '作品描述至少20个字符' },
+                            { max: 2000, message: '作品描述最多2000个字符' },
+                        ]}
+                        extra="支持 Markdown 格式,可以使用 # 标题、**粗体**、*斜体* 等格式"
+                    >
+                        <TextArea
+                            placeholder="请详细描述你的作品,包括创作理念、技术特点、使用说明等"
+                            rows={12}
+                            showCount
+                            maxLength={2000}
+                        />
+                    </Form.Item>
+                </Form>
+            </Modal>
+
+            <Modal
+                title="作品描述预览"
+                open={previewMode}
+                onCancel={(): void => setPreviewMode(false)}
+                footer={null}
+                width={800}
+            >
+                <div style={{ maxHeight: '60vh', overflow: 'auto' }}>
+                    <ReactMarkdown>{form.getFieldValue('description') || ''}</ReactMarkdown>
+                </div>
+            </Modal>
+        </>
+    );
+};
+
+// ==================== 版本编辑相关组件 ====================
+const VersionItem: React.FC<VersionItemProps> = ({
+    version,
+    index,
+    onEdit,
+    onDelete
+}) => {
+    return (
+        <Row align="middle" style={{ width: '100%' }}>
+            <Col span={20}>
+                <Space direction="vertical" style={{ width: '100%' }}>
+                    <Space>
+                        <Tag color="blue">v{version.version}</Tag>
+                        <Text strong>{version.versionDescription}</Text>
+                    </Space>
+                    {version.seedFile && (
+                        <Space>
+                            <FileTextOutlined />
+                            <Text type="secondary">{version.seedFile.name}</Text>
+                        </Space>
+                    )}
+                </Space>
+            </Col>
+            <Col span={4} style={{ textAlign: 'right' }}>
+                <Space>
+                    <Button
+                        type="text"
+                        icon={<EditOutlined />}
+                        onClick={(): void => onEdit(index)}
+                    />
+                    <Popconfirm
+                        title="确定要删除这个版本吗?"
+                        onConfirm={(): void => onDelete(index)}
+                        okText="确定"
+                        cancelText="取消"
+                    >
+                        <Button type="text" danger icon={<DeleteOutlined />} />
+                    </Popconfirm>
+                </Space>
+            </Col>
+        </Row>
+    );
+};
+
+const VersionEditForm: React.FC<VersionEditFormProps> = ({
+    form,
+    version,
+    onSave,
+    onCancel,
+    onFileChange
+}) => {
+    const beforeUpload = useCallback((file: RcFile): boolean => {
+        const isLt100M = file.size / 1024 / 1024 < 100;
+        if (!isLt100M) {
+            message.error('种子文件大小不能超过 100MB!');
+            return false;
+        }
+        return false;
+    }, []);
+
+    return (
+        <div style={{ width: '100%' }}>
+            <Form form={form} layout="vertical" initialValues={version}>
+                <Row gutter={16}>
+                    <Col span={6}>
+                        <Form.Item
+                            label="版本号"
+                            name="version"
+                            rules={[{ required: true, message: '请输入版本号' }]}
+                        >
+                            <Input placeholder="例如:1.0" />
+                        </Form.Item>
+                    </Col>
+                    <Col span={18}>
+                        <Form.Item
+                            label="版本描述"
+                            name="versionDescription"
+                            rules={[
+                                { required: true, message: '请输入版本描述' },
+                                { min: 10, message: '版本描述至少10个字符' },
+                            ]}
+                        >
+                            <TextArea
+                                placeholder="描述此版本的更新内容、新增功能等"
+                                rows={3}
+                                showCount
+                                maxLength={500}
+                            />
+                        </Form.Item>
+                    </Col>
+                </Row>
+
+                <Form.Item label="种子文件">
+                    <Dragger
+                        maxCount={1}
+                        beforeUpload={beforeUpload}
+                        fileList={version.seedFile ? [version.seedFile] : []}
+                        onChange={({ fileList }): void => onFileChange(fileList[0])}
+                        onRemove={(): void => onFileChange(undefined)}
+                    >
+                        <p className="ant-upload-drag-icon"><InboxOutlined /></p>
+                        <p className="ant-upload-text">点击或拖拽文件到此区域上传</p>
+                        <p className="ant-upload-hint">支持单个文件上传,文件大小不超过 100MB</p>
+                    </Dragger>
+                </Form.Item>
+
+                <Space>
+                    <Button type="primary" onClick={onSave}>
+                        保存
+                    </Button>
+                    <Button onClick={onCancel}>
+                        取消
+                    </Button>
+                </Space>
+            </Form>
+        </div>
+    );
+};
+
+// ==================== 版本管理组件 ====================
+export const EditWorkVersions: React.FC<EditVersionsProps> = ({
+    visible,
+    versions,
+    onCancel,
+    onSave
+}) => {
+    const [localVersions, setLocalVersions] = useState<VersionFormData[]>(versions);
+    const [editingIndex, setEditingIndex] = useState<number | null>(null);
+    const [form] = Form.useForm<VersionFormData>();
+    const [saving, setSaving] = useState<boolean>(false);
+
+    const handleAddVersion = useCallback((): void => {
+        const newVersion: VersionFormData = {
+            version: `${localVersions.length + 1}.0`,
+            versionDescription: '',
+            seedFile: undefined,
+        };
+        setLocalVersions([...localVersions, newVersion]);
+        setEditingIndex(localVersions.length);
+    }, [localVersions]);
+
+    const handleSaveVersion = useCallback((index: number): void => {
+        form.validateFields().then((values) => {
+            const newVersions = [...localVersions];
+            newVersions[index] = { ...newVersions[index], ...values };
+            setLocalVersions(newVersions);
+            setEditingIndex(null);
+            form.resetFields();
+            message.success('版本信息已保存');
+        }).catch(() => {
+            message.error('请完整填写版本信息');
+        });
+    }, [form, localVersions]);
+
+    const handleDeleteVersion = useCallback((index: number): void => {
+        const newVersions = localVersions.filter((_, i) => i !== index);
+        setLocalVersions(newVersions);
+        if (editingIndex === index) {
+            setEditingIndex(null);
+        }
+    }, [localVersions, editingIndex]);
+
+    const handleFileChange = useCallback((index: number, file: UploadFile | undefined): void => {
+        const newVersions = [...localVersions];
+        newVersions[index].seedFile = file;
+        setLocalVersions(newVersions);
+    }, [localVersions]);
+
+    const handleSave = useCallback(async (): Promise<void> => {
+        if (localVersions.length === 0) {
+            message.error('至少需要保留一个版本');
+            return;
+        }
+
+        const incompleteVersion = localVersions.find((v, index) =>
+            !v.version || !v.versionDescription || !v.seedFile || index === editingIndex
+        );
+
+        if (incompleteVersion) {
+            message.error('请完成所有版本的信息填写');
+            return;
+        }
+
+        setSaving(true);
+        try {
+            await onSave(localVersions);
+            message.success('版本信息更新成功!');
+            onCancel();
+        } catch {
+            message.error('更新失败,请重试');
+        } finally {
+            setSaving(false);
+        }
+    }, [localVersions, editingIndex, onSave, onCancel]);
+
+    return (
+        <Modal
+            title="编辑版本信息"
+            open={visible}
+            onCancel={onCancel}
+            footer={[
+                <Button key="cancel" onClick={onCancel}>
+                    取消
+                </Button>,
+                <Button
+                    key="save"
+                    type="primary"
+                    loading={saving}
+                    onClick={handleSave}
+                    icon={<SaveOutlined />}
+                >
+                    保存所有更改
+                </Button>,
+            ]}
+            width={900}
+        >
+            <div style={{ maxHeight: '60vh', overflow: 'auto' }}>
+                <List
+                    dataSource={localVersions}
+                    renderItem={(version, index): React.ReactElement => (
+                        <List.Item
+                            key={index}
+                            style={{
+                                background: editingIndex === index ? '#fafafa' : 'transparent',
+                                padding: 16,
+                                marginBottom: 16,
+                                border: '1px solid #f0f0f0',
+                                borderRadius: 8,
+                            }}
+                        >
+                            {editingIndex === index ? (
+                                <VersionEditForm
+                                    form={form}
+                                    version={version}
+                                    onSave={(): void => handleSaveVersion(index)}
+                                    onCancel={(): void => setEditingIndex(null)}
+                                    onFileChange={(file): void => handleFileChange(index, file)}
+                                />
+                            ) : (
+                                <VersionItem
+                                    version={version}
+                                    index={index}
+                                    onEdit={(idx): void => {
+                                        setEditingIndex(idx);
+                                        form.setFieldsValue(version);
+                                    }}
+                                    onDelete={handleDeleteVersion}
+                                />
+                            )}
+                        </List.Item>
+                    )}
+                />
+
+                {editingIndex === null && (
+                    <Button
+                        type="dashed"
+                        onClick={handleAddVersion}
+                        style={{ width: '100%', marginTop: 16 }}
+                        icon={<PlusOutlined />}
+                    >
+                        添加新版本
+                    </Button>
+                )}
+            </div>
+        </Modal>
+    );
+};
+
+// ==================== 评论管理组件 ====================
+export const EditWorkComment: React.FC<CommentItemProps> = ({
+    comment,
+    isAuthor,
+    onDelete,
+    level = 0
+}) => {
+    const [deleting, setDeleting] = useState<boolean>(false);
+
+    const handleDelete = useCallback(async (): Promise<void> => {
+        if (!comment.id) return;
+
+        setDeleting(true);
+        try {
+            await onDelete(comment.id);
+            message.success('评论删除成功');
+        } catch {
+            message.error('删除失败,请重试');
+        } finally {
+            setDeleting(false);
+        }
+    }, [comment.id, onDelete]);
+
+    return (
+        <div style={{ marginLeft: level * 24 }}>
+            <div
+                style={{
+                    background: '#fafafa',
+                    padding: 12,
+                    borderRadius: 8,
+                    marginBottom: 8,
+                }}
+            >
+                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
+                    <div style={{ flex: 1 }}>
+                        <Space style={{ marginBottom: 8 }}>
+                            <UserOutlined />
+                            <Text strong>{comment.author}</Text>
+                            {comment.createdAt && (
+                                <Text type="secondary" style={{ fontSize: 12 }}>
+                                    {new Date(comment.createdAt).toLocaleString()}
+                                </Text>
+                            )}
+                        </Space>
+                        <div>
+                            <Text>{comment.content}</Text>
+                        </div>
+                    </div>
+
+                    {isAuthor && comment.id && (
+                        <Popconfirm
+                            title="确定要删除这条评论吗?"
+                            onConfirm={handleDelete}
+                            okText="确定"
+                            cancelText="取消"
+                        >
+                            <Button
+                                type="text"
+                                danger
+                                size="small"
+                                icon={<DeleteOutlined />}
+                                loading={deleting}
+                            />
+                        </Popconfirm>
+                    )}
+                </div>
+            </div>
+
+            {/* 递归渲染子评论 */}
+            {comment.child && comment.child.length > 0 && (
+                <div>
+                    {comment.child.map((childComment, index) => (
+                        <EditWorkComment
+                            key={childComment.id || index}
+                            comment={childComment}
+                            isAuthor={isAuthor}
+                            onDelete={onDelete}
+                            level={level + 1}
+                        />
+                    ))}
+                </div>
+            )}
+        </div>
+    );
+};
+
+// ==================== 主编辑控制器组件 ====================
+export const EditWorkControls: React.FC<EditWorkControlsProps> = ({
+    artwork,
+    isAuthor,
+    onUpdate,
+}) => {
+    const [editCoverVisible, setEditCoverVisible] = useState<boolean>(false);
+    const [editDescriptionVisible, setEditDescriptionVisible] = useState<boolean>(false);
+    const [editVersionsVisible, setEditVersionsVisible] = useState<boolean>(false);
+
+    const handleUpdateCover = useCallback(async (coverUrl: string): Promise<void> => {
+        await onUpdate({ artworkCover: coverUrl });
+    }, [onUpdate]);
+
+    const handleUpdateDescription = useCallback(async (description: string): Promise<void> => {
+        await onUpdate({ artworkDescription: description });
+    }, [onUpdate]);
+
+    const handleUpdateVersions = useCallback(async (versions: VersionFormData[]): Promise<void> => {
+        // 转换为展示用的版本格式
+        const versionList = versions.map(v => ({
+            version: v.version,
+            versionDescription: v.versionDescription,
+            seedFile: v.seedFile?.name || '',
+        }));
+        await onUpdate({ versionList });
+    }, [onUpdate]);
+
+    if (!isAuthor) {
+        return null;
+    }
+
+    return (
+        <>
+            <Card title="作者管理" style={{ marginBottom: 24 }}>
+                <Space wrap>
+                    <Button
+                        icon={<EditOutlined />}
+                        onClick={(): void => setEditCoverVisible(true)}
+                    >
+                        编辑封面
+                    </Button>
+                    <Button
+                        icon={<EditOutlined />}
+                        onClick={(): void => setEditDescriptionVisible(true)}
+                    >
+                        编辑描述
+                    </Button>
+                    <Button
+                        icon={<EditOutlined />}
+                        onClick={(): void => setEditVersionsVisible(true)}
+                    >
+                        管理版本
+                    </Button>
+                </Space>
+            </Card>
+
+            <EditWorkCover
+                visible={editCoverVisible}
+                currentCover={artwork.artworkCover}
+                onCancel={(): void => setEditCoverVisible(false)}
+                onSave={handleUpdateCover}
+            />
+
+            <EditWorkDescription
+                visible={editDescriptionVisible}
+                currentDescription={artwork.artworkDescription}
+                onCancel={(): void => setEditDescriptionVisible(false)}
+                onSave={handleUpdateDescription}
+            />
+
+            <EditWorkVersions
+                visible={editVersionsVisible}
+                versions={artwork.versionList.map(v => ({
+                    version: v.version,
+                    versionDescription: v.versionDescription,
+                    seedFile: { name: v.seedFile } as UploadFile,
+                }))}
+                onCancel={(): void => setEditVersionsVisible(false)}
+                onSave={handleUpdateVersions}
+            />
+        </>
+    );
+};
\ No newline at end of file