feat: 新增健康档案模块,支持家庭邀请与个人健康数据管理

This commit is contained in:
richarjiang
2025-12-04 17:56:04 +08:00
parent e713ffbace
commit a254af92c7
28 changed files with 4177 additions and 315 deletions

View File

@@ -1,9 +1,11 @@
import NumberKeyboard from '@/components/NumberKeyboard';
import { HeaderBar } from '@/components/ui/HeaderBar';
import { WeightProgressBar } from '@/components/weight/WeightProgressBar';
import { WeightRecordCard } from '@/components/weight/WeightRecordCard';
import { Colors } from '@/constants/Colors';
import { getTabBarBottomPadding } from '@/constants/TabBar';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { useAuthGuard } from '@/hooks/useAuthGuard';
import { useColorScheme } from '@/hooks/useColorScheme';
import { useI18n } from '@/hooks/useI18n';
import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding';
@@ -39,14 +41,16 @@ export default function WeightRecordsPage() {
const colorScheme = useColorScheme();
const themeColors = Colors[colorScheme ?? 'light'];
const { isLoggedIn, ensureLoggedIn } = useAuthGuard();
const loadWeightHistory = useCallback(async () => {
if (!isLoggedIn) return;
try {
await dispatch(fetchWeightHistory() as any);
} catch (error) {
console.error(t('weightRecords.loadingHistory'), error);
}
}, [dispatch]);
}, [dispatch, isLoggedIn]);
useEffect(() => {
loadWeightHistory();
@@ -56,28 +60,36 @@ export default function WeightRecordsPage() {
setInputWeight(weight.toString());
};
const handleAddWeight = () => {
const handleAddWeight = async () => {
const ok = await ensureLoggedIn();
if (!ok) return;
setPickerType('current');
const weight = userProfile?.weight ? parseFloat(userProfile.weight) : 70.0;
initializeInput(weight);
setShowWeightPicker(true);
};
const handleEditInitialWeight = () => {
const handleEditInitialWeight = async () => {
const ok = await ensureLoggedIn();
if (!ok) return;
setPickerType('initial');
const initialWeight = userProfile?.initialWeight || userProfile?.weight || '70.0';
initializeInput(parseFloat(initialWeight));
setShowWeightPicker(true);
};
const handleEditTargetWeight = () => {
const handleEditTargetWeight = async () => {
const ok = await ensureLoggedIn();
if (!ok) return;
setPickerType('target');
const targetWeight = userProfile?.targetWeight || '60.0';
initializeInput(parseFloat(targetWeight));
setShowWeightPicker(true);
};
const handleEditWeightRecord = (record: WeightHistoryItem) => {
const handleEditWeightRecord = async (record: WeightHistoryItem) => {
const ok = await ensureLoggedIn();
if (!ok) return;
setPickerType('edit');
setEditingRecord(record);
initializeInput(parseFloat(record.weight));
@@ -85,6 +97,8 @@ export default function WeightRecordsPage() {
};
const handleDeleteWeightRecord = async (id: string) => {
const ok = await ensureLoggedIn();
if (!ok) return;
try {
await dispatch(deleteWeightRecord(id) as any);
await loadWeightHistory();
@@ -180,6 +194,12 @@ export default function WeightRecordsPage() {
const targetWeight = userProfile?.targetWeight ? parseFloat(userProfile.targetWeight) : 60.0;
const totalWeightLoss = initialWeight - currentWeight;
// 计算减重进度
const hasTargetWeight = targetWeight > 0 && initialWeight > targetWeight;
const totalToLose = initialWeight - targetWeight;
const actualLost = initialWeight - currentWeight;
const weightProgress = hasTargetWeight && totalToLose > 0 ? actualLost / totalToLose : 0;
return (
<View style={styles.container}>
{/* 背景 */}
@@ -295,6 +315,19 @@ export default function WeightRecordsPage() {
</View>
</View>
{/* 减重进度条 - 仅在设置了目标体重时显示 */}
{hasTargetWeight && (
<View style={styles.progressContainer}>
<WeightProgressBar
progress={weightProgress}
currentWeight={currentWeight}
targetWeight={targetWeight}
initialWeight={initialWeight}
showTopBorder={false}
/>
</View>
)}
{/* Monthly Records */}
{Object.keys(groupedHistory).length > 0 ? (
<View style={styles.historySection}>
@@ -628,6 +661,20 @@ const styles = StyleSheet.create({
marginLeft: 2,
},
// Progress Container
progressContainer: {
marginHorizontal: 24,
marginBottom: 24,
backgroundColor: '#ffffff',
borderRadius: 24,
padding: 20,
shadowColor: 'rgba(30, 41, 59, 0.06)',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 3,
},
// History Section
historySection: {
paddingHorizontal: 24,