diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 926f13e..51cbc86 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,5 +1,5 @@ # 构建阶段 -FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/node:18-alpine AS builder +FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/node:20-alpine AS builder # 设置工作目录 WORKDIR /app diff --git a/frontend/src/pages/Preview/PreviewPage.jsx b/frontend/src/pages/Preview/PreviewPage.jsx index 1ff2eea..0592b3a 100644 --- a/frontend/src/pages/Preview/PreviewPage.jsx +++ b/frontend/src/pages/Preview/PreviewPage.jsx @@ -202,6 +202,66 @@ function PreviewPage() { setTocItems(headings) } }, [markdownContent]) + // 解析相对路径 + const resolveRelativePath = (currentPath, relativePath) => { + if (relativePath.startsWith('/')) { + return relativePath.substring(1) + } + + const lastSlashIndex = currentPath.lastIndexOf('/') + const currentDir = lastSlashIndex !== -1 ? currentPath.substring(0, lastSlashIndex) : '' + + const parts = relativePath.split('/') + const dirParts = currentDir ? currentDir.split('/') : [] + + for (const part of parts) { + if (part === '..') { + dirParts.pop() + } else if (part !== '.' && part !== '') { + dirParts.push(part) + } + } + + return dirParts.join('/') + } + + // 处理 markdown 内部链接点击 + const handleMarkdownLink = (e, href) => { + if (!href || href.startsWith('http') || href.startsWith('//') || href.startsWith('#')) { + return + } + + const isMd = href.endsWith('.md') + const isPdf = href.toLowerCase().endsWith('.pdf') + + if (!isMd && !isPdf) return + + e.preventDefault() + + let decodedHref = href + try { + decodedHref = decodeURIComponent(href) + } catch (err) { + // ignore + } + + const targetPath = resolveRelativePath(selectedFile, decodedHref) + + const lastSlashIndex = targetPath.lastIndexOf('/') + const parentPath = lastSlashIndex !== -1 ? targetPath.substring(0, lastSlashIndex) : '' + if (parentPath && !openKeys.includes(parentPath)) { + const pathParts = parentPath.split('/') + const allParentPaths = [] + let currentPath = '' + for (const part of pathParts) { + currentPath = currentPath ? `${currentPath}/${part}` : part + allParentPaths.push(currentPath) + } + setOpenKeys([...new Set([...openKeys, ...allParentPaths])]) + } + + handleMenuClick({ key: targetPath }) + } // 处理菜单点击 const handleMenuClick = ({ key }) => { @@ -325,6 +385,17 @@ function PreviewPage() { ( + handleMarkdownLink(e, href)} + {...props} + > + {children} + + ), + }} > {markdownContent}