add:修改使用reportlab完成md转pdf

This commit is contained in:
2026-01-15 23:45:46 +08:00
parent cecc8c65be
commit 0cc1a9484e
7 changed files with 436 additions and 299 deletions

View File

@@ -2734,11 +2734,17 @@ async def api_pdf_convert(
# Return PDF file # Return PDF file
if download: if download:
from fastapi.responses import StreamingResponse from fastapi.responses import StreamingResponse
import urllib.parse
# 处理中文文件名 - 使用 URL 编码确保只包含 ASCII 字符
# 先将中文文件名进行百分比编码
safe_filename = urllib.parse.quote(output_filename, safe='')
return StreamingResponse( return StreamingResponse(
io.BytesIO(pdf_bytes), io.BytesIO(pdf_bytes),
media_type="application/pdf", media_type="application/pdf",
headers={ headers={
"Content-Disposition": f"attachment; filename=\"{output_filename}\"" "Content-Disposition": f"attachment; filename={safe_filename}"
} }
) )
else: else:

View File

@@ -38,6 +38,28 @@ except Exception:
HTML = None HTML = None
CSS = None CSS = None
try:
from xhtml2pdf import pisa as _pisa # type: ignore
_HAS_XHTML2PDF: bool = True
except Exception:
_pisa = None # type: ignore
_HAS_XHTML2PDF: bool = False
# reportlab 用于生成支持中文的 PDF
try:
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak
from reportlab.lib import colors
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
_HAS_REPORTLAB: bool = True
except Exception:
A4 = None
_HAS_REPORTLAB: bool = False
_mdit: Any = None _mdit: Any = None
_tasklists_plugin: Any = None _tasklists_plugin: Any = None
_deflist_plugin: Any = None _deflist_plugin: Any = None
@@ -688,6 +710,214 @@ def _stylesheets_for(css_name: Optional[str], css_text: Optional[str]):
sheets.append(CSS(filename=str(css_path))) sheets.append(CSS(filename=str(css_path)))
return sheets return sheets
def _render_pdf_with_reportlab(md: str) -> bytes:
"""
使用 reportlab 生成支持中文的 PDF纯 Python无外部依赖
"""
print(f"[DEBUG] _render_pdf_with_reportlab 被调用, md 长度: {len(md)}")
bio = io.BytesIO()
# 创建 PDF 文档
doc = SimpleDocTemplate(
bio,
pagesize=A4,
rightMargin=20*mm,
leftMargin=20*mm,
topMargin=20*mm,
bottomMargin=20*mm,
)
# 存放 PDF 元素的列表
story = []
styles = getSampleStyleSheet()
# 尝试注册中文字体
try:
# Windows 系统字体
font_path = r"C:\Windows\Fonts\msyh.ttc" # 微软雅黑
if Path(font_path).exists():
pdfmetrics.registerFont(TTFont('ChineseFont', font_path, subfontIndex=0))
chinese_font = 'ChineseFont'
else:
# 尝试其他常见字体路径
alternative_fonts = [
r"C:\Windows\Fonts\simhei.ttf", # 黑体
r"C:\Windows\Fonts\simsun.ttc", # 宋体
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc", # Linux
"/System/Library/Fonts/PingFang.ttc", # macOS
]
chinese_font = 'Helvetica' # 默认
for font in alternative_fonts:
if Path(font).exists():
try:
pdfmetrics.registerFont(TTFont('ChineseFont', font))
chinese_font = 'ChineseFont'
break
except:
continue
except Exception:
chinese_font = 'Helvetica'
# 创建支持中文的样式
title_style = ParagraphStyle(
'ChineseTitle',
parent=styles['Heading1'],
fontName=chinese_font,
fontSize=18,
textColor=colors.black,
spaceAfter=12,
spaceBefore=12,
)
heading2_style = ParagraphStyle(
'ChineseHeading2',
parent=styles['Heading2'],
fontName=chinese_font,
fontSize=14,
textColor=colors.black,
spaceAfter=10,
spaceBefore=10,
)
normal_style = ParagraphStyle(
'ChineseNormal',
parent=styles['Normal'],
fontName=chinese_font,
fontSize=10,
textColor=colors.black,
spaceAfter=8,
wordWrap='CJK', # 中文换行支持
)
code_style = ParagraphStyle(
'ChineseCode',
parent=styles['Code'],
fontName='Courier',
fontSize=9,
textColor=colors.black,
backColor=colors.lightgrey,
leftIndent=10,
)
# 解析 markdown
lines = md.split('\n')
in_code_block = False
code_lines = []
for line in lines:
# 代码块处理
if line.strip().startswith('```'):
if in_code_block:
# 代码块结束
code_text = '\n'.join(code_lines)
story.append(Paragraph(code_text.replace('<', '&lt;').replace('>', '&gt;'), code_style))
story.append(Spacer(1, 6*mm))
code_lines = []
in_code_block = False
else:
in_code_block = True
continue
if in_code_block:
code_lines.append(line)
continue
# 标题处理
if line.startswith('# '):
text = line[2:].strip()
story.append(Paragraph(text, title_style))
elif line.startswith('## '):
text = line[3:].strip()
story.append(Paragraph(text, heading2_style))
elif line.startswith('### '):
text = line[4:].strip()
story.append(Paragraph(text, heading2_style))
# 列表处理
elif line.strip().startswith('- ') or line.strip().startswith('* '):
text = line.strip()[2:]
story.append(Paragraph(f'{text}', normal_style))
elif re.match(r'^\d+\.\s', line.strip()):
text = re.sub(r'^\d+\.\s', '', line.strip())
story.append(Paragraph(text, normal_style))
# 空行
elif not line.strip():
story.append(Spacer(1, 3*mm))
# 普通段落
elif line.strip():
# 处理粗体和斜体
text = line.strip()
text = re.sub(r'\*\*(.+?)\*\*', r'<b>\1</b>', text)
text = re.sub(r'\*(.+?)\*', r'<i>\1</i>', text)
text = re.sub(r'`(.+?)`', r'<font face="Courier">\1</font>', text)
story.append(Paragraph(text, normal_style))
# 生成 PDF
doc.build(story)
return bio.getvalue()
def _render_pdf_with_xhtml2pdf(md: str, html: str, css_name: Optional[str], css_text: Optional[str]) -> bytes:
"""
使用 xhtml2pdf 渲染 PDF纯 Python无外部依赖
"""
# 使用简单的 markdown 转 HTML避免复杂的 normalize_html
simple_html = _render_markdown_html(md)
# 构建完整的 HTML 文档,确保格式正确
full_html = f'''<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
@page {{
margin: 20mm;
}}
body {{
font-family: "Microsoft YaHei", "SimSun", Arial, sans-serif;
font-size: 12pt;
line-height: 1.6;
}}
h1, h2, h3, h4, h5, h6 {{
color: #333;
margin-top: 1em;
margin-bottom: 0.5em;
}}
h1 {{ font-size: 24pt; font-weight: bold; }}
h2 {{ font-size: 20pt; font-weight: bold; }}
h3 {{ font-size: 16pt; font-weight: bold; }}
p {{ margin-bottom: 1em; }}
ul, ol {{ margin-left: 2em; }}
table {{
border-collapse: collapse;
width: 100%;
margin: 1em 0;
}}
th, td {{
border: 1px solid #ddd;
padding: 8px;
}}
th {{
background-color: #f2f2f2;
}}
a {{ color: #1d4ed8; text-decoration: underline; }}
</style>
</head>
<body>
{simple_html}
</body>
</html>'''
# 使用 BytesIO 接收 PDF 输出
bio = io.BytesIO()
# 调用 pisa.CreatePDF
_pisa.CreatePDF(
full_html,
dest=bio,
encoding='utf-8'
)
return bio.getvalue()
def md_to_pdf_bytes_with_renderer(md: str, renderer: str = "weasyprint", css_name: Optional[str] = None, css_text: Optional[str] = None, toc: bool = False, header_text: Optional[str] = None, footer_text: Optional[str] = None, logo_url: Optional[str] = None, copyright_text: Optional[str] = None, filename_text: Optional[str] = None, cover_src: Optional[str] = None, product_name: Optional[str] = None, document_name: Optional[str] = None, product_version: Optional[str] = None, document_version: Optional[str] = None) -> bytes: def md_to_pdf_bytes_with_renderer(md: str, renderer: str = "weasyprint", css_name: Optional[str] = None, css_text: Optional[str] = None, toc: bool = False, header_text: Optional[str] = None, footer_text: Optional[str] = None, logo_url: Optional[str] = None, copyright_text: Optional[str] = None, filename_text: Optional[str] = None, cover_src: Optional[str] = None, product_name: Optional[str] = None, document_name: Optional[str] = None, product_version: Optional[str] = None, document_version: Optional[str] = None) -> bytes:
html = normalize_html(md, options={ html = normalize_html(md, options={
"toc": "1" if toc else "", "toc": "1" if toc else "",
@@ -702,8 +932,38 @@ def md_to_pdf_bytes_with_renderer(md: str, renderer: str = "weasyprint", css_nam
"product_version": product_version, "product_version": product_version,
"document_version": document_version, "document_version": document_version,
}) })
# ========== PDF 渲染优先级 ==========
# 1. reportlab (首选) - 纯 Python支持中文跨平台兼容
# 2. WeasyPrint - 需要 GTK 系统库Windows 上安装复杂
# =====================================
print(f"[DEBUG] 开始 PDF 转换, _HAS_REPORTLAB={_HAS_REPORTLAB}, HTML is None={HTML is None}")
# 首选reportlab纯 Python支持中文无需外部依赖
if _HAS_REPORTLAB:
try:
print(f"[DEBUG] 尝试使用 reportlab...")
return _render_pdf_with_reportlab(md)
except Exception as e:
# reportlab 失败,记录错误并继续尝试下一个方案
import traceback
error_detail = traceback.format_exc()
print(f"[DEBUG] reportlab 失败: {str(e)}")
print(f"[DEBUG] 错误详情:\n{error_detail}")
# 备选WeasyPrint需要系统库支持
if HTML is not None: if HTML is not None:
stylesheets = _stylesheets_for(css_name, css_text) try:
pdf_bytes = HTML(string=html).write_pdf(stylesheets=stylesheets or None) print(f"[DEBUG] 尝试使用 WeasyPrint...")
return pdf_bytes stylesheets = _stylesheets_for(css_name, css_text)
raise RuntimeError("WeasyPrint is not available") pdf_bytes = HTML(string=html).write_pdf(stylesheets=stylesheets or None)
return pdf_bytes
except Exception as e:
# WeasyPrint 失败,记录错误
import traceback
error_detail = traceback.format_exc()
print(f"[DEBUG] WeasyPrint 失败: {str(e)}")
print(f"[DEBUG] 错误详情:\n{error_detail}")
raise RuntimeError("PDF 转换失败。reportlab 已安装但转换失败,请检查 markdown 格式")

View File

@@ -8,15 +8,15 @@
"name": "frontend", "name": "frontend",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"marked": "^17.0.1",
"vue": "^3.5.24" "vue": "^3.5.24"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^24.10.1", "@types/node": "^24.10.1",
"@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue": "^5.2.4",
"@vue/tsconfig": "^0.8.1", "@vue/tsconfig": "^0.8.1",
"marked": "^14.1.4",
"typescript": "~5.9.3", "typescript": "~5.9.3",
"vite": "^7.2.4", "vite": "^5.4.21",
"vue-tsc": "^3.1.4" "vue-tsc": "^3.1.4"
} }
}, },
@@ -67,445 +67,371 @@
} }
}, },
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"aix" "aix"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/android-arm": { "node_modules/@esbuild/android-arm": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"android" "android"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/android-arm64": { "node_modules/@esbuild/android-arm64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"android" "android"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/android-x64": { "node_modules/@esbuild/android-x64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"android" "android"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/darwin-arm64": { "node_modules/@esbuild/darwin-arm64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/darwin-x64": { "node_modules/@esbuild/darwin-x64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/freebsd-arm64": { "node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"freebsd" "freebsd"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/freebsd-x64": { "node_modules/@esbuild/freebsd-x64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"freebsd" "freebsd"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-arm": { "node_modules/@esbuild/linux-arm": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-arm64": { "node_modules/@esbuild/linux-arm64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-ia32": { "node_modules/@esbuild/linux-ia32": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-loong64": { "node_modules/@esbuild/linux-loong64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-mips64el": { "node_modules/@esbuild/linux-mips64el": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-ppc64": { "node_modules/@esbuild/linux-ppc64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-riscv64": { "node_modules/@esbuild/linux-riscv64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-s390x": { "node_modules/@esbuild/linux-s390x": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/linux-x64": { "node_modules/@esbuild/linux-x64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
} }
}, },
"node_modules/@esbuild/netbsd-x64": { "node_modules/@esbuild/netbsd-x64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"netbsd" "netbsd"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
} }
}, },
"node_modules/@esbuild/openbsd-x64": { "node_modules/@esbuild/openbsd-x64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"openbsd" "openbsd"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
} }
}, },
"node_modules/@esbuild/sunos-x64": { "node_modules/@esbuild/sunos-x64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"sunos" "sunos"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/win32-arm64": { "node_modules/@esbuild/win32-arm64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/win32-ia32": { "node_modules/@esbuild/win32-ia32": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@esbuild/win32-x64": { "node_modules/@esbuild/win32-x64": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
], ],
"engines": { "engines": {
"node": ">=18" "node": ">=12"
} }
}, },
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
@@ -514,13 +440,6 @@
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.50",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.50.tgz",
"integrity": "sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==",
"dev": true,
"license": "MIT"
},
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.53.3", "version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
@@ -847,19 +766,15 @@
} }
}, },
"node_modules/@vitejs/plugin-vue": { "node_modules/@vitejs/plugin-vue": {
"version": "6.0.2", "version": "5.2.4",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.2.tgz", "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz",
"integrity": "sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==", "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": {
"@rolldown/pluginutils": "1.0.0-beta.50"
},
"engines": { "engines": {
"node": "^20.19.0 || >=22.12.0" "node": "^18.0.0 || >=20.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0", "vite": "^5.0.0 || ^6.0.0",
"vue": "^3.2.25" "vue": "^3.2.25"
} }
}, },
@@ -1061,45 +976,41 @@
} }
}, },
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.25.12", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz",
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT",
"bin": { "bin": {
"esbuild": "bin/esbuild" "esbuild": "bin/esbuild"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=12"
}, },
"optionalDependencies": { "optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.12", "@esbuild/aix-ppc64": "0.21.5",
"@esbuild/android-arm": "0.25.12", "@esbuild/android-arm": "0.21.5",
"@esbuild/android-arm64": "0.25.12", "@esbuild/android-arm64": "0.21.5",
"@esbuild/android-x64": "0.25.12", "@esbuild/android-x64": "0.21.5",
"@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-arm64": "0.21.5",
"@esbuild/darwin-x64": "0.25.12", "@esbuild/darwin-x64": "0.21.5",
"@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-arm64": "0.21.5",
"@esbuild/freebsd-x64": "0.25.12", "@esbuild/freebsd-x64": "0.21.5",
"@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm": "0.21.5",
"@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-arm64": "0.21.5",
"@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-ia32": "0.21.5",
"@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-loong64": "0.21.5",
"@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-mips64el": "0.21.5",
"@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-ppc64": "0.21.5",
"@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-riscv64": "0.21.5",
"@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-s390x": "0.21.5",
"@esbuild/linux-x64": "0.25.12", "@esbuild/linux-x64": "0.21.5",
"@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.21.5",
"@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-x64": "0.21.5",
"@esbuild/openbsd-arm64": "0.25.12", "@esbuild/sunos-x64": "0.21.5",
"@esbuild/openbsd-x64": "0.25.12", "@esbuild/win32-arm64": "0.21.5",
"@esbuild/openharmony-arm64": "0.25.12", "@esbuild/win32-ia32": "0.21.5",
"@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-x64": "0.21.5"
"@esbuild/win32-arm64": "0.25.12",
"@esbuild/win32-ia32": "0.25.12",
"@esbuild/win32-x64": "0.25.12"
} }
}, },
"node_modules/estree-walker": { "node_modules/estree-walker": {
@@ -1108,24 +1019,6 @@
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -1151,15 +1044,15 @@
} }
}, },
"node_modules/marked": { "node_modules/marked": {
"version": "17.0.1", "version": "14.1.4",
"resolved": "https://registry.npmjs.org/marked/-/marked-17.0.1.tgz", "resolved": "https://registry.npmmirror.com/marked/-/marked-14.1.4.tgz",
"integrity": "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==", "integrity": "sha512-vkVZ8ONmUdPnjCKc5uTRvmkRbx4EAi2OkTOXmfTDhZz3OFqMNBM1oTTWwTr4HY4uAEojhzPf+Fy8F1DWa3Sndg==",
"license": "MIT", "dev": true,
"bin": { "bin": {
"marked": "bin/marked.js" "marked": "bin/marked.js"
}, },
"engines": { "engines": {
"node": ">= 20" "node": ">= 18"
} }
}, },
"node_modules/muggle-string": { "node_modules/muggle-string": {
@@ -1292,23 +1185,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.9.3", "version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
@@ -1331,24 +1207,20 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "7.2.4", "version": "5.4.21",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz", "resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.21.tgz",
"integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.21.3",
"fdir": "^6.5.0", "postcss": "^8.4.43",
"picomatch": "^4.0.3", "rollup": "^4.20.0"
"postcss": "^8.5.6",
"rollup": "^4.43.0",
"tinyglobby": "^0.2.15"
}, },
"bin": { "bin": {
"vite": "bin/vite.js" "vite": "bin/vite.js"
}, },
"engines": { "engines": {
"node": "^20.19.0 || >=22.12.0" "node": "^18.0.0 || >=20.0.0"
}, },
"funding": { "funding": {
"url": "https://github.com/vitejs/vite?sponsor=1" "url": "https://github.com/vitejs/vite?sponsor=1"
@@ -1357,25 +1229,19 @@
"fsevents": "~2.3.3" "fsevents": "~2.3.3"
}, },
"peerDependencies": { "peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0", "@types/node": "^18.0.0 || >=20.0.0",
"jiti": ">=1.21.0", "less": "*",
"less": "^4.0.0",
"lightningcss": "^1.21.0", "lightningcss": "^1.21.0",
"sass": "^1.70.0", "sass": "*",
"sass-embedded": "^1.70.0", "sass-embedded": "*",
"stylus": ">=0.54.8", "stylus": "*",
"sugarss": "^5.0.0", "sugarss": "*",
"terser": "^5.16.0", "terser": "^5.4.0"
"tsx": "^4.8.1",
"yaml": "^2.4.2"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@types/node": { "@types/node": {
"optional": true "optional": true
}, },
"jiti": {
"optional": true
},
"less": { "less": {
"optional": true "optional": true
}, },
@@ -1396,12 +1262,6 @@
}, },
"terser": { "terser": {
"optional": true "optional": true
},
"tsx": {
"optional": true
},
"yaml": {
"optional": true
} }
} }
}, },

