From 71beff1699701e18c2503791c7ba1437c89966aa Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期三, 30 九月 2026 15:26:43 +0800
Subject: [PATCH] feat(wxcp): 活动封面改用附件中间表,并修正附件地址同源
---
src/views/wxcp/activity/modules/form.vue | 54 ++++++++++++++++-
src/views/wxcp/activity/modules/signup-list.vue | 17 ++++-
src/utils/index.ts | 1
src/views/wxcp/activity/index.vue | 23 ++++++-
src/api/wxcp/activity.ts | 10 +++
src/views/wxcp/activity/data.ts | 13 +++-
src/utils/fileUrl.ts | 42 ++++++++++++++
7 files changed, 146 insertions(+), 14 deletions(-)
diff --git a/src/api/wxcp/activity.ts b/src/api/wxcp/activity.ts
index 5d5b1c8..ed27ef6 100644
--- a/src/api/wxcp/activity.ts
+++ b/src/api/wxcp/activity.ts
@@ -23,7 +23,15 @@
id?: number;
title?: string;
content?: string;
- coverUrl?: string;
+ /**
+ * 灏侀潰鍥炬枃浠剁紪鍙凤紙鏈�澶� 1 寮狅級
+ *
+ * 灏侀潰涓嶈惤涓氬姟琛ㄥ瓧娈碉紝缁熶竴璧� system_storage_attachment 涓棿琛紝
+ * 淇濆瓨鏃舵彁浜� blobIds锛屽洖鏄炬椂璇� attachmentList銆�
+ */
+ blobIds?: number[];
+ /** 灏侀潰鍥鹃檮浠跺垪琛紙鍚庣杩斿洖锛屾渶澶� 1 寮狅級 */
+ attachmentList?: SignupAttachment[];
location?: string;
startTime?: string;
endTime?: string;
diff --git a/src/utils/fileUrl.ts b/src/utils/fileUrl.ts
new file mode 100644
index 0000000..6590ae3
--- /dev/null
+++ b/src/utils/fileUrl.ts
@@ -0,0 +1,42 @@
+/**
+ * 淇鍚庣杩斿洖鐨勯檮浠惰闂湴鍧�
+ *
+ * 鍚庣鐢熸垚 url / previewURL / downloadURL 鏃朵細甯︿笂瀹冭嚜宸遍厤缃殑璁块棶鍩熷悕
+ * 锛堝綋鍓嶅悗绔厤鐨勬槸 192.168.1.6:48080锛夈�傚彧瑕佽鍩熷悕涓庡墠绔笉鍚屾簮銆佹垨鑰呰涓绘満
+ * 鍦ㄥ綋鍓嶇綉缁滈噷涓嶅彲杈撅紝`<img src>` 灏变細鐩存帴鍔犺浇澶辫触锛岄〉闈笂琛ㄧ幇涓恒�屽浘鐗囦笉鏄剧ず銆嶃��
+ *
+ * 杩欓噷鎶婅繖绫荤粷瀵瑰湴鍧�鏀瑰啓鎴愮浉瀵� API 鍓嶇紑鐨勮矾寰勶紝璁╁畠璧板綋鍓嶇珯鐐圭殑鍚屾簮璇锋眰锛�
+ * 寮�鍙戠幆澧冪粡 vite 鐨� /admin-api 浠g悊杞彂鍒板悗绔紝鐢熶骇鐜鍓嶅悗绔悓婧愭椂鍚屾牱鎴愮珛銆�
+ *
+ * 宸茬粡鏄浉瀵硅矾寰勩�佸悓婧愬湴鍧�锛屼互鍙� data:/blob: 涓�寰嬪師鏍疯繑鍥炪��
+ */
+export function toAccessibleFileUrl(raw?: string): string {
+ if (!raw) {
+ return '';
+ }
+ // 鐩稿鍦板潃銆乨ata:銆乥lob: 鐩存帴鏀捐
+ if (!/^https?:\/\//i.test(raw)) {
+ return raw;
+ }
+ try {
+ const url = new URL(raw);
+ // 鏈潵灏卞悓婧愶紝鏃犻渶澶勭悊
+ if (url.origin === window.location.origin) {
+ return raw;
+ }
+ const apiPrefix = (import.meta.env.VITE_GLOB_API_URL || '/admin-api').replace(
+ /\/+$/,
+ '',
+ );
+ // 鍛戒腑 API 鍓嶇紑鏃讹紝鎴彇鍓嶇紑鍙婂叾涔嬪悗鐨勮矾寰勪笌鏌ヨ涓�
+ const at = url.pathname.indexOf(`${apiPrefix}/`);
+ if (at >= 0) {
+ return `${url.pathname.slice(at)}${url.search}`;
+ }
+ // 涓嶆槸鏂囦欢鎺ュ彛鐨勫湴鍧�锛屼笉鍋氬鐞�
+ return raw;
+ } catch {
+ // URL 瑙f瀽澶辫触鏃朵繚鎸佸師鍊硷紝閬垮厤鎶婂彲鐢ㄥ湴鍧�鏀瑰潖
+ return raw;
+ }
+}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index cdedaf7..490f71a 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -1,5 +1,6 @@
import type { Recordable } from '@vben/types';
+export * from './fileUrl';
export * from './rangePickerProps';
export * from './routerHelper';
diff --git a/src/views/wxcp/activity/data.ts b/src/views/wxcp/activity/data.ts
index da4118e..4e883d8 100644
--- a/src/views/wxcp/activity/data.ts
+++ b/src/views/wxcp/activity/data.ts
@@ -85,10 +85,17 @@
help: '濉� 0 琛ㄧず涓嶉檺鍚嶉',
},
{
- fieldName: 'coverUrl',
+ // 灏侀潰璧伴檮浠朵腑闂磋〃锛氳繖閲屾彁浜� blobIds锛屽洖鏄捐 attachmentList锛堣 form.vue 鐨勬槧灏勫嚱鏁帮級
+ fieldName: 'blobIds',
label: '灏侀潰鍥�',
- component: 'Input',
- componentProps: { placeholder: '灏侀潰鍥惧湴鍧�锛堥�夊~锛�', disabled: readonly },
+ component: 'ImageUpload',
+ componentProps: {
+ valueKey: 'id',
+ maxNumber: 1,
+ multiple: false,
+ disabled: readonly,
+ },
+ help: '閫夊~锛屽缓璁� 16:9锛涗繚瀛樺悗灞曠ず鍦ㄦ椿鍔ㄦ姤鍚嶉〉椤堕儴',
formItemClass: 'col-span-2',
},
{
diff --git a/src/views/wxcp/activity/index.vue b/src/views/wxcp/activity/index.vue
index 9370cbb..1530c6e 100644
--- a/src/views/wxcp/activity/index.vue
+++ b/src/views/wxcp/activity/index.vue
@@ -14,6 +14,7 @@
getActivityPage,
publishActivity,
} from '#/api/wxcp/activity';
+import { toAccessibleFileUrl } from '#/utils';
import {
ACTIVITY_STATUS,
@@ -61,6 +62,13 @@
function handleCreate() {
formModalApi.setData({ formType: 'create' }).open();
+}
+
+/** 鍒楄〃缂╃暐鍥惧彇灏侀潰闄勪欢鐨勭涓�寮狅紝娌′紶灏侀潰杩斿洖绌轰覆 */
+function coverUrlOf(row: WxCpActivityApi.Activity): string {
+ const cover = row.attachmentList?.[0];
+ // 鍚庣杩斿洖鐨勬槸瀹冭嚜宸遍厤缃煙鍚嶇殑缁濆鍦板潃锛岄渶鏀瑰啓鎴愬悓婧愯矾寰勬墠鑳借 <img> 鍔犺浇
+ return toAccessibleFileUrl(cover?.url || cover?.previewURL);
}
function handleDetail(row: WxCpActivityApi.Activity) {
@@ -144,9 +152,18 @@
</template>
<template #title="{ row }">
- <Button type="link" class="p-0" @click="handleDetail(row)">
- {{ row.title }}
- </Button>
+ <div class="flex items-center gap-2">
+ <!-- 灏侀潰鏉ヨ嚜闄勪欢涓棿琛紝鏈笂浼犳椂涓嶅崰浣� -->
+ <img
+ v-if="coverUrlOf(row)"
+ :src="coverUrlOf(row)"
+ alt="灏侀潰"
+ class="h-9 w-14 shrink-0 rounded object-cover"
+ />
+ <Button type="link" class="p-0" @click="handleDetail(row)">
+ {{ row.title }}
+ </Button>
+ </div>
</template>
<template #signupCount="{ row }">
diff --git a/src/views/wxcp/activity/modules/form.vue b/src/views/wxcp/activity/modules/form.vue
index 05d379b..29b38d3 100644
--- a/src/views/wxcp/activity/modules/form.vue
+++ b/src/views/wxcp/activity/modules/form.vue
@@ -9,6 +9,7 @@
import { Button, message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
+import { toAccessibleFileUrl } from '#/utils';
import {
createActivity,
getActivity,
@@ -44,6 +45,47 @@
wrapperClass: 'grid-cols-2',
});
+/**
+ * 鎶婃椿鍔ㄨ鎯呮槧灏勬垚琛ㄥ崟鍊�
+ *
+ * 灏侀潰鍦ㄥ悗绔笉钀戒笟鍔¤〃瀛楁锛岃�屾槸瀛樺湪闄勪欢涓棿琛ㄩ噷锛�
+ * 鍥炴樉鏃惰鎶� attachmentList 杞垚涓婁紶缁勪欢鑳借瘑鍒殑鏂囦欢瀵硅薄銆�
+ */
+function activityToForm(
+ activity: WxCpActivityApi.Activity,
+): Record<string, unknown> {
+ const form: Record<string, unknown> = { ...activity };
+ form.blobIds = (activity.attachmentList ?? []).map((item) => ({
+ uid: String(item.id),
+ name: item.name || item.originalFilename || '',
+ url: toAccessibleFileUrl(item.url || item.previewURL),
+ status: 'done',
+ id: item.id,
+ }));
+ return form;
+}
+
+/**
+ * 鎶婁笂浼犵粍浠剁殑鍊艰鏁存垚 blobId 鏁扮粍
+ *
+ * ImageUpload 鍦� maxNumber=1 鏃惰繑鍥炵殑鏄崟涓�硷紙鑰屼笉鏄暟缁勶級锛�
+ * 鍚庣绛惧悕鏄� List<Long>锛岃繖閲岀粺涓�鍖呮垚鏁扮粍鍐嶆彁浜ゃ��
+ */
+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));
+}
+
const [Modal, modalApi] = useVbenModal({
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
@@ -59,7 +101,7 @@
modalApi.lock();
try {
const detail = await getActivity(data.id);
- await formApi.setValues(detail as unknown as Record<string, unknown>);
+ await formApi.setValues(activityToForm(detail));
} finally {
modalApi.unlock();
}
@@ -76,12 +118,16 @@
}
submitting.value = true;
try {
- const data = (await formApi.getValues()) as WxCpActivityApi.Activity;
+ const data = (await formApi.getValues()) as Record<string, unknown>;
+ const payload = {
+ ...data,
+ blobIds: normalizeBlobIds(data.blobIds),
+ } as WxCpActivityApi.Activity;
if (id.value) {
- await updateActivity({ ...data, id: id.value });
+ await updateActivity({ ...payload, id: id.value });
message.success('淇敼鎴愬姛');
} else {
- await createActivity(data);
+ await createActivity(payload);
message.success('鍒涘缓鎴愬姛锛岃鍦ㄥ垪琛ㄤ腑鍙戝竷鍚庡啀鎺ㄩ��');
}
await modalApi.close();
diff --git a/src/views/wxcp/activity/modules/signup-list.vue b/src/views/wxcp/activity/modules/signup-list.vue
index 2c1b953..fabaec0 100644
--- a/src/views/wxcp/activity/modules/signup-list.vue
+++ b/src/views/wxcp/activity/modules/signup-list.vue
@@ -16,6 +16,7 @@
} from 'ant-design-vue';
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
+import { toAccessibleFileUrl } from '#/utils';
import {
cancelSignup,
checkInSignup,
@@ -59,6 +60,16 @@
function isImage(item: WxCpActivityApi.SignupAttachment) {
return (item.contentType || '').startsWith('image/');
+}
+
+/** 鍚庣闄勪欢鍦板潃甯︾殑鏄悗绔嚜宸遍厤缃殑鍩熷悕锛屾敼鍐欐垚鍚屾簮璺緞鍚庢墠鑳借 <img> 鍔犺浇 */
+function fileUrl(item: WxCpActivityApi.SignupAttachment) {
+ return toAccessibleFileUrl(item.previewURL || item.url);
+}
+
+/** 涓嬭浇閾炬帴鍚岀悊锛屼紭鍏堢敤 downloadURL */
+function downloadUrl(item: WxCpActivityApi.SignupAttachment) {
+ return toAccessibleFileUrl(item.downloadURL || item.url);
}
function formatSize(bytes?: number) {
@@ -215,18 +226,18 @@
</div>
<a
v-if="isImage(item)"
- :href="item.previewURL || item.url"
+ :href="fileUrl(item)"
target="_blank"
rel="noopener noreferrer"
>
<img
- :src="item.previewURL || item.url"
+ :src="fileUrl(item)"
alt="闄勪欢棰勮"
class="max-h-40 rounded object-contain"
/>
</a>
<a
- :href="item.downloadURL || item.url"
+ :href="downloadUrl(item)"
target="_blank"
rel="noopener noreferrer"
class="text-xs text-blue-500 hover:underline"
--
Gitblit v1.9.3