import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:problem_check_system/modules/problem/controllers/problem_controller.dart'; import 'package:problem_check_system/data/models/problem_model.dart'; import 'package:problem_check_system/modules/problem/views/widgets/date_picker_button.dart'; import 'package:problem_check_system/modules/problem/views/widgets/problem_card.dart'; import 'package:problem_check_system/modules/problem/views/problem_form_page.dart'; class ProblemPage extends GetView { const ProblemPage({super.key}); @override Widget build(BuildContext context) { return DefaultTabController( initialIndex: 0, length: 2, child: Scaffold( body: ConstrainedBox( constraints: BoxConstraints(maxHeight: 812.h), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 375.w, height: 83.5.h, alignment: Alignment.bottomLeft, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [Color(0xFF418CFC), Color(0xFF3DBFFC)], ), ), child: TabBar( indicatorSize: TabBarIndicatorSize.tab, indicator: BoxDecoration( color: const Color(0xfffff7f7), borderRadius: BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(60), ), ), tabs: const [ Tab(text: '问题列表'), Tab(text: '历史问题列表'), ], labelStyle: TextStyle( fontFamily: 'MyFont', fontWeight: FontWeight.w800, fontSize: 14.sp, ), unselectedLabelStyle: TextStyle( fontFamily: 'MyFont', fontWeight: FontWeight.w800, fontSize: 14.sp, ), labelColor: Colors.black, unselectedLabelColor: Colors.white, ), ), Expanded( child: TabBarView( children: [ Column( children: [ Container( margin: EdgeInsets.all(16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [DatePickerButton(), DatePickerButton()], ), ), Expanded( child: Obx(() { if (controller.isLoading.value) { return Center(child: CircularProgressIndicator()); } return ListView.builder( // +1 是为了在列表末尾添加一个额外的“空”项 itemCount: controller.problems.length + 1, itemBuilder: (context, index) { // 如果是最后一个“空”项,返回一个 SizedBox if (index == controller.problems.length) { return SizedBox(height: 79.5.h); } // 否则,返回正常的列表项 final problem = controller.problems[index]; return _buildSwipeableProblemCard( problem, controller, ); }, ); }), ), ], ), Obx(() { if (controller.isLoading.value) { return Center(child: CircularProgressIndicator()); } return ListView.builder( itemCount: controller.problems.length, itemBuilder: (context, index) { final problem = controller.problems[index]; return _buildSwipeableProblemCard( problem, controller, viewType: ProblemCardViewType.checkbox, ); }, ); }), ], ), ), ], ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, floatingActionButton: Stack( children: [ Align( alignment: Alignment.bottomCenter, child: FloatingActionButton( heroTag: "btn_add", onPressed: () { Get.to(() => ProblemFormPage()); }, shape: CircleBorder(), backgroundColor: Colors.blue[300], foregroundColor: Colors.white, child: const Icon(Icons.add), ), ), Positioned( bottom: 56.h, // 设置距离底部100像素 right: 27.w, // 设置距离右侧16像素(通常的浮动按钮默认位置) child: Obx(() { final bool isOnline = controller.isOnline.value; return FloatingActionButton( heroTag: "btn_upload", onPressed: isOnline ? () => controller.uploadAllUnuploaded() : null, foregroundColor: Colors.white, backgroundColor: isOnline ? Colors.red[300] : Colors.grey[400], child: Icon( isOnline ? Icons.file_upload_outlined : Icons.cloud_off_outlined, ), ); }), ), ], ), ), ); } Widget _buildSwipeableProblemCard( Problem problem, ProblemController controller, { ProblemCardViewType viewType = ProblemCardViewType.buttons, }) { return Dismissible( key: Key(problem.id ?? UniqueKey().toString()), direction: DismissDirection.endToStart, background: Container( color: Colors.red, alignment: Alignment.centerRight, padding: EdgeInsets.only(right: 20.w), child: Icon(Icons.delete, color: Colors.white, size: 30.sp), ), confirmDismiss: (direction) async { return await _showDeleteConfirmationDialog(problem); }, onDismissed: (direction) { controller.deleteProblem(problem); Get.snackbar('成功', '问题已删除'); }, child: ProblemCard(problem, viewType: viewType), ); } Future _showDeleteConfirmationDialog(Problem problem) async { return await Get.bottomSheet( Container( padding: EdgeInsets.symmetric(horizontal: 16.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), ), child: SafeArea( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ SizedBox(height: 16), Text( '确认删除', textAlign: TextAlign.center, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), SizedBox(height: 8), Text( '确定要删除这个问题吗?此操作不可撤销。', textAlign: TextAlign.center, style: TextStyle(fontSize: 14, color: Colors.grey[600]), ), SizedBox(height: 24), ElevatedButton( onPressed: () => Get.back(result: true), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, padding: EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: Text( '删除', style: TextStyle(color: Colors.white, fontSize: 16), ), ), SizedBox(height: 8), TextButton( onPressed: () => Get.back(result: false), style: TextButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16), ), child: Text( '取消', style: TextStyle(color: Colors.grey[700], fontSize: 16), ), ), SizedBox(height: 16), ], ), ), ), isDismissible: false, ) ?? false; } }