From 3a6e220f5e0526a98433c439f206586270f1c83b Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Wed, 24 Apr 2024 18:10:18 +0800 Subject: [PATCH] no message --- .../components/trajectoryView.dart | 43 ++-- .../homework_correction/do_papers_job.dart | 91 ++++---- .../quick_check_personal.dart | 11 +- .../widget/answer_handwriting.dart | 220 ++++++++++++------ .../widget/student_kg_table.dart | 69 +++--- .../widget/student_zg_table.dart | 102 ++++---- 6 files changed, 320 insertions(+), 216 deletions(-) diff --git a/marking_app/lib/pages/homework_correction/components/trajectoryView.dart b/marking_app/lib/pages/homework_correction/components/trajectoryView.dart index 534d798..0f6568a 100644 --- a/marking_app/lib/pages/homework_correction/components/trajectoryView.dart +++ b/marking_app/lib/pages/homework_correction/components/trajectoryView.dart @@ -21,12 +21,7 @@ class TrajectoryView extends StatefulHookConsumerWidget { final double boxHeight; final String questionNumber; final JobNoteTakingTrajectory trajectory; - const TrajectoryView( - {required this.trajectory, - required this.questionNumber, - required this.boxHeight, - required this.boxWidth, - super.key}); + const TrajectoryView({required this.trajectory, required this.questionNumber, required this.boxHeight, required this.boxWidth, super.key}); @override TrajectoryViewState createState() => TrajectoryViewState(); @@ -152,15 +147,11 @@ class TrajectoryViewState extends ConsumerState { /// 试题范围框左上角 trajectorys - ..add(GestureRecording( - data: Offset(2.w, trajectory.pictureQuestionTop), scopeBox: true, annotationSwitch: false, eraser: false)) + ..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)) + data: Offset(imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop), scopeBox: true, annotationSwitch: false, eraser: false)) /// 左下角 ..add(GestureRecording( @@ -171,8 +162,7 @@ class TrajectoryViewState extends ConsumerState { /// 右下角 ..add(GestureRecording( - data: Offset( - imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop + trajectory.pictureQuestionHeight), + data: Offset(imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop + trajectory.pictureQuestionHeight), scopeBox: true, annotationSwitch: false, eraser: false)); @@ -181,12 +171,19 @@ class TrajectoryViewState extends ConsumerState { ref.read(jobDrawingTrajectoryProvider.notifier).setVal(trajectorys); }); if (lattices.isNotEmpty) { - Map> map = new Map.fromIterable(lattices, - key: (key) => key.stroke, - value: (value) { - return lattices.where((item) => item.stroke == value.stroke).toList() - ..sort((a, b) => a.time.compareTo(b.time)); - }); + // Map> map = new Map.fromIterable(lattices, + // key: (key) => key.stroke, + // value: (value) { + // return lattices.where((item) => item.stroke == value.stroke).toList() + // ..sort((a, b) => a.time.compareTo(b.time)); + // }); + + var map = Map>(); + for (var i = 0; i < lattices.length; i++) { + Lattices item = lattices[i]; + if (!map.containsKey(item.stroke)) map[item.stroke] = []; + map[item.stroke]!.add(item); // 添加笔画数据 + } List keys = map.keys.toList(); for (var i = 0; i < keys.length; i++) { @@ -199,8 +196,7 @@ class TrajectoryViewState extends ConsumerState { double theX = e.x * imagInfoModel!.scale!; double theY = e.y * imagInfoModel!.scale! + spacingHeight; - return GestureRecording( - eraser: false, data: Offset(theX, theY), usageTime: e.time.toInt(), annotationSwitch: false); + return GestureRecording(eraser: false, data: Offset(theX, theY), usageTime: e.time.toInt(), annotationSwitch: false); }).toList() ..add(GestureRecording(eraser: false, annotationSwitch: false)); // 原始轨迹展示 @@ -230,8 +226,7 @@ class TrajectoryViewState extends ConsumerState { if (duration2 == null && nextStrokesData != null) { // 此时最后一个笔画完成了 停止时间是在下一个笔画开始时间之差 Lattices minLattices = nextStrokesData.reduce((e1, e2) => e1.time < e2.time ? e1 : e2); - differenceInMilliseconds = - (Duration(milliseconds: minLattices.time.toInt()) - duration1).inMilliseconds; + differenceInMilliseconds = (Duration(milliseconds: minLattices.time.toInt()) - duration1).inMilliseconds; await Future.delayed(Duration(milliseconds: differenceInMilliseconds)); // 一个笔画完成进行下一个笔画的等待时间 } }; 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 5710bcf..46b95c3 100644 --- a/marking_app/lib/pages/homework_correction/do_papers_job.dart +++ b/marking_app/lib/pages/homework_correction/do_papers_job.dart @@ -366,37 +366,55 @@ Widget $dropdownBoxSwitchStudentsOrTypeView(BuildContext context, {required Func Expanded(flex: 1, child: SizedBox()), Expanded( flex: 4, - child: Container( - padding: EdgeInsets.only(left: 10.w), - decoration: BoxDecoration( - color: 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: Icon(Icons.keyboard_arrow_down_rounded), - value: _useSwitchStudentAndType.currentStudent.value?.studentId, - underline: Container(), - isExpanded: true, - items: _useSwitchStudentAndType.studentData.value.map((e) { - return DropdownMenuItem( - child: quickText(e.studentName, color: Color.fromRGBO(79, 79, 79, 1), size: 14.sp), - value: e.studentId, - ); - }).toList(), - hint: 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: Stack( + children: [ + Container( + padding: EdgeInsets.only(left: 10.w), + decoration: BoxDecoration( + color: 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: Icon(Icons.keyboard_arrow_down_rounded), + value: _useSwitchStudentAndType.currentStudent.value?.studentId, + underline: Container(), + isExpanded: true, + items: _useSwitchStudentAndType.studentData.value.map((e) { + return DropdownMenuItem( + child: quickText(e.studentName, color: Color.fromRGBO(79, 79, 79, 1), size: 14.sp), + value: e.studentId, + ); + }).toList(), + hint: 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); + }, + ), + ), + Positioned( + left: 2.w, + child: Stack( + alignment: const FractionalOffset(0.52, 0.24), + children: [ + Icon( + const IconData(0xe63d, fontFamily: "AlibabaIcon"), + size: 12.sp, + color: _useSwitchStudentAndType.isFirst.value ? Color.fromRGBO(76, 199, 147, 1) : Color.fromRGBO(164, 164, 164, 1), + ), + quickText('优先', size: 4.sp, color: Colors.white), + ], + ), + ), + ], ), ), Expanded(flex: 1, child: SizedBox()), @@ -458,17 +476,6 @@ Widget $dropdownBoxSwitchStudentsOrTypeView(BuildContext context, {required Func ), ), ), - Stack( - alignment: const FractionalOffset(0.52, 0.24), - children: [ - Icon( - const IconData(0xe63d, fontFamily: "AlibabaIcon"), - size: 12.sp, - color: _useSwitchStudentAndType.isFirst.value ? Color.fromRGBO(76, 199, 147, 1) : Color.fromRGBO(164, 164, 164, 1), - ), - quickText('优先', size: 4.sp, color: Colors.white), - ], - ), ], ), ), diff --git a/marking_app/lib/pages/homework_correction/quick_check_personal.dart b/marking_app/lib/pages/homework_correction/quick_check_personal.dart index 6021687..426618c 100644 --- a/marking_app/lib/pages/homework_correction/quick_check_personal.dart +++ b/marking_app/lib/pages/homework_correction/quick_check_personal.dart @@ -9,7 +9,6 @@ import 'package:marking_app/components/ReturnToHomepage.dart'; import 'package:marking_app/pages/homework_correction/widget/student_kg_table.dart'; import 'package:marking_app/pages/homework_correction/widget/student_zg_table.dart'; import 'package:marking_app/routes/RouterManager.dart'; -import 'package:marking_app/utils/common_utils.dart'; import 'package:marking_app/utils/request/rest_client.dart'; import 'package:marking_app/utils/toast_utils.dart'; @@ -179,6 +178,11 @@ class _QuickCheckPersonalState extends ConsumerState with Co child: StudentKgTable( headList: ['题号', '学生答案', '标准答案'], bodyList: studentInfo!.kgDetails, + questionNumCall: (no) { + showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId, questionNo: int.parse(no)).then((value) { + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + }); + }, ), ) ], @@ -222,6 +226,11 @@ class _QuickCheckPersonalState extends ConsumerState with Co child: StudentZgTable( headList: ['题号', '用时', '学生答案', '批注结果', '批注'], bodyList: studentInfo!.zgDetails, + questionNumCall: (no) { + showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId, questionNo: int.parse(no)).then((value) { + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + }); + }, ), ) ], diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index bb5591a..b31d7dc 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:json_annotation/json_annotation.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -48,13 +49,14 @@ class AnswerHandwriting extends Dialog { } } -Future showAnswerHandwriting(BuildContext context, {required int jobId, required int studentId, int? pageNum}) async { +Future showAnswerHandwriting(BuildContext context, {required int jobId, required int studentId, int? pageNum, int? questionNo}) async { return showDialog( context: context, builder: (BuildContext context) => AnswerHandwriting( jobId: jobId, studentId: studentId, pageNum: pageNum, + questionNo: questionNo, closeCall: () => Navigator.of(context).pop(), ), ); @@ -94,7 +96,10 @@ class AnswerHandwritingMainBox extends HookWidget { }); useValueChanged(_useStateModel.pageNum.value, (oldVal, __) { - if (oldVal != null && oldVal != _useStateModel.pageNum.value) _useStateModel.getData().catchError((e) => closeCall()); + if (oldVal != null && oldVal != _useStateModel.pageNum.value) { + _useStateModel.questionNo = null; + _useStateModel.getData().catchError((e) => closeCall()); + } }); useEffect(() { @@ -106,7 +111,6 @@ class AnswerHandwritingMainBox extends HookWidget { HandwritingInfo? _dataDetail = _useStateModel.handwritingDetail.value; if (_data == null || _dataDetail == null) return Container(); - print('数据长度:${_data.lattices.length}'); return Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, @@ -134,7 +138,7 @@ class AnswerHandwritingMainBox extends HookWidget { ), ], ), - $BottomPlaybar(_dataDetail.timeConsuming, _dataDetail.pauseCount), + $BottomPlaybar(_dataDetail.timeConsuming, _dataDetail.pauseCount, _dataDetail.pauseInterval), ], ); } @@ -143,7 +147,7 @@ class AnswerHandwritingMainBox extends HookWidget { class UseMainBoxState with CommonMixin { final int jobId; final int studentId; - final int? questionNo; + int? questionNo; final ValueNotifier pageNum; final ValueNotifier pageCount; final ValueNotifier handwritingData; @@ -223,7 +227,6 @@ class UseMainBoxState with CommonMixin { lattices[item.stroke]!.add(item); // 添加笔画数据 } - print('分组时间:${DateTime.now().millisecondsSinceEpoch}'); List latticeKeys = lattices.keys.toList(); int timeConsuming = 0; if (latticeKeys.isNotEmpty) { @@ -242,8 +245,8 @@ class UseMainBoxState with CommonMixin { } timeConsuming = lastTime - firstTime; } - print('获取数据总时间:${DateTime.now().millisecondsSinceEpoch}'); var pauseCount = 0; // 停顿次数 + List pauseInterval = []; for (var i = 0; i < latticeKeys.length; i++) { var currentLattices = lattices[latticeKeys[i]]!; // 当前循环笔画集合 var prevLattices = i == 0 ? null : lattices[latticeKeys[i - 1]]!; // 下一个笔画集合 @@ -254,35 +257,38 @@ class UseMainBoxState with CommonMixin { if (j != 0) { var prevItem = currentLattices[j - 1]; var adjacentSpacingTime = lattice.time - prevItem.time; + intervalTime = adjacentSpacingTime + prevItem.intervalTime; if (adjacentSpacingTime > 5000) { // 大于5秒算一次停顿 pauseCount++; + pauseInterval.add(PauseIntervalTime(startTime: prevItem.intervalTime, endTime: intervalTime)); } - intervalTime = adjacentSpacingTime + prevItem.intervalTime; } else { if (i != 0 && prevLattices != null) { var prevLatticeLastItem = prevLattices[prevLattices.length - 1]; var adjacentSpacingTime = lattice.time - prevLatticeLastItem.time; + intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime; if (adjacentSpacingTime > 5000) { // 大于5秒算一次停顿 pauseCount++; + pauseInterval.add(PauseIntervalTime(startTime: prevLatticeLastItem.intervalTime, endTime: intervalTime)); } - intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime; } } lattice.intervalTime = intervalTime; } } - return HandwritingInfo(pauseCount, timeConsuming, lattices); + return HandwritingInfo(pauseCount, timeConsuming, lattices, pauseInterval); } } class HandwritingInfo { int pauseCount; // 停顿次数 + List pauseInterval; int timeConsuming; // 耗时(毫秒) Map> strokeMap; // 笔画数据 - HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap); + HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap, this.pauseInterval); } // 图片展示 @@ -374,6 +380,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev List timers = []; int handwritingTime = 0; int handwritingDuration = 0; + double speed = 1; // 播放速度 @override void initState() { super.initState(); @@ -404,6 +411,13 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev toGoPause(); } break; + case PlaybackSpeedBus: + // 播放速度 + var _model = (e as PlaybackSpeedBus); + speed = _model.speed; + toGoPause(); // 先暂停再重新播放 + toGoPlay(); // 重新播放 + break; default: } }); @@ -456,6 +470,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev /// 拖动进度条后重新初始化数据 /// @param startTime 起始时间 单位秒 Future dragProgressBarInitData(int startTime, int totalDuration) async { + eventFire(model: JobHandwritingPlaybarBus(false)); timers.forEach((e) { if (e.isActive) e.cancel(); }); @@ -474,16 +489,17 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev for (var i = 0; i < _packagedHandwritingDataAll.length; i++) { var item = _packagedHandwritingDataAll[i]; - if (item.intervalTime <= startTime) { + if (item.intervalTime < startTime) { // 需要直接装配到直接打印的容器 executeImmediately.add(item); } else { + var intervalTime = item.intervalTime - startTime; // 需要等待的数据 waitingExecution.add(GestureHandwritingRecording( stroke: item.stroke, data: item.data, usageTime: item.usageTime, - intervalTime: item.intervalTime - startTime, + intervalTime: intervalTime < 0 ? 0 : intervalTime, )); } } @@ -518,7 +534,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev if (e.intervalTime == 0) { zhixinCall(e); } else { - var ter = Timer(Duration(milliseconds: e.intervalTime), () => zhixinCall(e)); + var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e)); timers.add(ter); } }); @@ -641,7 +657,7 @@ Widget $pageNumberBox(int pageNum) { } @hwidget -Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { +Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, List pauseIntervals) { var usePlaybar = UseBottomPlaybar.use(timeConsuming); useValueChanged(timeConsuming, (_, __) { @@ -656,6 +672,9 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { // 播放速度 useValueChanged(usePlaybar.constantFastSpeed.value, (_, __) { usePlaybar.eventFire(model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed)); + // 播放速度变化 + usePlaybar.playTimingSuspend(); + usePlaybar.playTimingStarts(); }); // 计时结束监听 useValueChanged(usePlaybar.useTime.value, (_, __) { @@ -668,7 +687,6 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { useEffect(() { usePlaybar.eventOn(callback: (e) { - // TODO 数据 switch (e.runtimeType) { case JobHandwritingPlaybarBus: // 出发播放暂停 @@ -676,23 +694,17 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { if (_val.play) { // 开始播放 usePlaybar.playTimingStarts(); - if (!usePlaybar.playPause.value) { - usePlaybar.playPause.value = true; - } + if (!usePlaybar.playPause.value) usePlaybar.playPause.value = true; } else { // 暂停播放 usePlaybar.playTimingSuspend(); - if (usePlaybar.playPause.value) { - usePlaybar.playPause.value = false; - } + if (usePlaybar.playPause.value) usePlaybar.playPause.value = false; } break; case JobHandwritingGetReadyBus: // 作业笔迹已经计算好坐标 可以开始播放 Future.delayed(Duration.zero, () => (usePlaybar.handWritingReady.value = true)); break; - case PlaybackSpeedBus: - break; default: } }); @@ -711,7 +723,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { height: 60.h, padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), alignment: Alignment.center, - color: Color.fromRGBO(0, 0, 0, 0.5), + color: Color.fromRGBO(0, 0, 0, 0.4), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -731,55 +743,92 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), SizedBox(width: 6.w), Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - height: 20.h, - // color: Theme.of(context).primaryColor, - child: Slider( - /// 进度条的值 - value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), + child: LayoutBuilder( + builder: (context, constraints) { + final double containerWidth = constraints.maxWidth; // 展示区域总宽度 + // print('总刻度:$timeConsuming,宽度:$containerWidth'); + // print('总时长:${pauseIntervals.map((e) => e.toJson()).toList()}'); + var unitScale = containerWidth / timeConsuming; // 单位刻度 + var pauseIntervalsLength = pauseIntervals.length; + List pauseTickMarks = pauseIntervals.asMap().keys.map((e) { + bool isLast = e == pauseIntervalsLength - 1; + bool isFirst = e == 0; + var item = pauseIntervals[e]; + return Positioned( + top: 0, + left: unitScale * item.startTime, + child: Container( + width: unitScale * (item.apart ?? 0), + height: 8.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: isFirst + ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) + : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), + ), + ), + ); + }).toList(); - /// 进度条的最小值(默认为 0) - min: 0.0, - - /// 进度条的最大值(默认为 1) - max: usePlaybar.handwritingDuration.value.toDouble(), - // divisions:1, - - /// 滑块以及滑块左侧的颜色 - // activeColor: Colors.red, - - /// 滑块右侧的颜色 - inactiveColor: Color.fromRGBO(217, 217, 217, 1), - - /// 进度值发生变化时触发的事件(注:把 onChanged 设置为 null 则说明 Slider 为不可用状态) - onChangeEnd: (value) { - usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 - usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - onChanged: (double value) { - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - ), - - // /// 手指按下滑块时触发的事件 - // onChangeStart: (value) => log('onChangeStart: $value'), - - // /// 手指从滑块抬起时触发的事件 - // onChangeEnd: (value) => log('onChangeEnd: $value'), - ), - SizedBox(height: 4.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return Column( + mainAxisSize: MainAxisSize.min, children: [ - quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), - quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), + Stack( + children: [ + Container( + height: 8.h, + width: containerWidth, + decoration: BoxDecoration( + // color: Color.fromRGBO(146, 146, 146, 1), + color: Color.fromRGBO(202, 201, 201, 1), + borderRadius: BorderRadius.circular(50.r), + ), + ), + ...pauseTickMarks, + Container( + height: 8.h, + // color: Theme.of(context).primaryColor, + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 8.h, // 轨道高度 + trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 + activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色 + inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 + thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0), + thumbColor: Colors.white, // 滑块颜色 + overlayShape: RoundSliderOverlayShape(overlayRadius: 0), + overlayColor: Colors.black54, // 滑块外圈颜色 + // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 + ), + child: Slider( + value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), + min: 0.0, + max: usePlaybar.handwritingDuration.value.toDouble(), + inactiveColor: Colors.transparent, + onChangeEnd: (value) { + usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 + usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + onChanged: (double value) { + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + ), + ), + ), + ], + ), + SizedBox(height: 4.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), + quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), + ], + ) ], - ) - ], + ); + }, ), ), SizedBox(width: 16.w), @@ -798,7 +847,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { child: quickText( '${usePlaybar.constantFastSpeed.value.name}', color: Color.fromRGBO(79, 114, 244, 1), - size: 10.sp, + size: 8.sp, align: TextAlign.center, ), ), @@ -808,6 +857,11 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { ); } +@swidget +Widget $pauseTickMark() { + return Container(); +} + class UseBottomPlaybar with EventBusMixin { final ValueNotifier handwritingDuration; // 笔迹总时长 final ValueNotifier playPause; // 播放暂停 @@ -844,7 +898,8 @@ class UseBottomPlaybar with EventBusMixin { void playTimingStarts() { if (useTime.value > 0) { timer.value?.cancel(); - timer.value = Timer.periodic(Duration(seconds: 1), (theTime) { + + timer.value = Timer.periodic(Duration(milliseconds: 1000 ~/ constantFastSpeed.value.speed), (theTime) { useTime.value -= 1; if (useTime.value < 0) { timer.value?.cancel(); @@ -898,9 +953,26 @@ enum PlaybackSpeed { ORIGINAL_SPEED(name: '原速播放', speed: 1), ONE_POINT_FIVE_SPEED(name: '1.5x播放', speed: 1.5), DOUBLE_SPEED(name: '2.0x播放', speed: 2), - TRIPLE_SPEED(name: '3.0x播放', speed: 3); + TRIPLE_SPEED(name: '3.0x播放', speed: 3), + FOUR_SPEED(name: '4.0x播放', speed: 4), + FIVE_SPEED(name: '5.0x播放', speed: 5), + SIX_SPEED(name: '6.0x播放', speed: 6); const PlaybackSpeed({required this.name, required this.speed}); final double speed; final String name; } + +@JsonSerializable() +class PauseIntervalTime extends Object { + int? apart; + int startTime; + int endTime; + PauseIntervalTime({required this.startTime, required this.endTime}) { + apart = endTime - startTime; + } + + factory PauseIntervalTime.fromJson(Map srcJson) => _$PauseIntervalTimeFromJson(srcJson); + + Map toJson() => _$PauseIntervalTimeToJson(this); +} diff --git a/marking_app/lib/pages/homework_correction/widget/student_kg_table.dart b/marking_app/lib/pages/homework_correction/widget/student_kg_table.dart index 7b622af..126455f 100644 --- a/marking_app/lib/pages/homework_correction/widget/student_kg_table.dart +++ b/marking_app/lib/pages/homework_correction/widget/student_kg_table.dart @@ -8,6 +8,7 @@ class StudentKgTable extends StatefulWidget { final List bodyList; final int? fixedRows; final int? fixedCols; + final Function(String)? questionNumCall; const StudentKgTable({ Key? key, @@ -15,6 +16,7 @@ class StudentKgTable extends StatefulWidget { required this.bodyList, this.fixedCols = 0, this.fixedRows = 0, + this.questionNumCall, }) : super(key: key); @override @@ -29,34 +31,51 @@ class _StudentKgTableState extends State { String sortString(String str) { return String.fromCharCodes(str.codeUnits.toList()..sort()); } + DataRow _getRow(int index, [Color? color]) { assert(index >= 0); KgDetails item = widget.bodyList[index]; return DataRow2.byIndex( index: index, - color: color != null ? MaterialStateProperty.all(color): null, + color: color != null ? MaterialStateProperty.all(color) : null, cells: [ - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionNo, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), + DataCell( + InkWell( + onTap: () { + if (widget.questionNumCall != null) { + widget.questionNumCall!(item.questionNo); + } + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text(item.questionNo, style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), + ), + ), ), - )), + ), DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.studentAnswer == null?'未作答':item.studentAnswer!, - style: TextStyle(fontSize: 12.sp, color: item.studentAnswer == null?Color(0xFF525252): - item.state == 2?Color(0xFF4CC793): - item.state == 1?Color(0xFFFF7474):item.state == 0?Color(0xFFD3D3D3):Colors.white), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text( + item.studentAnswer == null ? '未作答' : item.studentAnswer!, + style: TextStyle( + fontSize: 12.sp, + color: item.studentAnswer == null + ? Color(0xFF525252) + : item.state == 2 + ? Color(0xFF4CC793) + : item.state == 1 + ? Color(0xFFFF7474) + : item.state == 0 + ? Color(0xFFD3D3D3) + : Colors.white), ), ))), DataCell(Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionAnswer == null ?'无':item.questionAnswer!, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), + child: Text(item.questionAnswer == null ? '无' : item.questionAnswer!, style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), ), )), ], @@ -74,14 +93,10 @@ class _StudentKgTableState extends State { dataRowHeight: 40.r, headingRowHeight: 40.r, border: TableBorder( - horizontalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - bottom: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - verticalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid)), - headingRowColor: MaterialStateProperty.resolveWith((states) => - widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + horizontalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => widget.fixedCols! > 0 ? Colors.white : Colors.transparent), headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), fixedColumnsColor: Color(0xFFE6E6E6), fixedCornerColor: Colors.grey[400], @@ -95,14 +110,12 @@ class _StudentKgTableState extends State { var item = widget.headList[index]; return DataColumn2( label: Center( - child: Text(item, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), + child: Text(item, style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), ), // size: ColumnSize.S, - fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r)/3, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / 3, ); }), - rows: List.generate(widget.bodyList.length, - (index) => _getRow(index, Color(0xFFF5F5F5)))); + rows: List.generate(widget.bodyList.length, (index) => _getRow(index, Color(0xFFF5F5F5)))); } } diff --git a/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart b/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart index 58c283c..232284d 100644 --- a/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart +++ b/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:marking_app/common/model/job/job_data_report.dart'; import 'package:marking_app/pages/homework_correction/components/imgDialog.dart'; +import 'package:marking_app/pages/homework_correction/widget/answer_handwriting.dart'; import 'package:marking_app/utils/common_utils.dart'; import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; import 'package:photo_view/photo_view.dart'; @@ -12,6 +13,7 @@ class StudentZgTable extends StatefulWidget { final List bodyList; final int? fixedRows; final int? fixedCols; + final Function(String)? questionNumCall; const StudentZgTable({ Key? key, @@ -19,6 +21,7 @@ class StudentZgTable extends StatefulWidget { required this.bodyList, this.fixedCols = 0, this.fixedRows = 0, + this.questionNumCall, }) : super(key: key); @override @@ -29,7 +32,7 @@ class _StudentZgTableState extends State { final ScrollController _controller = ScrollController(); int? _sortColumnIndex; bool _sortAscending = true; - + /*void showImgDialog(BuildContext context,String imgUrl){ Navigator.push( context, @@ -37,8 +40,8 @@ class _StudentZgTableState extends State { return Scaffold( appBar: AppBar(), body: SizedBox( - *//* width: MediaQuery.of(context).size.width * 0.6, - height: MediaQuery.of(context).size.height * 0.6,*//* + */ /* width: MediaQuery.of(context).size.width * 0.6, + height: MediaQuery.of(context).size.height * 0.6,*/ /* child: PhotoView( imageProvider: NetworkImage(imgUrl)), @@ -70,57 +73,68 @@ class _StudentZgTableState extends State { KgDetails item = widget.bodyList[index]; return DataRow2.byIndex( index: index, - color: color != null ? MaterialStateProperty.all(color): null, + color: color != null ? MaterialStateProperty.all(color) : null, cells: [ - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionNo, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), - ), - )), - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(CommonUtils.second2HMS(item.useTime!), - style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), - ), - )), DataCell(InkWell( - onTap: (){ - if(item.state != 0){ - ImageDialog.showImgDialog(context,item.studentAnswer!); - } - + onTap: () { + if (widget.questionNumCall != null) { + widget.questionNumCall!(item.questionNo); + } }, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.state!=0 ?'查看':'--', - style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), + child: Text(item.questionNo, style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), ), ), )), DataCell(Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: item.state == 2? - Image.asset('assets/images/job_personal_correct_icon.png',width: 18.r,height: 18.r,):item.state == 1? - Image.asset('assets/images/job_personal_error_icon.png',width: 10.r,height: 10.r,):Text('', style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), + child: Text(CommonUtils.second2HMS(item.useTime!), style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), ), )), DataCell(InkWell( - onTap: (){ - if(item.state==1 || item.state==2){ - ImageDialog.showImgDialog(context,item.annotateAnswers!); + onTap: () { + if (item.state != 0) { + ImageDialog.showImgDialog(context, item.studentAnswer!); } - }, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.state==1 || item.state==2?'查看':'--', - style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), + child: Text(item.state != 0 ? '查看' : '--', style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), + ), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: item.state == 2 + ? Image.asset( + 'assets/images/job_personal_correct_icon.png', + width: 18.r, + height: 18.r, + ) + : item.state == 1 + ? Image.asset( + 'assets/images/job_personal_error_icon.png', + width: 10.r, + height: 10.r, + ) + : Text('', style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), + ), + )), + DataCell(InkWell( + onTap: () { + if (item.state == 1 || item.state == 2) { + ImageDialog.showImgDialog(context, item.annotateAnswers!); + } + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text(item.state == 1 || item.state == 2 ? '查看' : '--', style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), ), ), )), @@ -139,14 +153,10 @@ class _StudentZgTableState extends State { headingRowHeight: 40.r, dataRowHeight: 40.r, border: TableBorder( - horizontalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - bottom: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - verticalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid)), - headingRowColor: MaterialStateProperty.resolveWith((states) => - widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + horizontalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => widget.fixedCols! > 0 ? Colors.white : Colors.transparent), headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), fixedColumnsColor: Color(0xFFE6E6E6), fixedCornerColor: Colors.grey[400], @@ -160,14 +170,12 @@ class _StudentZgTableState extends State { var item = widget.headList[index]; return DataColumn2( label: Center( - child: Text(item, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), + child: Text(item, style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), ), // size: ColumnSize.S, - fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r)/5, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / 5, ); }), - rows: List.generate(widget.bodyList.length, - (index) => _getRow(index, Color(0xFFF5F5F5)))); + rows: List.generate(widget.bodyList.length, (index) => _getRow(index, Color(0xFFF5F5F5)))); } }