feat(nutrition): 添加营养分析历史记录删除和图片预览功能
- 新增删除营养分析记录功能,支持本地状态更新和API调用 - 添加图片全屏预览功能,支持缩放和手势操作 - 实现Liquid Glass风格的删除按钮,包含兼容性处理 - 优化历史记录页面布局和交互体验 - 更新Memory Bank文档,添加Liquid Glass按钮实现指南
This commit is contained in:
@@ -62,3 +62,87 @@ const styles = StyleSheet.create({
|
|||||||
- `app/profile/goals.tsx`
|
- `app/profile/goals.tsx`
|
||||||
- `app/workout/history.tsx`
|
- `app/workout/history.tsx`
|
||||||
- `app/challenges/[id]/leaderboard.tsx`
|
- `app/challenges/[id]/leaderboard.tsx`
|
||||||
|
|
||||||
|
## Liquid Glass 风格图标按钮实现
|
||||||
|
|
||||||
|
**最后更新**: 2025-10-16
|
||||||
|
|
||||||
|
### 问题描述
|
||||||
|
在应用中实现符合 Liquid Glass 设计风格的图标按钮,需要考虑毛玻璃效果和兼容性处理。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
使用 `GlassView` 组件实现毛玻璃效果,并提供不支持 Liquid Glass 的设备的降级方案。
|
||||||
|
|
||||||
|
### 实现模式
|
||||||
|
|
||||||
|
#### 1. 导入必要的组件和函数
|
||||||
|
```typescript
|
||||||
|
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 检查设备支持情况
|
||||||
|
```typescript
|
||||||
|
const isGlassAvailable = isLiquidGlassAvailable();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. 实现条件渲染的按钮
|
||||||
|
```typescript
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={handlePress}
|
||||||
|
disabled={isLoading}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
{isGlassAvailable ? (
|
||||||
|
<GlassView
|
||||||
|
style={styles.glassButton}
|
||||||
|
glassEffectStyle="clear" // 或 "regular"
|
||||||
|
tintColor="rgba(244, 67, 54, 0.2)" // 自定义色调
|
||||||
|
isInteractive={true} // 启用交互反馈
|
||||||
|
>
|
||||||
|
<Ionicons name="trash-outline" size={20} color="#F44336" />
|
||||||
|
</GlassView>
|
||||||
|
) : (
|
||||||
|
<View style={[styles.glassButton, styles.fallbackButton]}>
|
||||||
|
<Ionicons name="trash-outline" size={20} color="#F44336" />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. 定义样式
|
||||||
|
```typescript
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
glassButton: {
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
borderRadius: 18, // 圆形按钮
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
overflow: 'hidden', // 保证玻璃边界圆角效果
|
||||||
|
},
|
||||||
|
fallbackButton: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'rgba(244, 67, 54, 0.3)',
|
||||||
|
backgroundColor: 'rgba(244, 67, 54, 0.1)',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 重要注意事项
|
||||||
|
1. **兼容性处理**:必须使用 `isLiquidGlassAvailable()` 检查设备支持情况
|
||||||
|
2. **overflow: 'hidden'**:GlassView 组件需要设置此属性以保证圆角效果
|
||||||
|
3. **降级样式**:为不支持 Liquid Glass 的设备提供视觉上相似的替代方案
|
||||||
|
4. **交互反馈**:设置 `isInteractive={true}` 启用原生的触觉反馈
|
||||||
|
5. **色调自定义**:通过 `tintColor` 属性自定义按钮的颜色主题
|
||||||
|
|
||||||
|
### 常用配置
|
||||||
|
- **glassEffectStyle**: "clear"(透明)或 "regular"(常规)
|
||||||
|
- **tintColor**: 根据按钮功能选择合适的颜色
|
||||||
|
- 删除操作:红色系 `rgba(244, 67, 54, 0.2)`
|
||||||
|
- 确认操作:绿色系 `rgba(76, 175, 80, 0.2)`
|
||||||
|
- 信息操作:蓝色系 `rgba(33, 150, 243, 0.2)`
|
||||||
|
|
||||||
|
### 参考实现
|
||||||
|
- `app/food/nutrition-analysis-history.tsx` - 删除按钮实现
|
||||||
|
- `components/glass/button.tsx` - 通用 Glass 按钮组件
|
||||||
|
- `app/(tabs)/_layout.tsx` - 标签栏按钮实现
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
### UI 框架和样式
|
### UI 框架和样式
|
||||||
- **React Native Elements**: UI 组件库
|
- **React Native Elements**: UI 组件库
|
||||||
- **Expo UI**: 0.2.0-beta.7 - Expo UI 组件
|
- **Expo UI**: 0.2.0-beta.7 - Expo UI 组件
|
||||||
- **Expo Glass Effect**: 0.1.4 - Liquid Glass 毛玻璃效果
|
- **Expo Glass Effect**: 0.1.4 - Liquid Glass 毛玻璃效果, 优先使用
|
||||||
- **React Native Reanimated**: 4.1.0 - 高性能动画库
|
- **React Native Reanimated**: 4.1.0 - 高性能动画库
|
||||||
- **React Native Gesture Handler**: 2.28.0 - 手势处理
|
- **React Native Gesture Handler**: 2.28.0 - 手势处理
|
||||||
- **React Native SVG**: 15.12.1 - SVG 图形支持
|
- **React Native SVG**: 15.12.1 - SVG 图形支持
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { HeaderBar } from '@/components/ui/HeaderBar';
|
|||||||
import { Colors } from '@/constants/Colors';
|
import { Colors } from '@/constants/Colors';
|
||||||
import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding';
|
import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding';
|
||||||
import {
|
import {
|
||||||
|
deleteNutritionAnalysisRecord,
|
||||||
getNutritionAnalysisRecords,
|
getNutritionAnalysisRecords,
|
||||||
type GetNutritionRecordsParams,
|
type GetNutritionRecordsParams,
|
||||||
type NutritionAnalysisRecord,
|
type NutritionAnalysisRecord,
|
||||||
@@ -10,6 +11,7 @@ import {
|
|||||||
import { triggerLightHaptic } from '@/utils/haptics';
|
import { triggerLightHaptic } from '@/utils/haptics';
|
||||||
import { Ionicons } from '@expo/vector-icons';
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
|
||||||
import { Image } from 'expo-image';
|
import { Image } from 'expo-image';
|
||||||
import { LinearGradient } from 'expo-linear-gradient';
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
import { useRouter } from 'expo-router';
|
import { useRouter } from 'expo-router';
|
||||||
@@ -17,6 +19,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Alert,
|
Alert,
|
||||||
|
BackHandler,
|
||||||
FlatList,
|
FlatList,
|
||||||
RefreshControl,
|
RefreshControl,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
@@ -24,6 +27,7 @@ import {
|
|||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View
|
View
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
import ImageViewing from 'react-native-image-viewing';
|
||||||
|
|
||||||
export default function NutritionAnalysisHistoryScreen() {
|
export default function NutritionAnalysisHistoryScreen() {
|
||||||
const safeAreaTop = useSafeAreaTop();
|
const safeAreaTop = useSafeAreaTop();
|
||||||
@@ -39,6 +43,23 @@ export default function NutritionAnalysisHistoryScreen() {
|
|||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
const [statusFilter, setStatusFilter] = useState<string>('');
|
const [statusFilter, setStatusFilter] = useState<string>('');
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [showImagePreview, setShowImagePreview] = useState(false);
|
||||||
|
const [previewImageUri, setPreviewImageUri] = useState<string | null>(null);
|
||||||
|
const [deletingId, setDeletingId] = useState<number | null>(null);
|
||||||
|
const isGlassAvailable = isLiquidGlassAvailable();
|
||||||
|
|
||||||
|
// 处理Android返回键关闭图片预览
|
||||||
|
useEffect(() => {
|
||||||
|
const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
|
||||||
|
if (showImagePreview) {
|
||||||
|
setShowImagePreview(false);
|
||||||
|
return true; // 阻止默认返回行为
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => backHandler.remove();
|
||||||
|
}, [showImagePreview]);
|
||||||
|
|
||||||
// 获取历史记录
|
// 获取历史记录
|
||||||
const fetchRecords = useCallback(async (page: number = 1, isRefresh: boolean = false, currentStatusFilter?: string) => {
|
const fetchRecords = useCallback(async (page: number = 1, isRefresh: boolean = false, currentStatusFilter?: string) => {
|
||||||
@@ -177,6 +198,52 @@ export default function NutritionAnalysisHistoryScreen() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理图片预览
|
||||||
|
const handleImagePreview = useCallback((imageUrl: string) => {
|
||||||
|
triggerLightHaptic();
|
||||||
|
setPreviewImageUri(imageUrl);
|
||||||
|
setShowImagePreview(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 处理删除记录
|
||||||
|
const handleDeleteRecord = useCallback((recordId: number) => {
|
||||||
|
Alert.alert(
|
||||||
|
'确认删除',
|
||||||
|
'确定要删除这条营养分析记录吗?此操作无法撤销。',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: '取消',
|
||||||
|
style: 'cancel',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '删除',
|
||||||
|
style: 'destructive',
|
||||||
|
onPress: async () => {
|
||||||
|
try {
|
||||||
|
setDeletingId(recordId);
|
||||||
|
await deleteNutritionAnalysisRecord(recordId);
|
||||||
|
|
||||||
|
// 从本地状态中移除删除的记录
|
||||||
|
setRecords(prev => prev.filter(record => record.id !== recordId));
|
||||||
|
setTotal(prev => Math.max(0, prev - 1));
|
||||||
|
|
||||||
|
// 触发轻微震动反馈
|
||||||
|
triggerLightHaptic();
|
||||||
|
|
||||||
|
// 显示成功提示
|
||||||
|
Alert.alert('成功', '记录已删除');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[HISTORY] 删除记录失败:', error);
|
||||||
|
Alert.alert('错误', '删除失败,请稍后重试');
|
||||||
|
} finally {
|
||||||
|
setDeletingId(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 渲染历史记录项
|
// 渲染历史记录项
|
||||||
const renderRecordItem = useCallback(({ item }: { item: NutritionAnalysisRecord }) => {
|
const renderRecordItem = useCallback(({ item }: { item: NutritionAnalysisRecord }) => {
|
||||||
const isExpanded = expandedItems.has(item.id);
|
const isExpanded = expandedItems.has(item.id);
|
||||||
@@ -187,6 +254,11 @@ export default function NutritionAnalysisHistoryScreen() {
|
|||||||
{/* 头部信息 */}
|
{/* 头部信息 */}
|
||||||
<View style={styles.recordHeader}>
|
<View style={styles.recordHeader}>
|
||||||
<View style={styles.recordInfo}>
|
<View style={styles.recordInfo}>
|
||||||
|
{isSuccess && (
|
||||||
|
<Text style={styles.recordTitle}>
|
||||||
|
识别 {item.nutritionCount} 项营养素
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
<Text style={styles.recordDate}>
|
<Text style={styles.recordDate}>
|
||||||
{dayjs(item.createdAt).format('YYYY年M月D日 HH:mm')}
|
{dayjs(item.createdAt).format('YYYY年M月D日 HH:mm')}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -195,22 +267,54 @@ export default function NutritionAnalysisHistoryScreen() {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{isSuccess && (
|
{/* 删除按钮 */}
|
||||||
<Text style={styles.nutritionCount}>
|
<TouchableOpacity
|
||||||
识别 {item.nutritionCount} 项营养素
|
onPress={() => handleDeleteRecord(item.id)}
|
||||||
</Text>
|
disabled={deletingId === item.id}
|
||||||
)}
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
{isGlassAvailable ? (
|
||||||
|
<GlassView
|
||||||
|
style={styles.glassDeleteButton}
|
||||||
|
glassEffectStyle="clear"
|
||||||
|
tintColor="rgba(244, 67, 54, 0.2)"
|
||||||
|
isInteractive={true}
|
||||||
|
>
|
||||||
|
{deletingId === item.id ? (
|
||||||
|
<ActivityIndicator size="small" color="#F44336" />
|
||||||
|
) : (
|
||||||
|
<Ionicons name="trash-outline" size={20} color="#F44336" />
|
||||||
|
)}
|
||||||
|
</GlassView>
|
||||||
|
) : (
|
||||||
|
<View style={[styles.glassDeleteButton, styles.fallbackDeleteButton]}>
|
||||||
|
{deletingId === item.id ? (
|
||||||
|
<ActivityIndicator size="small" color="#F44336" />
|
||||||
|
) : (
|
||||||
|
<Ionicons name="trash-outline" size={20} color="#F44336" />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 图片预览 */}
|
{/* 图片预览 */}
|
||||||
{item.imageUrl && (
|
{item.imageUrl && (
|
||||||
<View style={styles.imageContainer}>
|
<TouchableOpacity
|
||||||
|
style={styles.imageContainer}
|
||||||
|
onPress={() => handleImagePreview(item.imageUrl)}
|
||||||
|
activeOpacity={0.9}
|
||||||
|
>
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: item.imageUrl }}
|
source={{ uri: item.imageUrl }}
|
||||||
style={styles.thumbnail}
|
style={styles.thumbnail}
|
||||||
contentFit="cover"
|
contentFit="cover"
|
||||||
/>
|
/>
|
||||||
</View>
|
{/* 预览提示图标 */}
|
||||||
|
<View style={styles.previewHint}>
|
||||||
|
<Ionicons name="expand-outline" size={16} color="#FFF" />
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 分析结果摘要 */}
|
{/* 分析结果摘要 */}
|
||||||
@@ -439,6 +543,33 @@ export default function NutritionAnalysisHistoryScreen() {
|
|||||||
ListFooterComponent={renderFooter}
|
ListFooterComponent={renderFooter}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 图片预览 */}
|
||||||
|
<ImageViewing
|
||||||
|
images={previewImageUri ? [{ uri: previewImageUri }] : []}
|
||||||
|
imageIndex={0}
|
||||||
|
visible={showImagePreview}
|
||||||
|
onRequestClose={() => setShowImagePreview(false)}
|
||||||
|
swipeToCloseEnabled={true}
|
||||||
|
doubleTapToZoomEnabled={true}
|
||||||
|
HeaderComponent={() => (
|
||||||
|
<View style={styles.imageViewerHeader}>
|
||||||
|
<Text style={styles.imageViewerHeaderText}>
|
||||||
|
{dayjs().format('YYYY年M月D日 HH:mm')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
FooterComponent={() => (
|
||||||
|
<View style={styles.imageViewerFooter}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.imageViewerFooterButton}
|
||||||
|
onPress={() => setShowImagePreview(false)}
|
||||||
|
>
|
||||||
|
<Text style={styles.imageViewerFooterButtonText}>关闭</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -508,12 +639,17 @@ const styles = StyleSheet.create({
|
|||||||
recordInfo: {
|
recordInfo: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
recordDate: {
|
recordTitle: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: Colors.light.text,
|
color: Colors.light.text,
|
||||||
marginBottom: 4,
|
marginBottom: 4,
|
||||||
},
|
},
|
||||||
|
recordDate: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.light.textSecondary,
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
statusBadge: {
|
statusBadge: {
|
||||||
paddingHorizontal: 8,
|
paddingHorizontal: 8,
|
||||||
paddingVertical: 4,
|
paddingVertical: 4,
|
||||||
@@ -525,19 +661,36 @@ const styles = StyleSheet.create({
|
|||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
color: '#FFF',
|
color: '#FFF',
|
||||||
},
|
},
|
||||||
nutritionCount: {
|
glassDeleteButton: {
|
||||||
fontSize: 14,
|
width: 36,
|
||||||
color: Colors.light.textSecondary,
|
height: 36,
|
||||||
fontWeight: '500',
|
borderRadius: 18,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
fallbackDeleteButton: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'rgba(244, 67, 54, 0.3)',
|
||||||
|
backgroundColor: 'rgba(244, 67, 54, 0.1)',
|
||||||
},
|
},
|
||||||
imageContainer: {
|
imageContainer: {
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
|
position: 'relative',
|
||||||
},
|
},
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: 120,
|
height: 120,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
},
|
},
|
||||||
|
previewHint: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 8,
|
||||||
|
right: 8,
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
borderRadius: 16,
|
||||||
|
padding: 6,
|
||||||
|
},
|
||||||
summaryContainer: {
|
summaryContainer: {
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
},
|
},
|
||||||
@@ -709,4 +862,41 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
},
|
},
|
||||||
|
// ImageViewing 组件样式
|
||||||
|
imageViewerHeader: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 60,
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
borderRadius: 12,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 12,
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
imageViewerHeaderText: {
|
||||||
|
color: '#FFF',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '500',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
imageViewerFooter: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 60,
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
alignItems: 'center',
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
imageViewerFooterButton: {
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
paddingHorizontal: 24,
|
||||||
|
paddingVertical: 12,
|
||||||
|
borderRadius: 20,
|
||||||
|
},
|
||||||
|
imageViewerFooterButtonText: {
|
||||||
|
color: '#FFF',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
@@ -451,13 +451,18 @@ const styles = StyleSheet.create({
|
|||||||
placeholderContainer: {
|
placeholderContainer: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
backgroundColor: '#F8F9FA',
|
backgroundColor: '#FFFFFF',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
borderRadius: 20,
|
borderRadius: 20,
|
||||||
borderWidth: 2,
|
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||||
borderColor: '#E9ECEF',
|
shadowOffset: {
|
||||||
borderStyle: 'dashed',
|
width: 0,
|
||||||
|
height: 4,
|
||||||
|
},
|
||||||
|
shadowOpacity: 0.15,
|
||||||
|
shadowRadius: 8,
|
||||||
|
elevation: 5,
|
||||||
},
|
},
|
||||||
placeholderContent: {
|
placeholderContent: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|||||||
@@ -229,3 +229,16 @@ export async function getNutritionAnalysisRecords(params?: GetNutritionRecordsPa
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除营养成分分析记录
|
||||||
|
*/
|
||||||
|
export async function deleteNutritionAnalysisRecord(recordId: number): Promise<any> {
|
||||||
|
try {
|
||||||
|
const response = await api.delete(`/diet-records/nutrition-analysis-records/${recordId}`);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[NUTRITION_RECORDS] 删除记录失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user