'use client' import { useState, useRef } from 'react' import { Button } from '@/components/ui/button' import { X, Image as ImageIcon } from 'lucide-react' import Image from 'next/image' import { Spinner } from '@/components/ui/spinner' import COS from 'cos-js-sdk-v5' interface ImageUploaderProps { value: string onChange: (url: string) => void } export function ImageUploader({ value, onChange }: ImageUploaderProps) { const [isUploading, setIsUploading] = useState(false) const [error, setError] = useState('') const fileInputRef = useRef(null) const handleFileSelect = async (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (!file) return // Validate file type if (!file.type.startsWith('image/')) { setError('请选择图片文件') return } // Validate file size (max 5MB) if (file.size > 5 * 1024 * 1024) { setError('图片大小不能超过 5MB') return } setError('') setIsUploading(true) try { // Get temp key const keyRes = await fetch('/api/cos/temp-key') if (!keyRes.ok) { throw new Error('获取上传凭证失败') } const keyData = await keyRes.json() // Generate unique filename const ext = file.name.split('.').pop() || 'jpg' const timestamp = Date.now() const randomStr = Math.random().toString(36).substring(2, 8) const filename = `mini_game/images/${timestamp}_${randomStr}.${ext}` // Initialize COS with temp credentials const cos = new COS({ getAuthorization: (_options, callback) => { callback({ TmpSecretId: keyData.credentials.tmpSecretId, TmpSecretKey: keyData.credentials.tmpSecretKey, SecurityToken: keyData.credentials.sessionToken, StartTime: keyData.startTime, ExpiredTime: keyData.expiredTime, }) }, }) // Upload file const uploadUrl = await new Promise((resolve, reject) => { cos.putObject( { Bucket: keyData.bucket, Region: keyData.region, Key: filename, Body: file, }, (err, data) => { if (err) { reject(new Error(err.message || '上传失败')) return } const url = `https://${keyData.bucket}.cos.${keyData.region}.myqcloud.com/${filename}` resolve(url) } ) }) onChange(uploadUrl) } catch (err) { console.error('Upload error:', err) setError(err instanceof Error ? err.message : '上传失败') } finally { setIsUploading(false) // Reset file input if (fileInputRef.current) { fileInputRef.current.value = '' } } } const handleRemove = () => { onChange('') setError('') } return (
{value ? (
预览图片
) : (
fileInputRef.current?.click()} > {isUploading ? ( <>

上传中...

) : ( <>

点击上传图片

支持 JPG、PNG,最大 5MB

)}
)} {error && (

{error}

)}
) }