Files
wushu/lib/views/profile/components/bug_list_page.dart
2026-03-31 03:15:04 +08:00

709 lines
25 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// 时间: 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<BugListPage> createState() => _BugListPageState();
}
class _BugListPageState extends State<BugListPage> {
// 模拟bug数据
final List<Map<String, dynamic>> _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': 'high',
'status': 'resolved',
'solution': '新版已修复',
'reproduction': '1. 极少鸿蒙用户仍会出现刷新率只有60帧无原生刷新率',
'resolveTime': '2026-04-10',
'reportTime': '2026-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': 'medium',
'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': '1. 进入设置页面\n2. 调整字体大小为最大值\n3. 浏览各个页面,观察文字是否显示完整',
'resolveTime': '2026-03-26',
'reportTime': '2026-03-18',
'affectedUsers': '少数用户',
'expanded': false, // 解决方案展开状态
'reproductionExpanded': false, // 复现步骤展开状态
},
{
'id': 6,
'title': '离线状态错误',
'description': '断网或网络异常,软件内未正确获取到',
'severity': 'low',
'status': 'resolved',
'solution': '优化字体大小适配逻辑,确保所有页面正确显示',
'reproduction': '1. 用户关闭在线状态,软件部分页面显示',
'resolveTime': '2026-03-26',
'reportTime': '2026-03-18',
'affectedUsers': '少数用户',
'expanded': false, // 解决方案展开状态
'reproductionExpanded': false, // 复现步骤展开状态
},
{
'id': 7,
'title': '主页点击“上一条” 显示无上一条',
'description': '未读取到历史记录',
'severity': 'low',
'status': 'resolved',
'solution': '优化字体大小适配逻辑,确保所有页面正确显示',
'reproduction': '1. 用户关闭在线状态,软件部分页面显示',
'resolveTime': '2026-03-26',
'reportTime': '2026-03-18',
'affectedUsers': '全部用户',
'expanded': false, // 解决方案展开状态
'reproductionExpanded': false, // 复现步骤展开状态
},
{
'id': 8,
'title': '软件冷启动出现长时间白屏',
'description': '未读取到历史记录',
'severity': 'low',
'status': 'resolved',
'solution': '闪白屏',
'reproduction': '首次按钮系统设置页面清理poes数据 大版本更新',
'resolveTime': '2026-03-26',
'reportTime': '2026-03-18',
'affectedUsers': '少数用户',
'expanded': false, // 解决方案展开状态
'reproductionExpanded': false, // 复现步骤展开状态
},
{
'id': 9,
'title': '软件黑屏',
'description': '未读取到历史记录',
'severity': 'low',
'status': 'resolved',
'solution': '优化字体大小适配逻辑,确保所有页面正确显示',
'reproduction': '极短时间内瞬发点击同一个按钮3次以上 页面路由加载异常',
'resolveTime': '2026-03-26',
'reportTime': '2026-03-18',
'affectedUsers': '少数用户',
'expanded': false, // 解决方案展开状态
'reproductionExpanded': false, // 复现步骤展开状态
},
{
'id': 10,
'title': '桌面卡片 天气温度显示999',
'description': '未读取到历史记录',
'severity': 'low',
'status': 'resolved',
'solution': '用户短时间内多次刷新获取api数据导致服务器启动防止cc自我保护机制不会此ip下放数据',
'reproduction': '极短时间内瞬发点击同一个按钮3次以上 页面路由加载异常',
'resolveTime': '2026-03-26',
'reportTime': '2026-03-18',
'affectedUsers': '少数用户',
'expanded': false, // 解决方案展开状态
'reproductionExpanded': false, // 复现步骤展开状态
},
{
'id': 11,
'title': '桌面卡片 设置页面闪白屏',
'description': '未读取到历史记录',
'severity': 'low',
'status': 'resolved',
'solution': '用户短时间内多次刷新获取api数据导致服务器启动防止cc自我保护机制不会此ip下放数据',
'reproduction': '极短时间内瞬发点击同一个按钮3次以上 页面路由加载异常',
'resolveTime': '2026-03-26',
'reportTime': '2026-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<void> _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<String, dynamic> 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(),
),
);
}