处理作业添加剩余未批改数量和总数量功能;笔记回显框题;处理阅卷有小题的情况下点击过快导致防爆力点击时间过长给用户带来卡顿的体验

This commit is contained in:
1147192855@qq.com 2024-02-29 16:08:17 +08:00
parent 3eeaed4446
commit 6060e503e7
9 changed files with 281 additions and 142 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -12,10 +12,13 @@ class GestureRecording {
bool annotationSwitch;
bool scopeBox;
GestureRecording({
required this.eraser,
required this.annotationSwitch,
this.data,
this.usageTime,
this.scopeBox = false,
});
}

View File

@ -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<String, dynamic> srcJson) => _$JobDoMarkingStatusInfoFromJson(srcJson);
Map<String, dynamic> toJson() => _$JobDoMarkingStatusInfoToJson(this);
}

View File

@ -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<String, dynamic> srcJson) => _$JobNoteTakingTrajectoryFromJson(srcJson);

View File

@ -58,13 +58,13 @@ class _SelectableKeyboardState extends ConsumerState<SelectableKeyboard>
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);
///

View File

@ -55,11 +55,13 @@ class _SelectableKeyboardState extends ConsumerState<SelectableKeyboardBottom>
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) {

View File

@ -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<TrajectoryView> {
@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<TrajectoryView> {
} else {
//
}
List<GestureRecording> trajectorys = [];
var trajectory = widget.trajectory;
List<Lattices> 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<int, List<Lattices>> map = new Map.fromIterable(lattices,
key: (key) => key.stroke,
@ -156,7 +187,7 @@ class TrajectoryViewState extends ConsumerState<TrajectoryView> {
return lattices.where((item) => item.stroke == value.stroke).toList()
..sort((a, b) => a.time.compareTo(b.time));
});
List<GestureRecording> trajectorys = [];
List<int> keys = map.keys.toList();
for (var i = 0; i < keys.length; i++) {
int theKey = keys[i];
@ -262,7 +293,7 @@ class TrajectoryViewState extends ConsumerState<TrajectoryView> {
}
class DrawingPainter extends CustomPainter {
final List<GestureRecording> points;
List<GestureRecording> 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];

View File

@ -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<DoPapersJobRefreshBus> {
}
}
/// 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<JobDoMarkingStatusInfo?> getData() async {
var _client = await getClient();
var result = await _client.getJobPageIndexInfo(taskId, pageIndex);
return result.data;
}
@override
Widget build(BuildContext context) {
var doMarkingInfo = useState<JobDoMarkingStatusInfo?>(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<ExamPaperAndScoringVi
child: Row(children: [
Expanded(
flex: 7,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final double containerWidth = constraints.maxWidth; //
final double containerHeight = constraints.maxHeight; //
child: Stack(
alignment: const FractionalOffset(0.96, 0.98),
children: [
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final double containerWidth = constraints.maxWidth; //
final double containerHeight = constraints.maxHeight; //
if (jobData == null) return Container(); //
if (jobData == null) return Container(); //
print('容器宽度:${containerWidth};容器高度:${containerHeight}');
return Stack(
children: [
JobPictureOverview(
jobData: jobData,
key: scaffoldKeyPictureOverview,
containerWidth: containerWidth,
containerHeight: containerHeight,
),
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),
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),

View File

@ -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<BaseStructureResult<List<JobReportJoinClass>>> getJobReportJoinClasses(@the_retrofit.Query("jobId") int jobId);
// =>
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Marking/tab")
Future<BaseStructureResult<JobDoMarkingStatusInfo>> getJobPageIndexInfo(
@the_retrofit.Query("taskId") int taskld, @the_retrofit.Query("pageIndex") int pagelndex);
// => ==>
@the_retrofit.GET("/api/jobs/job-report-knowledge-detail")
Future<BaseStructureResult<List<JobReportKnowledgeModel>>> getDetailKnowledge(