398 lines
12 KiB
TypeScript
398 lines
12 KiB
TypeScript
|
|
/**
|
|||
|
|
* 帮助与反馈页面 HelpScreen
|
|||
|
|
* 威友 - 常见问题、官方联系方式
|
|||
|
|
* 扁平化设计风格,可折叠问答,参考关于我们、设置页面
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import React, { useMemo, useState, useCallback } from 'react';
|
|||
|
|
import {
|
|||
|
|
View,
|
|||
|
|
StyleSheet,
|
|||
|
|
TouchableOpacity,
|
|||
|
|
ScrollView,
|
|||
|
|
Linking,
|
|||
|
|
Alert,
|
|||
|
|
} from 'react-native';
|
|||
|
|
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
|
|||
|
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|||
|
|
import { StatusBar } from 'expo-status-bar';
|
|||
|
|
import { useRouter } from 'expo-router';
|
|||
|
|
import {
|
|||
|
|
useAppColors,
|
|||
|
|
spacing,
|
|||
|
|
fontSizes,
|
|||
|
|
borderRadius,
|
|||
|
|
type AppColors,
|
|||
|
|
} from '../../theme';
|
|||
|
|
import { Text, SimpleHeader } from '../../components/common';
|
|||
|
|
import { useResponsive, useResponsiveSpacing } from '../../hooks';
|
|||
|
|
|
|||
|
|
const CONTENT_MAX_WIDTH = 720;
|
|||
|
|
|
|||
|
|
// 威友橙主题色
|
|||
|
|
const THEME_COLORS = {
|
|||
|
|
primary: '#FF6B35',
|
|||
|
|
primaryLight: '#FFF1EA',
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 官方联系邮箱
|
|||
|
|
const CONTACT_EMAIL = 'system@qczlit.cn';
|
|||
|
|
|
|||
|
|
interface FAQItem {
|
|||
|
|
q: string;
|
|||
|
|
a: string;
|
|||
|
|
/** 补充提示(如注意事项),与正文区分展示 */
|
|||
|
|
note?: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface FAQSection {
|
|||
|
|
key: string;
|
|||
|
|
title: string;
|
|||
|
|
icon: string;
|
|||
|
|
items: FAQItem[];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 常见问题内容
|
|||
|
|
const FAQ_SECTIONS: FAQSection[] = [
|
|||
|
|
{
|
|||
|
|
key: 'account',
|
|||
|
|
title: '账号与认证',
|
|||
|
|
icon: 'account-check-outline',
|
|||
|
|
items: [
|
|||
|
|
{
|
|||
|
|
q: '如何通过身份认证?',
|
|||
|
|
a: '进入「我的」页面,点击右上角齿轮状设置图标,选择「身份认证」。按提示填写学号/工号、真实姓名,并上传有效佐证材料。提交后通常等待 1-2 小时即可完成审核。',
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
q: '忘记密码怎么找回?',
|
|||
|
|
a: '在登录页点击「忘记密码」,通过已绑定的手机号或校内邮箱进行重置。若均未绑定,请联系客服人工处理。',
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
q: '如何绑定手机号?',
|
|||
|
|
a: '进入「我的」页面,点击「编辑资料」,选择「手机号」,输入手机号码并完成验证即可绑定。',
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
key: 'campus',
|
|||
|
|
title: '校园工具',
|
|||
|
|
icon: 'school-outline',
|
|||
|
|
items: [
|
|||
|
|
{
|
|||
|
|
q: '如何查看课表?',
|
|||
|
|
a: '进入「应用」页面,点击「课表」,点击左上角齿轮状设置图标,选择「同步教务系统」。输入学号/工号及教务系统密码即可同步。',
|
|||
|
|
note: '该密码与统一身份认证密码不同。如遗忘,可登录新教务系统,进入「个人中心」→「修改密码」进行重置,默认密码为身份证号码后 6 位。',
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
q: '如何查找学习资料?',
|
|||
|
|
a: '进入「应用」页面,点击「学习资料」,可按学科分类浏览,也可点击右上角搜索图标快速查找所需资料。',
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
key: 'notification',
|
|||
|
|
title: '消息与通知',
|
|||
|
|
icon: 'bell-outline',
|
|||
|
|
items: [
|
|||
|
|
{
|
|||
|
|
q: '如何及时收到消息通知?',
|
|||
|
|
a: '请先在手机系统「设置」→「通知管理」或「应用管理」中,找到本 App,开启通知权限及自启动/后台运行权限;然后进入 App 内「我的」页面,点击右上角齿轮状设置图标,进入「通知管理」,确认所需消息提醒均已开启。设置完成后重启 App 即可生效。',
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
function createHelpStyles(colors: AppColors) {
|
|||
|
|
return StyleSheet.create({
|
|||
|
|
container: {
|
|||
|
|
flex: 1,
|
|||
|
|
backgroundColor: colors.background.paper,
|
|||
|
|
},
|
|||
|
|
scrollContent: {
|
|||
|
|
paddingVertical: spacing.lg,
|
|||
|
|
},
|
|||
|
|
content: {
|
|||
|
|
maxWidth: CONTENT_MAX_WIDTH,
|
|||
|
|
alignSelf: 'center',
|
|||
|
|
width: '100%',
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 分组
|
|||
|
|
section: {
|
|||
|
|
marginBottom: spacing.xl,
|
|||
|
|
},
|
|||
|
|
sectionHeader: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
paddingHorizontal: spacing['2xl'],
|
|||
|
|
marginBottom: spacing.sm,
|
|||
|
|
marginTop: spacing.sm,
|
|||
|
|
},
|
|||
|
|
sectionIcon: {
|
|||
|
|
width: 22,
|
|||
|
|
height: 22,
|
|||
|
|
borderRadius: borderRadius.sm,
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
marginRight: spacing.sm,
|
|||
|
|
},
|
|||
|
|
sectionTitle: {
|
|||
|
|
fontWeight: '600',
|
|||
|
|
fontSize: fontSizes.sm,
|
|||
|
|
color: colors.text.secondary,
|
|||
|
|
textTransform: 'uppercase',
|
|||
|
|
letterSpacing: 0.5,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 问答卡片
|
|||
|
|
faqList: {
|
|||
|
|
backgroundColor: colors.background.paper,
|
|||
|
|
borderTopWidth: StyleSheet.hairlineWidth,
|
|||
|
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
|||
|
|
borderColor: colors.divider,
|
|||
|
|
overflow: 'hidden',
|
|||
|
|
},
|
|||
|
|
faqItem: {
|
|||
|
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
|||
|
|
borderBottomColor: colors.divider,
|
|||
|
|
},
|
|||
|
|
faqItemLast: {
|
|||
|
|
borderBottomWidth: 0,
|
|||
|
|
},
|
|||
|
|
faqQuestion: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
paddingVertical: 16,
|
|||
|
|
paddingHorizontal: spacing['2xl'],
|
|||
|
|
},
|
|||
|
|
questionText: {
|
|||
|
|
flex: 1,
|
|||
|
|
fontSize: fontSizes.lg,
|
|||
|
|
fontWeight: '500',
|
|||
|
|
color: colors.text.primary,
|
|||
|
|
lineHeight: fontSizes.lg * 1.4,
|
|||
|
|
},
|
|||
|
|
faqAnswer: {
|
|||
|
|
paddingHorizontal: spacing['2xl'],
|
|||
|
|
paddingBottom: 16,
|
|||
|
|
},
|
|||
|
|
answerText: {
|
|||
|
|
fontSize: fontSizes.md,
|
|||
|
|
lineHeight: fontSizes.md * 1.7,
|
|||
|
|
color: colors.text.secondary,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 补充提示
|
|||
|
|
noteContainer: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'flex-start',
|
|||
|
|
marginTop: spacing.md,
|
|||
|
|
padding: spacing.md,
|
|||
|
|
backgroundColor: THEME_COLORS.primaryLight,
|
|||
|
|
borderRadius: borderRadius.md,
|
|||
|
|
gap: spacing.sm,
|
|||
|
|
},
|
|||
|
|
noteText: {
|
|||
|
|
flex: 1,
|
|||
|
|
fontSize: fontSizes.sm,
|
|||
|
|
lineHeight: fontSizes.sm * 1.6,
|
|||
|
|
color: colors.text.secondary,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 联系我们
|
|||
|
|
contactCard: {
|
|||
|
|
marginHorizontal: spacing['2xl'],
|
|||
|
|
marginTop: spacing.sm,
|
|||
|
|
padding: spacing.xl,
|
|||
|
|
borderRadius: borderRadius.xl,
|
|||
|
|
backgroundColor: colors.background.default,
|
|||
|
|
alignItems: 'center',
|
|||
|
|
},
|
|||
|
|
contactIconWrap: {
|
|||
|
|
width: 52,
|
|||
|
|
height: 52,
|
|||
|
|
borderRadius: borderRadius.full,
|
|||
|
|
backgroundColor: THEME_COLORS.primary,
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
marginBottom: spacing.md,
|
|||
|
|
},
|
|||
|
|
contactTitle: {
|
|||
|
|
fontSize: fontSizes.xl,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: colors.text.primary,
|
|||
|
|
marginBottom: spacing.xs,
|
|||
|
|
},
|
|||
|
|
contactDesc: {
|
|||
|
|
fontSize: fontSizes.md,
|
|||
|
|
color: colors.text.secondary,
|
|||
|
|
textAlign: 'center',
|
|||
|
|
marginBottom: spacing.lg,
|
|||
|
|
lineHeight: fontSizes.md * 1.6,
|
|||
|
|
},
|
|||
|
|
contactButton: {
|
|||
|
|
flexDirection: 'row',
|
|||
|
|
alignItems: 'center',
|
|||
|
|
justifyContent: 'center',
|
|||
|
|
paddingVertical: spacing.md,
|
|||
|
|
paddingHorizontal: spacing.xl,
|
|||
|
|
borderRadius: borderRadius.full,
|
|||
|
|
backgroundColor: THEME_COLORS.primary,
|
|||
|
|
gap: spacing.sm,
|
|||
|
|
},
|
|||
|
|
contactButtonText: {
|
|||
|
|
fontSize: fontSizes.md,
|
|||
|
|
fontWeight: '600',
|
|||
|
|
color: '#fff',
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 底部版权
|
|||
|
|
footer: {
|
|||
|
|
alignItems: 'center',
|
|||
|
|
marginTop: spacing.xl,
|
|||
|
|
paddingBottom: spacing.xl,
|
|||
|
|
},
|
|||
|
|
footerText: {
|
|||
|
|
fontSize: fontSizes.sm,
|
|||
|
|
color: colors.text.hint,
|
|||
|
|
textAlign: 'center',
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const HelpScreen: React.FC = () => {
|
|||
|
|
const colors = useAppColors();
|
|||
|
|
const styles = useMemo(() => createHelpStyles(colors), [colors]);
|
|||
|
|
const insets = useSafeAreaInsets();
|
|||
|
|
const router = useRouter();
|
|||
|
|
const { isMobile } = useResponsive();
|
|||
|
|
const responsivePadding = useResponsiveSpacing({ xs: 8, sm: 12, md: 16, lg: 24, xl: 32 });
|
|||
|
|
|
|||
|
|
// 当前展开的问题 key(同一时刻仅展开一个)
|
|||
|
|
const [expandedKey, setExpandedKey] = useState<string | null>(
|
|||
|
|
`${FAQ_SECTIONS[0].key}-0`,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
const scrollBottomInset = isMobile ? 64 + 24 + insets.bottom + spacing.md : spacing.md;
|
|||
|
|
|
|||
|
|
const toggleItem = useCallback((key: string) => {
|
|||
|
|
setExpandedKey((prev) => (prev === key ? null : key));
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
const handleContactEmail = useCallback(async () => {
|
|||
|
|
const url = `mailto:${CONTACT_EMAIL}`;
|
|||
|
|
try {
|
|||
|
|
const canOpen = await Linking.canOpenURL(url);
|
|||
|
|
if (canOpen) {
|
|||
|
|
await Linking.openURL(url);
|
|||
|
|
} else {
|
|||
|
|
Alert.alert('联系我们', `请发送邮件至:${CONTACT_EMAIL}`);
|
|||
|
|
}
|
|||
|
|
} catch {
|
|||
|
|
Alert.alert('联系我们', `请发送邮件至:${CONTACT_EMAIL}`);
|
|||
|
|
}
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
const renderFAQItem = (
|
|||
|
|
section: FAQSection,
|
|||
|
|
item: FAQItem,
|
|||
|
|
index: number,
|
|||
|
|
) => {
|
|||
|
|
const key = `${section.key}-${index}`;
|
|||
|
|
const isExpanded = expandedKey === key;
|
|||
|
|
const isLast = index === section.items.length - 1;
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<View
|
|||
|
|
key={key}
|
|||
|
|
style={[styles.faqItem, isLast && styles.faqItemLast]}
|
|||
|
|
>
|
|||
|
|
<TouchableOpacity
|
|||
|
|
style={styles.faqQuestion}
|
|||
|
|
onPress={() => toggleItem(key)}
|
|||
|
|
activeOpacity={0.7}
|
|||
|
|
>
|
|||
|
|
<Text style={styles.questionText}>{item.q}</Text>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name={isExpanded ? 'chevron-up' : 'chevron-down'}
|
|||
|
|
size={20}
|
|||
|
|
color={colors.text.hint}
|
|||
|
|
/>
|
|||
|
|
</TouchableOpacity>
|
|||
|
|
{isExpanded && (
|
|||
|
|
<View style={styles.faqAnswer}>
|
|||
|
|
<Text style={styles.answerText}>{item.a}</Text>
|
|||
|
|
{item.note && (
|
|||
|
|
<View style={styles.noteContainer}>
|
|||
|
|
<MaterialCommunityIcons
|
|||
|
|
name="alert-circle-outline"
|
|||
|
|
size={16}
|
|||
|
|
color={THEME_COLORS.primary}
|
|||
|
|
/>
|
|||
|
|
<Text style={styles.noteText}>{item.note}</Text>
|
|||
|
|
</View>
|
|||
|
|
)}
|
|||
|
|
</View>
|
|||
|
|
)}
|
|||
|
|
</View>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const renderSection = (section: FAQSection) => (
|
|||
|
|
<View key={section.key} style={styles.section}>
|
|||
|
|
<View style={styles.sectionHeader}>
|
|||
|
|
<View style={[styles.sectionIcon, { backgroundColor: THEME_COLORS.primaryLight }]}>
|
|||
|
|
<MaterialCommunityIcons name={section.icon as any} size={14} color={THEME_COLORS.primary} />
|
|||
|
|
</View>
|
|||
|
|
<Text style={styles.sectionTitle}>{section.title}</Text>
|
|||
|
|
</View>
|
|||
|
|
<View style={styles.faqList}>
|
|||
|
|
{section.items.map((item, index) => renderFAQItem(section, item, index))}
|
|||
|
|
</View>
|
|||
|
|
</View>
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<SafeAreaView style={styles.container} edges={['top', 'bottom']}>
|
|||
|
|
<StatusBar style="auto" />
|
|||
|
|
<SimpleHeader title="帮助与反馈" onBack={() => router.back()} />
|
|||
|
|
<ScrollView
|
|||
|
|
contentContainerStyle={[
|
|||
|
|
styles.scrollContent,
|
|||
|
|
{ paddingBottom: scrollBottomInset, paddingHorizontal: responsivePadding },
|
|||
|
|
]}
|
|||
|
|
showsVerticalScrollIndicator={false}
|
|||
|
|
>
|
|||
|
|
<View style={styles.content}>
|
|||
|
|
{FAQ_SECTIONS.map(renderSection)}
|
|||
|
|
|
|||
|
|
{/* 联系我们 */}
|
|||
|
|
<View style={styles.contactCard}>
|
|||
|
|
<View style={styles.contactIconWrap}>
|
|||
|
|
<MaterialCommunityIcons name="email-outline" size={26} color="#fff" />
|
|||
|
|
</View>
|
|||
|
|
<Text style={styles.contactTitle}>没有找到答案?</Text>
|
|||
|
|
<Text style={styles.contactDesc}>
|
|||
|
|
如果以上内容未能解决您的问题,欢迎通过邮件与官方团队联系,我们会尽快为您处理。
|
|||
|
|
</Text>
|
|||
|
|
<TouchableOpacity
|
|||
|
|
style={styles.contactButton}
|
|||
|
|
onPress={handleContactEmail}
|
|||
|
|
activeOpacity={0.8}
|
|||
|
|
>
|
|||
|
|
<MaterialCommunityIcons name="email-fast-outline" size={18} color="#fff" />
|
|||
|
|
<Text style={styles.contactButtonText}>{CONTACT_EMAIL}</Text>
|
|||
|
|
</TouchableOpacity>
|
|||
|
|
</View>
|
|||
|
|
|
|||
|
|
<View style={styles.footer}>
|
|||
|
|
<Text style={styles.footerText}>© 2026 青春之旅电子信息科技(威海)有限公司</Text>
|
|||
|
|
</View>
|
|||
|
|
</View>
|
|||
|
|
</ScrollView>
|
|||
|
|
</SafeAreaView>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default HelpScreen;
|