Files
jaystar 28c4d7b3b4 feat: 实现减脂体重管理App完整功能
- 实现拍照识别食物功能(集成大语言模型视觉能力)
- 实现智能对话功能(集成大语言模型流式输出)
- 实现食物记录和卡路里管理功能
- 实现体重记录和统计功能
- 实现健康数据管理页面
- 配置数据库表结构(用户、食物记录、体重记录)
- 实现Express后端API路由
- 配置Tab导航和前端页面
- 采用健康运动配色方案
2026-02-02 15:17:50 +08:00

77 lines
2.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Platform } from 'react-native';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);
const API_BASE = (process.env.EXPO_PUBLIC_API_BASE ?? '').replace(/\/$/, '');
/**
* 创建跨平台兼容的文件对象,用于 FormData.append()
* - Web 端返回 File 对象
* - 移动端返回 { uri, type, name } 对象RN fetch 会自动处理)
* @param fileUri Expo 媒体库(如 expo-image-picker、expo-camera返回的 uri
* @param fileName 上传时的文件名,如 'photo.jpg'
* @param mimeType 文件 MIME 类型,如 'image/jpeg'、'audio/mpeg'
*/
export async function createFormDataFile(
fileUri: string,
fileName: string,
mimeType: string
): Promise<File | { uri: string; type: string; name: string }> {
if (Platform.OS === 'web') {
const response = await fetch(fileUri);
const blob = await response.blob();
return new File([blob], fileName, { type: mimeType });
}
return { uri: fileUri, type: mimeType, name: fileName };
}
/**
* 构建文件或图片完整的URL
* @param url 相对或绝对路径
* @param w 宽度 (px) - 自动向下取整
* @param h 高度 (px)
*/
export const buildAssetUrl = (url?: string | null, w?: number, h?: number): string | undefined => {
if (!url) return undefined;
if (/^https?:\/\//i.test(url)) return url; // 绝对路径直接返回
// 1. 去除 Base 尾部和 Path 头部的斜杠
const base = API_BASE;
const path = url.replace(/^\//, '');
const abs = `${base}/${path}`;
// 2. 无需缩略图则直接返回
if (!w && !h) return abs;
// 3. 构造参数,保留原有 Query (如有)
const separator = abs.includes('?') ? '&' : '?';
const query = [
w ? `w=${Math.floor(w)}` : '',
h ? `h=${Math.floor(h)}` : ''
].filter(Boolean).join('&');
return `${abs}${separator}${query}`;
};
/**
* 将UTC时间字符串转换为本地时间字符串
* @param utcDateStr UTC时间字符串格式如2025-11-26T01:49:48.009573
* @returns 本地时间字符串格式如2025-11-26 08:49:48
*/
export const convertToLocalTimeStr = (utcDateStr: string): string => {
if (!utcDateStr) {
return utcDateStr;
}
const microUtcRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{1,6}/;
if (!microUtcRegex.test(utcDateStr)) {
console.log('invalid utcDateStr:', utcDateStr);
return utcDateStr;
}
const normalized = utcDateStr.replace(/\.(\d{6})$/, (_, frac) => `.${frac.slice(0, 3)}`);
const d = dayjs.utc(normalized);
if (!d.isValid()) {
return utcDateStr;
}
return d.local().format('YYYY-MM-DD HH:mm:ss');
}