feat(medications): 增强药品详情页面的编辑功能

- 添加剂量、剂型和服药频率的交互式选择器
- 实现提醒时间的动态编辑和添加功能
- 引入玻璃效果优化删除按钮的视觉体验
- 重构常量配置,提取药物相关常量到独立文件
- 创建可复用的InfoCard组件支持玻璃效果
This commit is contained in:
richarjiang
2025-11-11 11:31:06 +08:00
parent 50525f82a1
commit 7ea558847d
4 changed files with 922 additions and 107 deletions

149
components/ui/InfoCard.tsx Normal file
View File

@@ -0,0 +1,149 @@
import type { Colors } from '@/constants/Colors';
import { Ionicons } from '@expo/vector-icons';
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
export interface InfoCardProps {
label: string;
value: string;
icon: keyof typeof Ionicons.glyphMap;
colors: (typeof Colors)[keyof typeof Colors];
onPress?: () => void;
clickable?: boolean;
glassEffectStyle?: 'clear' | 'regular';
tintColor?: string;
className?: string;
}
export const InfoCard: React.FC<InfoCardProps> = ({
label,
value,
icon,
colors,
onPress,
clickable = false,
glassEffectStyle = 'clear',
}) => {
const isGlassAvailable = isLiquidGlassAvailable();
// 如果可点击且有onPress回调使用TouchableOpacity包装
if (clickable && onPress) {
return (
<TouchableOpacity
style={styles.container}
onPress={onPress}
activeOpacity={0.7}
>
{isGlassAvailable ? (
<GlassView
style={[
styles.infoCard,
]}
glassEffectStyle={glassEffectStyle}
isInteractive={true}
>
<View style={styles.infoCardArrow}>
<Ionicons name="chevron-forward" size={16} color={colors.textMuted} />
</View>
<View style={styles.infoCardIcon}>
<Ionicons name={icon} size={16} color="#4C6EF5" />
</View>
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
</GlassView>
) : (
<View style={[styles.infoCard]}>
<View style={styles.infoCardArrow}>
<Ionicons name="chevron-forward" size={16} color={colors.textMuted} />
</View>
<View style={styles.infoCardIcon}>
<Ionicons name={icon} size={16} color="#4C6EF5" />
</View>
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
</View>
)}
</TouchableOpacity>
);
}
// 不可点击的版本
return (
<View style={styles.container}>
{isGlassAvailable ? (
<GlassView
style={[
styles.infoCard,
{
backgroundColor: 'transparent',
borderColor: `${colors.border}80`,
}
]}
glassEffectStyle={glassEffectStyle}
>
<View style={styles.infoCardIcon}>
<Ionicons name={icon} size={16} color="#4C6EF5" />
</View>
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
</GlassView>
) : (
<View style={[styles.infoCard, { backgroundColor: colors.surface }]}>
<View style={styles.infoCardIcon}>
<Ionicons name={icon} size={16} color="#4C6EF5" />
</View>
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
infoCard: {
flex: 1,
borderRadius: 20,
padding: 16,
backgroundColor: '#fff',
gap: 6,
shadowColor: '#000',
shadowOpacity: 0.04,
shadowRadius: 8,
shadowOffset: { width: 0, height: 4 },
elevation: 2,
position: 'relative',
overflow: 'hidden', // 保证玻璃边界圆角效果
},
infoCardArrow: {
position: 'absolute',
top: 12,
right: 12,
zIndex: 1,
},
infoCardIcon: {
width: 28,
height: 28,
borderRadius: 14,
backgroundColor: '#EEF1FF',
alignItems: 'center',
justifyContent: 'center',
},
infoCardLabel: {
fontSize: 13,
color: '#6B7280',
marginTop: 8,
},
infoCardValue: {
fontSize: 16,
fontWeight: '600',
color: '#1F2933',
},
});
export default InfoCard;