Add Chinese translations for medication management and personal settings

- Introduced new translation files for medication, personal, and weight management in Chinese.
- Updated the main index file to include the new translation modules.
- Enhanced the medication type definitions to include 'ointment'.
- Refactored workout type labels to utilize i18n for better localization support.
- Improved sleep quality descriptions and recommendations with i18n integration.
This commit is contained in:
richarjiang
2025-11-28 17:29:51 +08:00
parent fbe0c92f0f
commit bca6670390
42 changed files with 7972 additions and 6632 deletions

View File

@@ -559,19 +559,17 @@ export default function MedicationDetailScreen() {
const formLabel = medication ? t(`medications.manage.formLabels.${medication.form}`) : '';
const dosageLabel = medication ? `${medication.dosageValue} ${medication.dosageUnit}` : '--';
const startDateLabel = medication
? dayjs(medication.startDate).format('YYYY年M月D日')
: '--';
// 计算服药周期显示
const medicationPeriodLabel = useMemo(() => {
if (!medication) return '--';
const startDate = dayjs(medication.startDate).format('YYYY年M月D日');
const format = t('medications.detail.plan.dateFormat', { defaultValue: 'YYYY年M月D日' });
const startDate = dayjs(medication.startDate).format(format);
if (medication.endDate) {
// 有结束日期,显示开始日期到结束日期
const endDate = dayjs(medication.endDate).format('YYYY年M月D日');
const endDate = dayjs(medication.endDate).format(format);
return `${startDate} - ${endDate}`;
} else {
// 没有结束日期,显示长期
@@ -581,22 +579,23 @@ export default function MedicationDetailScreen() {
// 计算有效期显示
const expiryDateLabel = useMemo(() => {
if (!medication?.expiryDate) return '未设置';
if (!medication?.expiryDate) return t('medications.detail.plan.expiryStatus.notSet');
const expiry = dayjs(medication.expiryDate);
const today = dayjs();
const daysUntilExpiry = expiry.diff(today, 'day');
const format = t('medications.detail.plan.dateFormat', { defaultValue: 'YYYY年M月D日' });
if (daysUntilExpiry < 0) {
return `${expiry.format('YYYY年M月D日')} (已过期)`;
return `${expiry.format(format)} (${t('medications.detail.plan.expiryStatus.expired')})`;
} else if (daysUntilExpiry === 0) {
return `${expiry.format('YYYY年M月D日')} (今天到期)`;
return `${expiry.format(format)} (${t('medications.detail.plan.expiryStatus.expiresToday')})`;
} else if (daysUntilExpiry <= 30) {
return `${expiry.format('YYYY年M月D日')} (${daysUntilExpiry}天后到期)`;
return `${expiry.format(format)} (${t('medications.detail.plan.expiryStatus.expiresInDays', { days: daysUntilExpiry })})`;
} else {
return expiry.format('YYYY年M月D日');
return expiry.format(format);
}
}, [medication?.expiryDate]);
}, [medication?.expiryDate, t]);
const reminderTimes = medication?.medicationTimes?.length
? medication.medicationTimes.join('、')
@@ -617,8 +616,8 @@ export default function MedicationDetailScreen() {
const aiActionLabel = aiAnalysisLoading
? t('medications.detail.aiAnalysis.analyzingButton')
: hasAiAnalysis
? '重新分析'
: '获取 AI 分析';
? t('medications.detail.aiAnalysis.reanalyzeButton')
: t('medications.detail.aiAnalysis.getAnalysisButton');
const handleOpenNoteModal = useCallback(() => {
setNoteDraft(medication?.note ?? '');
@@ -645,15 +644,15 @@ export default function MedicationDetailScreen() {
const trimmed = nameDraft.trim();
if (!trimmed) {
Alert.alert(
'提示',
'药物名称不能为空'
t('common.hint'),
t('medications.detail.name.errors.empty')
);
return;
}
if (Array.from(trimmed).length > 10) {
Alert.alert(
'提示',
'药物名称不能超过10个字'
t('common.hint'),
t('medications.detail.name.errors.tooLong')
);
return;
}
@@ -675,8 +674,8 @@ export default function MedicationDetailScreen() {
} catch (err) {
console.error('更新药物名称失败', err);
Alert.alert(
'提示',
'名称更新失败,请稍后再试'
t('common.hint'),
t('medications.detail.name.errors.updateFailed')
);
} finally {
setNameSaving(false);
@@ -908,16 +907,17 @@ export default function MedicationDetailScreen() {
const handleStartDatePress = useCallback(() => {
if (!medication) return;
const startDate = dayjs(medication.startDate).format('YYYY年M月D日');
const format = t('medications.detail.plan.dateFormat', { defaultValue: 'YYYY年M月D日' });
const startDate = dayjs(medication.startDate).format(format);
let message;
if (medication.endDate) {
const endDate = dayjs(medication.endDate).format('YYYY年M月D日');
message = `${startDate}${endDate}`;
const endDate = dayjs(medication.endDate).format(format);
message = t('medications.detail.plan.periodRange', { startDate, endDate, defaultValue: `${startDate}${endDate}` });
} else {
message = `${startDate} 至长期`;
message = t('medications.detail.plan.periodLongTerm', { startDate, defaultValue: `${startDate} 至长期` });
}
Alert.alert('服药周期', message);
Alert.alert(t('medications.detail.plan.period'), message);
}, [medication, t]);
const handleTimePress = useCallback(() => {
@@ -990,7 +990,7 @@ export default function MedicationDetailScreen() {
} catch (err) {
console.error('更新有效期失败', err);
Alert.alert('更新失败', '有效期更新失败,请稍后重试');
Alert.alert(t('medications.detail.updateErrors.expiryDate'), t('medications.detail.updateErrors.expiryDateMessage'));
} finally {
setUpdatePending(false);
}
@@ -1185,7 +1185,7 @@ export default function MedicationDetailScreen() {
});
} catch (err: any) {
console.error('[MEDICATION_DETAIL] AI 草稿保存失败', err);
Alert.alert('保存失败', err?.message || '请稍后再试');
Alert.alert(t('medications.detail.aiDraft.saveError.title'), err?.message || t('medications.detail.aiDraft.saveError.message'));
} finally {
setAiDraftSaving(false);
}
@@ -1297,7 +1297,7 @@ export default function MedicationDetailScreen() {
<View style={styles.photoUploadingIndicator}>
<ActivityIndicator color={colors.primary} size="small" />
<Text style={[styles.uploadingText, { color: '#FFF' }]}>
...
{t('medications.detail.photo.uploading')}
</Text>
</View>
)}
@@ -1415,12 +1415,12 @@ export default function MedicationDetailScreen() {
</TouchableOpacity>
</Section>
<Section title="AI 分析" color={colors.text}>
<Section title={t('medications.detail.sections.aiAnalysis')} color={colors.text}>
<View style={[styles.aiCardContainer, { backgroundColor: colors.surface }]}>
<View style={styles.aiHeaderRow}>
<View style={styles.aiHeaderLeft}>
<Ionicons name="sparkles-outline" size={18} color={colors.primary} />
<Text style={[styles.aiHeaderTitle, { color: colors.text }]}></Text>
<Text style={[styles.aiHeaderTitle, { color: colors.text }]}>{t('medications.detail.aiAnalysis.title')}</Text>
</View>
<View
style={[
@@ -1439,7 +1439,7 @@ export default function MedicationDetailScreen() {
{ color: hasAiAnalysis ? '#16a34a' : aiAnalysisLocked ? '#ef4444' : colors.primary },
]}
>
{hasAiAnalysis ? '已生成' : aiAnalysisLocked ? '会员专享' : '待生成'}
{hasAiAnalysis ? t('medications.detail.aiAnalysis.status.generated') : aiAnalysisLocked ? t('medications.detail.aiAnalysis.status.memberExclusive') : t('medications.detail.aiAnalysis.status.pending')}
</Text>
</View>
</View>
@@ -1467,7 +1467,7 @@ export default function MedicationDetailScreen() {
style={styles.aiScoreBadge}
>
<Ionicons name="thumbs-up-outline" size={14} color="#fff" />
<Text style={styles.aiScoreBadgeText}>AI </Text>
<Text style={styles.aiScoreBadgeText}>{t('medications.detail.aiAnalysis.recommendation')}</Text>
</LinearGradient>
)}
</View>
@@ -1476,7 +1476,7 @@ export default function MedicationDetailScreen() {
{medication.name}
</Text>
<Text style={[styles.aiHeroSubtitle, { color: colors.textSecondary }]} numberOfLines={3}>
{aiAnalysisResult?.mainUsage || '获取 AI 分析,快速了解适用人群、成分安全与使用建议。'}
{aiAnalysisResult?.mainUsage || t('medications.detail.aiAnalysis.placeholder')}
</Text>
<View style={styles.aiChipRow}>
<View style={styles.aiChip}>
@@ -1527,7 +1527,7 @@ export default function MedicationDetailScreen() {
<View style={styles.aiColumns}>
<View style={[styles.aiBubbleCard, { backgroundColor: '#ECFEFF', borderColor: '#BAF2F4' }]}>
<View style={styles.aiBubbleHeader}>
<Text style={[styles.aiBubbleTitle, { color: '#0284c7' }]}></Text>
<Text style={[styles.aiBubbleTitle, { color: '#0284c7' }]}>{t('medications.detail.aiAnalysis.categories.suitableFor')}</Text>
<Ionicons name="checkmark-circle" size={16} color="#0ea5e9" />
</View>
{aiAnalysisResult.suitableFor.map((item, idx) => (
@@ -1540,7 +1540,7 @@ export default function MedicationDetailScreen() {
<View style={[styles.aiBubbleCard, { backgroundColor: '#FEF2F2', borderColor: '#FEE2E2' }]}>
<View style={styles.aiBubbleHeader}>
<Text style={[styles.aiBubbleTitle, { color: '#ef4444' }]}></Text>
<Text style={[styles.aiBubbleTitle, { color: '#ef4444' }]}>{t('medications.detail.aiAnalysis.categories.unsuitableFor')}</Text>
<Ionicons name="alert-circle" size={16} color="#ef4444" />
</View>
{aiAnalysisResult.unsuitableFor.map((item, idx) => (
@@ -1552,9 +1552,9 @@ export default function MedicationDetailScreen() {
</View>
</View>
{renderAdviceCard('可能的副作用', aiAnalysisResult.sideEffects, 'warning-outline', '#f59e0b', '#FFFBEB')}
{renderAdviceCard('储存建议', aiAnalysisResult.storageAdvice, 'cube-outline', '#10b981', '#ECFDF3')}
{renderAdviceCard('健康/使用建议', aiAnalysisResult.healthAdvice, 'sparkles-outline', '#6366f1', '#EEF2FF')}
{renderAdviceCard(t('medications.detail.aiAnalysis.categories.sideEffects'), aiAnalysisResult.sideEffects, 'warning-outline', '#f59e0b', '#FFFBEB')}
{renderAdviceCard(t('medications.detail.aiAnalysis.categories.storageAdvice'), aiAnalysisResult.storageAdvice, 'cube-outline', '#10b981', '#ECFDF3')}
{renderAdviceCard(t('medications.detail.aiAnalysis.categories.healthAdvice'), aiAnalysisResult.healthAdvice, 'sparkles-outline', '#6366f1', '#EEF2FF')}
</>
) : null}
@@ -1580,8 +1580,8 @@ export default function MedicationDetailScreen() {
<View style={styles.aiMembershipLeft}>
<Ionicons name="diamond-outline" size={18} color="#f59e0b" />
<View>
<Text style={styles.aiMembershipTitle}> AI </Text>
<Text style={styles.aiMembershipSub}>使</Text>
<Text style={styles.aiMembershipTitle}>{t('medications.detail.aiAnalysis.membershipCard.title')}</Text>
<Text style={styles.aiMembershipSub}>{t('medications.detail.aiAnalysis.membershipCard.subtitle')}</Text>
</View>
</View>
<Ionicons name="chevron-forward" size={18} color="#f59e0b" />
@@ -1622,22 +1622,67 @@ export default function MedicationDetailScreen() {
{isAiDraft ? (
<View style={styles.footerButtonContainer}>
<TouchableOpacity
style={styles.secondaryFooterBtn}
activeOpacity={0.9}
onPress={() => router.replace('/medications/ai-camera')}
>
<Text style={styles.secondaryFooterText}></Text>
{isLiquidGlassAvailable() ? (
<GlassView
style={[styles.secondaryFooterBtn, { borderWidth: 0, overflow: 'hidden', backgroundColor: 'transparent' }]}
glassEffectStyle="regular"
isInteractive={true}
>
<Text style={styles.secondaryFooterText}>{t('medications.detail.aiDraft.reshoot')}</Text>
</GlassView>
) : (
<View style={styles.secondaryFooterBtn}>
<Text style={styles.secondaryFooterText}>{t('medications.detail.aiDraft.reshoot')}</Text>
</View>
)}
</TouchableOpacity>
<TouchableOpacity
style={[styles.primaryFooterBtn, { backgroundColor: colors.primary }]}
style={{ flex: 1 }}
activeOpacity={0.9}
onPress={handleAiDraftSave}
disabled={aiDraftSaving}
>
{aiDraftSaving ? (
<ActivityIndicator color={colors.onPrimary} />
{isLiquidGlassAvailable() ? (
<GlassView
style={[
styles.primaryFooterBtn,
{
width: '100%',
shadowOpacity: 0,
backgroundColor: 'transparent',
overflow: 'hidden',
},
]}
glassEffectStyle="regular"
tintColor={colors.primary}
isInteractive={true}
>
{aiDraftSaving ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={[styles.primaryFooterText, { color: '#fff' }]}>
{t('medications.detail.aiDraft.saveAndCreate')}
</Text>
)}
</GlassView>
) : (
<Text style={[styles.primaryFooterText, { color: colors.onPrimary }]}></Text>
<View
style={[
styles.primaryFooterBtn,
{ width: '100%', backgroundColor: colors.primary },
]}
>
{aiDraftSaving ? (
<ActivityIndicator color={colors.onPrimary} />
) : (
<Text style={[styles.primaryFooterText, { color: colors.onPrimary }]}>
{t('medications.detail.aiDraft.saveAndCreate')}
</Text>
)}
</View>
)}
</TouchableOpacity>
</View>
@@ -1726,7 +1771,7 @@ export default function MedicationDetailScreen() {
<View style={styles.modalHandle} />
<View style={styles.modalHeader}>
<Text style={[styles.modalTitle, { color: colors.text }]}>
{t('medications.detail.name.edit')}
</Text>
<TouchableOpacity onPress={handleCloseNameModal} hitSlop={12}>
<Ionicons name="close" size={20} color={colors.textSecondary} />
@@ -1744,7 +1789,7 @@ export default function MedicationDetailScreen() {
<TextInput
value={nameDraft}
onChangeText={handleNameChange}
placeholder="请输入药物名称"
placeholder={t('medications.detail.name.placeholder')}
placeholderTextColor={colors.textMuted}
style={[styles.nameInput, { color: colors.text }]}
autoFocus
@@ -1777,7 +1822,7 @@ export default function MedicationDetailScreen() {
<ActivityIndicator color={colors.onPrimary} size="small" />
) : (
<Text style={[styles.modalActionPrimaryText, { color: colors.onPrimary }]}>
{t('common.save')}
</Text>
)}
</TouchableOpacity>
@@ -2599,7 +2644,7 @@ const styles = StyleSheet.create({
elevation: 4,
},
aiScoreBadgeText: {
fontSize: 12,
fontSize: 10,
fontWeight: '700',
color: '#fff',
},

View File

@@ -1,5 +1,6 @@
import { HeaderBar } from '@/components/ui/HeaderBar';
import { Colors } from '@/constants/Colors';
import { Colors, palette } from '@/constants/Colors';
import { useI18n } from '@/hooks/useI18n';
import { getMedicationRecognitionStatus } from '@/services/medications';
import { MedicationRecognitionTask } from '@/types/medication';
import { Ionicons } from '@expo/vector-icons';
@@ -13,14 +14,15 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
const { width: SCREEN_WIDTH } = Dimensions.get('window');
const STATUS_STEPS: { key: MedicationRecognitionTask['status']; label: string }[] = [
{ key: 'analyzing_product', label: '正在进行产品分析...' },
{ key: 'analyzing_suitability', label: '正在检测适宜人群...' },
{ key: 'analyzing_ingredients', label: '正在评估成分信息...' },
{ key: 'analyzing_effects', label: '正在生成安全建议...' },
const STEP_KEYS: MedicationRecognitionTask['status'][] = [
'analyzing_product',
'analyzing_suitability',
'analyzing_ingredients',
'analyzing_effects',
];
export default function MedicationAiProgressScreen() {
const { t } = useI18n();
const { taskId, cover } = useLocalSearchParams<{ taskId?: string; cover?: string }>();
const insets = useSafeAreaInsets();
const [task, setTask] = useState<MedicationRecognitionTask | null>(null);
@@ -35,11 +37,16 @@ export default function MedicationAiProgressScreen() {
const floatAnim = useRef(new Animated.Value(0)).current;
const opacityAnim = useRef(new Animated.Value(0.3)).current;
const steps = useMemo(() => STEP_KEYS.map(key => ({
key,
label: t(`medications.aiProgress.steps.${key}`)
})), [t]);
const currentStepIndex = useMemo(() => {
if (!task) return 0;
const idx = STATUS_STEPS.findIndex((step) => step.key === task.status);
const idx = STEP_KEYS.indexOf(task.status as any);
if (idx >= 0) return idx;
if (task.status === 'completed') return STATUS_STEPS.length;
if (task.status === 'completed') return STEP_KEYS.length;
return 0;
}, [task]);
@@ -77,12 +84,12 @@ export default function MedicationAiProgressScreen() {
pollingTimerRef.current = null;
}
// 显示错误提示弹窗
setErrorMessage(data.errorMessage || '识别失败,请重新拍摄');
setErrorMessage(data.errorMessage || t('medications.aiProgress.errors.default'));
setShowErrorModal(true);
}
} catch (err: any) {
console.error('[MEDICATION_AI] status failed', err);
setError(err?.message || '查询失败,请稍后再试');
setError(err?.message || t('medications.aiProgress.errors.queryFailed'));
} finally {
setLoading(false);
}
@@ -148,12 +155,12 @@ export default function MedicationAiProgressScreen() {
};
}, []);
const progress = task?.progress ?? Math.min(100, (currentStepIndex / STATUS_STEPS.length) * 100 + 10);
const progress = task?.progress ?? Math.min(100, (currentStepIndex / steps.length) * 100 + 10);
return (
<SafeAreaView style={styles.container}>
<LinearGradient colors={['#fdfdfd', '#f3f6fb']} style={StyleSheet.absoluteFill} />
<HeaderBar title="识别中" onBack={() => router.back()} transparent />
<LinearGradient colors={[palette.gray[25], palette.gray[50]]} style={StyleSheet.absoluteFill} />
<HeaderBar title={t('medications.aiProgress.title')} onBack={() => router.back()} transparent />
<View style={{ height: insets.top }} />
<View style={styles.heroCard}>
@@ -172,7 +179,7 @@ export default function MedicationAiProgressScreen() {
{/* 渐变蒙版边框,增加视觉层次 */}
<LinearGradient
colors={['rgba(14, 165, 233, 0.3)', 'rgba(6, 182, 212, 0.2)', 'transparent']}
colors={[Colors.light.primary + '4D', Colors.light.accentPurple + '33', 'transparent']}
style={styles.gradientBorder}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
@@ -206,7 +213,7 @@ export default function MedicationAiProgressScreen() {
</View>
<View style={styles.stepList}>
{STATUS_STEPS.map((step, index) => {
{steps.map((step, index) => {
const active = index === currentStepIndex;
const done = index < currentStepIndex;
return (
@@ -221,7 +228,7 @@ export default function MedicationAiProgressScreen() {
{task?.status === 'completed' && (
<View style={styles.stepRow}>
<View style={[styles.bullet, styles.bulletDone]} />
<Text style={[styles.stepLabel, styles.stepLabelDone]}>...</Text>
<Text style={[styles.stepLabel, styles.stepLabelDone]}>{t('medications.aiProgress.steps.completed')}</Text>
</View>
)}
</View>
@@ -251,7 +258,7 @@ export default function MedicationAiProgressScreen() {
<View style={styles.errorModalContent}>
{/* 标题 */}
<Text style={styles.errorModalTitle}></Text>
<Text style={styles.errorModalTitle}>{t('medications.aiProgress.modal.title')}</Text>
{/* 提示信息 */}
<View style={styles.errorMessageBox}>
@@ -268,29 +275,29 @@ export default function MedicationAiProgressScreen() {
<GlassView
style={styles.retryButton}
glassEffectStyle="regular"
tintColor="rgba(14, 165, 233, 0.9)"
tintColor={Colors.light.primary}
isInteractive={true}
>
<LinearGradient
colors={['rgba(14, 165, 233, 0.95)', 'rgba(6, 182, 212, 0.95)']}
colors={[Colors.light.primary, Colors.light.accentPurple]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.retryButtonGradient}
>
<Ionicons name="camera" size={20} color="#FFFFFF" style={{ marginRight: 8 }} />
<Text style={styles.retryButtonText}></Text>
<Text style={styles.retryButtonText}>{t('medications.aiProgress.modal.retry')}</Text>
</LinearGradient>
</GlassView>
) : (
<View style={styles.retryButton}>
<LinearGradient
colors={['#0ea5e9', '#06b6d4']}
colors={[Colors.light.primary, Colors.light.accentPurple]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.retryButtonGradient}
>
<Ionicons name="camera" size={20} color="#FFFFFF" style={{ marginRight: 8 }} />
<Text style={styles.retryButtonText}></Text>
<Text style={styles.retryButtonText}>{t('medications.aiProgress.modal.retry')}</Text>
</LinearGradient>
</View>
)}
@@ -311,9 +318,9 @@ const styles = StyleSheet.create({
marginHorizontal: 20,
marginTop: 24,
borderRadius: 24,
backgroundColor: '#fff',
backgroundColor: Colors.light.card,
padding: 16,
shadowColor: '#0f172a',
shadowColor: Colors.light.text,
shadowOpacity: 0.08,
shadowRadius: 18,
shadowOffset: { width: 0, height: 10 },
@@ -322,7 +329,7 @@ const styles = StyleSheet.create({
height: 230,
borderRadius: 18,
overflow: 'hidden',
backgroundColor: '#e2e8f0',
backgroundColor: palette.gray[50],
},
heroImage: {
width: '100%',
@@ -330,7 +337,7 @@ const styles = StyleSheet.create({
},
heroPlaceholder: {
flex: 1,
backgroundColor: '#e2e8f0',
backgroundColor: palette.gray[50],
},
// 深色蒙版层,让点阵更清晰可见
overlayMask: {
@@ -368,15 +375,15 @@ const styles = StyleSheet.create({
width: 5,
height: 5,
borderRadius: 2.5,
backgroundColor: '#FFFFFF',
shadowColor: '#0ea5e9',
backgroundColor: Colors.light.background,
shadowColor: Colors.light.primary,
shadowOpacity: 0.9,
shadowRadius: 6,
shadowOffset: { width: 0, height: 0 },
},
progressRow: {
height: 8,
backgroundColor: '#f1f5f9',
backgroundColor: palette.gray[50],
borderRadius: 10,
marginTop: 14,
overflow: 'hidden',
@@ -384,13 +391,13 @@ const styles = StyleSheet.create({
progressBar: {
height: '100%',
borderRadius: 10,
backgroundColor: '#0ea5e9',
backgroundColor: Colors.light.primary,
},
progressText: {
marginTop: 8,
fontSize: 14,
fontWeight: '700',
color: '#0f172a',
color: Colors.light.text,
textAlign: 'right',
},
stepList: {
@@ -407,24 +414,24 @@ const styles = StyleSheet.create({
width: 14,
height: 14,
borderRadius: 7,
backgroundColor: '#e2e8f0',
backgroundColor: palette.gray[50],
},
bulletActive: {
backgroundColor: '#0ea5e9',
backgroundColor: Colors.light.primary,
},
bulletDone: {
backgroundColor: '#22c55e',
backgroundColor: Colors.light.success,
},
stepLabel: {
fontSize: 15,
color: '#94a3b8',
color: Colors.light.textMuted,
},
stepLabelActive: {
color: '#0f172a',
color: Colors.light.text,
fontWeight: '700',
},
stepLabelDone: {
color: '#16a34a',
color: Colors.light.successDark,
fontWeight: '700',
},
loadingBox: {
@@ -433,7 +440,7 @@ const styles = StyleSheet.create({
gap: 12,
},
errorText: {
color: '#ef4444',
color: Colors.light.danger,
fontSize: 14,
},
// Modal 样式
@@ -445,10 +452,10 @@ const styles = StyleSheet.create({
},
errorModalContainer: {
width: SCREEN_WIDTH - 48,
backgroundColor: '#FFFFFF',
backgroundColor: Colors.light.card,
borderRadius: 28,
overflow: 'hidden',
shadowColor: '#0ea5e9',
shadowColor: Colors.light.primary,
shadowOpacity: 0.15,
shadowRadius: 24,
shadowOffset: { width: 0, height: 8 },
@@ -465,36 +472,36 @@ const styles = StyleSheet.create({
width: 96,
height: 96,
borderRadius: 48,
backgroundColor: 'rgba(14, 165, 233, 0.08)',
backgroundColor: palette.purple[50],
alignItems: 'center',
justifyContent: 'center',
},
errorModalTitle: {
fontSize: 22,
fontWeight: '700',
color: '#0f172a',
color: Colors.light.text,
marginBottom: 16,
textAlign: 'center',
},
errorMessageBox: {
backgroundColor: '#f0f9ff',
backgroundColor: palette.purple[25],
borderRadius: 16,
padding: 20,
marginBottom: 28,
width: '100%',
borderWidth: 1,
borderColor: 'rgba(14, 165, 233, 0.2)',
borderColor: palette.purple[200],
},
errorMessageText: {
fontSize: 15,
lineHeight: 24,
color: '#475569',
color: Colors.light.textSecondary,
textAlign: 'center',
},
retryButton: {
borderRadius: 16,
overflow: 'hidden',
shadowColor: '#0ea5e9',
shadowColor: Colors.light.primary,
shadowOpacity: 0.25,
shadowRadius: 12,
shadowOffset: { width: 0, height: 6 },
@@ -509,6 +516,6 @@ const styles = StyleSheet.create({
retryButtonText: {
fontSize: 18,
fontWeight: '700',
color: '#FFFFFF',
color: Colors.light.onPrimary,
},
});