fix(org-homepage): sign upyun imgs in preview; strip failed upload placeholders
Made-with: Cursor
This commit is contained in:
@@ -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("保存成功");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user