feat(medications): 添加药品详情页面和删除功能
新增药品详情页面,支持查看药品信息、编辑备注、切换提醒状态和删除药品 - 创建动态路由页面 /medications/[medicationId].tsx 展示药品详细信息 - 添加语音输入备注功能,支持 iOS 语音识别 - 实现药品删除确认对话框和删除操作 - 优化药品卡片点击跳转详情页面的交互 - 添加删除操作的加载状态和错误处理 - 改进药品管理页面的开关状态显示和加载指示器
This commit is contained in:
@@ -52,6 +52,13 @@ export default function MedicationsScreen() {
|
|||||||
router.push('/medications/manage-medications');
|
router.push('/medications/manage-medications');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleOpenMedicationDetails = useCallback((medicationId: string) => {
|
||||||
|
router.push({
|
||||||
|
pathname: '/medications/[medicationId]',
|
||||||
|
params: { medicationId },
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 加载药物和记录数据
|
// 加载药物和记录数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchMedications());
|
dispatch(fetchMedications());
|
||||||
@@ -255,6 +262,7 @@ export default function MedicationsScreen() {
|
|||||||
medication={item}
|
medication={item}
|
||||||
colors={colors}
|
colors={colors}
|
||||||
selectedDate={selectedDate}
|
selectedDate={selectedDate}
|
||||||
|
onOpenDetails={() => handleOpenMedicationDetails(item.medicationId)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
1036
app/medications/[medicationId].tsx
Normal file
1036
app/medications/[medicationId].tsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -59,7 +59,6 @@ export default function ManageMedicationsScreen() {
|
|||||||
const [activeFilter, setActiveFilter] = useState<FilterType>('all');
|
const [activeFilter, setActiveFilter] = useState<FilterType>('all');
|
||||||
const [pendingMedicationId, setPendingMedicationId] = useState<string | null>(null);
|
const [pendingMedicationId, setPendingMedicationId] = useState<string | null>(null);
|
||||||
|
|
||||||
const updateLoading = loading.update;
|
|
||||||
const listLoading = loading.medications && medications.length === 0;
|
const listLoading = loading.medications && medications.length === 0;
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
@@ -116,7 +115,7 @@ export default function ManageMedicationsScreen() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 创建独立的药品卡片组件,使用 React.memo 优化渲染
|
// 创建独立的药品卡片组件,使用 React.memo 优化渲染
|
||||||
const MedicationCard = React.memo(({ medication }: { medication: Medication }) => {
|
const MedicationCard = React.memo(({ medication, onPress }: { medication: Medication; onPress: () => void }) => {
|
||||||
const dosageLabel = `${medication.dosageValue} ${medication.dosageUnit || ''} ${FORM_LABELS[medication.form] ?? ''}`.trim();
|
const dosageLabel = `${medication.dosageValue} ${medication.dosageUnit || ''} ${FORM_LABELS[medication.form] ?? ''}`.trim();
|
||||||
const frequencyLabel = `${medication.repeatPattern === 'daily' ? '每日' : medication.repeatPattern === 'weekly' ? '每周' : '自定义'} | ${dosageLabel}`;
|
const frequencyLabel = `${medication.repeatPattern === 'daily' ? '每日' : medication.repeatPattern === 'weekly' ? '每周' : '自定义'} | ${dosageLabel}`;
|
||||||
const startDateLabel = dayjs(medication.startDate).isValid()
|
const startDateLabel = dayjs(medication.startDate).isValid()
|
||||||
@@ -127,7 +126,11 @@ export default function ManageMedicationsScreen() {
|
|||||||
: `${medication.timesPerDay} 次/日`;
|
: `${medication.timesPerDay} 次/日`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.card, { backgroundColor: colors.surface }]}>
|
<TouchableOpacity
|
||||||
|
style={[styles.card, { backgroundColor: colors.surface }]}
|
||||||
|
activeOpacity={0.9}
|
||||||
|
onPress={onPress}
|
||||||
|
>
|
||||||
<View style={styles.cardInfo}>
|
<View style={styles.cardInfo}>
|
||||||
<Image
|
<Image
|
||||||
source={medication.photoUrl ? { uri: medication.photoUrl } : DEFAULT_IMAGE}
|
source={medication.photoUrl ? { uri: medication.photoUrl } : DEFAULT_IMAGE}
|
||||||
@@ -144,15 +147,24 @@ export default function ManageMedicationsScreen() {
|
|||||||
</ThemedText>
|
</ThemedText>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<Switch
|
<View style={styles.switchContainer}>
|
||||||
value={medication.isActive}
|
<Switch
|
||||||
onValueChange={(value) => handleToggleMedication(medication, value)}
|
value={medication.isActive}
|
||||||
disabled={updateLoading || pendingMedicationId === medication.id}
|
onValueChange={(value) => handleToggleMedication(medication, value)}
|
||||||
trackColor={{ false: '#D9D9D9', true: colors.primary }}
|
disabled={pendingMedicationId === medication.id}
|
||||||
thumbColor={medication.isActive ? '#fff' : '#fff'}
|
trackColor={{ false: '#D9D9D9', true: colors.primary }}
|
||||||
ios_backgroundColor="#D9D9D9"
|
thumbColor={medication.isActive ? '#fff' : '#fff'}
|
||||||
/>
|
ios_backgroundColor="#D9D9D9"
|
||||||
</View>
|
/>
|
||||||
|
{pendingMedicationId === medication.id && (
|
||||||
|
<ActivityIndicator
|
||||||
|
size="small"
|
||||||
|
color={colors.primary}
|
||||||
|
style={styles.switchLoading}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
}, (prevProps, nextProps) => {
|
}, (prevProps, nextProps) => {
|
||||||
// 自定义比较函数,只有当药品的 isActive 状态或 ID 改变时才重新渲染
|
// 自定义比较函数,只有当药品的 isActive 状态或 ID 改变时才重新渲染
|
||||||
@@ -166,11 +178,24 @@ export default function ManageMedicationsScreen() {
|
|||||||
|
|
||||||
MedicationCard.displayName = 'MedicationCard';
|
MedicationCard.displayName = 'MedicationCard';
|
||||||
|
|
||||||
|
const handleOpenMedicationDetails = useCallback((medicationId: string) => {
|
||||||
|
router.push({
|
||||||
|
pathname: '/medications/[medicationId]',
|
||||||
|
params: { medicationId },
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const renderMedicationCard = useCallback(
|
const renderMedicationCard = useCallback(
|
||||||
(medication: Medication) => {
|
(medication: Medication) => {
|
||||||
return <MedicationCard key={medication.id} medication={medication} />;
|
return (
|
||||||
|
<MedicationCard
|
||||||
|
key={medication.id}
|
||||||
|
medication={medication}
|
||||||
|
onPress={() => handleOpenMedicationDetails(medication.id)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[handleToggleMedication, pendingMedicationId, updateLoading, colors]
|
[handleToggleMedication, pendingMedicationId, colors, handleOpenMedicationDetails]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -398,4 +423,13 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
|
switchContainer: {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
position: 'relative',
|
||||||
|
},
|
||||||
|
switchLoading: {
|
||||||
|
position: 'absolute',
|
||||||
|
marginLeft: 30, // 确保加载指示器显示在开关旁边
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ export type MedicationCardProps = {
|
|||||||
medication: MedicationDisplayItem;
|
medication: MedicationDisplayItem;
|
||||||
colors: (typeof import('@/constants/Colors').Colors)[keyof typeof import('@/constants/Colors').Colors];
|
colors: (typeof import('@/constants/Colors').Colors)[keyof typeof import('@/constants/Colors').Colors];
|
||||||
selectedDate: Dayjs;
|
selectedDate: Dayjs;
|
||||||
|
onOpenDetails?: (medication: MedicationDisplayItem) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function MedicationCard({ medication, colors, selectedDate }: MedicationCardProps) {
|
export function MedicationCard({ medication, colors, selectedDate, onOpenDetails }: MedicationCardProps) {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
@@ -134,34 +135,7 @@ export function MedicationCard({ medication, colors, selectedDate }: MedicationC
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (medication.status === 'missed') {
|
// 只要没有服药,都可以显示立即服用
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
activeOpacity={1}
|
|
||||||
disabled={true}
|
|
||||||
onPress={() => {
|
|
||||||
// 已错过的药物不能服用
|
|
||||||
console.log('已错过的药物不能服用');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isLiquidGlassAvailable() ? (
|
|
||||||
<GlassView
|
|
||||||
style={[styles.actionButton, styles.actionButtonMissed]}
|
|
||||||
glassEffectStyle="clear"
|
|
||||||
tintColor="rgba(156, 163, 175, 0.3)"
|
|
||||||
isInteractive={false}
|
|
||||||
>
|
|
||||||
<ThemedText style={styles.actionButtonTextMissed}>已错过</ThemedText>
|
|
||||||
</GlassView>
|
|
||||||
) : (
|
|
||||||
<View style={[styles.actionButton, styles.actionButtonMissed, styles.fallbackActionButtonMissed]}>
|
|
||||||
<ThemedText style={styles.actionButtonTextMissed}>已错过</ThemedText>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
activeOpacity={0.7}
|
activeOpacity={0.7}
|
||||||
@@ -193,7 +167,12 @@ export function MedicationCard({ medication, colors, selectedDate }: MedicationC
|
|||||||
const statusChip = renderStatusBadge();
|
const statusChip = renderStatusBadge();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.card, { shadowColor: colors.text }]}>
|
<TouchableOpacity
|
||||||
|
style={[styles.card, { shadowColor: colors.text }]}
|
||||||
|
activeOpacity={onOpenDetails ? 0.92 : 1}
|
||||||
|
onPress={() => onOpenDetails?.(medication)}
|
||||||
|
disabled={!onOpenDetails}
|
||||||
|
>
|
||||||
<View style={[styles.cardSurface, { backgroundColor: colors.surface }]}>
|
<View style={[styles.cardSurface, { backgroundColor: colors.surface }]}>
|
||||||
{statusChip ? <View style={styles.statusChipWrapper}>{statusChip}</View> : null}
|
{statusChip ? <View style={styles.statusChipWrapper}>{statusChip}</View> : null}
|
||||||
<View style={styles.cardBody}>
|
<View style={styles.cardBody}>
|
||||||
@@ -226,7 +205,7 @@ export function MedicationCard({ medication, colors, selectedDate }: MedicationC
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,4 +340,4 @@ const styles = StyleSheet.create({
|
|||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
265
components/ui/ConfirmationSheet.tsx
Normal file
265
components/ui/ConfirmationSheet.tsx
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
import * as Haptics from 'expo-haptics';
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
Animated,
|
||||||
|
Dimensions,
|
||||||
|
Modal,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
|
const { height: screenHeight } = Dimensions.get('window');
|
||||||
|
|
||||||
|
interface ConfirmationSheetProps {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onConfirm: () => void;
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
confirmText?: string;
|
||||||
|
cancelText?: string;
|
||||||
|
destructive?: boolean;
|
||||||
|
loading?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ConfirmationSheet({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
onConfirm,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
confirmText = '确认',
|
||||||
|
cancelText = '取消',
|
||||||
|
destructive = false,
|
||||||
|
loading = false,
|
||||||
|
}: ConfirmationSheetProps) {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const translateY = useRef(new Animated.Value(screenHeight)).current;
|
||||||
|
const backdropOpacity = useRef(new Animated.Value(0)).current;
|
||||||
|
const [modalVisible, setModalVisible] = useState(visible);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (visible) {
|
||||||
|
setModalVisible(true);
|
||||||
|
}
|
||||||
|
}, [visible]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!modalVisible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
translateY.setValue(screenHeight);
|
||||||
|
backdropOpacity.setValue(0);
|
||||||
|
|
||||||
|
Animated.parallel([
|
||||||
|
Animated.timing(backdropOpacity, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 200,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
Animated.spring(translateY, {
|
||||||
|
toValue: 0,
|
||||||
|
useNativeDriver: true,
|
||||||
|
bounciness: 6,
|
||||||
|
speed: 12,
|
||||||
|
}),
|
||||||
|
]).start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Animated.parallel([
|
||||||
|
Animated.timing(backdropOpacity, {
|
||||||
|
toValue: 0,
|
||||||
|
duration: 150,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
Animated.timing(translateY, {
|
||||||
|
toValue: screenHeight,
|
||||||
|
duration: 240,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
]).start(() => {
|
||||||
|
translateY.setValue(screenHeight);
|
||||||
|
backdropOpacity.setValue(0);
|
||||||
|
setModalVisible(false);
|
||||||
|
});
|
||||||
|
}, [visible, modalVisible, backdropOpacity, translateY]);
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirm = () => {
|
||||||
|
if (loading) return;
|
||||||
|
Haptics.notificationAsync(
|
||||||
|
destructive ? Haptics.NotificationFeedbackType.Error : Haptics.NotificationFeedbackType.Success
|
||||||
|
);
|
||||||
|
onConfirm();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!modalVisible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={modalVisible}
|
||||||
|
transparent
|
||||||
|
animationType="none"
|
||||||
|
onRequestClose={onClose}
|
||||||
|
statusBarTranslucent
|
||||||
|
>
|
||||||
|
<View style={styles.overlay}>
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
styles.backdrop,
|
||||||
|
{
|
||||||
|
opacity: backdropOpacity,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<TouchableOpacity style={StyleSheet.absoluteFillObject} activeOpacity={1} onPress={handleCancel} />
|
||||||
|
</Animated.View>
|
||||||
|
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
styles.sheet,
|
||||||
|
{
|
||||||
|
transform: [{ translateY }],
|
||||||
|
paddingBottom: Math.max(insets.bottom, 20),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<View style={styles.handle} />
|
||||||
|
<Text style={styles.title}>{title}</Text>
|
||||||
|
{description ? <Text style={styles.description}>{description}</Text> : null}
|
||||||
|
|
||||||
|
<View style={styles.actions}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.cancelButton}
|
||||||
|
activeOpacity={0.85}
|
||||||
|
onPress={handleCancel}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<Text style={styles.cancelText}>{cancelText}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[
|
||||||
|
styles.confirmButton,
|
||||||
|
destructive ? styles.destructiveButton : styles.primaryButton,
|
||||||
|
loading && styles.disabledButton,
|
||||||
|
]}
|
||||||
|
activeOpacity={0.85}
|
||||||
|
onPress={handleConfirm}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
{loading ? (
|
||||||
|
<ActivityIndicator color="#fff" />
|
||||||
|
) : (
|
||||||
|
<Text style={styles.confirmText}>{confirmText}</Text>
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</Animated.View>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
overlay: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
},
|
||||||
|
backdrop: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
backgroundColor: 'rgba(15, 23, 42, 0.45)',
|
||||||
|
},
|
||||||
|
sheet: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderTopLeftRadius: 28,
|
||||||
|
borderTopRightRadius: 28,
|
||||||
|
paddingHorizontal: 24,
|
||||||
|
paddingTop: 16,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOpacity: 0.12,
|
||||||
|
shadowRadius: 16,
|
||||||
|
shadowOffset: { width: 0, height: -4 },
|
||||||
|
elevation: 16,
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
handle: {
|
||||||
|
width: 50,
|
||||||
|
height: 4,
|
||||||
|
borderRadius: 2,
|
||||||
|
backgroundColor: '#E5E7EB',
|
||||||
|
alignSelf: 'center',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#111827',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: '#6B7280',
|
||||||
|
textAlign: 'center',
|
||||||
|
lineHeight: 22,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 12,
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
cancelButton: {
|
||||||
|
flex: 1,
|
||||||
|
height: 56,
|
||||||
|
borderRadius: 18,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: '#E5E7EB',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: '#F8FAFC',
|
||||||
|
},
|
||||||
|
cancelText: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#111827',
|
||||||
|
},
|
||||||
|
confirmButton: {
|
||||||
|
flex: 1,
|
||||||
|
height: 56,
|
||||||
|
borderRadius: 18,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
shadowColor: 'rgba(239, 68, 68, 0.45)',
|
||||||
|
shadowOffset: { width: 0, height: 10 },
|
||||||
|
shadowOpacity: 1,
|
||||||
|
shadowRadius: 20,
|
||||||
|
elevation: 6,
|
||||||
|
},
|
||||||
|
primaryButton: {
|
||||||
|
backgroundColor: '#2563EB',
|
||||||
|
},
|
||||||
|
destructiveButton: {
|
||||||
|
backgroundColor: '#EF4444',
|
||||||
|
},
|
||||||
|
disabledButton: {
|
||||||
|
opacity: 0.7,
|
||||||
|
},
|
||||||
|
confirmText: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#fff',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -498,18 +498,25 @@ const medicationsSlice = createSlice({
|
|||||||
// ==================== deleteMedication ====================
|
// ==================== deleteMedication ====================
|
||||||
builder
|
builder
|
||||||
.addCase(deleteMedicationAction.pending, (state) => {
|
.addCase(deleteMedicationAction.pending, (state) => {
|
||||||
|
console.log('[MEDICATIONS_SLICE] Delete operation pending');
|
||||||
state.loading.delete = true;
|
state.loading.delete = true;
|
||||||
state.error = null;
|
state.error = null;
|
||||||
})
|
})
|
||||||
.addCase(deleteMedicationAction.fulfilled, (state, action) => {
|
.addCase(deleteMedicationAction.fulfilled, (state, action) => {
|
||||||
|
console.log('[MEDICATIONS_SLICE] Delete operation fulfilled', { deletedId: action.payload });
|
||||||
state.loading.delete = false;
|
state.loading.delete = false;
|
||||||
const deletedId = action.payload;
|
const deletedId = action.payload;
|
||||||
state.medications = state.medications.filter((m) => m.id !== deletedId);
|
state.medications = state.medications.filter((m) => m.id !== deletedId);
|
||||||
state.activeMedications = state.activeMedications.filter(
|
state.activeMedications = state.activeMedications.filter(
|
||||||
(m) => m.id !== deletedId
|
(m) => m.id !== deletedId
|
||||||
);
|
);
|
||||||
|
console.log('[MEDICATIONS_SLICE] Medications after delete', {
|
||||||
|
totalMedications: state.medications.length,
|
||||||
|
activeMedications: state.activeMedications.length
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.addCase(deleteMedicationAction.rejected, (state, action) => {
|
.addCase(deleteMedicationAction.rejected, (state, action) => {
|
||||||
|
console.log('[MEDICATIONS_SLICE] Delete operation rejected', action.error);
|
||||||
state.loading.delete = false;
|
state.loading.delete = false;
|
||||||
state.error = action.error.message || '删除药物失败';
|
state.error = action.error.message || '删除药物失败';
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user