"use client"; /** * ImageUploadButton 图片上传按钮 * * 原始 Dart: lib/ui/chat/widgets/image_upload_button.dart(159 行) * * 原 Dart 使用 image_picker 库(移动端原生相册/相机) * 本轮使用 Web File API(``)以避免添加原生依赖 * * 行为: * - 点击按钮 → 弹出底部 sheet(相册 / 取消) * - 选择图片 → 读取为 base64 → dispatch ChatSendImage * - 上传中按钮显示加载指示器 */ import { useRef, useState } from "react"; import { useChatDispatch } from "@/stores/chat/chat-context"; import styles from "./image-upload-button.module.css"; export interface ImageUploadButtonProps { disabled?: boolean; } export function ImageUploadButton({ disabled = false }: ImageUploadButtonProps) { const dispatch = useChatDispatch(); const fileInputRef = useRef(null); const [showSheet, setShowSheet] = useState(false); const [isUploading, setIsUploading] = useState(false); const handleFile = async (file: File) => { if (isUploading) return; setIsUploading(true); setShowSheet(false); try { const buffer = await file.arrayBuffer(); const bytes = new Uint8Array(buffer); let binary = ""; for (let i = 0; i < bytes.byteLength; i++) { binary += String.fromCharCode(bytes[i]); } const base64 = window.btoa(binary); const ext = file.name.split(".").pop()?.toLowerCase() || "png"; const mime = file.type || `image/${ext}`; const dataUri = `data:${mime};base64,${base64}`; dispatch({ type: "ChatSendImage", imageBase64: dataUri }); } catch (e) { console.error("[ImageUpload] failed:", e); } finally { setIsUploading(false); } }; return ( <> {/* 隐藏的文件 input(触发文件选择) */} { const file = e.currentTarget.files?.[0]; if (file) void handleFile(file); e.currentTarget.value = ""; // 允许重选同一文件 }} /> {/* 底部选择 sheet(相册/取消) */} {showSheet && ( <>
setShowSheet(false)} />
)} ); }