diff --git a/README-notifications.md b/README-notifications.md
deleted file mode 100644
index 6950b16..0000000
--- a/README-notifications.md
+++ /dev/null
@@ -1,375 +0,0 @@
-# 推送通知功能使用指南
-
-## 快速开始
-
-### 1. 安装依赖
-
-推送通知功能已经集成到项目中,无需额外安装依赖。
-
-### 2. 基本使用
-
-在组件中使用推送通知功能:
-
-```typescript
-import { useNotifications } from '@/hooks/useNotifications';
-
-function MyComponent() {
- const { sendNotification, sendWorkoutReminder } = useNotifications();
-
- const handleSendNotification = async () => {
- await sendNotification({
- title: '测试通知',
- body: '这是一个测试通知',
- sound: true,
- priority: 'high'
- });
- };
-
- const handleSendWorkoutReminder = async () => {
- await sendWorkoutReminder('运动提醒', '该开始今天的普拉提训练了!');
- };
-
- return (
- // 你的组件内容
- );
-}
-```
-
-### 3. 使用辅助函数
-
-```typescript
-import { WorkoutNotificationHelpers, GoalNotificationHelpers } from '@/utils/notificationHelpers';
-
-// 发送运动开始提醒
-await WorkoutNotificationHelpers.sendWorkoutStartReminder('张三');
-
-// 发送目标达成通知
-await GoalNotificationHelpers.sendGoalAchievementNotification('张三', '每周运动3次');
-
-// 安排每日运动提醒
-await WorkoutNotificationHelpers.scheduleDailyWorkoutReminder('张三', 9, 0); // 每天上午9点
-```
-
-## 功能特性
-
-### ✅ 已实现功能
-
-- [x] 立即发送通知
-- [x] 定时发送通知
-- [x] 重复发送通知
-- [x] 通知权限管理
-- [x] 通知点击处理
-- [x] 通知取消功能
-- [x] 多种通知类型支持
-- [x] 通知模板系统
-- [x] 批量通知发送
-- [x] 通知状态查询
-
-### 📱 支持的通知类型
-
-1. **运动相关**
- - 运动开始提醒
- - 运动完成通知
- - 每日运动提醒
-
-2. **目标相关**
- - 目标达成通知
- - 目标进度更新
- - 目标截止提醒
-
-3. **心情相关**
- - 心情打卡提醒
- - 每日心情提醒
-
-4. **营养相关**
- - 营养记录提醒
- - 三餐提醒
-
-5. **通用通知**
- - 欢迎通知
- - 成就通知
- - 系统维护通知
-
-## 详细使用示例
-
-### 1. 在运动页面中使用
-
-```typescript
-import { WorkoutNotificationHelpers } from '@/utils/notificationHelpers';
-
-// 运动开始时
-const handleWorkoutStart = async () => {
- await WorkoutNotificationHelpers.sendWorkoutStartReminder(userName);
- // 开始运动逻辑
-};
-
-// 运动完成时
-const handleWorkoutComplete = async (duration: number) => {
- await WorkoutNotificationHelpers.sendWorkoutCompleteNotification(userName, duration);
- // 完成运动逻辑
-};
-```
-
-### 2. 在目标页面中使用
-
-```typescript
-import { GoalNotificationHelpers } from '@/utils/notificationHelpers';
-
-// 目标达成时
-const handleGoalAchieved = async (goalName: string) => {
- await GoalNotificationHelpers.sendGoalAchievementNotification(userName, goalName);
- // 目标达成逻辑
-};
-
-// 目标进度更新时
-const handleGoalProgress = async (goalName: string, progress: number) => {
- if (progress >= 50 && progress < 100) {
- await GoalNotificationHelpers.sendGoalProgressNotification(userName, goalName, progress);
- }
-};
-```
-
-### 3. 在心情页面中使用
-
-```typescript
-import { MoodNotificationHelpers } from '@/utils/notificationHelpers';
-
-// 安排每日心情打卡提醒
-const setupMoodReminder = async () => {
- await MoodNotificationHelpers.scheduleDailyMoodReminder(userName, 20, 0); // 每天晚上8点
-};
-```
-
-### 4. 在营养页面中使用
-
-```typescript
-import { NutritionNotificationHelpers } from '@/utils/notificationHelpers';
-
-// 安排营养记录提醒
-const setupNutritionReminders = async () => {
- await NutritionNotificationHelpers.scheduleNutritionReminders(userName);
-};
-```
-
-## 通知模板使用
-
-```typescript
-import { NotificationTemplates } from '@/utils/notificationHelpers';
-import { notificationService } from '@/services/notifications';
-
-// 使用模板发送通知
-const sendWorkoutNotification = async (userName: string) => {
- const notification = NotificationTemplates.workout.start(userName);
- await notificationService.sendImmediateNotification(notification);
-};
-
-const sendGoalNotification = async (userName: string, goalName: string) => {
- const notification = NotificationTemplates.goal.achievement(userName, goalName);
- await notificationService.sendImmediateNotification(notification);
-};
-```
-
-## 权限管理
-
-### 检查权限状态
-
-```typescript
-import { useNotifications } from '@/hooks/useNotifications';
-
-function MyComponent() {
- const { permissionStatus, requestPermission } = useNotifications();
-
- const handleRequestPermission = async () => {
- const status = await requestPermission();
- if (status === 'granted') {
- console.log('通知权限已授予');
- } else {
- console.log('通知权限被拒绝');
- }
- };
-
- return (
-
- 权限状态: {permissionStatus}
-
-
- );
-}
-```
-
-### 处理权限被拒绝
-
-```typescript
-const handleNotificationToggle = async (value: boolean) => {
- if (value) {
- try {
- const status = await requestPermission();
- if (status === 'granted') {
- setNotificationEnabled(true);
- } else {
- Alert.alert(
- '权限被拒绝',
- '请在系统设置中开启通知权限以获得最佳体验',
- [
- { text: '取消', style: 'cancel' },
- { text: '去设置', onPress: () => Linking.openSettings() }
- ]
- );
- }
- } catch (error) {
- Alert.alert('错误', '请求通知权限失败');
- }
- }
-};
-```
-
-## 通知管理
-
-### 取消特定通知
-
-```typescript
-import { notificationService } from '@/services/notifications';
-
-// 取消特定通知
-await notificationService.cancelNotification(notificationId);
-
-// 取消所有通知
-await notificationService.cancelAllNotifications();
-
-// 取消特定类型的通知
-import { GeneralNotificationHelpers } from '@/utils/notificationHelpers';
-await GeneralNotificationHelpers.cancelNotificationsByType('workout_reminder');
-```
-
-### 查询已安排的通知
-
-```typescript
-import { notificationService } from '@/services/notifications';
-
-// 获取所有已安排的通知
-const notifications = await notificationService.getAllScheduledNotifications();
-console.log('已安排的通知数量:', notifications.length);
-
-notifications.forEach(notification => {
- console.log('通知ID:', notification.identifier);
- console.log('通知标题:', notification.content.title);
- console.log('通知内容:', notification.content.body);
- console.log('通知类型:', notification.content.data?.type);
-});
-```
-
-## 测试功能
-
-### 使用测试组件
-
-项目中包含了一个完整的测试组件 `NotificationTest.tsx`,可以用来测试所有通知功能:
-
-```typescript
-import { NotificationTest } from '@/components/NotificationTest';
-
-// 在开发环境中使用
-function TestScreen() {
- return ;
-}
-```
-
-### 手动测试
-
-```typescript
-// 测试立即通知
-await sendNotification({
- title: '测试通知',
- body: '这是一个测试通知',
- sound: true,
- priority: 'high'
-});
-
-// 测试定时通知(5秒后)
-const futureDate = new Date(Date.now() + 5000);
-await scheduleNotification(
- {
- title: '定时测试',
- body: '这是一个5秒后的定时通知',
- sound: true
- },
- futureDate
-);
-
-// 测试重复通知(每分钟)
-await scheduleRepeatingNotification(
- {
- title: '重复测试',
- body: '这是一个每分钟重复的通知',
- sound: true
- },
- { minutes: 1 }
-);
-```
-
-## 最佳实践
-
-### 1. 通知内容设计
-
-- **标题**: 简洁明了,不超过50个字符
-- **内容**: 具体有用,不超过200个字符
-- **时机**: 选择合适的发送时间
-- **频率**: 避免过于频繁的通知
-
-### 2. 用户体验
-
-- 提供通知开关选项
-- 允许用户自定义通知时间
-- 支持通知类型的选择
-- 提供通知历史记录
-
-### 3. 错误处理
-
-- 始终处理权限请求失败
-- 提供用户友好的错误提示
-- 实现降级处理方案
-
-### 4. 性能优化
-
-- 避免同时发送大量通知
-- 及时清理不需要的通知
-- 合理使用重复通知
-
-## 故障排除
-
-### 常见问题
-
-1. **通知不显示**
- - 检查权限是否已授予
- - 确认应用是否在前台
- - 验证通知配置是否正确
-
-2. **定时通知不触发**
- - 检查设备是否重启
- - 确认应用是否被系统杀死
- - 验证时间设置是否正确
-
-3. **权限被拒绝**
- - 引导用户到系统设置
- - 提供权限说明
- - 实现降级处理方案
-
-### 调试技巧
-
-```typescript
-// 启用详细日志
-console.log('通知权限状态:', await notificationService.getPermissionStatus());
-console.log('已安排通知:', await notificationService.getAllScheduledNotifications());
-
-// 测试通知发送
-await notificationService.sendImmediateNotification({
- title: '调试通知',
- body: '这是一个调试通知',
- sound: true
-});
-```
-
-## 总结
-
-推送通知功能已经完整集成到项目中,提供了丰富的功能和良好的用户体验。开发者可以根据具体需求灵活使用各种通知功能,为用户提供个性化的提醒服务。
-
-如有任何问题或建议,请参考 `docs/notification-implementation.md` 文档或联系开发团队。
diff --git a/app.json b/app.json
index 504ef7d..6b6d47d 100644
--- a/app.json
+++ b/app.json
@@ -1,6 +1,6 @@
{
"expo": {
- "name": "海豹健康",
+ "name": "Out Live",
"slug": "digital-pilates",
"version": "1.0.5",
"orientation": "portrait",
diff --git a/app/(tabs)/statistics.tsx b/app/(tabs)/statistics.tsx
index 7450afb..c7fed35 100644
--- a/app/(tabs)/statistics.tsx
+++ b/app/(tabs)/statistics.tsx
@@ -15,7 +15,7 @@ import { useAuthGuard } from '@/hooks/useAuthGuard';
import { selectHealthDataByDate, setHealthData } from '@/store/healthSlice';
import { fetchDailyMoodCheckins, selectLatestMoodRecordByDate } from '@/store/moodSlice';
import { fetchDailyNutritionData, selectNutritionSummaryByDate } from '@/store/nutritionSlice';
-import { fetchTodayWaterStats, selectTodayStats } from '@/store/waterSlice';
+import { fetchTodayWaterStats } from '@/store/waterSlice';
import { getMonthDaysZh, getTodayIndexInMonth } from '@/utils/date';
import { ensureHealthPermissions, fetchHealthDataForDate, testHRVDataFetch } from '@/utils/health';
import { getTestHealthData } from '@/utils/mockHealthData';
@@ -89,8 +89,6 @@ export default function ExploreScreen() {
// 从 Redux 获取指定日期的健康数据
const healthData = useAppSelector(selectHealthDataByDate(currentSelectedDateString));
- // 获取今日喝水统计数据
- const todayWaterStats = useAppSelector(selectTodayStats);
// 解构健康数据(支持mock数据)
const mockData = useMockData ? getTestHealthData('mock') : null;
@@ -101,7 +99,7 @@ export default function ExploreScreen() {
const sleepDuration = useMockData ? (mockData?.sleepDuration ?? null) : (healthData?.sleepDuration ?? null);
const hrvValue = useMockData ? (mockData?.hrv ?? 0) : (healthData?.hrv ?? 0);
const oxygenSaturation = useMockData ? (mockData?.oxygenSaturation ?? null) : (healthData?.oxygenSaturation ?? null);
- const heartRate = useMockData ? (mockData?.heartRate ?? null) : (healthData?.heartRate ?? null);
+
const fitnessRingsData = useMockData ? {
activeCalories: mockData?.activeCalories ?? 0,
activeCaloriesGoal: mockData?.activeCaloriesGoal ?? 350,
@@ -455,7 +453,7 @@ export default function ExploreScreen() {
{/* 右边文字区域 */}
- 海豹健康
+ Out Live
{/* 开发环境调试按钮 */}
diff --git a/app/water-settings.tsx b/app/water-settings.tsx
index a89f76a..138d597 100644
--- a/app/water-settings.tsx
+++ b/app/water-settings.tsx
@@ -1,10 +1,12 @@
import { Colors } from '@/constants/Colors';
+import { useAuthGuard } from '@/hooks/useAuthGuard';
import { useColorScheme } from '@/hooks/useColorScheme';
import { useWaterDataByDate } from '@/hooks/useWaterData';
import { getQuickWaterAmount, setQuickWaterAmount } from '@/utils/userPreferences';
import { Ionicons } from '@expo/vector-icons';
import { Picker } from '@react-native-picker/picker';
import { Image } from 'expo-image';
+import { LinearGradient } from 'expo-linear-gradient';
import { router, useLocalSearchParams } from 'expo-router';
import React, { useEffect, useState } from 'react';
import {
@@ -32,6 +34,7 @@ const WaterSettings: React.FC = () => {
const { selectedDate } = useLocalSearchParams<{ selectedDate?: string }>();
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
const colorTokens = Colors[theme];
+ const { ensureLoggedIn } = useAuthGuard();
const [dailyGoal, setDailyGoal] = useState('2000');
const [quickAddAmount, setQuickAddAmount] = useState('250');
@@ -47,6 +50,19 @@ const WaterSettings: React.FC = () => {
// 使用新的 hook 来处理指定日期的饮水数据
const { waterRecords, dailyWaterGoal, updateWaterGoal, removeWaterRecord } = useWaterDataByDate(selectedDate);
+ // 检查登录状态
+ useEffect(() => {
+ const checkLoginStatus = async () => {
+ const isLoggedIn = await ensureLoggedIn();
+ if (!isLoggedIn) {
+ // 如果未登录,用户会被重定向到登录页面
+ return;
+ }
+ };
+
+ checkLoginStatus();
+ }, [ensureLoggedIn]);
+
const goalPresets = [1500, 2000, 2500, 3000, 3500, 4000];
const quickAddPresets = [100, 150, 200, 250, 300, 350, 400, 500];
@@ -203,7 +219,19 @@ const WaterSettings: React.FC = () => {
};
return (
-
+
+ {/* 背景渐变 */}
+
+
+ {/* 装饰性圆圈 */}
+
+
+
{
@@ -249,7 +277,7 @@ const WaterSettings: React.FC = () => {
快速添加默认值
- 设置点击右上角"+"按钮时添加的默认饮水量
+ {`设置点击右上角"+"按钮时添加的默认饮水量`}
{quickAddAmount}ml
@@ -382,6 +410,33 @@ const styles = StyleSheet.create({
container: {
flex: 1,
},
+ gradientBackground: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ },
+ decorativeCircle1: {
+ position: 'absolute',
+ top: 40,
+ right: 20,
+ width: 60,
+ height: 60,
+ borderRadius: 30,
+ backgroundColor: '#0EA5E9',
+ opacity: 0.1,
+ },
+ decorativeCircle2: {
+ position: 'absolute',
+ bottom: -15,
+ left: -15,
+ width: 40,
+ height: 40,
+ borderRadius: 20,
+ backgroundColor: '#0EA5E9',
+ opacity: 0.05,
+ },
keyboardAvoidingView: {
flex: 1,
},
@@ -395,19 +450,19 @@ const styles = StyleSheet.create({
marginBottom: 32,
},
sectionTitle: {
- fontSize: 20,
- fontWeight: '600',
+ fontSize: 16,
+ fontWeight: '500',
marginBottom: 20,
letterSpacing: -0.5,
},
subsectionTitle: {
- fontSize: 16,
+ fontSize: 14,
fontWeight: '500',
marginBottom: 12,
letterSpacing: -0.3,
},
sectionSubtitle: {
- fontSize: 14,
+ fontSize: 12,
fontWeight: '400',
lineHeight: 18,
},
@@ -582,15 +637,18 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 40,
- gap: 12,
+ gap: 16,
},
noRecordsText: {
- fontSize: 16,
- fontWeight: '600',
+ fontSize: 15,
+ fontWeight: '500',
+ lineHeight: 20,
},
noRecordsSubText: {
- fontSize: 14,
+ fontSize: 13,
textAlign: 'center',
+ lineHeight: 18,
+ opacity: 0.7,
},
modalBackdrop: {
...StyleSheet.absoluteFillObject,
diff --git a/components/WaterIntakeCard.tsx b/components/WaterIntakeCard.tsx
index 9ce379d..de8963f 100644
--- a/components/WaterIntakeCard.tsx
+++ b/components/WaterIntakeCard.tsx
@@ -1,3 +1,4 @@
+import { useAuthGuard } from '@/hooks/useAuthGuard';
import { useWaterDataByDate } from '@/hooks/useWaterData';
import { getQuickWaterAmount } from '@/utils/userPreferences';
import { useFocusEffect } from '@react-navigation/native';
@@ -26,6 +27,7 @@ const WaterIntakeCard: React.FC = ({
selectedDate
}) => {
const router = useRouter();
+ const { ensureLoggedIn } = useAuthGuard();
const { waterStats, dailyWaterGoal, waterRecords, addWaterRecord } = useWaterDataByDate(selectedDate);
const [quickWaterAmount, setQuickWaterAmount] = useState(150); // 默认值,将从用户偏好中加载
@@ -120,6 +122,12 @@ const WaterIntakeCard: React.FC = ({
// 处理添加喝水 - 右上角按钮直接添加
const handleQuickAddWater = async () => {
+ // 检查用户是否已登录
+ const isLoggedIn = await ensureLoggedIn();
+ if (!isLoggedIn) {
+ return;
+ }
+
// 触发震动反馈
if (process.env.EXPO_OS === 'ios') {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
@@ -135,7 +143,13 @@ const WaterIntakeCard: React.FC = ({
};
// 处理卡片点击 - 跳转到饮水设置页面
- const handleCardPress = () => {
+ const handleCardPress = async () => {
+ // 检查用户是否已登录
+ const isLoggedIn = await ensureLoggedIn();
+ if (!isLoggedIn) {
+ return;
+ }
+
// 触发震动反馈
if (process.env.EXPO_OS === 'ios') {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
diff --git a/components/weight/WeightHistoryCard.tsx b/components/weight/WeightHistoryCard.tsx
index 3dc98e6..58ada47 100644
--- a/components/weight/WeightHistoryCard.tsx
+++ b/components/weight/WeightHistoryCard.tsx
@@ -39,7 +39,7 @@ export function WeightHistoryCard() {
const dispatch = useAppDispatch();
const userProfile = useAppSelector((s) => s.user.profile);
const weightHistory = useAppSelector((s) => s.user.weightHistory);
- const [isLoading, setIsLoading] = useState(false);
+
const [showChart, setShowChart] = useState(false);
const [showBMIModal, setShowBMIModal] = useState(false);
@@ -71,12 +71,9 @@ export function WeightHistoryCard() {
const loadWeightHistory = async () => {
try {
- setIsLoading(true);
await dispatch(fetchWeightHistory() as any);
} catch (error) {
console.error('加载体重历史失败:', error);
- } finally {
- setIsLoading(false);
}
};
diff --git a/hooks/useAuthGuard.ts b/hooks/useAuthGuard.ts
index 956ac10..52c2420 100644
--- a/hooks/useAuthGuard.ts
+++ b/hooks/useAuthGuard.ts
@@ -3,6 +3,7 @@ import { usePathname, useRouter } from 'expo-router';
import { useCallback } from 'react';
import { Alert } from 'react-native';
+import { ROUTES } from '@/constants/Routes';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { api } from '@/services/api';
import { logout as logoutAction } from '@/store/userSlice';
@@ -24,7 +25,7 @@ export function useAuthGuard() {
const ensureLoggedIn = useCallback(async (options?: EnsureOptions): Promise => {
if (isLoggedIn) return true;
- const redirectTo = options?.redirectTo ?? currentPath ?? '/(tabs)';
+ const redirectTo = options?.redirectTo ?? currentPath ?? ROUTES.TAB_STATISTICS;
const paramsJson = options?.redirectParams ? JSON.stringify(options.redirectParams) : undefined;
router.push({
@@ -62,7 +63,7 @@ export function useAuthGuard() {
try {
// 调用 Redux action 清除本地状态和缓存
await dispatch(logoutAction()).unwrap();
-
+
// 跳转到登录页面
router.push('/auth/login');
} catch (error) {
@@ -95,13 +96,13 @@ export function useAuthGuard() {
try {
// 调用注销账号API
await api.delete('/api/users/delete-account');
-
+
// 清除额外的本地数据
await AsyncStorage.multiRemove(['@user_personal_info', '@onboarding_completed']);
-
+
// 执行退出登录逻辑
await dispatch(logoutAction()).unwrap();
-
+
Alert.alert('账号已注销', '您的账号已成功注销', [
{
text: '确定',
diff --git a/ios/Podfile b/ios/Podfile
index 6a64ccb..632f7b4 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -13,6 +13,8 @@ install! 'cocoapods',
prepare_react_native_project!
+project 'digitalpilates.xcodeproj'
+
target 'digitalpilates' do
use_expo_modules!
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index b597d4b..b39d3f1 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -2388,10 +2388,10 @@ SPEC CHECKSUMS:
ExpoSystemUI: 433a971503b99020318518ed30a58204288bab2d
ExpoWebBrowser: dc39a88485f007e61a3dff05d6a75f22ab4a2e92
EXTaskManager: 280143f6d8e596f28739d74bf34910300dcbd4ea
- fast_float: 23278fd30b349f976d2014f4aec9e2d7bc1c3806
+ fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6
FBLazyVector: d2a9cd223302b6c9aa4aa34c1a775e9db609eb52
- fmt: b85d977e8fe789fd71c77123f9f4920d88c4d170
- glog: 682871fb30f4a65f657bf357581110656ea90b08
+ fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
+ glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7
libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
@@ -2401,7 +2401,7 @@ SPEC CHECKSUMS:
QCloudCore: 6f8c67b96448472d2c6a92b9cfe1bdb5abbb1798
QCloudCOSXML: 92f50a787b4e8d9a7cb6ea8e626775256b4840a7
QCloudTrack: 20b79388365b4c8ed150019c82a56f1569f237f8
- RCT-Folly: 031db300533e2dfa954cdc5a859b792d5c14ed7b
+ RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82
RCTDeprecation: 5f638f65935e273753b1f31a365db6a8d6dc53b5
RCTRequired: 8b46a520ea9071e2bc47d474aa9ca31b4a935bd8
RCTTypeSafety: cc4740278c2a52cbf740592b0a0a40df1587c9ab
@@ -2490,6 +2490,6 @@ SPEC CHECKSUMS:
Yoga: adb397651e1c00672c12e9495babca70777e411e
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5
-PODFILE CHECKSUM: 8d79b726cf7814a1ef2e250b7a9ef91c07c77936
+PODFILE CHECKSUM: d6bbff2c1fc3ea45fb6bb3b1c3bb766a4f2d5dd4
COCOAPODS: 1.16.2
diff --git a/ios/WaterWidgetExtension.entitlements b/ios/WaterWidgetExtension.entitlements
deleted file mode 100644
index 0c67376..0000000
--- a/ios/WaterWidgetExtension.entitlements
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/ios/digitalpilates.xcodeproj/project.pbxproj b/ios/digitalpilates.xcodeproj/project.pbxproj
index f57ca3c..f985030 100644
--- a/ios/digitalpilates.xcodeproj/project.pbxproj
+++ b/ios/digitalpilates.xcodeproj/project.pbxproj
@@ -348,7 +348,7 @@
"FB_SONARKIT_ENABLED=1",
);
INFOPLIST_FILE = digitalpilates/Info.plist;
- INFOPLIST_KEY_CFBundleDisplayName = "海豹健康";
+ INFOPLIST_KEY_CFBundleDisplayName = "Out Live";
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -386,7 +386,7 @@
DEVELOPMENT_TEAM = 756WVXJ6MT;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64;
INFOPLIST_FILE = digitalpilates/Info.plist;
- INFOPLIST_KEY_CFBundleDisplayName = "海豹健康";
+ INFOPLIST_KEY_CFBundleDisplayName = "Out Live";
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
diff --git a/ios/digitalpilates/Info.plist b/ios/digitalpilates/Info.plist
index 8f1c6a9..086a0a8 100644
--- a/ios/digitalpilates/Info.plist
+++ b/ios/digitalpilates/Info.plist
@@ -11,7 +11,7 @@
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
- 海豹健康
+ Out Live
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
@@ -23,7 +23,7 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 1.0.8
+ 1.0.9
CFBundleSignature
????
CFBundleURLTypes
diff --git a/test-water-api.md b/test-water-api.md
deleted file mode 100644
index 33ffdb5..0000000
--- a/test-water-api.md
+++ /dev/null
@@ -1,135 +0,0 @@
-# 喝水记录 API 修复测试文档
-
-## 修复内容总结
-
-### 1. 服务层修复 (services/waterRecords.ts)
-
-#### 接口路径修复
-- ✅ 更新喝水目标:`/water-goal` → `/water-records/goal/daily`
-- ✅ 获取统计数据:`/water-stats/today` → `/water-records/stats`
-- ✅ 获取指定日期统计:`/water-stats/${date}` → `/water-records/stats?date=${date}`
-
-#### 数据结构修复
-- ✅ 字段名称:`remark` → `note`
-- ✅ 枚举值:`'manual' | 'auto' | 'other'` → `'Manual' | 'Auto'`
-- ✅ 新增字段:`recordedAt` (记录时间)
-- ✅ 响应结构:处理标准 API 响应格式 `{ data: {...}, pagination: {...} }`
-
-#### 类型定义更新
-```typescript
-// 旧版本
-interface WaterRecord {
- source: 'manual' | 'auto' | 'other';
- remark?: string;
-}
-
-// 新版本
-interface WaterRecord {
- source?: 'Manual' | 'Auto';
- note?: string;
- recordedAt: string;
-}
-```
-
-### 2. Redux Store 修复 (store/waterSlice.ts)
-
-#### Loading 状态完善
-- ✅ 新增:`create`, `update`, `delete` loading 状态
-
-#### 完成率计算修复
-- ✅ 统一使用百分比格式:`(totalAmount / dailyGoal) * 100`
-- ✅ 所有相关计算都已更新
-
-#### 日期字段处理
-- ✅ 优先使用 `recordedAt`,回退到 `createdAt`
-
-### 3. Hooks 修复 (hooks/useWaterData.ts)
-
-#### 函数签名更新
-```typescript
-// 旧版本
-addWaterRecord(amount: number, remark?: string)
-
-// 新版本
-addWaterRecord(amount: number, note?: string, recordedAt?: string)
-```
-
-#### 完成率计算
-- ✅ 返回百分比格式而非小数
-
-### 4. 组件修复
-
-#### WaterIntakeCard.tsx
-- ✅ 日期字段:优先使用 `recordedAt`
-- ✅ 完成率显示:移除多余的 `* 100` 计算
-
-#### AddWaterModal.tsx
-- ✅ 字段名称:`remark` → `note`
-- ✅ 数据结构:添加 `source: 'Manual'`
-
-## 测试要点
-
-### 1. API 调用测试
-```javascript
-// 测试创建记录
-const createResult = await createWaterRecord({
- amount: 250,
- note: "测试记录",
- source: "Manual",
- recordedAt: "2023-12-01T10:00:00.000Z"
-});
-
-// 测试获取统计
-const stats = await getTodayWaterStats();
-console.log('完成率应该是百分比:', stats.completionRate); // 应该是 0-100 的数值
-
-// 测试更新目标
-const goalResult = await updateWaterGoal({ dailyWaterGoal: 2500 });
-```
-
-### 2. Redux 状态测试
-```javascript
-// 测试完成率计算
-// 假设总量 1500ml,目标 2000ml
-// 期望完成率:75 (百分比)
-const expectedRate = (1500 / 2000) * 100; // 75
-```
-
-### 3. 组件渲染测试
-- ✅ 完成率显示正确(不会超过 100%)
-- ✅ 图表数据使用正确的时间字段
-- ✅ 表单提交使用正确的字段名称
-
-## 兼容性说明
-
-### 向后兼容
-- ✅ 保留了 `createdAt` 字段的回退逻辑
-- ✅ 保留了单日期查询的兼容性处理
-- ✅ 保留了原有的选择器函数
-
-### 新功能支持
-- ✅ 支持自定义记录时间 (`recordedAt`)
-- ✅ 支持新的 API 响应格式
-- ✅ 支持百分比格式的完成率
-
-## 需要验证的功能
-
-1. **创建记录**:确保新记录包含正确的字段
-2. **更新记录**:确保更新时使用正确的字段名
-3. **删除记录**:确保删除后统计数据正确更新
-4. **目标设置**:确保目标更新后完成率重新计算
-5. **统计查询**:确保返回正确的百分比格式完成率
-6. **图表显示**:确保使用正确的时间字段进行分组
-
-## 潜在问题
-
-1. **时区处理**:`recordedAt` 字段的时区处理需要注意
-2. **数据迁移**:现有数据可能没有 `recordedAt` 字段
-3. **API 兼容性**:确保后端 API 已经更新到新版本
-
-## 建议测试流程
-
-1. 单元测试:测试各个函数的输入输出
-2. 集成测试:测试 Redux 状态管理
-3. 端到端测试:测试完整的用户操作流程
-4. API 测试:使用 Postman 或类似工具测试 API 接口
\ No newline at end of file