diff --git a/.gitignore b/.gitignore index fccfa47..3ca6f9a 100644 --- a/.gitignore +++ b/.gitignore @@ -198,3 +198,4 @@ marking_app/lib/common/model/report/report_marking_detail_params.g.dart marking_app/lib/common/model/report/report_marking_detail.g.dart marking_app/lib/common/model/job/job_report_knowledge_model.g.dart marking_app/lib/common/model/job/job_report_question_deatil_model.g.dart +marking_app/lib/common/model/job/job_do_marking_status_info.g.dart diff --git a/marking_app/lib/common/model/job/gesture_recording.dart b/marking_app/lib/common/model/job/gesture_recording.dart index f140744..a2ea382 100644 --- a/marking_app/lib/common/model/job/gesture_recording.dart +++ b/marking_app/lib/common/model/job/gesture_recording.dart @@ -12,10 +12,13 @@ class GestureRecording { bool annotationSwitch; + bool scopeBox; + GestureRecording({ required this.eraser, required this.annotationSwitch, this.data, this.usageTime, + this.scopeBox = false, }); } diff --git a/marking_app/lib/common/model/job/job_do_marking_status_info.dart b/marking_app/lib/common/model/job/job_do_marking_status_info.dart new file mode 100644 index 0000000..8d9655e --- /dev/null +++ b/marking_app/lib/common/model/job/job_do_marking_status_info.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'job_do_marking_status_info.g.dart'; + +@JsonSerializable() +class JobDoMarkingStatusInfo extends Object { + @JsonKey(name: 'pageIndex') + int pageIndex; + + @JsonKey(name: 'total') + int total; + + @JsonKey(name: 'finishCount') + int finishCount; + + @JsonKey(name: 'surplusNo') + int surplusNo; + + JobDoMarkingStatusInfo(this.pageIndex, this.total, this.finishCount, [this.surplusNo = 0]) { + this.surplusNo = total - finishCount; + } + + factory JobDoMarkingStatusInfo.fromJson(Map srcJson) => _$JobDoMarkingStatusInfoFromJson(srcJson); + + Map toJson() => _$JobDoMarkingStatusInfoToJson(this); +} diff --git a/marking_app/lib/common/model/job/job_note_taking_trajectory.dart b/marking_app/lib/common/model/job/job_note_taking_trajectory.dart index 5aec683..1f595de 100644 --- a/marking_app/lib/common/model/job/job_note_taking_trajectory.dart +++ b/marking_app/lib/common/model/job/job_note_taking_trajectory.dart @@ -11,13 +11,16 @@ class JobNoteTakingTrajectory extends Object { String paperPicture; @JsonKey(name: 'resetTime') - int resetTime; + int? resetTime; + + @JsonKey(name: 'pictureQuestionTop') + double pictureQuestionTop; + + @JsonKey(name: 'pictureQuestionHeight') + double pictureQuestionHeight; JobNoteTakingTrajectory( - this.lattices, - this.paperPicture, - this.resetTime, - ); + this.lattices, this.paperPicture, this.resetTime, this.pictureQuestionHeight, this.pictureQuestionTop); factory JobNoteTakingTrajectory.fromJson(Map srcJson) => _$JobNoteTakingTrajectoryFromJson(srcJson); diff --git a/marking_app/lib/components/marking/selectable_keyboard.dart b/marking_app/lib/components/marking/selectable_keyboard.dart index f4048d1..5bda0f4 100644 --- a/marking_app/lib/components/marking/selectable_keyboard.dart +++ b/marking_app/lib/components/marking/selectable_keyboard.dart @@ -58,13 +58,13 @@ class _SelectableKeyboardState extends ConsumerState late RemoveListener _markingSubtopicSwitchingListener; late bool _openAuxiliary; num? _tensVal; // 当前选中十位分值 - final Duration easyThrottleTime = Duration(milliseconds: 800); + late Duration easyThrottleTime; @override void initState() { super.initState(); // 初始化不执行 - + easyThrottleTime = Duration(milliseconds: widget.hasSubtopic ? 400 : 800); _scrollController = ScrollController()..addListener(scrollListener); /// 小题切换监听,重置键盘 diff --git a/marking_app/lib/components/marking/selectable_keyboard_bottom.dart b/marking_app/lib/components/marking/selectable_keyboard_bottom.dart index b513a4b..5f99dd6 100644 --- a/marking_app/lib/components/marking/selectable_keyboard_bottom.dart +++ b/marking_app/lib/components/marking/selectable_keyboard_bottom.dart @@ -55,11 +55,13 @@ class _SelectableKeyboardState extends ConsumerState late RemoveListener _markingKeyboardListener; late RemoveListener _markingSubtopicSwitchingListener; num? _tensVal; // 当前选中十位分值 - final Duration easyThrottleTime = Duration(seconds: 1); + late Duration easyThrottleTime; @override void initState() { super.initState(); + + easyThrottleTime = Duration(milliseconds: widget.hasSubtopic ? 400 : 1000); // 初始化不执行 _scrollController = ScrollController()..addListener(scrollListener); _markingSubtopicSwitchingListener = ref.read(markingSubtopicSwitchingProvider.notifier).addListener((state) { diff --git a/marking_app/lib/pages/homework_correction/components/trajectoryView.dart b/marking_app/lib/pages/homework_correction/components/trajectoryView.dart index 03f0936..534d798 100644 --- a/marking_app/lib/pages/homework_correction/components/trajectoryView.dart +++ b/marking_app/lib/pages/homework_correction/components/trajectoryView.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:async/async.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -43,10 +42,8 @@ class TrajectoryViewState extends ConsumerState { @override void initState() { - print('初始化笔记回显页面.....................'); super.initState(); oldQuestionNumber = widget.questionNumber; - print('进入页面.......21211'); theImageStreamListener = ImageStreamListener((ImageInfo info, bool _) { if (imagInfoModel != null && widget.questionNumber == oldQuestionNumber) return; @@ -146,9 +143,43 @@ class TrajectoryViewState extends ConsumerState { } else { // 容器等于图片比例 图片会拉升或者缩小图片铺满整个容器 此时图片展示宽高就等于容器宽高 } + List trajectorys = []; var trajectory = widget.trajectory; List lattices = trajectory.lattices; + trajectory.pictureQuestionTop = trajectory.pictureQuestionTop * imagInfoModel!.scale! + spacingHeight; + trajectory.pictureQuestionHeight = trajectory.pictureQuestionHeight * imagInfoModel!.scale!; + + /// 试题范围框左上角 + trajectorys + ..add(GestureRecording( + data: Offset(2.w, trajectory.pictureQuestionTop), scopeBox: true, annotationSwitch: false, eraser: false)) + + /// 右上角 + ..add(GestureRecording( + data: Offset(imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop), + scopeBox: true, + annotationSwitch: false, + eraser: false)) + + /// 左下角 + ..add(GestureRecording( + data: Offset(2.w, trajectory.pictureQuestionTop + trajectory.pictureQuestionHeight), + scopeBox: true, + annotationSwitch: false, + eraser: false)) + + /// 右下角 + ..add(GestureRecording( + data: Offset( + imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop + trajectory.pictureQuestionHeight), + scopeBox: true, + annotationSwitch: false, + eraser: false)); + + Future.delayed(Duration.zero, () { + ref.read(jobDrawingTrajectoryProvider.notifier).setVal(trajectorys); + }); if (lattices.isNotEmpty) { Map> map = new Map.fromIterable(lattices, key: (key) => key.stroke, @@ -156,7 +187,7 @@ class TrajectoryViewState extends ConsumerState { return lattices.where((item) => item.stroke == value.stroke).toList() ..sort((a, b) => a.time.compareTo(b.time)); }); - List trajectorys = []; + List keys = map.keys.toList(); for (var i = 0; i < keys.length; i++) { int theKey = keys[i]; @@ -262,7 +293,7 @@ class TrajectoryViewState extends ConsumerState { } class DrawingPainter extends CustomPainter { - final List points; + List points; DrawingPainter({required this.points}) : super(); @@ -271,9 +302,30 @@ class DrawingPainter extends CustomPainter { ..strokeCap = StrokeCap.round ..strokeWidth = 0.5.sp; + /// 范围框 + Paint scopeBox = Paint() + ..color = Colors.red + ..strokeCap = StrokeCap.round + ..strokeWidth = 1.2.sp; + @override void paint(Canvas canvas, Size size) { if (points.length > 1) { + if (points.length >= 4) { + var sketchingFrame = points.take(4).where((e) => e.scopeBox && e.data != null).toList(); + if (sketchingFrame.length == 4) { + var sketchingFramePoints = sketchingFrame.map((e) => e.data!).toList(); + + // 假设points按照顺时针或逆时针方向给出了正方形的四个顶点 + canvas.drawLine(sketchingFramePoints[0], sketchingFramePoints[2], scopeBox); + canvas.drawLine(sketchingFramePoints[0], sketchingFramePoints[1], scopeBox); + canvas.drawLine(sketchingFramePoints[2], sketchingFramePoints[3], scopeBox); + canvas.drawLine(sketchingFramePoints[1], sketchingFramePoints[3], scopeBox); + } + if (sketchingFrame.length > 0) { + points = points.where((element) => !element.scopeBox).toList(); + } + } for (int i = 0; i < points.length - 1; i++) { GestureRecording item = points[i]; GestureRecording nextItem = points[i + 1]; diff --git a/marking_app/lib/pages/homework_correction/do_papers_job.dart b/marking_app/lib/pages/homework_correction/do_papers_job.dart index 802a65c..2e985b8 100644 --- a/marking_app/lib/pages/homework_correction/do_papers_job.dart +++ b/marking_app/lib/pages/homework_correction/do_papers_job.dart @@ -11,6 +11,7 @@ import 'package:marking_app/common/mixin/common.dart'; import 'package:marking_app/common/model/common/base_structure_result.dart'; import 'package:marking_app/common/model/event_bus/jobs/job_do_papers_student_bus.dart'; import 'package:marking_app/common/model/job/job_concerned_with_student.dart'; +import 'package:marking_app/common/model/job/job_do_marking_status_info.dart'; import 'package:marking_app/common/model/job/job_page_tab.dart'; import 'package:marking_app/common/model/job/job_review_submission.dart'; import 'package:marking_app/common/model/job/marking_text_question_job.dart'; @@ -101,6 +102,43 @@ class DoPapersJob extends HookWidget with EventBusMixin { } } +/// 批阅情况(已阅55/54) +class ReviewStatusInfo extends HookWidget with CommonMixin { + final int taskId; + final int pageIndex; + const ReviewStatusInfo({required this.taskId, required this.pageIndex, super.key}); + + Future getData() async { + var _client = await getClient(); + var result = await _client.getJobPageIndexInfo(taskId, pageIndex); + return result.data; + } + + @override + Widget build(BuildContext context) { + var doMarkingInfo = useState(null); + useEffect(() { + getData().then((value) => doMarkingInfo.value = value); + return () {}; + }, []); + + if (doMarkingInfo.value == null) return Container(); + return Container( + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + quickText('已阅', color: Color.fromRGBO(117, 117, 117, 1), size: 10.sp), + quickText(doMarkingInfo.value!.finishCount, + color: Color.fromRGBO(76, 199, 147, 1), size: 12.sp, fontWeight: FontWeight.bold), + quickText('/', color: Color.fromRGBO(117, 117, 117, 1), size: 12.sp), + quickText(doMarkingInfo.value!.surplusNo, color: Color.fromRGBO(117, 117, 117, 1), size: 10.sp), + ], + ), + ); + } +} + // 切换下拉框 (学生和试卷状态) @hwidget Widget $dropdownBoxSwitchStudentsOrTypeView(BuildContext context, @@ -437,55 +475,63 @@ class _EexamPaperAndScoringViewState extends ConsumerState easyThrottle('TestQuestionSwitch', - () => switchTestQuestions(jobData: jobData, toNextQuestion: false)), - child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp), + print('容器宽度:${containerWidth};容器高度:${containerHeight}'); + return Stack( + children: [ + JobPictureOverview( + jobData: jobData, + key: scaffoldKeyPictureOverview, + containerWidth: containerWidth, + containerHeight: containerHeight, ), - ), - // 下一题 按钮 - if (canNormalNext) - Positioned( - right: 2.w, - top: (containerHeight / 2) - 20.h, - child: FloatingActionButton( - heroTag: '点击前往下一题', - tooltip: '点击前往下一题', - elevation: 6.r, - backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), - onPressed: () => - easyThrottle('TestQuestionSwitch', () => switchTestQuestions(jobData: jobData)), - child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp), - ), - ), - ], - ); - }, + if (canNormalPrevious) + Positioned( + left: 3.w, + top: (containerHeight / 2) - 20.h, + child: FloatingActionButton( + heroTag: '点击前往上一题', + tooltip: '点击前往上一题', + focusColor: Theme.of(context).primaryColor, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + elevation: 6.r, + onPressed: () => easyThrottle('TestQuestionSwitch', + () => switchTestQuestions(jobData: jobData, toNextQuestion: false)), + child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp), + ), + ), + // 下一题 按钮 + if (canNormalNext) + Positioned( + right: 2.w, + top: (containerHeight / 2) - 20.h, + child: FloatingActionButton( + heroTag: '点击前往下一题', + tooltip: '点击前往下一题', + elevation: 6.r, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + onPressed: () => + easyThrottle('TestQuestionSwitch', () => switchTestQuestions(jobData: jobData)), + child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp), + ), + ), + ], + ); + }, + ), + + /// 批阅进度详情 + ReviewStatusInfo(taskId: widget.taskId, pageIndex: jobData!.pageIndex) + ], ), ), Expanded( @@ -586,88 +632,6 @@ Widget $examPaperAndScoringKeyboardView( return Column( children: [ - Container( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.r), - child: $MaterialBtn( - bgc: Colors.white, - borderRadius: BorderRadius.circular(2.r), - onTap: () => easyThrottle('homework_review_submission_callback', () { - _useDoScoring.goToScoringShortcut(enumMode: ToScoringShortcut.ALL_PAIRS); - // toSubmit(); - }, duration: Duration(milliseconds: 500)), - child: Container( - width: double.infinity, - alignment: Alignment.center, - padding: EdgeInsets.symmetric(vertical: 8.r), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(2.r)), - child: quickText( - '全对', - size: 12.sp, - color: Color.fromRGBO(81, 81, 81, 1), - fontWeight: FontWeight.bold, - ), - ), - ), - ), - SizedBox(height: 7.h), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.r), - child: $MaterialBtn( - bgc: Colors.white, - borderRadius: BorderRadius.circular(2.r), - onTap: () => easyThrottle('homework_review_submission_callback', () { - _useDoScoring.goToScoringShortcut(enumMode: ToScoringShortcut.ALL_WRONG); - // toSubmit(); - }, duration: Duration(milliseconds: 500)), - child: Container( - width: double.infinity, - alignment: Alignment.center, - padding: EdgeInsets.symmetric(vertical: 8.r), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(2.r)), - child: quickText( - '全错', - size: 12.sp, - color: Color.fromRGBO(81, 81, 81, 1), - fontWeight: FontWeight.bold, - ), - ), - ), - ), - SizedBox(height: 7.h), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.r), - child: $MaterialBtn( - bgc: Colors.transparent, - borderRadius: BorderRadius.circular(2.r), - onTap: () => _useDoScoring.goToScoringShortcut(enumMode: ToScoringShortcut.CANCELLATION), - child: Container( - width: double.infinity, - alignment: Alignment.center, - padding: EdgeInsets.symmetric(vertical: 8.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(2.r), - border: Border.all( - width: 1.r, - color: Colors.white, - ), - ), - child: quickText( - '取消', - size: 12.sp, - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ), - SizedBox(height: 10.h), Expanded( child: ListView.builder( padding: EdgeInsets.zero, @@ -687,7 +651,6 @@ Widget $examPaperAndScoringKeyboardView( title: Column( mainAxisSize: MainAxisSize.min, children: [ - SizedBox(height: 16.h), $MaterialBtn( onTap: () => easyThrottle('view_homework_notes', () => viewHomeworkNotes(subJobQuestion)), bgc: Color.fromRGBO(88, 87, 87, 1), @@ -781,12 +744,95 @@ Widget $examPaperAndScoringKeyboardView( ], ), ), + SizedBox(height: 16.h), ], ), ); }, ), ), + Container( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.r), + child: $MaterialBtn( + bgc: Colors.white, + borderRadius: BorderRadius.circular(2.r), + onTap: () => easyThrottle('homework_review_submission_callback', () { + _useDoScoring.goToScoringShortcut(enumMode: ToScoringShortcut.ALL_PAIRS); + // toSubmit(); + }, duration: Duration(milliseconds: 500)), + child: Container( + width: double.infinity, + alignment: Alignment.center, + padding: EdgeInsets.symmetric(vertical: 8.r), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(2.r)), + child: quickText( + '全对', + size: 12.sp, + color: Color.fromRGBO(81, 81, 81, 1), + fontWeight: FontWeight.bold, + ), + ), + ), + ), + SizedBox(height: 7.h), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.r), + child: $MaterialBtn( + bgc: Colors.white, + borderRadius: BorderRadius.circular(2.r), + onTap: () => easyThrottle('homework_review_submission_callback', () { + _useDoScoring.goToScoringShortcut(enumMode: ToScoringShortcut.ALL_WRONG); + // toSubmit(); + }, duration: Duration(milliseconds: 500)), + child: Container( + width: double.infinity, + alignment: Alignment.center, + padding: EdgeInsets.symmetric(vertical: 8.r), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(2.r)), + child: quickText( + '全错', + size: 12.sp, + color: Color.fromRGBO(81, 81, 81, 1), + fontWeight: FontWeight.bold, + ), + ), + ), + ), + SizedBox(height: 7.h), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.r), + child: $MaterialBtn( + bgc: Colors.transparent, + borderRadius: BorderRadius.circular(2.r), + onTap: () => _useDoScoring.goToScoringShortcut(enumMode: ToScoringShortcut.CANCELLATION), + child: Container( + width: double.infinity, + alignment: Alignment.center, + padding: EdgeInsets.symmetric(vertical: 8.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(2.r), + border: Border.all( + width: 1.r, + color: Colors.white, + ), + ), + child: quickText( + '取消', + size: 12.sp, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + SizedBox(height: 36.h), + ], + ), + ), if (questions.isNotEmpty) Padding( padding: EdgeInsets.symmetric(horizontal: 10.r), diff --git a/marking_app/lib/utils/request/rest_client.dart b/marking_app/lib/utils/request/rest_client.dart index 438aff6..a604f15 100644 --- a/marking_app/lib/utils/request/rest_client.dart +++ b/marking_app/lib/utils/request/rest_client.dart @@ -15,6 +15,7 @@ import 'package:marking_app/common/model/common/upload_img_secret_key.dart'; import 'package:marking_app/common/model/job/job_collect_params.dart'; import 'package:marking_app/common/model/job/job_concerned_with_student.dart'; import 'package:marking_app/common/model/job/job_concerned_with_student_params.dart'; +import 'package:marking_app/common/model/job/job_do_marking_status_info.dart'; import 'package:marking_app/common/model/job/job_note_taking_trajectory.dart'; import 'package:marking_app/common/model/job/job_page_tab.dart'; import 'package:marking_app/common/model/job/job_report_join_class.dart'; @@ -260,6 +261,11 @@ abstract class RestClient { @the_retrofit.GET("/api/jobs/student-job-for-class") Future>> getJobReportJoinClasses(@the_retrofit.Query("jobId") int jobId); + // 作业 => 或者作业在当前题型下批阅情况 + @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Marking/tab") + Future> getJobPageIndexInfo( + @the_retrofit.Query("taskId") int taskld, @the_retrofit.Query("pageIndex") int pagelndex); + // 作业 => 报告 ==> 获取知识点详情 @the_retrofit.GET("/api/jobs/job-report-knowledge-detail") Future>> getDetailKnowledge(