feat(medications): 添加药品详情页面和删除功能
新增药品详情页面,支持查看药品信息、编辑备注、切换提醒状态和删除药品 - 创建动态路由页面 /medications/[medicationId].tsx 展示药品详细信息 - 添加语音输入备注功能,支持 iOS 语音识别 - 实现药品删除确认对话框和删除操作 - 优化药品卡片点击跳转详情页面的交互 - 添加删除操作的加载状态和错误处理 - 改进药品管理页面的开关状态显示和加载指示器
This commit is contained in:
@@ -52,6 +52,13 @@ export default function MedicationsScreen() {
|
||||
router.push('/medications/manage-medications');
|
||||
}, []);
|
||||
|
||||
const handleOpenMedicationDetails = useCallback((medicationId: string) => {
|
||||
router.push({
|
||||
pathname: '/medications/[medicationId]',
|
||||
params: { medicationId },
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 加载药物和记录数据
|
||||
useEffect(() => {
|
||||
dispatch(fetchMedications());
|
||||
@@ -255,6 +262,7 @@ export default function MedicationsScreen() {
|
||||
medication={item}
|
||||
colors={colors}
|
||||
selectedDate={selectedDate}
|
||||
onOpenDetails={() => handleOpenMedicationDetails(item.medicationId)}
|
||||
/>
|
||||
))}
|
||||
</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 [pendingMedicationId, setPendingMedicationId] = useState<string | null>(null);
|
||||
|
||||
const updateLoading = loading.update;
|
||||
const listLoading = loading.medications && medications.length === 0;
|
||||
|
||||
useFocusEffect(
|
||||
@@ -116,7 +115,7 @@ export default function ManageMedicationsScreen() {
|
||||
);
|
||||
|
||||
// 创建独立的药品卡片组件,使用 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 frequencyLabel = `${medication.repeatPattern === 'daily' ? '每日' : medication.repeatPattern === 'weekly' ? '每周' : '自定义'} | ${dosageLabel}`;
|
||||
const startDateLabel = dayjs(medication.startDate).isValid()
|
||||
@@ -127,7 +126,11 @@ export default function ManageMedicationsScreen() {
|
||||
: `${medication.timesPerDay} 次/日`;
|
||||
|
||||
return (
|
||||
<View style={[styles.card, { backgroundColor: colors.surface }]}>
|
||||
<TouchableOpacity
|
||||
style={[styles.card, { backgroundColor: colors.surface }]}
|
||||
activeOpacity={0.9}
|
||||
onPress={onPress}
|
||||
>
|
||||
<View style={styles.cardInfo}>
|
||||
<Image
|
||||
source={medication.photoUrl ? { uri: medication.photoUrl } : DEFAULT_IMAGE}
|
||||
@@ -144,15 +147,24 @@ export default function ManageMedicationsScreen() {
|
||||
</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
<Switch
|
||||
value={medication.isActive}
|
||||
onValueChange={(value) => handleToggleMedication(medication, value)}
|
||||
disabled={updateLoading || pendingMedicationId === medication.id}
|
||||
trackColor={{ false: '#D9D9D9', true: colors.primary }}
|
||||
thumbColor={medication.isActive ? '#fff' : '#fff'}
|
||||
ios_backgroundColor="#D9D9D9"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.switchContainer}>
|
||||
<Switch
|
||||
value={medication.isActive}
|
||||
onValueChange={(value) => handleToggleMedication(medication, value)}
|
||||
disabled={pendingMedicationId === medication.id}
|
||||
trackColor={{ false: '#D9D9D9', true: colors.primary }}
|
||||
thumbColor={medication.isActive ? '#fff' : '#fff'}
|
||||
ios_backgroundColor="#D9D9D9"
|
||||
/>
|
||||
{pendingMedicationId === medication.id && (
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color={colors.primary}
|
||||
style={styles.switchLoading}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}, (prevProps, nextProps) => {
|
||||
// 自定义比较函数,只有当药品的 isActive 状态或 ID 改变时才重新渲染
|
||||
@@ -166,11 +178,24 @@ export default function ManageMedicationsScreen() {
|
||||
|
||||
MedicationCard.displayName = 'MedicationCard';
|
||||
|
||||
const handleOpenMedicationDetails = useCallback((medicationId: string) => {
|
||||
router.push({
|
||||
pathname: '/medications/[medicationId]',
|
||||
params: { medicationId },
|
||||
});
|
||||
}, []);
|
||||
|
||||
const renderMedicationCard = useCallback(
|
||||
(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 (
|
||||
@@ -398,4 +423,13 @@ const styles = StyleSheet.create({
|
||||
fontSize: 14,
|
||||
textAlign: 'center',
|
||||
},
|
||||
switchContainer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
position: 'relative',
|
||||
},
|
||||
switchLoading: {
|
||||
position: 'absolute',
|
||||
marginLeft: 30, // 确保加载指示器显示在开关旁边
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user