import { useState, useEffect, useRef } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { Layout, Button, Modal, Input, Spin, Anchor } from 'antd' import { CloseOutlined, LockOutlined, MenuFoldOutlined, MenuUnfoldOutlined, FileTextOutlined } from '@ant-design/icons' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import rehypeHighlight from 'rehype-highlight' import rehypeSlug from 'rehype-slug' import 'highlight.js/styles/github.css' import GithubSlugger from 'github-slugger' import Toast from '@/components/Toast/Toast' import DocFloatActions from '@/components/DocFloatActions/DocFloatActions' import VirtualPDFViewer from '@/components/PDFViewer/VirtualPDFViewer' import { getFileSharePublicInfo, verifyFileSharePassword, getFileShareContent, exportFileSharePDF, } from '@/api/share' import './PreviewPage.css' const { Content, Sider } = Layout function FileSharePage() { const { shareCode } = useParams() const navigate = useNavigate() const contentRef = useRef(null) const [shareInfo, setShareInfo] = useState(null) const [contentInfo, setContentInfo] = useState(null) const [loading, setLoading] = useState(true) const [isMobile, setIsMobile] = useState(false) const [tocCollapsed, setTocCollapsed] = useState(false) const [tocItems, setTocItems] = useState([]) const [passwordModalVisible, setPasswordModalVisible] = useState(false) const [password, setPassword] = useState('') useEffect(() => { loadFileShare() }, [shareCode]) useEffect(() => { const checkMobile = () => setIsMobile(window.innerWidth < 768) checkMobile() window.addEventListener('resize', checkMobile) return () => window.removeEventListener('resize', checkMobile) }, []) useEffect(() => { const markdownContent = contentInfo?.type === 'markdown' ? (contentInfo.content || '') : '' if (!markdownContent) { setTocItems([]) return } const slugger = new GithubSlugger() const headings = [] markdownContent.split('\n').forEach((line) => { const match = line.match(/^(#{1,6})\s+(.+)$/) if (!match) return const level = match[1].length const title = match[2].trim() const key = slugger.slug(title) headings.push({ key: `#${key}`, href: `#${key}`, title, level }) }) setTocItems(headings) }, [contentInfo]) const handleClose = () => { if (window.history.length > 1) { navigate(-1) return } navigate('/') } const loadFileShare = async () => { setLoading(true) try { const infoRes = await getFileSharePublicInfo(shareCode) setShareInfo(infoRes.data) if (infoRes.data.has_password) { setContentInfo(null) setPasswordModalVisible(true) setLoading(false) return } const contentRes = await getFileShareContent(shareCode) setContentInfo(contentRes.data) } catch (error) { console.error('Load file share error:', error) Toast.error('加载失败', '分享链接不存在或已失效') } finally { setLoading(false) } } const handleVerifyPassword = async () => { if (!password.trim()) { Toast.warning('提示', '请输入访问密码') return } try { await verifyFileSharePassword(shareCode, password) const contentRes = await getFileShareContent(shareCode, password) setContentInfo(contentRes.data) setPasswordModalVisible(false) Toast.success('验证成功') } catch (error) { Toast.error('访问密码错误') } } const handleExportPDF = () => { if (!contentInfo || contentInfo.type === 'pdf') return window.open(exportFileSharePDF(shareCode), '_blank') } return (
{shareInfo.project_name}
}该文件分享需要访问密码,请输入密码后继续浏览。