View File

@@ -9,15 +9,15 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"marked": "^17.0.1",
"vue": "^3.5.24" "vue": "^3.5.24"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^24.10.1", "@types/node": "^24.10.1",
"@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue": "^5.2.4",
"@vue/tsconfig": "^0.8.1", "@vue/tsconfig": "^0.8.1",
"marked": "^14.1.4",
"typescript": "~5.9.3", "typescript": "~5.9.3",
"vite": "^7.2.4", "vite": "^5.4.21",
"vue-tsc": "^3.1.4" "vue-tsc": "^3.1.4"
} }
} }

View File

@@ -3,10 +3,11 @@ import { ref } from 'vue'
import DocToMd from './components/DocToMd.vue' import DocToMd from './components/DocToMd.vue'
import BatchProcess from './components/BatchProcess.vue' import BatchProcess from './components/BatchProcess.vue'
import MdToDoc from './components/MdToDoc.vue' import MdToDoc from './components/MdToDoc.vue'
import MdToPdf from './components/MdToPdf.vue'
import ConfigModal from './components/ConfigModal.vue' import ConfigModal from './components/ConfigModal.vue'
const showConfig = ref(false) const showConfig = ref(false)
const activePage = ref<'doc-to-md' | 'batch' | 'md-to-doc'>('doc-to-md') const activePage = ref<'doc-to-md' | 'batch' | 'md-to-doc' | 'md-to-pdf'>('doc-to-md')
</script> </script>
<template> <template>
@@ -20,12 +21,14 @@ const activePage = ref<'doc-to-md' | 'batch' | 'md-to-doc'>('doc-to-md')
<div class="top-tab" :class="{active: activePage === 'doc-to-md'}" @click="activePage = 'doc-to-md'">DOCX/PDF Markdown</div> <div class="top-tab" :class="{active: activePage === 'doc-to-md'}" @click="activePage = 'doc-to-md'">DOCX/PDF Markdown</div>
<div class="top-tab" :class="{active: activePage === 'batch'}" @click="activePage = 'batch'">批量处理</div> <div class="top-tab" :class="{active: activePage === 'batch'}" @click="activePage = 'batch'">批量处理</div>
<div class="top-tab" :class="{active: activePage === 'md-to-doc'}" @click="activePage = 'md-to-doc'">Markdown DOCX/PDF</div> <div class="top-tab" :class="{active: activePage === 'md-to-doc'}" @click="activePage = 'md-to-doc'">Markdown DOCX/PDF</div>
<div class="top-tab" :class="{active: activePage === 'md-to-pdf'}" @click="activePage = 'md-to-pdf'">Markdown PDF</div>
</div> </div>
<div class="main-content"> <div class="main-content">
<DocToMd v-if="activePage === 'doc-to-md'" /> <DocToMd v-if="activePage === 'doc-to-md'" />
<BatchProcess v-if="activePage === 'batch'" /> <BatchProcess v-if="activePage === 'batch'" />
<MdToDoc v-if="activePage === 'md-to-doc'" /> <MdToDoc v-if="activePage === 'md-to-doc'" />
<MdToPdf v-if="activePage === 'md-to-pdf'" />
</div> </div>
<ConfigModal v-model="showConfig" /> <ConfigModal v-model="showConfig" />

