From c76252e5685eff2457264fcbb0606418d399b7ce Mon Sep 17 00:00:00 2001 From: Junhui Chen Date: Wed, 16 Jul 2025 19:30:03 +0800 Subject: [PATCH] =?UTF-8?q?enhance:=20=E7=B1=BB=E5=9E=8B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/file-upload/files-uploader.tsx | 15 +- lib/background-uploader/index.ts | 2 +- lib/background-uploader/types.ts | 97 +++++++++- types/upload.ts | 210 ---------------------- 4 files changed, 97 insertions(+), 227 deletions(-) diff --git a/components/file-upload/files-uploader.tsx b/components/file-upload/files-uploader.tsx index c8984b1..2c6cc04 100644 --- a/components/file-upload/files-uploader.tsx +++ b/components/file-upload/files-uploader.tsx @@ -1,8 +1,7 @@ import { addMaterial, confirmUpload, getUploadUrl } from '@/lib/background-uploader/api'; -import { ConfirmUpload, FileUploadItem, UploadResult, UploadTask } from '@/lib/background-uploader/types'; +import { ConfirmUpload, FileUploadItem, UploadResult, UploadTask, ImagesuploaderProps, ExifData, defaultExifData } from '@/lib/background-uploader/types'; import { uploadFileWithProgress } from '@/lib/background-uploader/uploader'; import { compressImage } from '@/lib/image-process/imageCompress'; -import { defaultExifData, ExifData, ImagesuploaderProps } from '@/types/upload'; import * as ImageManipulator from 'expo-image-manipulator'; import * as ImagePicker from 'expo-image-picker'; import * as Location from 'expo-location'; @@ -24,7 +23,7 @@ export const ImagesUploader: React.FC = ({ fileType = ['images'], }) => { const [isLoading, setIsLoading] = useState(false); - + const [files, setFiles] = useState([]); const [uploadQueue, setUploadQueue] = useState([]); // 请求权限 @@ -63,12 +62,14 @@ export const ImagesUploader: React.FC = ({ // 创建上传项 const newFileItem: FileUploadItem = { id: fileId, + uri: asset.uri, + previewUrl: asset.uri, // 使用 asset.uri 作为初始预览 name: asset.fileName || 'file', progress: 0, - status: 'uploading' as const, - error: null, + status: 'uploading', + error: undefined, type: isVideo ? 'video' : 'image', - thumbnail: null, + thumbnail: undefined, }; setUploadQueue(prev => [...prev, newFileItem]); @@ -190,7 +191,7 @@ export const ImagesUploader: React.FC = ({ item.id === fileId ? { ...item, - status: 'done' as const, + status: 'success' as const, progress: 100, thumbnail: uploadResults.thumbnail } diff --git a/lib/background-uploader/index.ts b/lib/background-uploader/index.ts index ab50353..e317411 100644 --- a/lib/background-uploader/index.ts +++ b/lib/background-uploader/index.ts @@ -159,7 +159,7 @@ export const processMediaUpload = async (asset: ExtendedAsset) => { const originalResult = await uploadOriginalFile(); // 如果是图片,再上传压缩文件 - let compressedResult = { success: true, file_id: null }; + let compressedResult: { success: boolean; file_id?: string | null; error?: any } = { success: true, file_id: null }; if (!isVideo) { compressedResult = await uploadCompressedFile(); // 添加素材 diff --git a/lib/background-uploader/types.ts b/lib/background-uploader/types.ts index 7d2970c..08a763c 100644 --- a/lib/background-uploader/types.ts +++ b/lib/background-uploader/types.ts @@ -15,17 +15,96 @@ export type UploadTask = { }; }; -// 上传队列项 -export type FileUploadItem = { - id: string; - name: string; - progress: number; - status: 'pending' | 'uploading' | 'done' | 'error'; - error: string | null; - type: 'image' | 'video'; - thumbnail: string | null; +// 文件元数据信息 +interface FileSize { + value: number; + unit: string; +} + +interface FileMetadata { + originalName: string; + type: string; + isCompressed: string; + fileType: string; +} + +// 后端返回的文件信息 +interface FileInfo { + file_id: number; + name: string; + size: FileSize; + content_type: string; // 这里与 ConfirmUpload 的 content_type 定义不同,需要注意 + upload_time: string; + storage_medium: string; + file_path: string; // 这里与 ConfirmUpload 的 file_path 定义不同 + uploader_id: number; + upload_status: string; + deletion_status: string; + metadata: FileMetadata; +} + +// 上传队列项 - 作为唯一的类型定义 +// 定义 EXIF 数据类型 +export type ExifData = { + GPSLatitude?: number | undefined; + GPSLongitude?: number | undefined; + GPSAltitude?: number | undefined; + DateTimeOriginal?: string | undefined; + Make?: string | undefined; + Model?: string | undefined; + ExposureTime?: number | undefined; + FNumber?: number | undefined; + ISOSpeedRatings?: number | undefined; + FocalLength?: number | undefined; + [key: string]: any; }; +// 默认的 EXIF 数据结构 +export const defaultExifData: ExifData = { + GPSLatitude: undefined, + GPSLongitude: undefined, + GPSAltitude: undefined, + DateTimeOriginal: undefined, + Make: undefined, + Model: undefined, + ExposureTime: undefined, + FNumber: undefined, + ISOSpeedRatings: undefined, + FocalLength: undefined, +}; + +// 压缩图片可配置参数 +export interface ImagesuploaderProps { + children?: React.ReactNode; + style?: import('react-native').StyleProp; + onPickImage?: (file: File, exifData: ExifData) => void; + compressQuality?: number; + maxWidth?: number; + maxHeight?: number; + preserveExif?: boolean; + uploadOriginal?: boolean; + onUploadComplete?: (result: FileUploadItem[]) => void; + onProgress?: (progress: any) => void; // TODO: Define a proper type for progress + multipleChoice?: boolean; + fileType?: any[]; // TODO: Use MediaType from expo-image-picker + showPreview?: boolean; +} + +export interface FileUploadItem { + id: string; + uri: string; // 用于本地展示的资源URI + name: string; + progress: number; + status: 'pending' | 'uploading' | 'success' | 'error'; // 统一状态 + error?: string | null; + previewUrl: string; // 预览URL + file?: File; + type: 'image' | 'video'; + thumbnail?: string; // 缩略图URL + thumbnailFile?: File; // 缩略图文件对象 + originalFile?: FileInfo // 上传后返回的文件信息 +} + // 确认上传返回 export type ConfirmUpload = { file_id: string; diff --git a/types/upload.ts b/types/upload.ts index ccf5afa..e69de29 100644 --- a/types/upload.ts +++ b/types/upload.ts @@ -1,210 +0,0 @@ -import { MediaType } from "expo-image-picker"; -import { ReactNode } from "react"; -import { StyleProp, ViewStyle } from "react-native"; - -export interface FileStatus { - file: File; - status: 'pending' | 'uploading' | 'success' | 'error'; - progress: number; - error?: string; -} -export interface MaterialFile { - id: string; - file_name: string; - url: string; -} - -export interface OutputVideoFile { - id: string; - file_name: string; - url: string; -} - -export interface ManualTask { - task_id: string; - user_id: string; - status: 'Created' | 'Processing' | 'Completed' | 'Failed'; - created_at: string; - started_at: string; - completed_at: string; - failure_reason: string | null; - template_id: number; - source_files: MaterialFile[]; - output_video_file?: OutputVideoFile; -} - -export interface Size { - value: number; - unit: 'B' | 'KB' | 'MB' | 'GB' | 'TB'; -} - -export interface ContentType { - value: string; -} - -export interface FilePath { - value: string; -} - -export interface Metadata { - [key: string]: any; -} - -export type UploadStatus = 'Pending' | 'Uploading' | 'Completed' | 'Failed'; -export type DeletionStatus = 'Active' | 'PendingDeletion' | 'Deleted'; - -export interface ConfirmUpload { - file_id: string; - upload_url: string - name: string; - size: Size; - content_type: ContentType; - upload_time: string; // ISO date string - storage_medium: string; - file_path: FilePath; - uploader_id: number; - upload_status: UploadStatus; - deletion_status: DeletionStatus; - metadata: Metadata; -} - -// 定义 EXIF 数据类型 -export type ExifData = { - GPSLatitude?: number | undefined; - GPSLongitude?: number | undefined; - GPSAltitude?: number | undefined; - DateTimeOriginal?: string | undefined; - Make?: string | undefined; - Model?: string | undefined; - ExposureTime?: number | undefined; - FNumber?: number | undefined; - ISOSpeedRatings?: number | undefined; - FocalLength?: number | undefined; - [key: string]: any; -}; - -// 默认的 EXIF 数据结构 -export const defaultExifData: ExifData = { - GPSLatitude: undefined, - GPSLongitude: undefined, - GPSAltitude: undefined, - DateTimeOriginal: undefined, - Make: undefined, - Model: undefined, - ExposureTime: undefined, - FNumber: undefined, - ISOSpeedRatings: undefined, - FocalLength: undefined, -}; - -// 压缩图片可配置参数 -export interface ImagesuploaderProps { - children?: ReactNode; - style?: StyleProp; - onPickImage?: (file: File, exifData: ExifData) => void; - /** 压缩质量,0-1 之间的数字,默认为 0.8 */ - compressQuality?: number; - /** 最大宽度,图片会被等比例缩放 */ - maxWidth?: number; - /** 最大高度,图片会被等比例缩放 */ - maxHeight?: number; - /** 是否保留 EXIF 数据,默认为 true */ - preserveExif?: boolean; - /** 是否上传原图,默认为 false */ - uploadOriginal?: boolean; - /** 上传完成回调 */ - onUploadComplete?: UploadCompleteCallback; - /** 进度 */ - onProgress?: (progress: FileStatus) => void; - /** 多选单选 默认单选*/ - multipleChoice?: boolean; - /** 文件类型 默认图片*/ - fileType?: MediaType[]; - /** 是否展示预览 默认展示*/ - showPreview?: boolean; -} - -// 定义上传结果类型 -export interface UploadResult { - originalUrl?: string; - compressedUrl: string; - file: File; - exifData: ExifData; - originalFile: ConfirmUpload; - compressedFile: ConfirmUpload; - thumbnail: string; - thumbnailFile: File; -} - -// 定义上传完成回调类型 -export type UploadCompleteCallback = (result: FileUploadItem[]) => void; - -// 单张图片上传完成回调类型 -export type UploadSingleCompleteCallback = (result: FileUploadItem) => void; - -// 定义上传 URL 响应类型 -export interface UploadUrlResponse { - expires_in: number; - file_id: string; - file_path: string; - upload_url: string; -} -interface FileSize { - value: number; - unit: string; -} - -interface FileMetadata { - originalName: string; - type: string; - isCompressed: string; - fileType: string; -} -interface FileInfo { - file_id: number; - name: string; - size: FileSize; - content_type: ContentType; - upload_time: string; - storage_medium: string; - file_path: FilePath; - uploader_id: number; - upload_status: string; - deletion_status: string; - metadata: FileMetadata; -} -export interface FileUploadItem { - id: string; - uri: string; - name: string; - progress: number; - status: 'pending' | 'uploading' | 'success' | 'error'; - error?: string; - previewUrl: string; - file?: File; - type: 'image' | 'video'; - thumbnail?: string; // 缩略图URL - thumbnailFile?: File; // 缩略图文件对象 - originalFile?: FileInfo -} - -// 压缩图片可配置参数 -export interface ImagesPickerProps { - children?: ReactNode; - style?: StyleProp; - onPickImage?: (file: File, exifData: ExifData) => void; - /** 压缩质量,0-1 之间的数字,默认为 0.8 */ - compressQuality?: number; - /** 最大宽度,图片会被等比例缩放 */ - maxWidth?: number; - /** 最大高度,图片会被等比例缩放 */ - maxHeight?: number; - /** 是否保留 EXIF 数据,默认为 true */ - preserveExif?: boolean; - /** 是否上传原图,默认为 false */ - uploadOriginal?: boolean; - /** 上传完成回调 */ - onUploadComplete?: UploadSingleCompleteCallback; - /** 进度 */ - onProgress?: (progress: FileStatus) => void; -} \ No newline at end of file