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