avatar-upload.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { useState } from 'react'
  2. import { View, Image } from '@tarojs/components'
  3. import Taro from '@tarojs/taro'
  4. import { cn } from '../utils/cn'
  5. interface AvatarUploadProps {
  6. currentAvatar?: string
  7. onUploadSuccess?: (result: any) => void
  8. onUploadError?: (error: Error) => void
  9. size?: number
  10. editable?: boolean
  11. }
  12. export function AvatarUpload({
  13. currentAvatar,
  14. onUploadSuccess,
  15. onUploadError,
  16. size = 96,
  17. editable = true
  18. }: AvatarUploadProps) {
  19. const [uploading, setUploading] = useState(false)
  20. const [progress, setProgress] = useState(0)
  21. const handleChooseImage = async () => {
  22. if (!editable || uploading) return
  23. // 简化版本:只显示提示,不实际处理上传
  24. Taro.showToast({
  25. title: '头像上传功能需要在项目中实现',
  26. icon: 'none'
  27. })
  28. // 调用错误回调,提示需要实现
  29. onUploadError?.(new Error('头像上传功能需要在项目中实现,请参考原mini项目中的minio工具'))
  30. }
  31. const avatarSize = size
  32. return (
  33. <View
  34. className="relative inline-block"
  35. onClick={handleChooseImage}
  36. >
  37. <View
  38. className={cn(
  39. "relative overflow-hidden rounded-full",
  40. "border-4 border-white shadow-lg",
  41. editable && "cursor-pointer active:scale-95 transition-transform duration-150",
  42. uploading && "opacity-75"
  43. )}
  44. style={{ width: avatarSize, height: avatarSize }}
  45. >
  46. <Image
  47. src={currentAvatar || 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=160&h=160&fit=crop&crop=face'}
  48. mode="aspectFill"
  49. className="w-full h-full"
  50. />
  51. {uploading && (
  52. <View className="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
  53. <View className="text-white text-xs">{progress}%</View>
  54. </View>
  55. )}
  56. </View>
  57. {editable && !uploading && (
  58. <View
  59. className={cn(
  60. "absolute -bottom-1 -right-1",
  61. "w-8 h-8 bg-blue-500 rounded-full",
  62. "flex items-center justify-center shadow-md",
  63. "border-2 border-white"
  64. )}
  65. >
  66. <View className="i-heroicons-camera-20-solid w-4 h-4 text-white" />
  67. </View>
  68. )}
  69. {uploading && (
  70. <View
  71. className={cn(
  72. "absolute -bottom-1 -right-1",
  73. "w-8 h-8 bg-gray-500 rounded-full",
  74. "flex items-center justify-center shadow-md",
  75. "border-2 border-white"
  76. )}
  77. >
  78. <View className="i-heroicons-arrow-path-20-solid w-4 h-4 text-white animate-spin" />
  79. </View>
  80. )}
  81. </View>
  82. )
  83. }