|
|
@@ -84,81 +84,64 @@ export const uploadFile = async (
|
|
|
folder = "avatar",
|
|
|
): Promise<string | null> => {
|
|
|
try {
|
|
|
- // iOS ImagePicker 可能返回各种格式的路径,统一处理
|
|
|
+ // 处理 URI
|
|
|
let processedUri = decodeURI(fileUri);
|
|
|
if (Platform.OS === "ios") {
|
|
|
- // 确保有 file:// 前缀
|
|
|
if (!processedUri.startsWith("file://") && !processedUri.startsWith("http")) {
|
|
|
processedUri = `file://${processedUri}`;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const formData = new FormData();
|
|
|
-
|
|
|
- // 获取文件名
|
|
|
+ // 获取文件名和类型
|
|
|
const fileName = processedUri.split("/").pop() || `avatar_${Date.now()}.jpg`;
|
|
|
+ const fileExt = fileName.split(".").pop()?.toLowerCase() || "jpg";
|
|
|
+ const mimeType = fileExt === "png" ? "image/png" : "image/jpeg";
|
|
|
|
|
|
- // 创建文件对象 (React Native 格式)
|
|
|
- const fileObj = {
|
|
|
+ console.log("[uploadFile] 开始上传, uri:", processedUri.substring(0, 80), "fileName:", fileName);
|
|
|
+
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append("file", {
|
|
|
uri: processedUri,
|
|
|
- type: "image/jpeg",
|
|
|
+ type: mimeType,
|
|
|
name: fileName,
|
|
|
- } as any;
|
|
|
-
|
|
|
- formData.append("file", fileObj);
|
|
|
+ } as any);
|
|
|
formData.append("appId", "supermart-acetoys");
|
|
|
formData.append("folder", folder);
|
|
|
|
|
|
- // 获取 token
|
|
|
const token = getToken();
|
|
|
- console.log("[uploadFile] token:", token ? "有" : "无", "uri:", processedUri.substring(0, 50));
|
|
|
-
|
|
|
- // 构建 track header(与 Vue 原项目 http.js 一致)
|
|
|
- const track = JSON.stringify({
|
|
|
- os: Platform.OS === "ios" ? 5 : 6,
|
|
|
- version: "1.0.5",
|
|
|
- deviceCode: "",
|
|
|
- bundleId: "com.wonderful.mart",
|
|
|
- channel: "wonderful",
|
|
|
- });
|
|
|
+ console.log("[uploadFile] token:", token ? "有" : "无");
|
|
|
|
|
|
+ // 使用与 Vue wx.uploadFile 完全一致的请求方式:只传 Authentication header
|
|
|
const response = await fetch("https://mm.acefig.com/api/oss/file/upload", {
|
|
|
method: "POST",
|
|
|
headers: {
|
|
|
- // 不设置 Content-Type,让 fetch 自动处理 multipart/form-data 边界
|
|
|
Authentication: token || "",
|
|
|
- track: track,
|
|
|
},
|
|
|
body: formData,
|
|
|
});
|
|
|
|
|
|
- console.log("[uploadFile] 响应状态:", response.status);
|
|
|
+ const responseText = await response.text();
|
|
|
+ console.log("[uploadFile] 状态:", response.status, "响应:", responseText?.substring(0, 300));
|
|
|
|
|
|
- // 检查响应状态
|
|
|
if (!response.ok) {
|
|
|
- const errorText = await response.text();
|
|
|
- console.error("[uploadFile] 上传失败 状态:", response.status, "内容:", errorText);
|
|
|
+ console.error("[uploadFile] HTTP错误:", response.status);
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- const text = await response.text();
|
|
|
- console.log("[uploadFile] 响应内容:", text?.substring(0, 200));
|
|
|
-
|
|
|
- if (!text) {
|
|
|
- console.error("[uploadFile] 上传响应为空");
|
|
|
+ if (!responseText) {
|
|
|
+ console.error("[uploadFile] 响应为空");
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- const result = JSON.parse(text);
|
|
|
- // code 可能是数字或字符串
|
|
|
+ const result = JSON.parse(responseText);
|
|
|
if ((result.code === 0 || result.code === "0") && result.data?.url) {
|
|
|
console.log("[uploadFile] 成功:", result.data.url);
|
|
|
return result.data.url;
|
|
|
}
|
|
|
- console.error("[uploadFile] 上传返回错误:", JSON.stringify(result));
|
|
|
+ console.error("[uploadFile] 业务错误:", JSON.stringify(result));
|
|
|
return null;
|
|
|
} catch (error) {
|
|
|
- console.error("[uploadFile] 上传文件异常:", error);
|
|
|
+ console.error("[uploadFile] 异常:", error);
|
|
|
return null;
|
|
|
}
|
|
|
};
|