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>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, nextTick, onMounted, ref } from "vue";
|
import { computedAsync } from "@vueuse/core";
|
||||||
|
import { defineComponent, nextTick, onMounted, ref } from "vue";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
CellGroup,
|
CellGroup,
|
||||||
@@ -56,11 +57,38 @@ import {
|
|||||||
import { marked } from "marked";
|
import { marked } from "marked";
|
||||||
import useOrg from "~/store/org";
|
import useOrg from "~/store/org";
|
||||||
import { ImageHelper } from "~/utils";
|
import { ImageHelper } from "~/utils";
|
||||||
|
import { UpyunAccess } from "~/utils/upyun";
|
||||||
|
|
||||||
const ORG_HOMEPAGE_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
const ORG_HOMEPAGE_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
||||||
|
|
||||||
marked.setOptions({ breaks: true, gfm: true });
|
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({
|
export default defineComponent({
|
||||||
name: "org-homepage",
|
name: "org-homepage",
|
||||||
components: {
|
components: {
|
||||||
@@ -75,10 +103,15 @@ export default defineComponent({
|
|||||||
const markdownFieldRef = ref<InstanceType<typeof Field> | null>(null);
|
const markdownFieldRef = ref<InstanceType<typeof Field> | null>(null);
|
||||||
const imageUploading = ref(false);
|
const imageUploading = ref(false);
|
||||||
|
|
||||||
const previewHtml = computed(() => {
|
const previewHtml = computedAsync(
|
||||||
const raw = (markdownText.value || "").trim();
|
async () => {
|
||||||
return raw ? marked(raw) : '<p class="preview-empty">暂无内容</p>';
|
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 getMarkdownTextarea = (): HTMLTextAreaElement | null => {
|
||||||
const root = markdownFieldRef.value as unknown as { $el?: HTMLElement };
|
const root = markdownFieldRef.value as unknown as { $el?: HTMLElement };
|
||||||
@@ -154,7 +187,8 @@ export default defineComponent({
|
|||||||
showFailToast("请先选择机构");
|
showFailToast("请先选择机构");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
markdownText.value = (await getHomepage(store.currentOrgId)) || "";
|
const loaded = (await getHomepage(store.currentOrgId)) || "";
|
||||||
|
markdownText.value = stripBrokenCompressMarkdown(loaded);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSave = async () => {
|
const onSave = async () => {
|
||||||
@@ -162,7 +196,9 @@ export default defineComponent({
|
|||||||
showFailToast("请先选择机构");
|
showFailToast("请先选择机构");
|
||||||
return;
|
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) {
|
if (ok) {
|
||||||
showSuccessToast("保存成功");
|
showSuccessToast("保存成功");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user