View File

@@ -303,3 +303,10 @@ export async function syncServerTime(method?: string, ntpServer?: string): Promi
return { ok: false } return { ok: false }
} }
} }
export async function convertMarkdownToPdf(formData: FormData): Promise<Response> {
return apiFetch(`/api/pdf/convert`, {
method: 'POST',
body: formData
})
}

View File

@@ -7,8 +7,9 @@ export default defineConfig({
server: { server: {
proxy: { proxy: {
'/api': { '/api': {
target: 'http://localhost:8000', target: 'http://127.0.0.1:8000',
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path,
configure: (proxy) => { configure: (proxy) => {
const p = proxy as any const p = proxy as any
p.timeout = 120000 p.timeout = 120000
@@ -16,7 +17,7 @@ export default defineConfig({
}, },
}, },
'/config': { '/config': {
target: 'http://localhost:8000', target: 'http://127.0.0.1:8000',
changeOrigin: true, changeOrigin: true,
configure: (proxy) => { configure: (proxy) => {
const p = proxy as any const p = proxy as any
@@ -25,7 +26,7 @@ export default defineConfig({
}, },
}, },
'/md': { '/md': {
target: 'http://localhost:8000', target: 'http://127.0.0.1:8000',
changeOrigin: true, changeOrigin: true,
configure: (proxy) => { configure: (proxy) => {
const p = proxy as any const p = proxy as any
@@ -34,7 +35,7 @@ export default defineConfig({
}, },
}, },
'/refresh.js': { '/refresh.js': {
target: 'http://localhost:8000', target: 'http://127.0.0.1:8000',
changeOrigin: true, changeOrigin: true,
configure: (proxy) => { configure: (proxy) => {
const p = proxy as any const p = proxy as any