498 lines
14 KiB
TypeScript
498 lines
14 KiB
TypeScript
|
|
/**
|
|||
|
|
* 身份认证设置页面
|
|||
|
|
* 用户查看认证状态、提交认证申请
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import React, { useEffect, useState } from 'react';
|
|||
|
|
import {
|
|||
|
|
View,
|
|||
|
|
Text,
|
|||
|
|
StyleSheet,
|
|||
|
|
TouchableOpacity,
|
|||
|
|
ScrollView,
|
|||
|
|
Image,
|
|||
|
|
Alert,
|
|||
|
|
ActivityIndicator,
|
|||
|
|
} from 'react-native';
|
|||
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|||
|
|
import { useRouter } from 'expo-router';
|
|||
|
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|||
|
|
import { useAppColors, type AppColors } from '../../theme';
|
|||
|
|
import {
|
|||
|
|
useVerificationStore,
|
|||
|
|
useVerificationStatus,
|
|||
|
|
useVerificationLoading,
|
|||
|
|
} from '../../stores/verificationStore';
|
|||
|
|
import { showPrompt } from '../../services/promptService';
|
|||
|
|
import * as hrefs from '../../navigation/hrefs';
|
|||
|
|
|
|||
|
|
const THEME_COLORS = {
|
|||
|
|
primary: '#FF6B35',
|
|||
|
|
primaryLight: '#FF8C5A',
|
|||
|
|
primaryDark: '#E55A2B',
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const STATUS_CONFIG = {
|
|||
|
|
not_submitted: {
|
|||
|
|
title: '未认证',
|
|||
|
|
description: '完成身份认证,解锁更多专属功能',
|
|||
|
|
icon: 'account-question-outline',
|
|||
|
|
color: '#999',
|
|||
|
|
},
|
|||
|
|
pending: {
|
|||
|
|
title: '审核中',
|
|||
|
|
description: '您的认证申请正在审核中,请耐心等待',
|
|||
|
|
icon: 'clock-outline',
|
|||
|
|
color: '#FFA500',
|
|||
|
|
},
|
|||
|
|
approved: {
|
|||
|
|
title: '已认证',
|
|||
|
|
description: '您已完成身份认证',
|
|||
|
|
icon: 'check-decagram',
|
|||
|
|
color: '#4CAF50',
|
|||
|
|
},
|
|||
|
|
rejected: {
|
|||
|
|
title: '认证失败',
|
|||
|
|
description: '您的认证申请被拒绝,可以重新提交',
|
|||
|
|
icon: 'close-circle-outline',
|
|||
|
|
color: '#F44336',
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const IDENTITY_TEXT: Record<string, string> = {
|
|||
|
|
general: '普通用户',
|
|||
|
|
student: '在校学生',
|
|||
|
|
teacher: '教职工',
|
|||
|
|
staff: '工作人员',
|
|||
|
|
alumni: '校友',
|
|||
|
|
external: '外部人员',
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export const VerificationSettingsScreen: React.FC = () => {
|
|||
|
|
const colors = useAppColors();
|
|||
|
|
const styles = createStyles(colors);
|
|||
|
|
const router = useRouter();
|
|||
|
|
const status = useVerificationStatus();
|
|||
|
|
const loading = useVerificationLoading();
|
|||
|
|
const { fetchStatus, reset } = useVerificationStore();
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
fetchStatus();
|
|||
|
|
return () => {
|
|||
|
|
reset();
|
|||
|
|
};
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
const handleStartVerification = () => {
|
|||
|
|
router.push('/auth/verification-guide');
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleViewRecords = () => {
|
|||
|
|
showPrompt({
|
|||
|
|
title: '认证记录',
|
|||
|
|
message: '认证记录功能即将上线',
|
|||
|
|
type: 'info',
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (loading && !status) {
|
|||
|
|
return (
|
|||
|
|
<SafeAreaView style={styles.container}>
|
|||
|
|
<View style={styles.loadingContainer}>
|
|||
|
|
<ActivityIndicator size="large" color={THEME_COLORS.primary} />
|
|||
|
|
</View>
|
|||
|
|
</SafeAreaView>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const statusConfig = STATUS_CONFIG[status?.verification_status || 'not_submitted'];
|
|||
|
|
const identityText = IDENTITY_TEXT[status?.identity || 'general'];
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<SafeAreaView style={styles.container}>
|
|||
|
|
<View style={styles.header}>
|
|||
|
|
<TouchableOpacity
|
|||
|
|
style={styles.backButton}
|
|||
|
|
onPress={() => router.back()}
|
|||
|
|
activeOpacity={0.8}
|
|||
|
|
>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name="arrow-left"
|
|||
|
|
size={24}
|
|||
|
|
color={colors.text?.primary || '#333'}
|
|||
|
|
/>
|
|||
|
|
</TouchableOpacity>
|
|||
|
|
<Text style={styles.headerTitle}>身份认证</Text>
|
|||
|
|
<View style={styles.headerRight} />
|
|||
|
|
</View>
|
|||
|
|
|
|||
|
|
<ScrollView
|
|||
|
|
contentContainerStyle={styles.scrollContent}
|
|||
|
|
showsVerticalScrollIndicator={false}
|
|||
|
|
>
|
|||
|
|
{/* 状态卡片 */}
|
|||
|
|
<View style={styles.statusCard}>
|
|||
|
|
<View style={[styles.statusIconContainer, { backgroundColor: statusConfig.color + '20' }]}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name={statusConfig.icon as any}
|
|||
|
|
size={48}
|
|||
|
|
color={statusConfig.color}
|
|||
|
|
/>
|
|||
|
|
</View>
|
|||
|
|
<Text style={styles.statusTitle}>{statusConfig.title}</Text>
|
|||
|
|
<Text style={styles.statusDescription}>{statusConfig.description}</Text>
|
|||
|
|
|
|||
|
|
{status?.verification_status === 'approved' && (
|
|||
|
|
<View style={styles.identityBadge}>
|
|||
|
|
<MaterialCommunityIcons name="check-circle" size={16} color={THEME_COLORS.primary} />
|
|||
|
|
<Text style={styles.identityText}>{identityText}</Text>
|
|||
|
|
</View>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{status?.latest_record?.reject_reason && (
|
|||
|
|
<View style={styles.rejectReasonContainer}>
|
|||
|
|
<Text style={styles.rejectReasonLabel}>拒绝原因:</Text>
|
|||
|
|
<Text style={styles.rejectReasonText}>
|
|||
|
|
{status.latest_record.reject_reason}
|
|||
|
|
</Text>
|
|||
|
|
</View>
|
|||
|
|
)}
|
|||
|
|
</View>
|
|||
|
|
|
|||
|
|
{/* 认证优势 */}
|
|||
|
|
{status?.verification_status !== 'approved' && (
|
|||
|
|
<View style={styles.benefitsSection}>
|
|||
|
|
<Text style={styles.sectionTitle}>认证优势</Text>
|
|||
|
|
<View style={styles.benefitsList}>
|
|||
|
|
<View style={styles.benefitItem}>
|
|||
|
|
<View style={styles.benefitIconContainer}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name="verified"
|
|||
|
|
size={24}
|
|||
|
|
color={THEME_COLORS.primary}
|
|||
|
|
/>
|
|||
|
|
</View>
|
|||
|
|
<View style={styles.benefitContent}>
|
|||
|
|
<Text style={styles.benefitTitle}>专属认证标识</Text>
|
|||
|
|
<Text style={styles.benefitDescription}>
|
|||
|
|
获得身份认证徽章,提升账号可信度
|
|||
|
|
</Text>
|
|||
|
|
</View>
|
|||
|
|
</View>
|
|||
|
|
|
|||
|
|
<View style={styles.benefitItem}>
|
|||
|
|
<View style={styles.benefitIconContainer}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name="lock-open-variant"
|
|||
|
|
size={24}
|
|||
|
|
color={THEME_COLORS.primary}
|
|||
|
|
/>
|
|||
|
|
</View>
|
|||
|
|
<View style={styles.benefitContent}>
|
|||
|
|
<Text style={styles.benefitTitle}>解锁专属频道</Text>
|
|||
|
|
<Text style={styles.benefitDescription}>
|
|||
|
|
访问仅限认证用户的专属内容和频道
|
|||
|
|
</Text>
|
|||
|
|
</View>
|
|||
|
|
</View>
|
|||
|
|
|
|||
|
|
<View style={styles.benefitItem}>
|
|||
|
|
<View style={styles.benefitIconContainer}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name="account-group"
|
|||
|
|
size={24}
|
|||
|
|
color={THEME_COLORS.primary}
|
|||
|
|
/>
|
|||
|
|
</View>
|
|||
|
|
<View style={styles.benefitContent}>
|
|||
|
|
<Text style={styles.benefitTitle}>加入社群圈子</Text>
|
|||
|
|
<Text style={styles.benefitDescription}>
|
|||
|
|
加入需要身份认证的校友群、班级群等
|
|||
|
|
</Text>
|
|||
|
|
</View>
|
|||
|
|
</View>
|
|||
|
|
</View>
|
|||
|
|
</View>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{/* 操作按钮 */}
|
|||
|
|
<View style={styles.actionSection}>
|
|||
|
|
{(status?.verification_status === 'not_submitted' ||
|
|||
|
|
status?.verification_status === 'rejected') && (
|
|||
|
|
<TouchableOpacity
|
|||
|
|
style={styles.primaryButton}
|
|||
|
|
onPress={handleStartVerification}
|
|||
|
|
activeOpacity={0.9}
|
|||
|
|
>
|
|||
|
|
<MaterialCommunityIcons name="shield-check-outline" size={20} color="#FFF" />
|
|||
|
|
<Text style={styles.primaryButtonText}>
|
|||
|
|
{status?.verification_status === 'rejected' ? '重新认证' : '开始认证'}
|
|||
|
|
</Text>
|
|||
|
|
</TouchableOpacity>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{status?.verification_status === 'pending' && (
|
|||
|
|
<TouchableOpacity
|
|||
|
|
style={styles.secondaryButton}
|
|||
|
|
onPress={handleViewRecords}
|
|||
|
|
activeOpacity={0.8}
|
|||
|
|
>
|
|||
|
|
<MaterialCommunityIcons name="file-document-outline" size={20} color={THEME_COLORS.primary} />
|
|||
|
|
<Text style={styles.secondaryButtonText}>查看认证记录</Text>
|
|||
|
|
</TouchableOpacity>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{status?.verification_status === 'approved' && (
|
|||
|
|
<>
|
|||
|
|
<View style={styles.verifiedInfo}>
|
|||
|
|
<View style={styles.verifiedInfoRow}>
|
|||
|
|
<Text style={styles.verifiedInfoLabel}>认证身份</Text>
|
|||
|
|
<Text style={styles.verifiedInfoValue}>{identityText}</Text>
|
|||
|
|
</View>
|
|||
|
|
{status.latest_record?.real_name && (
|
|||
|
|
<View style={styles.verifiedInfoRow}>
|
|||
|
|
<Text style={styles.verifiedInfoLabel}>真实姓名</Text>
|
|||
|
|
<Text style={styles.verifiedInfoValue}>
|
|||
|
|
{status.latest_record.real_name}
|
|||
|
|
</Text>
|
|||
|
|
</View>
|
|||
|
|
)}
|
|||
|
|
{status.latest_record?.department && (
|
|||
|
|
<View style={styles.verifiedInfoRow}>
|
|||
|
|
<Text style={styles.verifiedInfoLabel}>院系/部门</Text>
|
|||
|
|
<Text style={styles.verifiedInfoValue}>
|
|||
|
|
{status.latest_record.department}
|
|||
|
|
</Text>
|
|||
|
|
</View>
|
|||
|
|
)}
|
|||
|
|
</View>
|
|||
|
|
</>
|
|||
|
|
)}
|
|||
|
|
</View>
|
|||
|
|
|
|||
|
|
{/* 帮助信息 */}
|
|||
|
|
<View style={styles.helpSection}>
|
|||
|
|
<Text style={styles.helpTitle}>遇到问题?</Text>
|
|||
|
|
<Text style={styles.helpText}>
|
|||
|
|
如果在认证过程中遇到问题,请联系客服或在设置中提交反馈
|
|||
|
|
</Text>
|
|||
|
|
</View>
|
|||
|
|
</ScrollView>
|
|||
|
|
</SafeAreaView>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
function createStyles(colors: AppColors) {
|
|||
|
|
return StyleSheet.create({
|
|||
|
|
container: {
|
|||
|
|
flex: 1,
|
|||
|
|
backgroundColor: '#fff',
|
|||
|
|
},
|
|||
|
|
loadingContainer: {
|
|||
|
|
flex: 1,
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
},
|
|||
|
|
header: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
justifyContent: 'space-between',
|
|||
|
|
paddingHorizontal: 16,
|
|||
|
|
paddingVertical: 12,
|
|||
|
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
|||
|
|
borderBottomColor: colors.divider || '#E0E0E0',
|
|||
|
|
},
|
|||
|
|
backButton: {
|
|||
|
|
width: 40,
|
|||
|
|
height: 40,
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
},
|
|||
|
|
headerTitle: {
|
|||
|
|
fontSize: 18,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: colors.text?.primary || '#333',
|
|||
|
|
},
|
|||
|
|
headerRight: {
|
|||
|
|
width: 40,
|
|||
|
|
},
|
|||
|
|
scrollContent: {
|
|||
|
|
flexGrow: 1,
|
|||
|
|
padding: 24,
|
|||
|
|
},
|
|||
|
|
statusCard: {
|
|||
|
|
alignItems: 'center',
|
|||
|
|
paddingVertical: 32,
|
|||
|
|
paddingHorizontal: 24,
|
|||
|
|
backgroundColor: '#F9F9F9',
|
|||
|
|
borderRadius: 16,
|
|||
|
|
marginBottom: 24,
|
|||
|
|
},
|
|||
|
|
statusIconContainer: {
|
|||
|
|
width: 96,
|
|||
|
|
height: 96,
|
|||
|
|
borderRadius: 48,
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
marginBottom: 16,
|
|||
|
|
},
|
|||
|
|
statusTitle: {
|
|||
|
|
fontSize: 24,
|
|||
|
|
fontWeight: '700',
|
|||
|
|
color: colors.text?.primary || '#333',
|
|||
|
|
marginBottom: 8,
|
|||
|
|
},
|
|||
|
|
statusDescription: {
|
|||
|
|
fontSize: 15,
|
|||
|
|
color: colors.text?.secondary || '#666',
|
|||
|
|
textAlign: 'center',
|
|||
|
|
lineHeight: 22,
|
|||
|
|
},
|
|||
|
|
identityBadge: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
backgroundColor: '#FFF5F0',
|
|||
|
|
borderRadius: 20,
|
|||
|
|
paddingVertical: 8,
|
|||
|
|
paddingHorizontal: 16,
|
|||
|
|
marginTop: 16,
|
|||
|
|
},
|
|||
|
|
identityText: {
|
|||
|
|
fontSize: 14,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: THEME_COLORS.primary,
|
|||
|
|
marginLeft: 6,
|
|||
|
|
},
|
|||
|
|
rejectReasonContainer: {
|
|||
|
|
marginTop: 16,
|
|||
|
|
padding: 12,
|
|||
|
|
backgroundColor: '#FFF3F3',
|
|||
|
|
borderRadius: 8,
|
|||
|
|
width: '100%',
|
|||
|
|
},
|
|||
|
|
rejectReasonLabel: {
|
|||
|
|
fontSize: 13,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: '#F44336',
|
|||
|
|
marginBottom: 4,
|
|||
|
|
},
|
|||
|
|
rejectReasonText: {
|
|||
|
|
fontSize: 13,
|
|||
|
|
color: '#D32F2F',
|
|||
|
|
lineHeight: 18,
|
|||
|
|
},
|
|||
|
|
benefitsSection: {
|
|||
|
|
marginBottom: 24,
|
|||
|
|
},
|
|||
|
|
sectionTitle: {
|
|||
|
|
fontSize: 17,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: colors.text?.primary || '#333',
|
|||
|
|
marginBottom: 16,
|
|||
|
|
},
|
|||
|
|
benefitsList: {
|
|||
|
|
gap: 12,
|
|||
|
|
},
|
|||
|
|
benefitItem: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'flex-start',
|
|||
|
|
backgroundColor: '#F9F9F9',
|
|||
|
|
borderRadius: 12,
|
|||
|
|
padding: 16,
|
|||
|
|
},
|
|||
|
|
benefitIconContainer: {
|
|||
|
|
width: 48,
|
|||
|
|
height: 48,
|
|||
|
|
borderRadius: 12,
|
|||
|
|
backgroundColor: '#FFF5F0',
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
marginRight: 12,
|
|||
|
|
},
|
|||
|
|
benefitContent: {
|
|||
|
|
flex: 1,
|
|||
|
|
},
|
|||
|
|
benefitTitle: {
|
|||
|
|
fontSize: 15,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: colors.text?.primary || '#333',
|
|||
|
|
marginBottom: 4,
|
|||
|
|
},
|
|||
|
|
benefitDescription: {
|
|||
|
|
fontSize: 13,
|
|||
|
|
color: colors.text?.secondary || '#666',
|
|||
|
|
lineHeight: 18,
|
|||
|
|
},
|
|||
|
|
actionSection: {
|
|||
|
|
marginBottom: 24,
|
|||
|
|
},
|
|||
|
|
primaryButton: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
height: 56,
|
|||
|
|
borderRadius: 14,
|
|||
|
|
backgroundColor: THEME_COLORS.primary,
|
|||
|
|
},
|
|||
|
|
primaryButtonText: {
|
|||
|
|
fontSize: 17,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: '#FFF',
|
|||
|
|
marginLeft: 8,
|
|||
|
|
},
|
|||
|
|
secondaryButton: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
height: 56,
|
|||
|
|
borderRadius: 14,
|
|||
|
|
backgroundColor: '#FFF5F0',
|
|||
|
|
borderWidth: 1,
|
|||
|
|
borderColor: THEME_COLORS.primary,
|
|||
|
|
},
|
|||
|
|
secondaryButtonText: {
|
|||
|
|
fontSize: 17,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: THEME_COLORS.primary,
|
|||
|
|
marginLeft: 8,
|
|||
|
|
},
|
|||
|
|
verifiedInfo: {
|
|||
|
|
backgroundColor: '#F9F9F9',
|
|||
|
|
borderRadius: 12,
|
|||
|
|
padding: 16,
|
|||
|
|
},
|
|||
|
|
verifiedInfoRow: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
justifyContent: 'space-between',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
paddingVertical: 8,
|
|||
|
|
},
|
|||
|
|
verifiedInfoLabel: {
|
|||
|
|
fontSize: 15,
|
|||
|
|
color: colors.text?.secondary || '#666',
|
|||
|
|
},
|
|||
|
|
verifiedInfoValue: {
|
|||
|
|
fontSize: 15,
|
|||
|
|
fontWeight: '500',
|
|||
|
|
color: colors.text?.primary || '#333',
|
|||
|
|
},
|
|||
|
|
helpSection: {
|
|||
|
|
alignItems: 'center',
|
|||
|
|
paddingVertical: 16,
|
|||
|
|
},
|
|||
|
|
helpTitle: {
|
|||
|
|
fontSize: 15,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: colors.text?.primary || '#333',
|
|||
|
|
marginBottom: 8,
|
|||
|
|
},
|
|||
|
|
helpText: {
|
|||
|
|
fontSize: 13,
|
|||
|
|
color: colors.text?.hint || '#999',
|
|||
|
|
textAlign: 'center',
|
|||
|
|
lineHeight: 18,
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default VerificationSettingsScreen;
|