fix: 修复布局问题

This commit is contained in:
imeepos
2025-11-12 10:02:55 +08:00
parent 26cd0139bf
commit a7d922b535
12 changed files with 876 additions and 699 deletions

View File

@@ -210,5 +210,5 @@ export async function recordTokenUsage(
* 跳转到充值页面
*/
export function redirectToPricePage() {
router.push('/exchange' as any);
router.push('/exchange');
}

5
lib/api/todo.md Normal file
View File

@@ -0,0 +1,5 @@
页面:/profile
点击顶部 月付 应该跳转到 app\recharge.tsx
点击顶部的 余额 应该跳转到 app\exchange.tsx

View File

@@ -1,4 +1,4 @@
import { apiClient } from './client';
import { storage } from '../storage';
export interface UploadResponse {
success: boolean;
@@ -11,6 +11,10 @@ export interface UploadResponse {
message?: string;
}
async function getAuthToken(): Promise<string> {
return (await storage.getItem(`bestaibest.better-auth.session_token`)) || '';
}
/**
* 上传文件到服务器
* @param uri 本地文件 URI可以是 blob: 或 file:// 格式)
@@ -31,43 +35,100 @@ export async function uploadFile(uri: string, type: 'image' | 'video'): Promise<
};
}
// 先获取 blob 以确定实际的 MIME 类型
const response = await fetch(uri);
const blob = await response.blob();
// 从 blob 获取实际的 MIME 类型
let mimeType = blob.type;
// 如果 blob 没有 type则根据参数推断
if (!mimeType || mimeType === 'application/octet-stream') {
mimeType = type === 'image' ? 'image/jpeg' : 'video/mp4';
}
// 根据 MIME 类型确定文件扩展名
let extension: string;
if (mimeType.startsWith('image/')) {
const imageExtensions: Record<string, string> = {
'image/jpeg': 'jpg',
'image/png': 'png',
'image/gif': 'gif',
'image/webp': 'webp',
};
extension = imageExtensions[mimeType] || 'jpg';
} else {
const videoExtensions: Record<string, string> = {
'video/mp4': 'mp4',
'video/webm': 'webm',
'video/avi': 'avi',
'video/quicktime': 'mov',
};
extension = videoExtensions[mimeType] || 'mp4';
}
// 生成文件名
const filename = `${type}_${Date.now()}.${extension}`;
// 创建 File 对象
const file = new File([blob], filename, { type: mimeType });
// 创建 FormData
const formData = new FormData();
formData.append('file', file);
// 从 URI 中提取文件信息
const filename = uri.split('/').pop() || `${type}_${Date.now()}`;
const match = /\.(\w+)$/.exec(filename);
const fileType = match ? match[1] : (type === 'image' ? 'jpg' : 'mp4');
// 获取认证 token
const token = await getAuthToken();
// 添加文件到 FormData
formData.append('file', {
uri,
type: type === 'image' ? `image/${fileType}` : `video/${fileType}`,
name: filename,
} as any);
formData.append('type', type);
// 上传文件
const response = await fetch(`${process.env.EXPO_PUBLIC_API_URL || 'https://api.mixvideo.bowong.cc'}/api/upload`, {
// 上传文件(不要手动设置 Content-Type让浏览器自动添加 boundary
const uploadResponse = await fetch(`https://api.mixvideo.bowong.cc/api/file/upload/s3`, {
method: 'POST',
headers: token ? {
'Authorization': `Bearer ${token}`,
} : {},
body: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.statusText}`);
if (!uploadResponse.ok) {
const errorData = await uploadResponse.json();
const errorMessage = errorData?.error?.message || errorData?.message || uploadResponse.statusText;
throw new Error(`Upload failed: ${errorMessage}`);
}
const result = await response.json();
const result = await uploadResponse.json();
if (!result.success) {
throw new Error(result.message || 'Upload failed');
// 支持多种返回格式:
// 1. { status: true, msg: "...", data: "url" } - 实际 S3 上传格式
// 2. { success: true, data: { url, ... } }
// 3. { data: { status: true, data: "url" } }
if (result.status === true && result.data) {
// 格式 1实际 S3 格式)
return {
success: true,
data: {
url: result.data,
filename: filename,
size: file.size,
mimeType: mimeType,
},
};
} else if (result.data?.status && result.data?.data) {
// 格式 3
return {
success: true,
data: {
url: result.data.data,
filename: filename,
size: file.size,
mimeType: mimeType,
},
};
} else if (result.success && result.data) {
// 格式 2
return result;
} else {
throw new Error(result.error?.message || result.msg || result.message || 'Upload failed');
}
return result;
} catch (error) {
console.error('Failed to upload file:', error);
return {