Files
wushu/lib/views/profile/components/bug_list_page.dart
2026-04-01 18:40:21 +08:00

715 lines
24 KiB
Dart
Raw 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': '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<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(),
),
);
}