From 2b695bfabdceccb0ee19c12c8e655bd7f47a6e2f Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期二, 27 十月 2026 18:06:44 +0800
Subject: [PATCH] feat(wxcp): 通知前端支持图片/视频/Markdown/多图文与成员预览

---
 src/views/wxcp/notice/modules/form.vue |  151 +++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 117 insertions(+), 34 deletions(-)

diff --git a/src/views/wxcp/notice/modules/form.vue b/src/views/wxcp/notice/modules/form.vue
index cab9ba2..15b9099 100644
--- a/src/views/wxcp/notice/modules/form.vue
+++ b/src/views/wxcp/notice/modules/form.vue
@@ -9,6 +9,7 @@
 import { Button, message } from 'ant-design-vue';
 
 import { useVbenForm } from '#/adapter/form';
+import { toAccessibleFileUrl } from '#/utils';
 import {
   createNotice,
   getNotice,
@@ -16,6 +17,7 @@
 } from '#/api/wxcp/notice';
 
 import { NOTICE_TYPE, useNoticeFormSchema } from '../data';
+import ArticleEditor from './article-editor.vue';
 
 defineOptions({ name: 'WxCpNoticeForm' });
 
@@ -24,6 +26,14 @@
 const formType = ref<NoticeFormType>('create');
 const id = ref<number>();
 const submitting = ref(false);
+/** 褰撳墠妯℃澘绫诲瀷锛岀敤浜庢帶鍒跺鍥炬枃缂栬緫鍣ㄦ樉闅� */
+const noticeType = ref<number>(NOTICE_TYPE.TEXT);
+/** 澶氬浘鏂囨潯鐩紙琛ㄥ崟椤逛箣澶栧崟鐙淮鎶わ級 */
+const articles = ref<WxCpNoticeApi.NoticeArticle[]>([]);
+
+const showArticleEditor = computed(
+  () => noticeType.value === NOTICE_TYPE.MULTI_NEWS,
+);
 
 const isEdit = computed(() => formType.value !== 'detail');
 const title = computed(() => {
@@ -31,6 +41,82 @@
   if (id.value) return '缂栬緫閫氱煡';
   return '鏂板缓閫氱煡';
 });
