Files
RN_Template/RN_TEMPLATE/app/services/api/uploadApi.ts

151 lines
4.0 KiB
TypeScript
Raw Normal View History

2026-02-05 13:16:05 +08:00
/**
* Upload API for file uploads via proxy to MinIO
* Supports both Web and Native platforms
*/
import { Platform } from "react-native"
const OSS_BASE_URL = "https://oss.upay01.com"
// Upload response type
export interface UploadResponse {
code: number
message: string
data?: {
filename: string
originalName: string
size: number
mimetype: string
url: string
}
}
/**
* Convert a URI to Blob (for Web platform)
*/
async function uriToBlob(uri: string): Promise<Blob> {
const response = await fetch(uri)
const blob = await response.blob()
return blob
}
/**
* Upload file on Web platform
*/
async function uploadFileWeb(
uri: string,
fileName: string,
mimeType: string,
): Promise<{ kind: "ok"; url: string } | { kind: "error"; message: string }> {
try {
// Convert URI to Blob for Web
const blob = await uriToBlob(uri)
const file = new File([blob], fileName, { type: mimeType })
const formData = new FormData()
formData.append("file", file)
const response = await fetch(`${OSS_BASE_URL}/api/proxy/upload`, {
method: "POST",
body: formData,
})
const data: UploadResponse = await response.json()
if (response.ok && data.code === 200 && data.data?.url) {
return { kind: "ok", url: data.data.url }
} else {
return { kind: "error", message: data.message || "Upload failed" }
}
} catch (e) {
if (__DEV__ && e instanceof Error) {
console.error(`Upload error: ${e.message}`)
}
return { kind: "error", message: "Upload failed" }
}
}
/**
* Upload file on Native platform (iOS/Android)
*/
function uploadFileNative(
uri: string,
fileName: string,
mimeType: string,
): Promise<{ kind: "ok"; url: string } | { kind: "error"; message: string }> {
return new Promise((resolve) => {
try {
const xhr = new XMLHttpRequest()
xhr.onload = () => {
if (__DEV__) {
console.log("Upload response status:", xhr.status)
console.log("Upload response body:", xhr.responseText)
}
if (xhr.status === 200) {
try {
const response: UploadResponse = JSON.parse(xhr.responseText)
if (response.code === 200 && response.data?.url) {
resolve({ kind: "ok", url: response.data.url })
} else {
resolve({ kind: "error", message: response.message || "Upload failed" })
}
} catch {
resolve({ kind: "error", message: "Invalid response" })
}
} else {
if (__DEV__) {
console.log("Upload failed - Status:", xhr.status, "Response:", xhr.responseText)
}
resolve({ kind: "error", message: `Upload failed with status ${xhr.status}` })
}
}
xhr.onerror = () => {
resolve({ kind: "error", message: "Network error" })
}
xhr.ontimeout = () => {
resolve({ kind: "error", message: "Upload timeout" })
}
xhr.open("POST", `${OSS_BASE_URL}/api/proxy/upload`)
xhr.timeout = 60000
// React Native specific FormData format
const formData = new FormData()
formData.append("file", {
uri: uri,
type: mimeType,
name: fileName,
} as any)
xhr.send(formData)
} catch (e) {
if (__DEV__ && e instanceof Error) {
console.error(`Upload error: ${e.message}`)
}
resolve({ kind: "error", message: "Upload failed" })
}
})
}
/**
* Upload a file to OSS storage
* Automatically handles Web vs Native platform differences
* @param uri - Local file URI
* @param fileName - File name
* @param mimeType - MIME type of the file
* @returns Upload result with URL or error
*/
export async function uploadFile(
uri: string,
fileName: string,
mimeType: string,
): Promise<{ kind: "ok"; url: string } | { kind: "error"; message: string }> {
if (Platform.OS === "web") {
return uploadFileWeb(uri, fileName, mimeType)
} else {
return uploadFileNative(uri, fileName, mimeType)
}
}