708 lines
22 KiB
Dart
708 lines
22 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import '../../../core/theme/app_colors.dart';
|
||
import '../../../shared/widgets/custom_app_bar.dart';
|
||
|
||
/// 帮助与反馈页面
|
||
class HelpFeedbackScreen extends StatefulWidget {
|
||
const HelpFeedbackScreen({super.key});
|
||
|
||
@override
|
||
State<HelpFeedbackScreen> createState() => _HelpFeedbackScreenState();
|
||
}
|
||
|
||
class _HelpFeedbackScreenState extends State<HelpFeedbackScreen>
|
||
with SingleTickerProviderStateMixin {
|
||
late TabController _tabController;
|
||
final TextEditingController _feedbackController = TextEditingController();
|
||
String _selectedFeedbackType = '功能建议';
|
||
String _contactEmail = '';
|
||
bool _isSubmitting = false;
|
||
|
||
final List<String> _feedbackTypes = [
|
||
'功能建议',
|
||
'问题反馈',
|
||
'内容错误',
|
||
'性能问题',
|
||
'其他'
|
||
];
|
||
|
||
final List<Map<String, dynamic>> _faqList = [
|
||
{
|
||
'question': '如何开始学习?',
|
||
'answer': '点击首页的"开始学习"按钮,选择适合您的学习模式。我们提供单词学习、语法练习、听力训练等多种学习方式。',
|
||
'category': '学习指导'
|
||
},
|
||
{
|
||
'question': '如何设置学习目标?',
|
||
'answer': '进入个人中心 > 设置 > 学习设置,您可以设置每日单词目标和学习时长目标。系统会根据您的目标提供个性化的学习计划。',
|
||
'category': '学习指导'
|
||
},
|
||
{
|
||
'question': '如何查看学习进度?',
|
||
'answer': '在个人中心可以查看详细的学习统计,包括学习天数、掌握单词数、学习时长等数据。',
|
||
'category': '学习指导'
|
||
},
|
||
{
|
||
'question': '忘记密码怎么办?',
|
||
'answer': '在登录页面点击"忘记密码",输入您的邮箱地址,我们会发送重置密码的链接到您的邮箱。',
|
||
'category': '账户问题'
|
||
},
|
||
{
|
||
'question': '如何修改个人信息?',
|
||
'answer': '进入个人中心 > 个人信息,您可以修改头像、用户名、邮箱等个人信息。',
|
||
'category': '账户问题'
|
||
},
|
||
{
|
||
'question': '如何开启/关闭通知?',
|
||
'answer': '进入个人中心 > 设置 > 通知设置,您可以自定义各种通知的开启状态和提醒时间。',
|
||
'category': '设置问题'
|
||
},
|
||
{
|
||
'question': '音频播放不了怎么办?',
|
||
'answer': '请检查网络连接和设备音量设置。如果问题持续存在,可以尝试重启应用或清除缓存。',
|
||
'category': '技术问题'
|
||
},
|
||
{
|
||
'question': '应用运行缓慢怎么办?',
|
||
'answer': '建议清除应用缓存,关闭其他后台应用,确保设备有足够的存储空间。如果问题持续,请联系客服。',
|
||
'category': '技术问题'
|
||
},
|
||
{
|
||
'question': '学习数据会丢失吗?',
|
||
'answer': '您的学习数据会自动同步到云端,即使更换设备也不会丢失。建议保持网络连接以确保数据及时同步。',
|
||
'category': '数据安全'
|
||
},
|
||
{
|
||
'question': '如何导出学习记录?',
|
||
'answer': '目前暂不支持导出功能,但您可以在学习统计页面查看详细的学习数据和进度图表。',
|
||
'category': '数据安全'
|
||
},
|
||
];
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_tabController = TabController(length: 2, vsync: this);
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_tabController.dispose();
|
||
_feedbackController.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: AppColors.surface,
|
||
appBar: CustomAppBar(
|
||
title: '帮助与反馈',
|
||
bottom: TabBar(
|
||
controller: _tabController,
|
||
labelColor: AppColors.primary,
|
||
unselectedLabelColor: AppColors.onSurfaceVariant,
|
||
indicatorColor: AppColors.primary,
|
||
tabs: const [
|
||
Tab(text: '常见问题'),
|
||
Tab(text: '意见反馈'),
|
||
],
|
||
),
|
||
),
|
||
body: TabBarView(
|
||
controller: _tabController,
|
||
children: [
|
||
_buildFAQTab(),
|
||
_buildFeedbackTab(),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建常见问题标签页
|
||
Widget _buildFAQTab() {
|
||
final categories = _faqList.map((faq) => faq['category'] as String).toSet().toList();
|
||
|
||
return SingleChildScrollView(
|
||
child: Column(
|
||
children: [
|
||
// 搜索框
|
||
Container(
|
||
margin: const EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(12),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.05),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: TextField(
|
||
decoration: InputDecoration(
|
||
hintText: '搜索问题...',
|
||
prefixIcon: Icon(Icons.search, color: AppColors.onSurfaceVariant),
|
||
border: InputBorder.none,
|
||
contentPadding: const EdgeInsets.symmetric(
|
||
horizontal: 16,
|
||
vertical: 12,
|
||
),
|
||
),
|
||
onChanged: (value) {
|
||
// TODO: 实现搜索功能
|
||
},
|
||
),
|
||
),
|
||
|
||
// 快速入口
|
||
Container(
|
||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'快速入口',
|
||
style: TextStyle(
|
||
fontSize: 18,
|
||
fontWeight: FontWeight.bold,
|
||
color: AppColors.onSurface,
|
||
),
|
||
),
|
||
const SizedBox(height: 12),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: _buildQuickActionCard(
|
||
icon: Icons.school,
|
||
title: '学习指南',
|
||
subtitle: '新手入门教程',
|
||
onTap: () => _showLearningGuide(),
|
||
),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: _buildQuickActionCard(
|
||
icon: Icons.contact_support,
|
||
title: '在线客服',
|
||
subtitle: '实时帮助支持',
|
||
onTap: () => _contactCustomerService(),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 24),
|
||
|
||
// 分类问题列表
|
||
...categories.map((category) => _buildFAQCategory(category)),
|
||
|
||
const SizedBox(height: 32),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建意见反馈标签页
|
||
Widget _buildFeedbackTab() {
|
||
return SingleChildScrollView(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
// 反馈类型选择
|
||
Text(
|
||
'反馈类型',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: AppColors.onSurface,
|
||
),
|
||
),
|
||
const SizedBox(height: 12),
|
||
Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(12),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.05),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: DropdownButtonFormField<String>(
|
||
value: _selectedFeedbackType,
|
||
decoration: const InputDecoration(
|
||
border: InputBorder.none,
|
||
contentPadding: EdgeInsets.symmetric(
|
||
horizontal: 16,
|
||
vertical: 12,
|
||
),
|
||
),
|
||
items: _feedbackTypes.map((type) {
|
||
return DropdownMenuItem<String>(
|
||
value: type,
|
||
child: Text(type),
|
||
);
|
||
}).toList(),
|
||
onChanged: (value) {
|
||
setState(() {
|
||
_selectedFeedbackType = value!;
|
||
});
|
||
},
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 24),
|
||
|
||
// 反馈内容
|
||
Text(
|
||
'反馈内容',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: AppColors.onSurface,
|
||
),
|
||
),
|
||
const SizedBox(height: 12),
|
||
Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(12),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.05),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: TextField(
|
||
controller: _feedbackController,
|
||
maxLines: 6,
|
||
decoration: const InputDecoration(
|
||
hintText: '请详细描述您遇到的问题或建议...',
|
||
border: InputBorder.none,
|
||
contentPadding: EdgeInsets.all(16),
|
||
),
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 24),
|
||
|
||
// 联系邮箱
|
||
Text(
|
||
'联系邮箱(可选)',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: AppColors.onSurface,
|
||
),
|
||
),
|
||
const SizedBox(height: 12),
|
||
Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(12),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.05),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: TextField(
|
||
onChanged: (value) {
|
||
_contactEmail = value;
|
||
},
|
||
decoration: const InputDecoration(
|
||
hintText: '请输入您的邮箱地址',
|
||
border: InputBorder.none,
|
||
contentPadding: EdgeInsets.symmetric(
|
||
horizontal: 16,
|
||
vertical: 12,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 32),
|
||
|
||
// 提交按钮
|
||
SizedBox(
|
||
width: double.infinity,
|
||
child: ElevatedButton(
|
||
onPressed: _isSubmitting ? null : _submitFeedback,
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: AppColors.primary,
|
||
foregroundColor: Colors.white,
|
||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
),
|
||
child: _isSubmitting
|
||
? const SizedBox(
|
||
height: 20,
|
||
width: 20,
|
||
child: CircularProgressIndicator(
|
||
strokeWidth: 2,
|
||
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||
),
|
||
)
|
||
: const Text(
|
||
'提交反馈',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 16),
|
||
|
||
// 提示信息
|
||
Container(
|
||
padding: const EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
color: AppColors.primary.withOpacity(0.1),
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Icon(
|
||
Icons.info_outline,
|
||
color: AppColors.primary,
|
||
size: 20,
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: Text(
|
||
'我们会认真对待每一条反馈,并在24小时内回复您的问题。',
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
color: AppColors.primary,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建快速操作卡片
|
||
Widget _buildQuickActionCard({
|
||
required IconData icon,
|
||
required String title,
|
||
required String subtitle,
|
||
required VoidCallback onTap,
|
||
}) {
|
||
return GestureDetector(
|
||
onTap: onTap,
|
||
child: Container(
|
||
padding: const EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(12),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.05),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: Column(
|
||
children: [
|
||
Icon(
|
||
icon,
|
||
color: AppColors.primary,
|
||
size: 32,
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
title,
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
fontWeight: FontWeight.w600,
|
||
color: AppColors.onSurface,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
subtitle,
|
||
style: TextStyle(
|
||
fontSize: 12,
|
||
color: AppColors.onSurfaceVariant,
|
||
),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建FAQ分类
|
||
Widget _buildFAQCategory(String category) {
|
||
final categoryFAQs = _faqList.where((faq) => faq['category'] == category).toList();
|
||
|
||
return Container(
|
||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(12),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.05),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Text(
|
||
category,
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold,
|
||
color: AppColors.onSurface,
|
||
),
|
||
),
|
||
),
|
||
...categoryFAQs.map((faq) => _buildFAQItem(faq)),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建FAQ项目
|
||
Widget _buildFAQItem(Map<String, dynamic> faq) {
|
||
return ExpansionTile(
|
||
title: Text(
|
||
faq['question'],
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
fontWeight: FontWeight.w500,
|
||
color: AppColors.onSurface,
|
||
),
|
||
),
|
||
children: [
|
||
Padding(
|
||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||
child: Text(
|
||
faq['answer'],
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
color: AppColors.onSurfaceVariant,
|
||
height: 1.5,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
/// 显示学习指南
|
||
void _showLearningGuide() {
|
||
showDialog(
|
||
context: context,
|
||
builder: (context) {
|
||
return AlertDialog(
|
||
title: const Text('学习指南'),
|
||
content: const SingleChildScrollView(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Text(
|
||
'1. 注册并完善个人信息',
|
||
style: TextStyle(fontWeight: FontWeight.w600),
|
||
),
|
||
SizedBox(height: 8),
|
||
Text('创建账户后,请完善您的英语水平、学习目标等信息,以便为您提供个性化的学习内容。'),
|
||
SizedBox(height: 16),
|
||
Text(
|
||
'2. 设置学习目标',
|
||
style: TextStyle(fontWeight: FontWeight.w600),
|
||
),
|
||
SizedBox(height: 8),
|
||
Text('在设置中制定每日学习目标,包括单词数量和学习时长,系统会帮助您跟踪进度。'),
|
||
SizedBox(height: 16),
|
||
Text(
|
||
'3. 选择学习模式',
|
||
style: TextStyle(fontWeight: FontWeight.w600),
|
||
),
|
||
SizedBox(height: 8),
|
||
Text('根据您的需求选择单词学习、语法练习、听力训练等不同的学习模式。'),
|
||
SizedBox(height: 16),
|
||
Text(
|
||
'4. 坚持每日学习',
|
||
style: TextStyle(fontWeight: FontWeight.w600),
|
||
),
|
||
SizedBox(height: 8),
|
||
Text('保持每日学习习惯,利用碎片时间进行学习,积少成多提升英语水平。'),
|
||
],
|
||
),
|
||
),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () => Navigator.pop(context),
|
||
child: const Text('知道了'),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 联系客服
|
||
void _contactCustomerService() {
|
||
showDialog(
|
||
context: context,
|
||
builder: (context) {
|
||
return AlertDialog(
|
||
title: const Text('联系客服'),
|
||
content: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
const Text('您可以通过以下方式联系我们:'),
|
||
const SizedBox(height: 16),
|
||
Row(
|
||
children: [
|
||
const Icon(Icons.email, size: 20),
|
||
const SizedBox(width: 8),
|
||
const Text('邮箱:'),
|
||
GestureDetector(
|
||
onTap: () {
|
||
Clipboard.setData(const ClipboardData(text: 'support@aienglish.com'));
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(content: Text('邮箱地址已复制')),
|
||
);
|
||
},
|
||
child: Text(
|
||
'support@aienglish.com',
|
||
style: TextStyle(
|
||
color: AppColors.primary,
|
||
decoration: TextDecoration.underline,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 8),
|
||
Row(
|
||
children: [
|
||
const Icon(Icons.phone, size: 20),
|
||
const SizedBox(width: 8),
|
||
const Text('电话:'),
|
||
GestureDetector(
|
||
onTap: () {
|
||
Clipboard.setData(const ClipboardData(text: '400-123-4567'));
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(content: Text('电话号码已复制')),
|
||
);
|
||
},
|
||
child: Text(
|
||
'400-123-4567',
|
||
style: TextStyle(
|
||
color: AppColors.primary,
|
||
decoration: TextDecoration.underline,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 8),
|
||
const Row(
|
||
children: [
|
||
Icon(Icons.access_time, size: 20),
|
||
SizedBox(width: 8),
|
||
Text('服务时间:9:00-18:00(工作日)'),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () => Navigator.pop(context),
|
||
child: const Text('确定'),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 提交反馈
|
||
Future<void> _submitFeedback() async {
|
||
if (_feedbackController.text.trim().isEmpty) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('请输入反馈内容'),
|
||
backgroundColor: Colors.red,
|
||
),
|
||
);
|
||
return;
|
||
}
|
||
|
||
setState(() {
|
||
_isSubmitting = true;
|
||
});
|
||
|
||
try {
|
||
// TODO: 实现提交反馈的API调用
|
||
await Future.delayed(const Duration(seconds: 2)); // 模拟网络请求
|
||
|
||
if (mounted) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('反馈提交成功,感谢您的建议!'),
|
||
backgroundColor: Colors.green,
|
||
),
|
||
);
|
||
|
||
// 清空表单
|
||
_feedbackController.clear();
|
||
_contactEmail = '';
|
||
setState(() {
|
||
_selectedFeedbackType = '功能建议';
|
||
});
|
||
}
|
||
} catch (e) {
|
||
if (mounted) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('提交失败:$e'),
|
||
backgroundColor: Colors.red,
|
||
),
|
||
);
|
||
}
|
||
} finally {
|
||
if (mounted) {
|
||
setState(() {
|
||
_isSubmitting = false;
|
||
});
|
||
}
|
||
}
|
||
}
|
||
} |