+
+/**
+ * 鎶婇檮浠跺垪琛ㄨ浆鎴愪笂浼犵粍浠惰兘璇嗗埆鐨勬枃浠跺璞�
+ *
+ * 鍥炴樉瀵硅薄蹇呴』甯� response锛氱粍浠惰浜� resultField 鍚庡彧璁� item.response锛�
+ * 涓嶅甫鐨勮瘽銆岃繘缂栬緫椤典笉鍔ㄥ浘鐩存帴淇濆瓨銆嶄細璧� URL 鍒嗘敮 鈫� NaN 鈫� [] 鈫� 鍥捐娓呯┖
+ */
+function attachmentsToUploadFiles(
+  list: WxCpNoticeApi.NoticeAttachment[] | undefined,
+) {
+  return (list ?? []).map((item) => {
+    const name = item.name || item.originalFilename || '';
+    const url = toAccessibleFileUrl(item.url || item.previewURL);
+    return {
+      uid: String(item.id),
+      name,
+      url,
+      status: 'done',
+      id: item.id,
+      response: { id: item.id, name, url },
+    };
+  });
+}
+
+/**
+ * 鎶婁笂浼犵粍浠剁殑鍊艰鏁存垚 blobId 鏁扮粍
+ *
+ * ImageUpload 鍦� maxNumber=1 鏃惰繑鍥炲崟涓�艰�屼笉鏄暟缁勶紝杩欓噷缁熶竴鍖呮垚鏁扮粍鍐嶆彁浜�
+ */
+function normalizeBlobIds(value: unknown): number[] {
+  const list = Array.isArray(value)
+    ? value
+    : value === '' || value === null || value === undefined
+      ? []
+      : [value];
+  return list
+    .map((item) =>
+      item && typeof item === 'object' && 'id' in item
+        ? Number((item as { id: unknown }).id)
+        : Number(item),
+    )
+    .filter((blobId) => Number.isFinite(blobId));
+}
+
+/**
+ * 鎶婇�氱煡璇︽儏鏄犲皠鎴愯〃鍗曞��
+ *
+ * 鍥剧墖/闄勪欢涓嶈惤涓氬姟琛ㄥ瓧娈碉紝缁熶竴瀛樺湪闄勪欢涓棿琛紝
+ * 鍥炴樉鏃舵妸 imageAttachmentList / fileAttachmentList 杞垚涓婁紶缁勪欢鏂囦欢瀵硅薄銆�
+ * 鍘嗗彶鏁版嵁鍙湁鏃х増 fileBlobId锛岃繖閲屽厹搴曟垚鍗曚釜闄勪欢锛岄伩鍏嶇紪杈戝悗闄勪欢涓㈠け銆�
+ */
+function noticeToForm(
+  detail: WxCpNoticeApi.Notice,
+): Record<string, unknown> {
+  const form: Record<string, unknown> = { ...detail };
+  form.imageBlobIds = attachmentsToUploadFiles(detail.imageAttachmentList);
+  form.videoBlobIds = attachmentsToUploadFiles(detail.videoAttachmentList);
+  form.fileBlobIds =
+    detail.fileAttachmentList?.length
+      ? attachmentsToUploadFiles(detail.fileAttachmentList)
+      : detail.fileBlobId
+        ? [
+            {
+              uid: String(detail.fileBlobId),
+              name: detail.fileName || '',
+              status: 'done',
+              id: detail.fileBlobId,
+              response: {
+                id: detail.fileBlobId,
+                name: detail.fileName || '',
+              },
+            },
+          ]
+        : [];
+  return form;
+}
 
 const [Form, formApi] = useVbenForm({
   commonConfig: {
@@ -42,6 +128,9 @@
   schema: [],
   showDefaultActions: false,
   wrapperClass: 'grid-cols-1',
+  handleValuesChange: (values) => {
+    noticeType.value = (values.noticeType as number) ?? NOTICE_TYPE.TEXT;
+  },
 });
 
 const [Modal, modalApi] = useVbenModal({
@@ -59,24 +148,18 @@
       modalApi.lock();
       try {
         const detail = await getNotice(data.id);
-        const values: Record<string, unknown> = { ...detail };
-        // 鏂囦欢閫氱煡锛氭妸 blobId 杩樺師鎴愪笂浼犵粍浠跺彲璇嗗埆鐨勬枃浠跺璞�
-        if (detail.noticeType === NOTICE_TYPE.FILE && detail.fileBlobId) {
-          values.fileBlobId = [
-            {
-              uid: String(detail.fileBlobId),
-              name: detail.fileName || '',
-              status: 'done',
-              id: detail.fileBlobId,
-            },
-          ];
-        }
-        await formApi.setValues(values);
+        noticeType.value = detail.noticeType ?? NOTICE_TYPE.TEXT;
+        articles.value = (detail.articleList ?? []).map((item) => ({
+          ...item,
+        }));
+        await formApi.setValues(noticeToForm(detail));
       } finally {
         modalApi.unlock();
       }
     } else {
       await formApi.resetForm();
+      noticeType.value = NOTICE_TYPE.TEXT;
+      articles.value = [];
       await formApi.setValues({ noticeType: NOTICE_TYPE.TEXT }, false);
     }
   },
@@ -91,30 +174,23 @@
   try {
     const data = (await formApi.getValues()) as WxCpNoticeApi.Notice;
     // 淇濆瓨鏃跺彧鍋氭枃浠跺綊涓�鍖栵紱鍏蜂綋妯℃澘蹇呭~椤瑰湪鎺ㄩ�佹椂鎸夋墍閫夋ā鏉挎牎楠�
-    const noticeType = data.noticeType ?? NOTICE_TYPE.TEXT;
-    if (noticeType === NOTICE_TYPE.FILE) {
-      const raw = data.fileBlobId as unknown;
-      let blobId: number | undefined;
-      if (Array.isArray(raw)) {
-        const first = raw[0];
-        blobId =
-          typeof first === 'number'
-            ? first
-            : (first as { id?: number } | undefined)?.id;
-      } else if (typeof raw === 'number') {
-        blobId = raw;
-      } else if (raw && typeof raw === 'object') {
-        blobId = (raw as { id?: number }).id;
-      }
-      data.fileBlobId = blobId;
-    } else {
-      data.fileBlobId = undefined;
-    }
+    const payload = {
+      ...data,
+      // null = 涓嶆敼鍔紝[] = 娓呯┖锛涜繖閲岀粺涓�鎻愪氦鏁扮粍锛屽垏鎹㈡ā鏉垮悗鏃ч檮浠朵細琚竻鎺�
+      imageBlobIds: normalizeBlobIds(data.imageBlobIds),
+      fileBlobIds: normalizeBlobIds(data.fileBlobIds),
+      videoBlobIds: normalizeBlobIds(data.videoBlobIds),
+      // 澶氬浘鏂囨潯鐩崟鐙淮鎶わ紝鍙湁璇ユā鏉挎彁浜わ紱null 琛ㄧず涓嶆敼鍔�
+      articleList: showArticleEditor.value ? articles.value : undefined,
+      // 鏃х増鍗曢檮浠跺瓧娈典笉鍐嶄娇鐢紝閬垮厤鍜� fileBlobIds 閲嶅
+      fileBlobId: undefined,
+      fileName: undefined,
+    } as WxCpNoticeApi.Notice;
     if (id.value) {
-      await updateNotice({ ...data, id: id.value });
+      await updateNotice({ ...payload, id: id.value });
       message.success('淇敼鎴愬姛');
     } else {
-      await createNotice(data);
+      await createNotice(payload);
       message.success('鍒涘缓鎴愬姛锛岃鍦ㄥ垪琛ㄤ腑鍙戝竷鍚庡啀鎺ㄩ��');
     }
     await modalApi.close();
@@ -131,6 +207,13 @@
   <Modal :title="title" class="w-3/5">
     <Form class="mx-4" />
 
+    <div v-if="showArticleEditor" class="mx-4 mt-2">
+      <ArticleEditor
+        v-model="articles"
+        :disabled="formType === 'detail'"
+      />
+    </div>
+
     <template #footer>
       <div class="flex justify-end gap-2">
         <Button @click="modalApi.close()">鍙栨秷</Button>

--
Gitblit v1.9.3