feat(media): implement caching for chat media and update components to use cached media

This commit is contained in:
2026-06-30 15:59:33 +08:00
parent 78d8aae22e
commit ccd2d6bd48
15 changed files with 591 additions and 42 deletions
+20 -1
View File
@@ -1,4 +1,5 @@
"use client";
/* eslint-disable @next/next/no-img-element */
/**
* ImageBubble 图片气泡
*
@@ -13,6 +14,7 @@ import { useState } from "react";
import { ROUTE_BUILDERS } from "@/router/routes";
import { useCachedChatMediaUrl } from "../hooks/use-cached-chat-media-url";
import styles from "./image-bubble.module.css";
export interface ImageBubbleProps {
@@ -28,9 +30,15 @@ export function ImageBubble({
}: ImageBubbleProps) {
const router = useRouter();
const [error, setError] = useState(false);
const { mediaUrl } = useCachedChatMediaUrl({
messageId,
remoteUrl: imageUrl,
kind: "image",
});
const src = decodeBase64Image(imageUrl);
const src = decodeBase64Image(mediaUrl || imageUrl);
const canOpen = Boolean(messageId);
const shouldUseNativeImage = isBrowserLocalImageSrc(src);
const openImage = () => {
if (!messageId) return;
@@ -54,6 +62,13 @@ export function ImageBubble({
>
{error ? (
<div className={styles.errorFallback}>🖼</div>
) : shouldUseNativeImage ? (
<img
className={styles.image}
src={src}
alt=""
onError={() => setError(true)}
/>
) : (
<Image
className={styles.image}
@@ -80,3 +95,7 @@ function decodeBase64Image(uri: string): string {
// 裸 base64 字符串 → 包装成 data URIPNG 兜底)
return `data:image/png;base64,${uri}`;
}
function isBrowserLocalImageSrc(src: string): boolean {
return src.startsWith("blob:") || src.startsWith("data:");
}