diff --git a/.gitignore b/.gitignore index 3e65d0d..62d7c41 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,5 @@ making_school_asignment_app/lib/common/api/retrofit_client.g.dart making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart +making_school_asignment_app/lib/common/api/retrofit_client.g.dart +making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart diff --git a/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_result.dart b/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_result.dart index 065b8a6..d4b757f 100644 --- a/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_result.dart +++ b/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_result.dart @@ -1,3 +1,4 @@ +import 'package:get/get.dart'; import 'package:json_annotation/json_annotation.dart'; part 'do_paper_details_result.g.dart'; @@ -5,7 +6,15 @@ part 'do_paper_details_result.g.dart'; @JsonSerializable(checked: true) class DoPaperDetailsResult extends Object { @JsonKey(name: 'templateIds') - Object templateIds; + Map templateIds; + + // 自定义字段 + @JsonKey(name: 'templateIdKeys') + List? templateIdKeys; + + // 自定义字段 + @JsonKey(name: 'templateIdKeyMap') + Map? templateIdKeyMap; @JsonKey(name: 'students') List students; @@ -16,16 +25,20 @@ class DoPaperDetailsResult extends Object { @JsonKey(name: 'studentId') int studentId; - @JsonKey(name: 'annotatedCount') + // 自定义字段 + @JsonKey(name: 'priority', defaultValue: false) + bool priority; + + @JsonKey(name: 'annotatedCount') // 当前试题批阅数量 int annotatedCount; - @JsonKey(name: 'submitCount') + @JsonKey(name: 'submitCount') // 当前试题提交数量 int submitCount; - @JsonKey(name: 'zgtAnswer') + @JsonKey(name: 'zgtAnswer') // 主观题作答图片 String zgtAnswer; - @JsonKey(name: 'zgtAnnotate') + @JsonKey(name: 'zgtAnnotate') // 主观题批注图片 String? zgtAnnotate; @JsonKey(name: 'lastAnswerTime') @@ -61,7 +74,26 @@ class DoPaperDetailsResult extends Object { this.unSubmitStudents, this.lastPage, this.nextPage, - ); + this.templateIdKeys, + this.templateIdKeyMap, + this.priority, + ) { + if (templateIds.keys.isNotEmpty) { + templateIdKeys = templateIds.keys.map((e) => int.parse(e)).toList(); + templateIdKeyMap = {}; + for (var i = 1; i <= templateIdKeys!.length; i++) { + var theVal = templateIdKeys![i - 1]; + templateIdKeyMap![i] = theVal; + templateIdKeyMap![theVal] = i; + } + } + + // 找到当前学生是否是优先批阅 + if (students.isNotEmpty) { + var currentStudent = students.firstWhereOrNull((e) => e.id == studentId); + if (currentStudent != null) priority = currentStudent.isPriority; + } + } factory DoPaperDetailsResult.fromJson(Map srcJson) => _$DoPaperDetailsResultFromJson(srcJson); diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart index da4ef23..75223dc 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart @@ -1,11 +1,16 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; import 'package:making_school_asignment_app/common/utils/utils.dart'; import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; +part 'dropdown_switch_students_type.g.dart'; + /// 学生和页码切换 class DropdownSwitchStudentsType extends StatefulWidget { const DropdownSwitchStudentsType({super.key}); @@ -16,7 +21,7 @@ class DropdownSwitchStudentsType extends StatefulWidget { class _DropdownSwitchStudentsTypeState extends State { final logic = Get.find(); - final sateData = Get.find().state; + final sateData = Get.find().state.data; @override Widget build(BuildContext context) { @@ -43,24 +48,28 @@ class _DropdownSwitchStudentsTypeState extends State color: const Color.fromRGBO(244, 244, 244, 1), borderRadius: BorderRadius.circular(4.r), ), - child: DropdownButton( - isExpanded: true, - underline: Container(), - padding: EdgeInsets.only(right: 4.w), - icon: const Icon(Icons.keyboard_arrow_down_rounded), - value: 1, // TODO 数据 - hint: const Text('请选择作业页码'), // 锚点的显示文本 - items: [1, 2, 3].map((e) { - // 数据 - return DropdownMenuItem( - value: e, - child: quickText('$e页', color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp), - ); - }).toList(), - onChanged: (value) { - // _useSwitchStudentAndType.currentTab.value = _useSwitchStudentAndType.tabs.value.firstWhere((element) => element.pageIndex == value); - }, - ), + child: Obx(() { + return DropdownButton( + isExpanded: true, + underline: Container(), + padding: EdgeInsets.only(right: 4.w), + icon: const Icon(Icons.keyboard_arrow_down_rounded), + value: sateData.value?.templateId, // TODO 数据 + hint: const Text('请选择作业页码'), // 锚点的显示文本 + items: sateData.value?.templateIdKeys?.map((e) { + return DropdownMenuItem( + value: e, + child: quickText('${sateData.value!.templateIdKeyMap![e]}页', color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp), + ); + }).toList(), + onChanged: (value) { + if (logic.state.param.value.templateId == value) return; + logic.state.param.value.templateId = value; + logic.state.param.value = DoPaperDetailsParam.fromJson(logic.state.param.value.toJson()); + // _useSwitchStudentAndType.currentTab.value = _useSwitchStudentAndType.tabs.value.firstWhere((element) => element.pageIndex == value); + }, + ); + }), ), ), const Expanded(flex: 1, child: SizedBox()), @@ -74,42 +83,37 @@ class _DropdownSwitchStudentsTypeState extends State color: const Color.fromRGBO(244, 244, 244, 1), borderRadius: BorderRadius.circular(4.r), ), - child: DropdownButton( - onTap: () { - // 打开的时候请求刷新学生 - // _useSwitchStudentAndType.getDataForStudents(taskId: taskId); - }, - padding: EdgeInsets.only(right: 4.w), - icon: const Icon(Icons.keyboard_arrow_down_rounded), - value: '汪杨', - underline: Container(), - isExpanded: true, - items: ['汪杨'].map((e) { - return DropdownMenuItem( - value: e, - child: quickText(e, color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp), - ); - }).toList(), - hint: const Text('请选择学生'), // 锚点的显示文本 - onChanged: (value) { - // JobConcernedWithStudent? currentStudent = _useSwitchStudentAndType.currentStudent.value; - // if (currentStudent?.studentId == value) return; - // _useSwitchStudentAndType.studentBusInfo.value = null; // 置空BUS通知记录 - // _useSwitchStudentAndType.currentStudent.value = - // _useSwitchStudentAndType.studentData.value.firstWhereOrNull((element) => element.studentId == value); - }, - ), + child: Obx(() { + return DropdownButton( + padding: EdgeInsets.only(right: 4.w), + icon: const Icon(Icons.keyboard_arrow_down_rounded), + value: sateData.value?.studentId, + underline: Container(), + isExpanded: true, + items: sateData.value?.students.map((e) { + return DropdownMenuItem(value: e.id, child: quickText(e.name, color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp)); + }).toList(), + hint: const Text('请选择学生'), // 锚点的显示文本 + onChanged: (value) { + if (logic.state.param.value.studentId == value) return; + logic.state.param.value.studentId = value; + logic.state.param.value = DoPaperDetailsParam.fromJson(logic.state.param.value.toJson()); + }, + ); + }), ), Positioned( left: 2.w, child: Stack( alignment: const FractionalOffset(0.52, 0.24), children: [ - Icon( - const IconData(0xe63d, fontFamily: "AlibabaIcon"), - size: 12.sp, - color: true ? const Color.fromRGBO(76, 199, 147, 1) : const Color.fromRGBO(164, 164, 164, 1), - ), + Obx(() { + return Icon( + const IconData(0xe63d, fontFamily: "AlibabaIcon"), + size: 12.sp, + color: sateData.value?.priority ?? false ? const Color.fromRGBO(76, 199, 147, 1) : const Color.fromRGBO(164, 164, 164, 1), + ); + }), quickText('优先', size: 4.sp, color: Colors.white), ], ), @@ -120,62 +124,12 @@ class _DropdownSwitchStudentsTypeState extends State const Expanded(flex: 1, child: SizedBox()), Expanded( flex: isPad() ? 4 : 5, - child: Row( + child: const Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, children: [ - // if (_useSwitchStudentAndType.isFinish.value && - // _useSwitchStudentAndType.tabs.value.firstWhereOrNull((e) => e.finishCount < e.total) != null) - Expanded( - child: Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Icon(Icons.flip_camera_android_outlined, size: 10.sp, color: Theme.of(context).primaryColor.withOpacity(0.8)), - SizedBox(width: 1.w), - InkWell( - onTap: () => easyThrottle( - 'DO_PAPERS_JOB_CONTINUE_TO_REVIEW', - () { - // var _currentTabNew = _useSwitchStudentAndType.tabs.value.firstWhere((e) => e.finishCount < e.total); - // _useSwitchStudentAndType.eventFire(model: MarkingTextQuestionJobTabParamsBus(taskId, _currentTabNew.pageIndex)); - }, - ), - child: quickText( - '继续批阅', - size: 10.sp, - decoration: TextDecoration.underline, - color: Theme.of(context).primaryColor.withOpacity(0.9), - ), - ), - SizedBox(width: 2.w), - ], - ), - ), - Expanded( - child: InkWell( - onTap: () => easyThrottle('DO_PAPERS_JOB_HISTORICAL_HOMEWORK', () { - // JobConcernedWithStudent? _studentModel = _useSwitchStudentAndType.currentStudent.value; - // if (_studentModel == null) return; - // String url = - // '${RouterManager.jobPersonalDetailPath}?studentId=${_studentModel.studentId}&studentName=${Uri.encodeComponent(_studentModel.studentName)}'; - // RouterManager.router.navigateTo(context, url, transition: getTransition()); - }), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Icon(Icons.location_history, size: 12.sp, color: const Color.fromRGBO(104, 103, 103, 1)), - SizedBox(width: 1.w), - quickText( - '历史作业', - size: 10.sp, - decoration: TextDecoration.underline, - color: Theme.of(context).primaryColor.withOpacity(0.8), - ), - ], - ), - ), - ), + $ContinueToReview(), // 继续批阅 + $HistoryHomework() // 学生历史作业 ], ), ), @@ -184,3 +138,87 @@ class _DropdownSwitchStudentsTypeState extends State ); } } + +@swidget +Widget $continueToReview(BuildContext context, {bool isFloatingAction = false}) { + final logic = Get.find(); + final sateData = Get.find().state.data; + return Obx(() { + var data = sateData.value; + var param = logic.state.param.value; + int? submitCount = data?.submitCount; // 提交数量 + int? annotatedCount = data?.annotatedCount; // 批阅数量 + + if (data == null || (submitCount == annotatedCount || (param.templateId == null && param.studentId == null))) return const SizedBox(); + callFun() => easyThrottle( + 'DO_PAPERS_JOB_CONTINUE_TO_REVIEW', + () { + var param = logic.state.param.value; + param.templateId = null; + param.studentId = null; + logic.state.param.value = DoPaperDetailsParam.fromJson(param.toJson()); + }, + ); + if (isFloatingAction) { + return FloatingActionButton( + elevation: 8, + tooltip: "继续批阅", + backgroundColor: Colors.white, + onPressed: callFun, + child: Icon(Icons.flip_camera_android_outlined, size: 20.sp, color: Theme.of(context).primaryColor), + ); + } + return Expanded( + child: InkWell( + onTap: callFun, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(Icons.flip_camera_android_outlined, size: 12.sp, color: Theme.of(context).primaryColor.withOpacity(0.8)), + SizedBox(width: 1.w), + quickText( + '继续批阅', + size: 10.sp, + decoration: TextDecoration.underline, + color: Theme.of(context).primaryColor.withOpacity(0.9), + ), + SizedBox(width: 2.w), + ], + ), + )); + }); +} + +// 学生历史作业 +@swidget +Widget $historyHomework(BuildContext context) { + final sateData = Get.find().state.data; + return Expanded( + child: InkWell( + onTap: () => easyThrottle('DO_PAPERS_JOB_HISTORICAL_HOMEWORK', () { + // TODO 学生历史作业页面跳转 + int? studentId = sateData.value?.studentId; + if (kDebugMode) print(studentId); + // JobConcernedWithStudent? _studentModel = _useSwitchStudentAndType.currentStudent.value; + // if (_studentModel == null) return; + // String url = + // '${RouterManager.jobPersonalDetailPath}?studentId=${_studentModel.studentId}&studentName=${Uri.encodeComponent(_studentModel.studentName)}'; + // RouterManager.router.navigateTo(context, url, transition: getTransition()); + }), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Icon(Icons.location_history, size: 12.sp, color: const Color.fromRGBO(104, 103, 103, 1)), + SizedBox(width: 1.w), + quickText( + '历史作业', + size: 10.sp, + decoration: TextDecoration.underline, + color: Theme.of(context).primaryColor.withOpacity(0.8), + ), + ], + ), + ), + ); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/favorite_widget.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/favorite_widget.dart index aa80e7d..2094f65 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/favorite_widget.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/favorite_widget.dart @@ -69,11 +69,13 @@ class _FavoriteState extends State with RequestToolMixin { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Icon( - const IconData(0xe63c, fontFamily: "AlibabaIcon"), - size: 18.sp, - color: favorite.value ? const Color.fromRGBO(255, 172, 48, 1) : const Color.fromRGBO(164, 164, 164, 1), - ), + Obx(() { + return Icon( + const IconData(0xe63c, fontFamily: "AlibabaIcon"), + size: 18.sp, + color: favorite.value ? const Color.fromRGBO(255, 172, 48, 1) : const Color.fromRGBO(164, 164, 164, 1), + ); + }), SizedBox(width: 6.w), ], ), diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart new file mode 100644 index 0000000..81817f7 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; + +import 'dropdown_switch_students_type.dart'; + +part 'question_paper_view.g.dart'; + +// 试题详情 +class QuestionPaperView extends StatefulWidget { + const QuestionPaperView({super.key}); + + @override + State createState() => _QuestionPaperViewState(); +} + +class _QuestionPaperViewState extends State { + final logic = Get.find(); + final sateData = Get.find().state; + + @override + Widget build(BuildContext context) { + return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { + var maxWidth = constraints.maxWidth; + var maxHeight = constraints.maxHeight; + return Stack( + children: [ + $MainBox(maxWidth, maxHeight), + Positioned( + left: 3.w, + top: (maxHeight / 2) - 20.h, + child: Obx(() { + LastPage? lastPageVal = sateData.data.value?.lastPage; + if (lastPageVal == null) return const SizedBox(); + + return FloatingActionButton( + heroTag: '点击前往上一题', + tooltip: '点击前往上一题', + focusColor: Theme.of(context).primaryColor, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + elevation: 6.r, + onPressed: () => easyThrottle('TestQuestionSwitch', () { + var param = sateData.param.value; + param.studentId = lastPageVal.studentId; + param.templateId = lastPageVal.templateId; + sateData.param.value = DoPaperDetailsParam.fromJson(param.toJson()); + }), + child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp), + ); + }), + ), + Positioned( + right: 2.w, + top: (maxHeight / 2) - 20.h, + child: Obx(() { + NextPage? nextPageVal = sateData.data.value?.nextPage; + if (nextPageVal == null) return const SizedBox(); + + return FloatingActionButton( + heroTag: '点击前往下一题', + tooltip: '点击前往下一题', + elevation: 6.r, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + onPressed: () => easyThrottle('TestQuestionSwitch', () { + var param = sateData.param.value; + param.studentId = nextPageVal.studentId; + param.templateId = nextPageVal.templateId; + sateData.param.value = DoPaperDetailsParam.fromJson(param.toJson()); + }), + child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp), + ); + }), + ), + ], + ); + }); + } +} + +@hwidget +Widget $mainBox(double maxWidth, double maxHeight) { + useEffect(() { + return () {}; + }, []); + return Stack( + alignment: const FractionalOffset(0.94, 0.94), + children: [ + Container( + width: maxWidth, + height: maxHeight, + color: Colors.yellow, + ), + // 继续批阅按钮 + const $ContinueToReview(isFloatingAction: true) + ], + ); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart index 1ebfd78..f3548e4 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart @@ -39,6 +39,7 @@ class HomeworkReviewBinding extends Bindings { } class HomeworkReviewLogic extends GetxController with RequestToolMixin { + late StreamSubscription _paramListen; final HomeworkReviewState state = HomeworkReviewState(); final HomeworkReviewAnnotationsControlState annotationState = HomeworkReviewAnnotationsControlState(); @@ -52,10 +53,18 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin { subject: Get.arguments['subject'], ).obs; state.data = Rx(null); - getList(); + getData(); + // 参数变化更新作业详情 + _paramListen = state.param.listen((e) => getData()); } - void getList() async { + @override + void disposeId(Object id) { + _paramListen.cancel(); + super.disposeId(id); + } + + void getData() async { var timerControl = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading()); try { DoPaperDetailsResult? data = await getClient().getDoPaperDetails(state.param.value); diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart index e57df4d..85138a7 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart @@ -9,6 +9,7 @@ import 'components/bottom_operation_bar.dart'; import 'components/button_floating_action.dart'; import 'components/dropdown_switch_students_type.dart'; import 'components/favorite_widget.dart'; +import 'components/question_paper_view.dart'; import 'configuration_files/index.dart'; class HomeworkReview extends StatefulWidget { @@ -40,7 +41,7 @@ class _HomeworkReviewState extends State { return Scaffold( appBar: AppBar( // titleSpacing: 0, - leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => {}), + leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => Get.back()), iconTheme: const IconThemeData(color: Colors.black), title: quickText(sateData.param.value.homeworkName), backgroundColor: Colors.white, @@ -57,8 +58,7 @@ class _HomeworkReviewState extends State { // 下拉切换 const DropdownSwitchStudentsType(), SizedBox(height: 1.h), - // Expanded(child: ExamPaperAndScoringView(taskId: taskId, className: className)), - const Expanded(child: SizedBox()), + const Expanded(child: QuestionPaperView()), const BottomAnnotationSwitch(), ], ), diff --git a/making_school_asignment_app/pubspec.lock b/making_school_asignment_app/pubspec.lock index ff1f028..3936129 100644 --- a/making_school_asignment_app/pubspec.lock +++ b/making_school_asignment_app/pubspec.lock @@ -350,6 +350,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.2.2" + flutter_hooks: + dependency: "direct main" + description: + name: flutter_hooks + sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.20.5" flutter_lints: dependency: "direct dev" description: diff --git a/making_school_asignment_app/pubspec.yaml b/making_school_asignment_app/pubspec.yaml index a07fdb9..70e7ff4 100644 --- a/making_school_asignment_app/pubspec.yaml +++ b/making_school_asignment_app/pubspec.yaml @@ -80,6 +80,7 @@ dependencies: dropdown_button2: ^2.3.9 syncfusion_flutter_datepicker: ^25.2.5 easy_debounce: ^2.0.3 # 防抖节流 + flutter_hooks: ^0.20.5 dev_dependencies: flutter_test: