From c3edff465ba80872be35299e74abf5821732b869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E7=94=B7?= Date: Tue, 28 Apr 2026 10:45:11 +0800 Subject: [PATCH] feat(org-home): render homepage markdown with signed images on teacher/student home Made-with: Cursor --- src/pages/org/homepage.vue | 37 +------ src/pages/student/home.vue | 162 ++++++++++++++++++++----------- src/pages/teacher/home.vue | 159 ++++++++++++++++++++---------- src/utils/orgHomepageMarkdown.ts | 46 +++++++++ 4 files changed, 265 insertions(+), 139 deletions(-) create mode 100644 src/utils/orgHomepageMarkdown.ts diff --git a/src/pages/org/homepage.vue b/src/pages/org/homepage.vue index 99ab5aa..6f66b81 100644 --- a/src/pages/org/homepage.vue +++ b/src/pages/org/homepage.vue @@ -54,41 +54,12 @@ import { showSuccessToast, Uploader, } from "vant"; -import { marked } from "marked"; import useOrg from "~/store/org"; import { ImageHelper } from "~/utils"; -import { UpyunAccess } from "~/utils/upyun"; +import { renderOrgHomepageMarkdown, stripBrokenCompressMarkdown } from "~/utils/orgHomepageMarkdown"; const ORG_HOMEPAGE_IMAGE_MAX_BYTES = 10 * 1024 * 1024; -marked.setOptions({ breaks: true, gfm: true }); - -/** 历史失败上传留在正文里的占位,避免继续污染预览 */ -function stripBrokenCompressMarkdown(md: string): string { - return md - .replace(/!\[[^\]]*\]\(\s*failed to open file[^)]*\)/g, "") - .replace(/\n{3,}/g, "\n\n"); -} - -/** 预览区 img:又拍云需带 _upt,否则浏览器无法加载 */ -async function signUpyunImagesInMarkedHtml(html: string): Promise { - if (typeof document === "undefined" || !html.includes(" { - const src = el.getAttribute("src"); - if (!src?.includes("upyun")) return; - const signed = await UpyunAccess.getSign(src); - if (signed) el.setAttribute("src", signed); - }), - ); - return wrap.innerHTML; -} - export default defineComponent({ name: "org-homepage", components: { @@ -107,8 +78,10 @@ export default defineComponent({ async () => { const raw = (markdownText.value || "").trim(); if (!raw) return '

暂无内容

'; - const html = marked.parse(raw) as string; - return signUpyunImagesInMarkedHtml(html); + const html = await renderOrgHomepageMarkdown(raw); + return html.trim() + ? html + : '

暂无内容

'; }, '

暂无内容

', ); diff --git a/src/pages/student/home.vue b/src/pages/student/home.vue index 895a4a0..264fdd2 100644 --- a/src/pages/student/home.vue +++ b/src/pages/student/home.vue @@ -1,92 +1,144 @@ diff --git a/src/pages/teacher/home.vue b/src/pages/teacher/home.vue index f2c25a4..bf2f73c 100644 --- a/src/pages/teacher/home.vue +++ b/src/pages/teacher/home.vue @@ -1,89 +1,144 @@ diff --git a/src/utils/orgHomepageMarkdown.ts b/src/utils/orgHomepageMarkdown.ts new file mode 100644 index 0000000..bbe577c --- /dev/null +++ b/src/utils/orgHomepageMarkdown.ts @@ -0,0 +1,46 @@ +import { marked } from "marked"; +import { UpyunAccess } from "~/utils/upyun"; + +marked.setOptions({ breaks: true, gfm: true }); + +/** 历史失败上传留在正文里的占位,避免继续污染渲染 */ +export function stripBrokenCompressMarkdown(md: string): string { + return md + .replace(/!\[[^\]]*\]\(\s*failed to open file[^)]*\)/g, "") + .replace(/\n{3,}/g, "\n\n"); +} + +/** + * 窄屏编辑器可能把 `![](url)` 折成两行,GFM 无法识别,合并为单行。 + */ +function normalizeMarkdownImageLineBreaks(md: string): string { + return md.replace(/!\[([^\]]*)\]\s*\r?\n\s*\(/g, "![$1]("); +} + +/** 预览 / 首页:img 又拍直链需带 _upt */ +export async function signUpyunImagesInMarkedHtml(html: string): Promise { + if (typeof document === "undefined" || !html.includes(" { + const src = el.getAttribute("src"); + if (!src?.includes("upyun")) return; + const signed = await UpyunAccess.getSign(src); + if (signed) el.setAttribute("src", signed); + }), + ); + return wrap.innerHTML; +} + +/** 机构首页 Markdown → 可展示的 HTML(含又拍图签名) */ +export async function renderOrgHomepageMarkdown(markdown: string): Promise { + let cleaned = stripBrokenCompressMarkdown(markdown || ""); + cleaned = normalizeMarkdownImageLineBreaks(cleaned).trim(); + if (!cleaned) return ""; + const html = marked.parse(cleaned) as string; + return signUpyunImagesInMarkedHtml(html); +}