/// 时间: 2026-03-30 /// 功能: 已知bug列表页面 /// 介绍: 显示应用已知bug、解决方法和解决时间的底部弹窗页面 /// 最新变化: 新增bug列表页面,支持下拉刷新和滚动查看 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../../constants/app_constants.dart'; class BugListPage extends StatefulWidget { const BugListPage({super.key}); @override State createState() => _BugListPageState(); } class _BugListPageState extends State { // 模拟bug数据 final List> _bugs = [ { 'id': 1, 'title': '输入法无法弹出', 'description': '输入框无焦点,输入法无法弹出', 'severity': 'medium', // high, medium, low 'status': 'pending', // pending, in_progress, resolved 'solution': '1.重启手机', 'reproduction': '1. 打开系统设置 - 存储 清理缓存\n2. 打开软件poes输入框页面\n*仅极少部分鸿蒙用户触发此现象', 'resolveTime': '修复中', 'reportTime': '2026-03-25', 'affectedUsers': '鸿蒙5/6用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 2, 'title': '软件页面刷新率只有60帧', 'description': '软件外120帧,打开软件后,刷新率只有60帧', 'severity': 'low', 'status': 'in_progress', 'solution': '新版已修复', 'reproduction': '1. 极少鸿蒙用户仍会出现刷新率只有60帧,无原生刷新率', 'resolveTime': '2026-04-10', 'reportTime': '03-20', 'affectedUsers': '鸿蒙5/6用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 3, 'title': '应用信息 设备类型显示 未知', 'description': '已适配安卓 win web系统', 'severity': 'low', 'status': 'resolved', 'solution': '部分web ohos系统未识别到系统类型', 'reproduction': 'harmonyos系统检测字段为\n ohos,openharmony,harmony\n 不在字段中的设备无法识别', 'resolveTime': '修复中', 'reportTime': '2026-03-15', 'affectedUsers': '少数用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 4, 'title': '软件横屏后,部分页面无法点击', 'description': '暂未适配横屏', 'severity': 'high', 'status': 'pending', 'solution': '增加重试机制和离线缓存功能', 'reproduction': '1. 开启屏幕旋转,手机横屏', 'resolveTime': '适配中', 'reportTime': '2026-03-22', 'affectedUsers': '大部分用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 5, 'title': '笔记页面时间显示1970xxx', 'description': '在其他页面点击创建添加笔记,笔记时间显示异常', 'severity': 'low', 'status': 'resolved', 'solution': '', 'reproduction': '', 'resolveTime': '已解决', 'reportTime': '2026-03-18', 'affectedUsers': '少数用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 6, 'title': '离线状态错误', 'description': '断网或网络异常,软件内未正确获取到', 'severity': 'pending', 'status': 'in_progress', 'solution': '在线状态未识别到网络打开', 'reproduction': '1. 用户关闭在线状态,软件部分页面显示', 'resolveTime': '下个版本', 'reportTime': '2026-03-18', 'affectedUsers': '少数用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 7, 'title': '主页点击“上一条” 显示无上一条', 'description': '未读取到历史记录', 'severity': 'high', 'status': 'in_progress', 'solution': '已知bug, 概率触发', 'reproduction': '1. 主页 点击 上一条', 'resolveTime': '暂无修复计划', 'reportTime': '03-18', 'affectedUsers': '全部用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 8, 'title': '软件冷启动出现长时间白屏', 'description': '未读取到历史记录', 'severity': 'low', 'status': 'in_progress', 'solution': '建议锁后台,或者后台挂起', 'reproduction': '首次按钮,系统设置页面清理数据 大版本更新', 'resolveTime': '下个版本', 'reportTime': '2026-03-18', 'affectedUsers': '少数用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 9, 'title': '软件黑屏', 'description': '多次点击同一个路由按钮5次以上', 'severity': 'low', 'status': '', 'solution': '概率触发', 'reproduction': '极短时间内瞬发点击同一个按钮3次以上 页面路由加载异常', 'resolveTime': '新版已修复', 'reportTime': '2026-03-18', 'affectedUsers': '少数用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 10, 'title': '桌面卡片 天气温度显示999', 'description': '未读取到历史记录', 'severity': 'low', 'status': '', 'solution': '用户短时间内多次刷新获取api数据,导致服务器启动防止cc自我保护机制,不会此ip下放数据', 'reproduction': '天气频繁切换,导致温度显示异常999', 'resolveTime': '下个版本', 'reportTime': '2026-03', 'affectedUsers': '少数用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, { 'id': 11, 'title': '桌面卡片 设置页面闪白屏', 'description': '软件自身优化问题', 'severity': 'low', 'status': 'pending', 'solution': '用户短时间内多次刷新获取api数据,导致服务器启动防止cc自我保护机制,不会此ip下放数据', 'reproduction': '极短时间内瞬发点击同一个按钮3次以上 页面路由加载异常', 'resolveTime': '下个版本', 'reportTime': '03-18', 'affectedUsers': '少数用户', 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, ]; final ScrollController _scrollController = ScrollController(); bool _isRefreshing = false; // 切换bug展开状态 void _toggleBugExpanded(int bugId) { setState(() { final bugIndex = _bugs.indexWhere((bug) => bug['id'] == bugId); if (bugIndex != -1) { _bugs[bugIndex]['expanded'] = !_bugs[bugIndex]['expanded']; } }); HapticFeedback.lightImpact(); } // 切换复现步骤展开状态 void _toggleReproductionExpanded(int bugId) { setState(() { final bugIndex = _bugs.indexWhere((bug) => bug['id'] == bugId); if (bugIndex != -1) { _bugs[bugIndex]['reproductionExpanded'] = !_bugs[bugIndex]['reproductionExpanded']; } }); HapticFeedback.lightImpact(); } @override void dispose() { _scrollController.dispose(); super.dispose(); } Color _getSeverityColor(String severity) { switch (severity) { case 'high': return Colors.red; case 'medium': return Colors.orange; case 'low': return Colors.green; default: return Colors.grey; } } String _getSeverityText(String severity) { switch (severity) { case 'high': // 高优先级默认红色 return '高'; case 'medium': return '中'; case 'low': return '低'; default: return '未知'; } } Color _getStatusColor(String status) { switch (status) { case 'resolved': // 已解决状态默认绿色 return Colors.green; case 'in_progress': // 解决中状态默认蓝色 return Colors.blue; case 'pending': // 待解决状态默认橙色 return Colors.orange; default: return Colors.grey; // 未知状态默认灰色 } } String _getStatusText(String status) { switch (status) { case 'resolved': return '已解决'; case 'in_progress': return '解决中'; case 'pending': return '待解决'; default: return '未知'; } } Future _refresh() async { setState(() { _isRefreshing = true; }); // 模拟网络请求延迟 await Future.delayed(const Duration(seconds: 1)); setState(() { _isRefreshing = false; }); HapticFeedback.lightImpact(); } @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), child: Column( children: [ // 顶部拖拽条和标题 _buildHeader(), // bug列表 Expanded( child: RefreshIndicator( onRefresh: _refresh, color: AppConstants.primaryColor, child: ListView.builder( controller: _scrollController, physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.all(16), itemCount: _bugs.length + 1, itemBuilder: (context, index) { if (index == _bugs.length) { return _buildFooter(); } final bug = _bugs[index]; return _buildBugItem(bug); }, ), ), ), ], ), ); } Widget _buildHeader() { return Column( children: [ // 拖拽条 Container( width: 40, height: 4, margin: const EdgeInsets.only(top: 8), decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(2), ), ), // 标题栏 Container( padding: const EdgeInsets.all(16), child: Row( children: [ Icon( Icons.bug_report, color: AppConstants.primaryColor, size: 24, ), const SizedBox(width: 12), Expanded( child: Text( '已知问题列表', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppConstants.primaryColor, ), ), ), TextButton( onPressed: () => Navigator.pop(context), child: const Text('关闭'), ), ], ), ), const Divider(height: 1), ], ); } Widget _buildFooter() { return Container( padding: const EdgeInsets.symmetric(vertical: 24), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container(width: 40, height: 1, color: Colors.grey[300]), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( '已经到底了', style: TextStyle(fontSize: 13, color: Colors.grey[500]), ), ), Container(width: 40, height: 1, color: Colors.grey[300]), ], ), const SizedBox(height: 8), Text( '共 ${_bugs.length} 个已知问题', style: TextStyle(fontSize: 12, color: Colors.grey[400]), ), ], ), ); } Widget _buildBugItem(Map bug) { final bool isExpanded = bug['expanded'] ?? false; return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[200]!), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 5, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 顶部信息行 Container( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 标题和状态标签 Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Text( bug['title'] ?? '未知问题', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: _getStatusColor( bug['status'], ).withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), border: Border.all( color: _getStatusColor(bug['status']), width: 1, ), ), child: Text( _getStatusText(bug['status']), style: TextStyle( fontSize: 12, color: _getStatusColor(bug['status']), fontWeight: FontWeight.w500, ), ), ), ], ), const SizedBox(height: 8), // 问题描述 Text( bug['description'] ?? '暂无描述', style: const TextStyle( fontSize: 14, color: Colors.black54, height: 1.4, ), ), const SizedBox(height: 12), // 严重程度和影响用户 Row( children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: _getSeverityColor( bug['severity'], ).withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.priority_high, size: 12, color: _getSeverityColor(bug['severity']), ), const SizedBox(width: 4), Text( '${_getSeverityText(bug['severity'])}优先级', style: TextStyle( fontSize: 11, color: _getSeverityColor(bug['severity']), fontWeight: FontWeight.w500, ), ), ], ), ), const SizedBox(width: 12), Icon(Icons.people, size: 14, color: Colors.grey[600]), const SizedBox(width: 4), Text( bug['affectedUsers'] ?? '未知用户', style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), ], ), const SizedBox(height: 12), // 解决方案和复现步骤按钮 Row( children: [ Expanded( child: ElevatedButton.icon( onPressed: () => _toggleBugExpanded(bug['id']), icon: Icon( isExpanded ? Icons.expand_less : Icons.expand_more, size: 18, ), label: Text( isExpanded ? '收起解决方案' : '查看解决方案', style: const TextStyle(fontSize: 14), ), style: ElevatedButton.styleFrom( backgroundColor: AppConstants.primaryColor.withValues( alpha: 0.1, ), foregroundColor: AppConstants.primaryColor, elevation: 0, padding: const EdgeInsets.symmetric(vertical: 8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( color: AppConstants.primaryColor.withValues( alpha: 0.3, ), ), ), ), ), ), const SizedBox(width: 8), Expanded( child: ElevatedButton.icon( onPressed: () => _toggleReproductionExpanded(bug['id']), icon: Icon( bug['reproductionExpanded'] ? Icons.expand_less : Icons.expand_more, size: 18, ), label: Text( bug['reproductionExpanded'] ? '收起复现' : '查看复现', style: const TextStyle(fontSize: 14), ), style: ElevatedButton.styleFrom( backgroundColor: AppConstants.secondaryColor .withValues(alpha: 0.1), foregroundColor: const Color(0xFF018786), // 更深的青色 elevation: 0, padding: const EdgeInsets.symmetric(vertical: 8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( color: const Color( 0xFF018786, ).withValues(alpha: 0.3), ), ), ), ), ), ], ), ], ), ), // 解决方案区域(可展开/收起) if (isExpanded) ...[ const Divider(height: 1), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey[50], borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(12), bottomRight: Radius.circular(12), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.lightbulb_outline, color: AppConstants.primaryColor, size: 16, ), const SizedBox(width: 8), Text( '解决方案', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: AppConstants.primaryColor, ), ), ], ), const SizedBox(height: 8), Text( bug['solution'] ?? '暂无解决方案', style: const TextStyle( fontSize: 13, color: Colors.black54, height: 1.4, ), ), const SizedBox(height: 12), // 时间信息 Row( children: [ Icon(Icons.schedule, size: 14, color: Colors.grey[600]), const SizedBox(width: 4), Text( '预计解决: ${bug['resolveTime'] ?? '待定'}', style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), const SizedBox(width: 16), Icon(Icons.report, size: 14, color: Colors.grey[600]), const SizedBox(width: 4), Text( '报告时间: ${bug['reportTime'] ?? '未知'}', style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), ], ), ], ), ), ], // 复现步骤区域(可展开/收起) if (bug['reproductionExpanded']) ...[ const Divider(height: 1), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey[50], borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(12), bottomRight: Radius.circular(12), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.replay, color: const Color(0xFF018786), // 更深的青色 size: 16, ), const SizedBox(width: 8), Text( '复现步骤', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: const Color(0xFF018786), // 更深的青色 ), ), ], ), const SizedBox(height: 8), Text( bug['reproduction'] ?? '暂无复现步骤', style: const TextStyle( fontSize: 13, color: Colors.black54, height: 1.4, ), ), ], ), ), ], ], ), ); } } // 显示bug列表的底部弹窗方法 void showBugListBottomSheet(BuildContext context) { showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isScrollControlled: true, // 允许弹窗占据全屏高度 builder: (context) => Container( height: MediaQuery.of(context).size.height * 0.85, // 设置弹窗高度为屏幕的85% child: const BugListPage(), ), ); }