From d098633a673d0d48e7c95cbb04cb0eb4e2621714 Mon Sep 17 00:00:00 2001 From: liangxu Date: Wed, 3 Jun 2026 15:49:01 +0800 Subject: [PATCH] feat(media-supply): add image upload functionality and enhance HTML handling in article processing --- .../src/views/MediaSupplySubmitView.vue | 9 ++- .../internal/tenant/app/media_supply_test.go | 47 ++++++++++++- .../internal/tenant/app/meijiequan_client.go | 69 ++++++++++++------- 3 files changed, 98 insertions(+), 27 deletions(-) diff --git a/apps/admin-web/src/views/MediaSupplySubmitView.vue b/apps/admin-web/src/views/MediaSupplySubmitView.vue index 181c790..42ab07c 100644 --- a/apps/admin-web/src/views/MediaSupplySubmitView.vue +++ b/apps/admin-web/src/views/MediaSupplySubmitView.vue @@ -21,7 +21,7 @@ import { computed, reactive, ref } from 'vue' import { useRouter } from 'vue-router' import ArticleEditorCanvas from '@/components/ArticleEditorCanvas.vue' -import { articlesApi, mediaSupplyApi } from '@/lib/api' +import { articlesApi, imagesApi, mediaSupplyApi } from '@/lib/api' import { clearMediaSupplySubmitSelection, loadMediaSupplySubmitSelection, @@ -194,6 +194,11 @@ async function submitOrder(): Promise { await createOrderMutation.mutateAsync() } +async function uploadEditorImage(file: File): Promise { + const result = await imagesApi.upload(file) + return result.url +} + function cancelSubmit(): void { void router.push({ name: 'media-supply-resources' }) } @@ -377,7 +382,7 @@ function stripLeadingTitleHeading(titleValue: string, markdownValue: string): st v-model="form.content" :article-id="null" :ai-optimize-enabled="false" - :upload-image="undefined" + :upload-image="uploadEditorImage" /> diff --git a/server/internal/tenant/app/media_supply_test.go b/server/internal/tenant/app/media_supply_test.go index 1f6f6a8..df1a0bd 100644 --- a/server/internal/tenant/app/media_supply_test.go +++ b/server/internal/tenant/app/media_supply_test.go @@ -292,8 +292,51 @@ func TestMeijiequanCreateOrderFormMatchesUpstreamShape(t *testing.T) { func TestMeijiequanArticleHTMLKeepsExistingHTML(t *testing.T) { input := `

a

正文

` - if got := meijiequanArticleHTML(input); got != input { - t.Fatalf("expected html passthrough, got %s", got) + got := meijiequanArticleHTML(input) + if !strings.Contains(got, `

正文

`) { + t.Fatalf("expected html image and paragraphs to be preserved, got %s", got) + } +} + +func TestMeijiequanArticleHTMLConvertsMilkdownMixedMarkdown(t *testing.T) { + input := strings.Join([]string{ + "# 标题", + "", + `

图注

`, + "", + "## 小标题", + "", + "- 第一条", + "- **第二条**", + "", + "| 维度 | 说明 |", + "| --- | --- |", + "| 环保 | ENF |", + }, "\n") + + got := meijiequanArticleHTML(input) + if !strings.Contains(got, "

标题

") || + !strings.Contains(got, `小标题") || + !strings.Contains(got, "
  • 第一条
  • ") || + !strings.Contains(got, "第二条") || + !strings.Contains(got, "") || + !strings.Contains(got, "") { + t.Fatalf("unexpected mixed markdown html: %s", got) + } +} + +func TestMeijiequanArticleHTMLBackfillsImageSrcFromOriginalSrc(t *testing.T) { + got := meijiequanArticleHTML(`

    a

    `) + if !strings.Contains(got, `src="http://example.test/original.png"`) || + !strings.Contains(got, `_src="http://example.test/original.png"`) { + t.Fatalf("expected src and _src to be normalized, got %s", got) } } diff --git a/server/internal/tenant/app/meijiequan_client.go b/server/internal/tenant/app/meijiequan_client.go index b06f328..8f9093e 100644 --- a/server/internal/tenant/app/meijiequan_client.go +++ b/server/internal/tenant/app/meijiequan_client.go @@ -19,6 +19,8 @@ import ( goredis "github.com/redis/go-redis/v9" "github.com/yuin/goldmark" + "github.com/yuin/goldmark/extension" + goldhtml "github.com/yuin/goldmark/renderer/html" nethtml "golang.org/x/net/html" "golang.org/x/net/html/atom" @@ -1153,28 +1155,16 @@ func meijiequanArticleHTML(content string) string { if source == "" { return "" } - if looksLikeHTML(source) { - return source - } return markdownToMeijiequanHTML(source) } -func looksLikeHTML(source string) bool { - lower := strings.ToLower(strings.TrimSpace(source)) - return strings.Contains(lower, "
    ENF