fix(org-homepage): sign upyun imgs in preview; strip failed upload placeholders

Made-with: Cursor
This commit is contained in:
2026-04-28 09:46:48 +08:00
parent 925decd472
commit 4db9bc82c8
+43 -7
View File
@@ -44,7 +44,8 @@
</template>
<script lang="ts">
import { computed, defineComponent, nextTick, onMounted, ref } from "vue";
import { computedAsync } from "@vueuse/core";
import { defineComponent, nextTick, onMounted, ref } from "vue";
import {
Button,
CellGroup,
@@ -56,11 +57,38 @@ import {
import { marked } from "marked";
import useOrg from "~/store/org";
import { ImageHelper } from "~/utils";
import { UpyunAccess } from "~/utils/upyun";
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<string> {
if (typeof document === "undefined" || !html.includes("<img")) {
return html;
}
const wrap = document.createElement("div");
wrap.innerHTML = html;
const imgs = wrap.querySelectorAll("img[src]");
await Promise.all(
Array.from(imgs).map(async (el) => {
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: {
@@ -75,10 +103,15 @@ export default defineComponent({
const markdownFieldRef = ref<InstanceType<typeof Field> | null>(null);
const imageUploading = ref(false);
const previewHtml = computed(() => {
const raw = (markdownText.value || "").trim();
return raw ? marked(raw) : '<p class="preview-empty">暂无内容</p>';
});
const previewHtml = computedAsync(
async () => {
const raw = (markdownText.value || "").trim();
if (!raw) return '<p class="preview-empty">暂无内容</p>';
const html = marked.parse(raw) as string;
return signUpyunImagesInMarkedHtml(html);
},
'<p class="preview-empty">暂无内容</p>',
);
const getMarkdownTextarea = (): HTMLTextAreaElement | null => {
const root = markdownFieldRef.value as unknown as { $el?: HTMLElement };
@@ -154,7 +187,8 @@ export default defineComponent({
showFailToast("请先选择机构");
return;
}
markdownText.value = (await getHomepage(store.currentOrgId)) || "";
const loaded = (await getHomepage(store.currentOrgId)) || "";
markdownText.value = stripBrokenCompressMarkdown(loaded);
});
const onSave = async () => {
@@ -162,7 +196,9 @@ export default defineComponent({
showFailToast("请先选择机构");
return;
}
const ok = await saveHomepage(store.currentOrgId, markdownText.value);
const cleaned = stripBrokenCompressMarkdown(markdownText.value);
markdownText.value = cleaned;
const ok = await saveHomepage(store.currentOrgId, cleaned);
if (ok) {
showSuccessToast("保存成功");
}