|
|
|
// problem_page.dart
|
|
|
|
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 StatelessWidget {
|
|
|
|
const ProblemPage({super.key});
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
final ProblemController problemController = Get.find<ProblemController>();
|
|
|
|
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: Stack(
|
|
|
|
children: [
|
|
|
|
Obx(() {
|
|
|
|
if (problemController.isLoading.value) {
|
|
|
|
return Center(
|
|
|
|
child: CircularProgressIndicator(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ListView.builder(
|
|
|
|
itemCount: problemController.problems.length,
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
final problem =
|
|
|
|
problemController.problems[index];
|
|
|
|
return _buildSwipeableProblemCard(
|
|
|
|
problem,
|
|
|
|
problemController,
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
Positioned(
|
|
|
|
bottom: 5.h,
|
|
|
|
right: 160.5.w,
|
|
|
|
child: FloatingActionButton(
|
|
|
|
heroTag: "123",
|
|
|
|
onPressed: () {
|
|
|
|
Get.to(() => ProblemFormPage());
|
|
|
|
},
|
|
|
|
shape: CircleBorder(),
|
|
|
|
backgroundColor: Colors.blue[300],
|
|
|
|
foregroundColor: Colors.white,
|
|
|
|
child: const Icon(Icons.add),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
Obx(() {
|
|
|
|
if (problemController.isLoading.value) {
|
|
|
|
return Center(child: CircularProgressIndicator());
|
|
|
|
}
|
|
|
|
|
|
|
|
return ListView.builder(
|
|
|
|
itemCount: problemController.problems.length,
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
final problem = problemController.problems[index];
|
|
|
|
return _buildSwipeableProblemCard(
|
|
|
|
problem,
|
|
|
|
problemController,
|
|
|
|
viewType: ProblemCardViewType.checkbox,
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
floatingActionButton: Obx(() {
|
|
|
|
final bool isOnline = problemController.isOnline.value;
|
|
|
|
return FloatingActionButton(
|
|
|
|
heroTag: "abc",
|
|
|
|
onPressed: isOnline
|
|
|
|
? () => problemController.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<bool> _showDeleteConfirmationDialog(Problem problem) async {
|
|
|
|
return await Get.bottomSheet<bool>(
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|