feat: 公告中心展示皮肤站公告配图
Sync source to CNB / Sync Git ref (push) Skipped

公告数据保留 imageName,登录后按公告附件接口拉取图片并以 blob URL 展示,列表显示缩略图、详情显示大图,组件卸载时回收。
This commit is contained in:
AxTps committed 2026-10-23 21:42:55 +08:00
1 parent ec89ec5cec
commit 8bb01924cd
2 files changed
+23

No files matched your search

@@ -236,6 +236,7 @@ async function refresh() {
if (parsed && !disposed) { if (parsed && !disposed) {
sync(parsed, true) sync(parsed, true)
saveCache(parsed) saveCache(parsed)
for (const item of parsed) void loadImage(item, token)
} }
} catch { } catch {
// Remote fetch failed; previously cached items remain displayed // Remote fetch failed; previously cached items remain displayed
@@ -316,6 +317,7 @@ onUnmounted(() => {
if (interval) clearInterval(interval) if (interval) clearInterval(interval)
if (advanceTimer) clearTimeout(advanceTimer) if (advanceTimer) clearTimeout(advanceTimer)
window.removeEventListener(OPEN_REMOTE_ANNOUNCEMENT_CENTER_EVENT, handleOpenCenter) window.removeEventListener(OPEN_REMOTE_ANNOUNCEMENT_CENTER_EVENT, handleOpenCenter)
revokeImages()
}) })
</script> </script>
@@ -378,6 +380,12 @@ onUnmounted(() => {
class="mt-1.5 size-2 shrink-0 rounded-full" class="mt-1.5 size-2 shrink-0 rounded-full"
:class="read.has(announcementKey(item)) ? 'opacity-0' : 'bg-red'" :class="read.has(announcementKey(item)) ? 'opacity-0' : 'bg-red'"
/> />
<img
v-if="imageUrls[item.id]"
:src="imageUrls[item.id]"
alt=""
class="size-10 shrink-0 rounded object-cover"
/>
<span class="min-w-0 flex-1"> <span class="min-w-0 flex-1">
<span class="block truncate font-medium text-[var(--color-text-primary)]">{{ <span class="block truncate font-medium text-[var(--color-text-primary)]">{{
item.title item.title
@@ -393,6 +401,12 @@ onUnmounted(() => {
<h2 class="mb-4 text-xl font-semibold text-[var(--color-text-primary)]"> <h2 class="mb-4 text-xl font-semibold text-[var(--color-text-primary)]">
{{ selected.title }} {{ selected.title }}
</h2> </h2>
<img
v-if="imageUrls[selected.id]"
:src="imageUrls[selected.id]"
alt=""
class="mb-4 max-h-80 w-full rounded-lg object-contain"
/>
<div <div
class="markdown-body break-words" class="markdown-body break-words"
@click="contentClick" @click="contentClick"
@@ -11,6 +11,7 @@ export type RemoteAnnouncement = {
published_at: string published_at: string
action_url: string | null action_url: string | null
action_label: string | null action_label: string | null
image_name: string | null
} }
export function safeAnnouncementUrl(value: unknown): string | null { export function safeAnnouncementUrl(value: unknown): string | null {
@@ -62,6 +63,10 @@ export function parseAnnouncements(value: unknown): RemoteAnnouncement[] | null
ends_at: item.ends_at ?? null, ends_at: item.ends_at ?? null,
action_label: item.action_label ?? null, action_label: item.action_label ?? null,
action_url: item.action_url ?? null, action_url: item.action_url ?? null,
image_name:
typeof item.image_name === 'string' && item.image_name.trim()
? item.image_name
: null,
} as RemoteAnnouncement) } as RemoteAnnouncement)
} }
const rank = { low: 0, normal: 1, high: 2, critical: 3 } const rank = { low: 0, normal: 1, high: 2, critical: 3 }
@@ -143,6 +148,10 @@ export function mapBroadcastAnnouncements(payload: unknown): RemoteAnnouncement[
published_at: published, published_at: published,
action_url: null, action_url: null,
action_label: null, action_label: null,
image_name:
typeof item.imageName === 'string' && item.imageName.trim()
? item.imageName
: null,
}) })
} }
const rank = { low: 0, normal: 1, high: 2, critical: 3 } const rank = { low: 0, normal: 1, high: 2, critical: 3 }