fix: 修复文档转换与预览链路中的图片、文件名和错误处理问题
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Document;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class DocumentPreviewService
|
||||
{
|
||||
@@ -11,8 +10,6 @@ class DocumentPreviewService
|
||||
* 将文档的 Markdown 内容转换为 HTML 用于预览
|
||||
* 统一用于 Filament 后台内联预览和独立预览页面
|
||||
*
|
||||
* @param Document $document
|
||||
* @return string HTML 内容
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function convertToHtml(Document $document): string
|
||||
@@ -23,8 +20,6 @@ class DocumentPreviewService
|
||||
/**
|
||||
* 将 Markdown 转换为 HTML
|
||||
*
|
||||
* @param Document $document
|
||||
* @return string HTML 内容
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function convertMarkdownToHtml(Document $document): string
|
||||
@@ -35,30 +30,57 @@ class DocumentPreviewService
|
||||
throw new \Exception('Markdown 内容为空');
|
||||
}
|
||||
|
||||
// 获取 Markdown 文件的目录
|
||||
$markdownDir = dirname($document->markdown_path);
|
||||
app(DocumentConversionService::class)->ensureMarkdownMediaAssets($document);
|
||||
|
||||
// 修复图片路径:将 ./media/ 替换为 /markdown/{dir}/media/
|
||||
$markdownContent = preg_replace_callback(
|
||||
'/\(\.\/media\/([^)]+)\)/',
|
||||
function ($matches) use ($markdownDir) {
|
||||
$filename = $matches[1];
|
||||
return '(/markdown/' . $markdownDir . '/media/' . $filename . ')';
|
||||
},
|
||||
$markdownContent
|
||||
);
|
||||
$markdownContent = $this->stripPreviewFrontMatter($markdownContent);
|
||||
$markdownContent = $this->rewriteMarkdownMediaPaths($document, $markdownContent);
|
||||
|
||||
// 使用 MarkdownRenderService 转换为 HTML
|
||||
$renderService = app(MarkdownRenderService::class);
|
||||
|
||||
return $renderService->render($markdownContent);
|
||||
}
|
||||
|
||||
protected function stripPreviewFrontMatter(string $markdownContent): string
|
||||
{
|
||||
if (!preg_match('/\A---\R(?P<frontmatter>.*?\R)---\R*/s', $markdownContent, $matches)) {
|
||||
return $markdownContent;
|
||||
}
|
||||
|
||||
$frontMatter = $matches['frontmatter'] ?? '';
|
||||
|
||||
if (!preg_match('/^(author|source_file):/m', $frontMatter)) {
|
||||
return $markdownContent;
|
||||
}
|
||||
|
||||
return (string) preg_replace('/\A---\R.*?\R---\R*/s', '', $markdownContent, 1);
|
||||
}
|
||||
|
||||
protected function rewriteMarkdownMediaPaths(Document $document, string $markdownContent): string
|
||||
{
|
||||
$documentDir = dirname($document->markdown_path);
|
||||
|
||||
return (string) preg_replace_callback(
|
||||
'/!\[(?<alt>[^\]]*)]\((?<path>(?:\.\/)?media\/[^)]+)\)/',
|
||||
function (array $matches) use ($documentDir): string {
|
||||
$relativePath = trim($matches['path'] ?? '');
|
||||
$relativePath = preg_replace('/^\.?\//', '', $relativePath) ?? $relativePath;
|
||||
$relativePath = ltrim(str_replace('\\', '/', $relativePath), '/');
|
||||
|
||||
$segments = array_filter(
|
||||
explode('/', $documentDir . '/' . $relativePath),
|
||||
fn (string $segment): bool => $segment !== ''
|
||||
);
|
||||
|
||||
$url = '/markdown-media/' . implode('/', array_map('rawurlencode', $segments));
|
||||
|
||||
return sprintf('', $matches['alt'] ?? '', $url);
|
||||
},
|
||||
$markdownContent
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文档是否可以预览
|
||||
*
|
||||
* @param Document $document
|
||||
* @return bool
|
||||
*/
|
||||
public function canPreview(Document $document): bool
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user