Compare commits
2 Commits
1fbb102370
...
8c10e6eb4d
| Author | SHA1 | Date |
|---|---|---|
|
|
8c10e6eb4d | |
|
|
aa9dd3d83c |
|
|
@ -224,3 +224,6 @@ marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart
|
|||
marking_app/lib/pages/homework_correction/job_home.g.dart
|
||||
marking_app/lib/common/model/marking/keyboard_assist_event.g.dart
|
||||
marking_app/lib/common/model/marking/marking_history_zoom_info.g.dart
|
||||
marking_app/lib/common/model/job/job_handwriting.g.dart
|
||||
marking_app/lib/utils/my_time_util.g.dart
|
||||
marking_app/lib/pages/homework_correction/widget/answer_handwriting.g.dart
|
||||
|
|
|
|||
|
|
@ -14,11 +14,30 @@ class GestureRecording {
|
|||
|
||||
bool scopeBox;
|
||||
|
||||
int intervalTime; // 间隔时间
|
||||
|
||||
GestureRecording({
|
||||
required this.eraser,
|
||||
required this.annotationSwitch,
|
||||
this.data,
|
||||
this.usageTime,
|
||||
this.scopeBox = false,
|
||||
this.intervalTime = 0,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 手势记录(原稿笔记还原)
|
||||
*/
|
||||
class GestureHandwritingRecording {
|
||||
int stroke;
|
||||
int usageTime; // 用时
|
||||
Offset data;
|
||||
int intervalTime; // 间隔时间
|
||||
GestureHandwritingRecording({
|
||||
required this.stroke,
|
||||
required this.data,
|
||||
required this.usageTime,
|
||||
required this.intervalTime,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'job_handwriting.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class JobHandwriting extends Object {
|
||||
@JsonKey(name: 'lattices')
|
||||
List<Lattices> lattices;
|
||||
|
||||
@JsonKey(name: 'paperPicture')
|
||||
String paperPicture;
|
||||
|
||||
@JsonKey(name: 'pageNum')
|
||||
int pageNum;
|
||||
|
||||
@JsonKey(name: 'pageCount')
|
||||
int pageCount;
|
||||
|
||||
JobHandwriting(this.lattices, this.paperPicture, this.pageNum, this.pageCount);
|
||||
|
||||
factory JobHandwriting.fromJson(Map<String, dynamic> srcJson) => _$JobHandwritingFromJson(srcJson);
|
||||
|
||||
Map<String, dynamic> toJson() => _$JobHandwritingToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class Lattices extends Object {
|
||||
@JsonKey(name: 'stroke')
|
||||
int stroke;
|
||||
|
||||
@JsonKey(name: 'x')
|
||||
double x;
|
||||
|
||||
@JsonKey(name: 'y')
|
||||
double y;
|
||||
|
||||
@JsonKey(name: 'time')
|
||||
int time;
|
||||
|
||||
@JsonKey(name: 'intervalTime')
|
||||
int intervalTime;
|
||||
|
||||
Lattices(this.stroke, this.x, this.y, this.time, [this.intervalTime = 0]);
|
||||
|
||||
factory Lattices.fromJson(Map<String, dynamic> srcJson) => _$LatticesFromJson(srcJson);
|
||||
|
||||
Map<String, dynamic> toJson() => _$LatticesToJson(this);
|
||||
}
|
||||
|
|
@ -36,12 +36,7 @@ class TestQuestionsImageInfo extends Object {
|
|||
double? imageHeightOffsetend;
|
||||
|
||||
TestQuestionsImageInfo(
|
||||
{required this.width,
|
||||
required this.height,
|
||||
required this.url,
|
||||
required this.boxWidth,
|
||||
required this.boxHeight,
|
||||
this.pixelRatio = 1}) {
|
||||
{required this.width, required this.height, required this.url, required this.boxWidth, required this.boxHeight, this.pixelRatio = 1}) {
|
||||
// print('图片宽度:$width');
|
||||
// print('图片高度:$height');
|
||||
|
||||
|
|
@ -60,6 +55,14 @@ class TestQuestionsImageInfo extends Object {
|
|||
}
|
||||
}
|
||||
|
||||
// 重新计算
|
||||
void calculateStartAndEndHeight([double otherHeight = 0]) {
|
||||
if (scaleHeight != null) {
|
||||
imageHeightOffsetStart = (boxHeight - (scaleHeight! + otherHeight)) / 2;
|
||||
imageHeightOffsetend = imageHeightOffsetStart! + scaleHeight!;
|
||||
}
|
||||
}
|
||||
|
||||
factory TestQuestionsImageInfo.fromJson(Map<String, dynamic> srcJson) => _$TestQuestionsImageInfoFromJson(srcJson);
|
||||
|
||||
Map<String, dynamic> toJson() => _$TestQuestionsImageInfoToJson(this);
|
||||
|
|
|
|||
|
|
@ -76,14 +76,17 @@ class _JobHomeState extends State<JobHome> with CommonMixin, EventBusMixin, Auto
|
|||
child: ListView(
|
||||
children: [
|
||||
Container(
|
||||
height: 200.h,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/job_home_top_bgm.png'),
|
||||
fit: BoxFit.fill, // 完全填充
|
||||
),
|
||||
constraints: BoxConstraints(
|
||||
minHeight: 200.h,
|
||||
maxWidth: double.infinity,
|
||||
),
|
||||
// decoration: BoxDecoration(
|
||||
// image: DecorationImage(
|
||||
// image: AssetImage('assets/images/job_home_top_bgm.png'),
|
||||
// fit: BoxFit.fitWidth, // 完全填充
|
||||
// ),
|
||||
// ),
|
||||
child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth),
|
||||
),
|
||||
SizedBox(height: 30.h),
|
||||
SlidingData([
|
||||
|
|
@ -104,8 +107,8 @@ class _JobHomeState extends State<JobHome> with CommonMixin, EventBusMixin, Auto
|
|||
navigationUrl: '${RouterManager.jobStudentGroupPath}?page=set',
|
||||
)
|
||||
], 0),
|
||||
spaceWidth,
|
||||
$TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0),
|
||||
// spaceWidth,
|
||||
// $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
/// 原稿作业回显
|
||||
// 回显批注轨迹
|
||||
|
||||
import 'package:marking_app/common/model/job/gesture_recording.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:marking_app/common/mixin/common.dart';
|
||||
|
||||
final jobHandwritingDrawingTrajectoryProvider =
|
||||
StateNotifierProvider<JobHandwritingDrawingTrajectoryProviderHandle, List<GestureHandwritingRecording>>(
|
||||
(ref) => JobHandwritingDrawingTrajectoryProviderHandle([]));
|
||||
|
||||
class JobHandwritingDrawingTrajectoryProviderHandle extends StateNotifier<List<GestureHandwritingRecording>> with CommonMixin {
|
||||
JobHandwritingDrawingTrajectoryProviderHandle(List<GestureHandwritingRecording> progress) : super(progress);
|
||||
|
||||
setVal(List<GestureHandwritingRecording> val) {
|
||||
state = val;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
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/job/job_data_report.dart';
|
||||
|
|
@ -12,20 +13,20 @@ 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';
|
||||
|
||||
class QuickCheckPersonal extends StatefulWidget {
|
||||
import 'providers/handwriting_drawing_trajectory_provider.dart';
|
||||
import 'widget/answer_handwriting.dart';
|
||||
|
||||
class QuickCheckPersonal extends StatefulHookConsumerWidget {
|
||||
final int jobId;
|
||||
final int studentId;
|
||||
|
||||
const QuickCheckPersonal(
|
||||
{Key? key, required this.jobId, required this.studentId})
|
||||
: super(key: key);
|
||||
const QuickCheckPersonal({Key? key, required this.jobId, required this.studentId}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<QuickCheckPersonal> createState() => _QuickCheckPersonalState();
|
||||
ConsumerState<QuickCheckPersonal> createState() => _QuickCheckPersonalState();
|
||||
}
|
||||
|
||||
class _QuickCheckPersonalState extends State<QuickCheckPersonal>
|
||||
with CommonMixin {
|
||||
class _QuickCheckPersonalState extends ConsumerState<QuickCheckPersonal> with CommonMixin {
|
||||
StudentDetails? studentInfo;
|
||||
|
||||
void initState() {
|
||||
|
|
@ -40,18 +41,16 @@ class _QuickCheckPersonalState extends State<QuickCheckPersonal>
|
|||
params['jobid'] = widget.jobId;
|
||||
// params['jobid'] = '521646983660101';
|
||||
params['studentId'] = widget.studentId;
|
||||
BaseStructureResult<StudentDetails?> data =
|
||||
await _client.getJobPersonalReport(params);
|
||||
if(data.data!.studentId != null){
|
||||
BaseStructureResult<StudentDetails?> data = await _client.getJobPersonalReport(params);
|
||||
if (data.data!.studentId != null) {
|
||||
setState(() {
|
||||
studentInfo = data.data;
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
Navigator.pop(context);
|
||||
ToastUtils.showError('暂无数据');
|
||||
}
|
||||
EasyLoading.dismiss();
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -89,20 +88,19 @@ class _QuickCheckPersonalState extends State<QuickCheckPersonal>
|
|||
alignment: Alignment.center,
|
||||
),
|
||||
),*/
|
||||
|
||||
],
|
||||
),
|
||||
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 14.r,left: 14.r),
|
||||
padding: EdgeInsets.only(top: 14.r, left: 14.r),
|
||||
child: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: (){
|
||||
RouterManager.router.navigateTo(context, '${RouterManager.jobPersonalDetailPath}?studentId=${widget.studentId}&studentName=${Uri.encodeComponent(studentInfo!.studentName!)}');
|
||||
onTap: () {
|
||||
RouterManager.router.navigateTo(context,
|
||||
'${RouterManager.jobPersonalDetailPath}?studentId=${widget.studentId}&studentName=${Uri.encodeComponent(studentInfo!.studentName!)}');
|
||||
},
|
||||
child: Container(
|
||||
width: 93.r,
|
||||
|
|
@ -112,12 +110,23 @@ class _QuickCheckPersonalState extends State<QuickCheckPersonal>
|
|||
borderRadius: BorderRadius.circular(4.r),
|
||||
),
|
||||
child: Center(
|
||||
child: Text('历史查询',style: TextStyle(fontSize: 10.r,color: Color(0xFF2080F7)),),
|
||||
child: Text(
|
||||
'历史查询',
|
||||
style: TextStyle(fontSize: 10.r, color: Color(0xFF2080F7)),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10.r,),
|
||||
Container(
|
||||
),
|
||||
SizedBox(
|
||||
width: 10.r,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId).then((value) {
|
||||
ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
width: 93.r,
|
||||
height: 28.r,
|
||||
decoration: BoxDecoration(
|
||||
|
|
@ -125,7 +134,11 @@ class _QuickCheckPersonalState extends State<QuickCheckPersonal>
|
|||
borderRadius: BorderRadius.circular(4.r),
|
||||
),
|
||||
child: Center(
|
||||
child: Text('原稿笔迹',style: TextStyle(fontSize: 10.r,color: Color(0xFF4CC793)),),
|
||||
child: Text(
|
||||
'原稿笔迹',
|
||||
style: TextStyle(fontSize: 10.r, color: Color(0xFF4CC793)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -147,22 +160,22 @@ class _QuickCheckPersonalState extends State<QuickCheckPersonal>
|
|||
children: [
|
||||
Text(
|
||||
'客观题',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: Color(0xFF5C5C5C),fontWeight: FontWeight.w600),
|
||||
style: TextStyle(fontSize: 14.sp, color: Color(0xFF5C5C5C), fontWeight: FontWeight.w600),
|
||||
),
|
||||
SizedBox(
|
||||
width: 10.r,
|
||||
),
|
||||
Text(
|
||||
'${studentInfo!.kgValidRate}%',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: Color(0xFF6888FD),fontWeight: FontWeight.w600),
|
||||
style: TextStyle(fontSize: 14.sp, color: Color(0xFF6888FD), fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.r,),
|
||||
SizedBox(
|
||||
height: studentInfo!.kgDetails.length>8?300.r:studentInfo!.kgDetails.length * 40.r + 40.r,
|
||||
height: 10.r,
|
||||
),
|
||||
SizedBox(
|
||||
height: studentInfo!.kgDetails.length > 8 ? 300.r : studentInfo!.kgDetails.length * 40.r + 40.r,
|
||||
child: StudentKgTable(
|
||||
headList: ['题号', '学生答案', '标准答案'],
|
||||
bodyList: studentInfo!.kgDetails,
|
||||
|
|
@ -171,7 +184,9 @@ class _QuickCheckPersonalState extends State<QuickCheckPersonal>
|
|||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15.r,),
|
||||
SizedBox(
|
||||
height: 15.r,
|
||||
),
|
||||
//主观题
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r),
|
||||
|
|
@ -188,24 +203,24 @@ class _QuickCheckPersonalState extends State<QuickCheckPersonal>
|
|||
children: [
|
||||
Text(
|
||||
'主观题',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: Color(0xFF5C5C5C),fontWeight: FontWeight.w600),
|
||||
style: TextStyle(fontSize: 14.sp, color: Color(0xFF5C5C5C), fontWeight: FontWeight.w600),
|
||||
),
|
||||
SizedBox(
|
||||
width: 10.r,
|
||||
),
|
||||
Text(
|
||||
'${studentInfo!.zgValidRate}%',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: Color(0xFF6888FD),fontWeight: FontWeight.w600),
|
||||
style: TextStyle(fontSize: 14.sp, color: Color(0xFF6888FD), fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.r,),
|
||||
SizedBox(
|
||||
height: studentInfo!.zgDetails.length>8?300.r:studentInfo!.zgDetails.length * 40.r + 40.r,
|
||||
height: 10.r,
|
||||
),
|
||||
SizedBox(
|
||||
height: studentInfo!.zgDetails.length > 8 ? 300.r : studentInfo!.zgDetails.length * 40.r + 40.r,
|
||||
child: StudentZgTable(
|
||||
headList: ['题号', '用时', '学生答案','批注结果','批注'],
|
||||
headList: ['题号', '用时', '学生答案', '批注结果', '批注'],
|
||||
bodyList: studentInfo!.zgDetails,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,906 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:marking_app/common/mixin/common.dart';
|
||||
import 'package:marking_app/common/model/job/job_handwriting.dart';
|
||||
import 'package:marking_app/common/model/job/test_questions_image_info.dart';
|
||||
import 'package:marking_app/pages/common/event_bus_mixin.dart';
|
||||
import 'package:marking_app/pages/homework_correction/hooks/use_cached_img_refresh.dart';
|
||||
import 'package:marking_app/utils/index.dart';
|
||||
import 'package:marking_app/utils/my_text.dart';
|
||||
import 'package:marking_app/utils/my_time_util.dart';
|
||||
|
||||
import '../../../common/model/job/gesture_recording.dart';
|
||||
import '../providers/handwriting_drawing_trajectory_provider.dart';
|
||||
|
||||
part 'answer_handwriting.g.dart';
|
||||
|
||||
/// 学生答题轨迹
|
||||
class AnswerHandwriting extends Dialog {
|
||||
final int jobId;
|
||||
final int studentId;
|
||||
final int? pageNum;
|
||||
final int? questionNo;
|
||||
final Function closeCall;
|
||||
const AnswerHandwriting({required this.jobId, required this.studentId, required this.closeCall, this.pageNum, this.questionNo});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Container(
|
||||
width: ScreenUtil().screenWidth - 60.r,
|
||||
alignment: Alignment.center,
|
||||
child: AnswerHandwritingMainBox(
|
||||
jobId: jobId,
|
||||
studentId: studentId,
|
||||
pageNum: pageNum,
|
||||
questionNo: questionNo,
|
||||
closeCall: closeCall,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showAnswerHandwriting(BuildContext context, {required int jobId, required int studentId, int? pageNum}) async {
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AnswerHandwriting(
|
||||
jobId: jobId,
|
||||
studentId: studentId,
|
||||
pageNum: pageNum,
|
||||
closeCall: () => Navigator.of(context).pop(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 主图
|
||||
class AnswerHandwritingMainBox extends HookWidget {
|
||||
const AnswerHandwritingMainBox({
|
||||
required this.jobId,
|
||||
required this.studentId,
|
||||
required this.closeCall,
|
||||
this.pageNum,
|
||||
this.questionNo,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
final int jobId;
|
||||
final int studentId;
|
||||
final int? pageNum;
|
||||
final int? questionNo;
|
||||
final Function closeCall;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var _useStateModel = UseMainBoxState.use(jobId, studentId, pageNum, questionNo);
|
||||
|
||||
useValueChanged<JobHandwriting?, void>(_useStateModel.handwritingData.value, (_, __) {
|
||||
var theData = _useStateModel.handwritingData.value;
|
||||
_useStateModel.pageNum.value = theData?.pageNum;
|
||||
_useStateModel.pageCount.value = theData?.pageCount ?? 0;
|
||||
_useStateModel.playPause.value = false;
|
||||
_useStateModel.constantFastSpeed.value = false;
|
||||
Future.delayed(Duration.zero, () {
|
||||
_useStateModel.handwritingKey.currentState?.ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
|
||||
});
|
||||
_useStateModel.handwritingDetail.value = _useStateModel.getHandwritingDetail(theData);
|
||||
});
|
||||
|
||||
useValueChanged<int?, void>(_useStateModel.pageNum.value, (oldVal, __) {
|
||||
if (oldVal != null && oldVal != _useStateModel.pageNum.value) _useStateModel.getData().catchError((e) => closeCall());
|
||||
});
|
||||
|
||||
useEffect(() {
|
||||
_useStateModel.getData().catchError((e) => closeCall());
|
||||
return () {};
|
||||
}, []);
|
||||
|
||||
JobHandwriting? _data = _useStateModel.handwritingData.value;
|
||||
HandwritingInfo? _dataDetail = _useStateModel.handwritingDetail.value;
|
||||
|
||||
if (_data == null || _dataDetail == null) return Container();
|
||||
print('数据长度:${_data.lattices.length}');
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: const FractionalOffset(0, 0.5),
|
||||
children: [
|
||||
// 图片展示主框
|
||||
HandwritingDrawBox(
|
||||
_data.paperPicture,
|
||||
_dataDetail,
|
||||
key: _useStateModel.handwritingKey,
|
||||
),
|
||||
$PageNumberBox(_data.pageNum),
|
||||
// 上一页按钮
|
||||
$PreviousNutton(
|
||||
_useStateModel.pageNum.value,
|
||||
() => _useStateModel.pageNum.value = _useStateModel.pageNum.value! - 1,
|
||||
),
|
||||
// 下一题按钮
|
||||
$NextPageButton(
|
||||
_useStateModel.pageNum.value,
|
||||
_useStateModel.pageCount.value,
|
||||
() => _useStateModel.pageNum.value = _useStateModel.pageNum.value! + 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
$BottomPlaybar(_dataDetail.timeConsuming, _dataDetail.pauseCount),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UseMainBoxState with CommonMixin {
|
||||
final int jobId;
|
||||
final int studentId;
|
||||
final int? questionNo;
|
||||
final ValueNotifier<int?> pageNum;
|
||||
final ValueNotifier<int> pageCount;
|
||||
final ValueNotifier<JobHandwriting?> handwritingData;
|
||||
final ValueNotifier<HandwritingInfo?> handwritingDetail;
|
||||
|
||||
final ValueNotifier<bool> playPause; // 播放暂停
|
||||
final ValueNotifier<bool> constantFastSpeed; // 原速、快速 默认原速
|
||||
|
||||
GlobalKey<_HandwritingDrawBoxState> handwritingKey;
|
||||
|
||||
UseMainBoxState._({
|
||||
required this.jobId,
|
||||
required this.studentId,
|
||||
required this.pageNum,
|
||||
required this.handwritingData,
|
||||
required this.questionNo,
|
||||
required this.pageCount,
|
||||
required this.playPause,
|
||||
required this.constantFastSpeed,
|
||||
required this.handwritingDetail,
|
||||
required this.handwritingKey,
|
||||
});
|
||||
|
||||
// 工厂构造函数
|
||||
factory UseMainBoxState.use(int jobId, int studentId, [int? pageNum, int? questionNo]) {
|
||||
return UseMainBoxState._(
|
||||
jobId: jobId,
|
||||
studentId: studentId,
|
||||
questionNo: questionNo,
|
||||
pageNum: useState(pageNum),
|
||||
handwritingData: useState(null),
|
||||
handwritingDetail: useState(null),
|
||||
pageCount: useState(0),
|
||||
playPause: useState(false),
|
||||
constantFastSpeed: useState(false),
|
||||
handwritingKey: GlobalKey(),
|
||||
);
|
||||
}
|
||||
|
||||
Future getData() async {
|
||||
try {
|
||||
ToastUtils.showLoading();
|
||||
var _client = await getClient();
|
||||
var res = await _client.getHandwriting(jobId, studentId, questionNo, pageNum.value);
|
||||
if (res?.success ?? false) {
|
||||
handwritingData.value = res!.data;
|
||||
if (handwritingData.value!.lattices.isEmpty) {
|
||||
Future.delayed(Duration.zero, () => ToastUtils.showInfo('此页试题没有笔迹'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
Future.delayed(Duration(seconds: 1), () => ToastUtils.showError(res?.message ?? '笔记数据请求失败'));
|
||||
} catch (e) {
|
||||
print(e);
|
||||
} finally {
|
||||
ToastUtils.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
HandwritingInfo? getHandwritingDetail(JobHandwriting? theData) {
|
||||
if (theData == null) return null;
|
||||
print('开始时间:${DateTime.now().millisecondsSinceEpoch}');
|
||||
// 笔画分组
|
||||
// var lattices = Map<int, List<Lattices>>.fromIterable(
|
||||
// theData.lattices,
|
||||
// key: (key) => key.stroke,
|
||||
// value: (value) {
|
||||
// // return theData.lattices.where((item) => item.stroke == value.stroke).toList()..sort((a, b) => a.time.compareTo(b.time));
|
||||
// return theData.lattices.where((item) => item.stroke == value.stroke).toList();
|
||||
// },
|
||||
// );
|
||||
var lattices = Map<int, List<Lattices>>();
|
||||
var theLattices = theData.lattices;
|
||||
for (var i = 0; i < theLattices.length; i++) {
|
||||
Lattices item = theLattices[i];
|
||||
if (!lattices.containsKey(item.stroke)) lattices[item.stroke] = [];
|
||||
lattices[item.stroke]!.add(item); // 添加笔画数据
|
||||
}
|
||||
|
||||
print('分组时间:${DateTime.now().millisecondsSinceEpoch}');
|
||||
List<int> latticeKeys = lattices.keys.toList();
|
||||
int timeConsuming = 0;
|
||||
if (latticeKeys.isNotEmpty) {
|
||||
List<Lattices>? firstAction = lattices[latticeKeys[0]];
|
||||
List<Lattices>? lastAction = lattices[latticeKeys[latticeKeys.length - 1]];
|
||||
int firstTime = 0;
|
||||
int lastTime = 0;
|
||||
|
||||
if (firstAction?.isNotEmpty ?? false) {
|
||||
// 第一个笔画集合
|
||||
firstTime = firstAction![0].time;
|
||||
}
|
||||
if (lastAction?.isNotEmpty ?? false) {
|
||||
// 最后一笔画集合
|
||||
lastTime = lastAction![0].time;
|
||||
}
|
||||
timeConsuming = lastTime - firstTime;
|
||||
}
|
||||
print('获取数据总时间:${DateTime.now().millisecondsSinceEpoch}');
|
||||
var pauseCount = 0; // 停顿次数
|
||||
for (var i = 0; i < latticeKeys.length; i++) {
|
||||
var currentLattices = lattices[latticeKeys[i]]!; // 当前循环笔画集合
|
||||
var prevLattices = i == 0 ? null : lattices[latticeKeys[i - 1]]!; // 下一个笔画集合
|
||||
for (var j = 0; j < currentLattices.length; j++) {
|
||||
var intervalTime = 0;
|
||||
var lattice = currentLattices[j];
|
||||
|
||||
if (j != 0) {
|
||||
var prevItem = currentLattices[j - 1];
|
||||
var adjacentSpacingTime = lattice.time - prevItem.time;
|
||||
if (adjacentSpacingTime > 5000) {
|
||||
// 大于5秒算一次停顿
|
||||
pauseCount++;
|
||||
}
|
||||
intervalTime = adjacentSpacingTime + prevItem.intervalTime;
|
||||
} else {
|
||||
if (i != 0 && prevLattices != null) {
|
||||
var prevLatticeLastItem = prevLattices[prevLattices.length - 1];
|
||||
var adjacentSpacingTime = lattice.time - prevLatticeLastItem.time;
|
||||
if (adjacentSpacingTime > 5000) {
|
||||
// 大于5秒算一次停顿
|
||||
pauseCount++;
|
||||
}
|
||||
intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime;
|
||||
}
|
||||
}
|
||||
lattice.intervalTime = intervalTime;
|
||||
}
|
||||
}
|
||||
return HandwritingInfo(pauseCount, timeConsuming, lattices);
|
||||
}
|
||||
}
|
||||
|
||||
class HandwritingInfo {
|
||||
int pauseCount; // 停顿次数
|
||||
int timeConsuming; // 耗时(毫秒)
|
||||
Map<int, List<Lattices>> strokeMap; // 笔画数据
|
||||
|
||||
HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap);
|
||||
}
|
||||
|
||||
// 图片展示
|
||||
@hwidget
|
||||
Widget $theCachedNetworkImage(ImageWidgetBuilder imageBuilder, {required String imageUrl}) {
|
||||
UseCachedImgRefresh _useImgRefsh = UseCachedImgRefresh.use();
|
||||
|
||||
return CachedNetworkImage(
|
||||
key: _useImgRefsh.imageKey.value,
|
||||
fit: BoxFit.contain,
|
||||
imageUrl: imageUrl,
|
||||
imageBuilder: imageBuilder,
|
||||
placeholder: (context, url) => Center(child: SpinKitWaveSpinner(color: Theme.of(context).primaryColor, size: 50.r)),
|
||||
errorWidget: (context, url, error) {
|
||||
return GestureDetector(
|
||||
onTap: () => (_useImgRefsh.imageKey.value = UniqueKey()),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset('assets/images/test_paper_loading_failed.png'),
|
||||
quickText('加载失败,点击重试', color: Color.fromRGBO(148, 163, 182, 1), size: 12.sp),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 上一页
|
||||
@swidget
|
||||
Widget $previousNutton(BuildContext context, int? pageNum, Function call) {
|
||||
if (pageNum != null && pageNum > 1)
|
||||
return Positioned(
|
||||
left: 3.w,
|
||||
child: FloatingActionButton(
|
||||
heroTag: '点击前往上一题',
|
||||
tooltip: '点击前往上一题',
|
||||
focusColor: Theme.of(context).primaryColor,
|
||||
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1),
|
||||
elevation: 6.r,
|
||||
onPressed: () => easyThrottle('answer_handwriting_previous', () => call()),
|
||||
child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp),
|
||||
),
|
||||
);
|
||||
|
||||
return SizedBox();
|
||||
}
|
||||
|
||||
/// 下一页
|
||||
@swidget
|
||||
Widget $nextPageButton(BuildContext context, int? pageNum, int totalNum, Function call) {
|
||||
if (pageNum != null && pageNum < totalNum)
|
||||
return Positioned(
|
||||
right: 3.w,
|
||||
child: FloatingActionButton(
|
||||
heroTag: '点击前往下一题',
|
||||
tooltip: '点击前往下一题',
|
||||
elevation: 6.r,
|
||||
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1),
|
||||
onPressed: () => easyThrottle('answer_handwriting_next', () => call()),
|
||||
child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp),
|
||||
),
|
||||
);
|
||||
|
||||
return SizedBox();
|
||||
}
|
||||
|
||||
// 笔记还原主框
|
||||
class HandwritingDrawBox extends StatefulHookConsumerWidget {
|
||||
final String image;
|
||||
final HandwritingInfo handwritingData;
|
||||
// final double boxWidth;
|
||||
// final double boxHeight;
|
||||
const HandwritingDrawBox(this.image, this.handwritingData, {super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<HandwritingDrawBox> createState() => _HandwritingDrawBoxState();
|
||||
}
|
||||
|
||||
class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with EventBusMixin {
|
||||
ImageStream? imageStream; // 图片监听数据
|
||||
TestQuestionsImageInfo? imagInfoModel; // 试题图片数据
|
||||
late ImageStreamListener theImageStreamListener;
|
||||
|
||||
List<List<GestureHandwritingRecording>> _packagedHandwritingDatas = [];
|
||||
List<GestureHandwritingRecording> _packagedHandwritingDataAll = [];
|
||||
List<GestureHandwritingRecording> pendingData = []; // 待执行数据
|
||||
List<Timer> timers = [];
|
||||
int handwritingTime = 0;
|
||||
int handwritingDuration = 0;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
eventOn(callback: (e) {
|
||||
switch (e.runtimeType) {
|
||||
case JobHandwritingRunTimeBus:
|
||||
var _model = (e as JobHandwritingRunTimeBus);
|
||||
var _runtime = _model.runTimeVal;
|
||||
handwritingDuration = _model.totalVal;
|
||||
handwritingTime = _runtime;
|
||||
if (_runtime <= 0) {
|
||||
pendingData.clear();
|
||||
}
|
||||
break;
|
||||
case JobHandwritingDragProgressBarBus:
|
||||
var _model = (e as JobHandwritingDragProgressBarBus);
|
||||
dragProgressBarInitData(_model.changeVal, _model.totalVal);
|
||||
break;
|
||||
case JobHandwritingPlaybarBus:
|
||||
// 播放 暂停
|
||||
var _val = e as JobHandwritingPlaybarBus;
|
||||
if (_val.play) {
|
||||
// 播放
|
||||
toGoPlay();
|
||||
} else {
|
||||
// 暂停
|
||||
toGoPause();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
theImageStreamListener = ImageStreamListener((ImageInfo info, bool _) {
|
||||
if (imagInfoModel != null) return;
|
||||
imagInfoModel = TestQuestionsImageInfo(
|
||||
// 获取图片的宽高
|
||||
boxHeight: ScreenUtil().scaleHeight, // 图片展示自适应所以 这里无法获取容器的高度
|
||||
boxWidth: ScreenUtil().screenWidth - 60.r,
|
||||
url: widget.image,
|
||||
height: info.image.height.toDouble(),
|
||||
width: info.image.width.toDouble(),
|
||||
)..calculateStartAndEndHeight(60.h); // 60.h是底部的播放栏高度
|
||||
getCalculatedSize();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
timers.forEach((e) {
|
||||
if (e.isActive) e.cancel();
|
||||
});
|
||||
try {
|
||||
imageStream?.removeListener(theImageStreamListener);
|
||||
eventCancel();
|
||||
} catch (e) {}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// 暂停播放
|
||||
Future<void> toGoPause() async {
|
||||
timers.forEach((e) {
|
||||
if (e.isActive) e.cancel();
|
||||
});
|
||||
timers = [];
|
||||
if (pendingData.isNotEmpty && handwritingTime > 0 && (handwritingDuration - handwritingTime > 0)) {
|
||||
// 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间
|
||||
pendingData = pendingData.map((e) {
|
||||
return GestureHandwritingRecording(
|
||||
stroke: e.stroke,
|
||||
data: e.data,
|
||||
usageTime: e.usageTime,
|
||||
intervalTime: e.intervalTime - (handwritingDuration - handwritingTime) * 1000,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
/// 拖动进度条后重新初始化数据
|
||||
/// @param startTime 起始时间 单位秒
|
||||
Future<void> dragProgressBarInitData(int startTime, int totalDuration) async {
|
||||
timers.forEach((e) {
|
||||
if (e.isActive) e.cancel();
|
||||
});
|
||||
timers = [];
|
||||
pendingData.clear();
|
||||
|
||||
if (startTime == 0) {
|
||||
ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
|
||||
pendingData.addAll(_packagedHandwritingDataAll);
|
||||
} else {
|
||||
// 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间
|
||||
startTime = startTime * 1000; // 转为毫秒
|
||||
List<GestureHandwritingRecording> executeImmediately = []; // 立即执行数据
|
||||
List<GestureHandwritingRecording> waitingExecution = []; // 等待执行数据
|
||||
|
||||
for (var i = 0; i < _packagedHandwritingDataAll.length; i++) {
|
||||
var item = _packagedHandwritingDataAll[i];
|
||||
|
||||
if (item.intervalTime <= startTime) {
|
||||
// 需要直接装配到直接打印的容器
|
||||
executeImmediately.add(item);
|
||||
} else {
|
||||
// 需要等待的数据
|
||||
waitingExecution.add(GestureHandwritingRecording(
|
||||
stroke: item.stroke,
|
||||
data: item.data,
|
||||
usageTime: item.usageTime,
|
||||
intervalTime: item.intervalTime - startTime,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pendingData = waitingExecution;
|
||||
ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(executeImmediately);
|
||||
eventFire(model: JobHandwritingPlaybarBus(true));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> zhixinCall(GestureHandwritingRecording e) async {
|
||||
if (mounted) {
|
||||
List<GestureHandwritingRecording> trajectorys = ref.read(jobHandwritingDrawingTrajectoryProvider)..add(e);
|
||||
ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(List.from(trajectorys));
|
||||
pendingData.remove(e); // 执行后删除容器中的当前动作
|
||||
}
|
||||
}
|
||||
|
||||
/// 开始播放
|
||||
Future<void> toGoPlay() async {
|
||||
handwritingTime = 0;
|
||||
var executableData = _packagedHandwritingDataAll;
|
||||
if (pendingData.isNotEmpty) {
|
||||
// 待执行的数据没有执行完成 就继续执行待执行数据
|
||||
executableData = pendingData;
|
||||
} else {
|
||||
pendingData.addAll(_packagedHandwritingDataAll);
|
||||
ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
|
||||
}
|
||||
|
||||
executableData.forEach((e) {
|
||||
if (e.intervalTime == 0) {
|
||||
zhixinCall(e);
|
||||
} else {
|
||||
var ter = Timer(Duration(milliseconds: e.intervalTime), () => zhixinCall(e));
|
||||
timers.add(ter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 计算尺寸
|
||||
Future<void> getCalculatedSize() async {
|
||||
if (imagInfoModel == null) return;
|
||||
var dataInfo = widget.handwritingData;
|
||||
Map<int, List<Lattices>> mapData = dataInfo.strokeMap;
|
||||
if (mapData.isNotEmpty) {
|
||||
List<int> keys = mapData.keys.toList();
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
List<GestureHandwritingRecording> newTrajectoryData = mapData[keys[i]]!.map((e) {
|
||||
double theX = e.x * imagInfoModel!.scale!;
|
||||
double theY = e.y * imagInfoModel!.scale!;
|
||||
|
||||
return GestureHandwritingRecording(
|
||||
data: Offset(theX, theY),
|
||||
usageTime: e.time.toInt(),
|
||||
intervalTime: e.intervalTime,
|
||||
stroke: e.stroke,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
_packagedHandwritingDatas.add(newTrajectoryData); // 分组数据
|
||||
_packagedHandwritingDataAll.addAll(newTrajectoryData); // 不分组数据
|
||||
}
|
||||
Future.delayed(Duration.zero, () => eventFire(model: JobHandwritingGetReadyBus())); // 通知外部可以播放笔迹
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<GestureHandwritingRecording> points = ref.watch(jobHandwritingDrawingTrajectoryProvider);
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
child: CustomPaint(
|
||||
foregroundPainter: DrawingPainter(points: points),
|
||||
// size: Size(ScreenUtil().screenWidth - 60.r, widget.boxHeight),
|
||||
child: RepaintBoundary(
|
||||
child: $TheCachedNetworkImage(
|
||||
imageUrl: widget.image,
|
||||
(context, imageProvider) {
|
||||
Image imageWidget = Image(image: imageProvider, fit: BoxFit.contain);
|
||||
if (imagInfoModel == null) {
|
||||
imageStream?.removeListener(theImageStreamListener);
|
||||
// 视图中展示图片的尺寸计算获取
|
||||
imageStream = imageWidget.image.resolve(ImageConfiguration());
|
||||
imageStream?.addListener(theImageStreamListener);
|
||||
}
|
||||
|
||||
return imageWidget;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DrawingPainter extends CustomPainter {
|
||||
List<GestureHandwritingRecording> points;
|
||||
|
||||
DrawingPainter({required this.points}) : super();
|
||||
|
||||
// Paint paintBrush = Paint()
|
||||
// ..color = Colors.black
|
||||
// ..strokeCap = StrokeCap.round
|
||||
// ..strokeWidth = 0.5.sp;
|
||||
|
||||
//[定义画笔]
|
||||
final Paint paintBrush = Paint()
|
||||
//画笔颜色
|
||||
..color = Colors.black
|
||||
//画笔笔触类型
|
||||
..strokeCap = StrokeCap.round
|
||||
//是否启动抗锯齿
|
||||
// ..isAntiAlias = true
|
||||
//绘画风格,默认为填充
|
||||
// ..style = PaintingStyle.fill
|
||||
//画笔的宽度
|
||||
..strokeWidth = 0.6.r;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
// canvas.drawPoints(PointMode.points, thePoints, paintBrush);
|
||||
var _length = points.length;
|
||||
for (int i = 0; i < _length; i++) {
|
||||
GestureHandwritingRecording item = points[i];
|
||||
GestureHandwritingRecording? nextItem = i + 1 >= _length ? null : points[i + 1];
|
||||
Offset? offsetData = item.data;
|
||||
|
||||
Offset? nextOffsetData = nextItem?.data;
|
||||
if (nextOffsetData != null && item.stroke == nextItem?.stroke) {
|
||||
canvas.drawLine(offsetData, nextOffsetData, paintBrush);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(DrawingPainter oldDelegate) => true;
|
||||
}
|
||||
|
||||
@swidget
|
||||
Widget $pageNumberBox(int pageNum) {
|
||||
return Positioned(
|
||||
top: 6.h,
|
||||
right: 4.w,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.47),
|
||||
borderRadius: BorderRadius.circular(5.r),
|
||||
),
|
||||
child: quickText('第$pageNum页', color: Colors.white, size: 10.sp),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@hwidget
|
||||
Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) {
|
||||
var usePlaybar = UseBottomPlaybar.use(timeConsuming);
|
||||
|
||||
useValueChanged<int, void>(timeConsuming, (_, __) {
|
||||
var seds = timeConsuming ~/ 1000;
|
||||
if ((timeConsuming % 1000) > 500) seds += 1;
|
||||
usePlaybar.handwritingDuration.value = seds;
|
||||
});
|
||||
|
||||
useValueChanged<int, void>(usePlaybar.handwritingDuration.value, (_, __) {
|
||||
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value;
|
||||
});
|
||||
// 播放速度
|
||||
useValueChanged<PlaybackSpeed, void>(usePlaybar.constantFastSpeed.value, (_, __) {
|
||||
usePlaybar.eventFire(model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed));
|
||||
});
|
||||
// 计时结束监听
|
||||
useValueChanged<int, void>(usePlaybar.useTime.value, (_, __) {
|
||||
var _runtime = usePlaybar.useTime.value;
|
||||
if (_runtime <= 0 || usePlaybar.handwritingDuration.value == _runtime) {
|
||||
Future.delayed(Duration.zero, () => (usePlaybar.playPause.value = false)); // 初始化播放按钮
|
||||
}
|
||||
usePlaybar.eventFire(model: JobHandwritingRunTimeBus(_runtime, usePlaybar.handwritingDuration.value));
|
||||
});
|
||||
|
||||
useEffect(() {
|
||||
usePlaybar.eventOn(callback: (e) {
|
||||
// TODO 数据
|
||||
switch (e.runtimeType) {
|
||||
case JobHandwritingPlaybarBus:
|
||||
// 出发播放暂停
|
||||
var _val = e as JobHandwritingPlaybarBus;
|
||||
if (_val.play) {
|
||||
// 开始播放
|
||||
usePlaybar.playTimingStarts();
|
||||
if (!usePlaybar.playPause.value) {
|
||||
usePlaybar.playPause.value = true;
|
||||
}
|
||||
} else {
|
||||
// 暂停播放
|
||||
usePlaybar.playTimingSuspend();
|
||||
if (usePlaybar.playPause.value) {
|
||||
usePlaybar.playPause.value = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JobHandwritingGetReadyBus:
|
||||
// 作业笔迹已经计算好坐标 可以开始播放
|
||||
Future.delayed(Duration.zero, () => (usePlaybar.handWritingReady.value = true));
|
||||
break;
|
||||
case PlaybackSpeedBus:
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
return () {
|
||||
try {
|
||||
usePlaybar.eventCancel();
|
||||
usePlaybar.timer.value?.cancel();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return Container(
|
||||
height: 60.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||||
alignment: Alignment.center,
|
||||
color: Color.fromRGBO(0, 0, 0, 0.5),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (usePlaybar.handWritingReady.value)
|
||||
InkWell(
|
||||
onTap: () => easyThrottle('job_handwriting_play_pause', () {
|
||||
usePlaybar.playPause.value = !usePlaybar.playPause.value;
|
||||
usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value));
|
||||
}),
|
||||
child: Icon(
|
||||
!usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline,
|
||||
color: Colors.white,
|
||||
size: 28.r,
|
||||
),
|
||||
)
|
||||
else
|
||||
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(),
|
||||
|
||||
/// 进度条的最小值(默认为 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,
|
||||
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),
|
||||
InkWell(
|
||||
onTap: () => easyThrottle('job_handwriting_speed', () {
|
||||
var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value);
|
||||
if (theIndex == PlaybackSpeed.values.length - 1) {
|
||||
theIndex = -1;
|
||||
}
|
||||
usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1];
|
||||
}),
|
||||
child: Container(
|
||||
// alignment: Alignment.,
|
||||
padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
|
||||
decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)),
|
||||
child: quickText(
|
||||
'${usePlaybar.constantFastSpeed.value.name}',
|
||||
color: Color.fromRGBO(79, 114, 244, 1),
|
||||
size: 10.sp,
|
||||
align: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class UseBottomPlaybar with EventBusMixin {
|
||||
final ValueNotifier<int> handwritingDuration; // 笔迹总时长
|
||||
final ValueNotifier<bool> playPause; // 播放暂停
|
||||
final ValueNotifier<PlaybackSpeed> constantFastSpeed; // 原速、快速 默认原速
|
||||
final ValueNotifier<bool> handWritingReady;
|
||||
|
||||
final ValueNotifier<int> useTime; // 耗时 单位:(秒)
|
||||
|
||||
final ValueNotifier<Timer?> timer;
|
||||
|
||||
UseBottomPlaybar._(
|
||||
{required this.handWritingReady,
|
||||
required this.handwritingDuration,
|
||||
required this.playPause,
|
||||
required this.constantFastSpeed,
|
||||
required this.useTime,
|
||||
required this.timer});
|
||||
|
||||
// 工厂构造函数
|
||||
factory UseBottomPlaybar.use(int milliseconds) {
|
||||
int handwritingDuration = milliseconds ~/ 1000;
|
||||
if ((milliseconds % 1000) > 500) handwritingDuration += 1;
|
||||
return UseBottomPlaybar._(
|
||||
playPause: useState(false),
|
||||
constantFastSpeed: useState(PlaybackSpeed.ORIGINAL_SPEED),
|
||||
useTime: useState(handwritingDuration),
|
||||
timer: useState(null),
|
||||
handwritingDuration: useState(handwritingDuration),
|
||||
handWritingReady: useState(false),
|
||||
);
|
||||
}
|
||||
|
||||
/// 开始计时
|
||||
void playTimingStarts() {
|
||||
if (useTime.value > 0) {
|
||||
timer.value?.cancel();
|
||||
timer.value = Timer.periodic(Duration(seconds: 1), (theTime) {
|
||||
useTime.value -= 1;
|
||||
if (useTime.value < 0) {
|
||||
timer.value?.cancel();
|
||||
timer.value = null;
|
||||
useTime.value = handwritingDuration.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// 暂停
|
||||
void playTimingSuspend() {
|
||||
timer.value?.cancel();
|
||||
timer.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 播放按钮
|
||||
class JobHandwritingPlaybarBus {
|
||||
bool play;
|
||||
JobHandwritingPlaybarBus(this.play);
|
||||
}
|
||||
|
||||
// 笔迹是否已经准备好(笔迹计算好坐标后通知通知栏可以开始播放)
|
||||
class JobHandwritingGetReadyBus {
|
||||
JobHandwritingGetReadyBus();
|
||||
}
|
||||
|
||||
// 笔记运行时间
|
||||
class JobHandwritingRunTimeBus {
|
||||
int runTimeVal;
|
||||
int totalVal;
|
||||
JobHandwritingRunTimeBus(this.runTimeVal, this.totalVal);
|
||||
}
|
||||
|
||||
// 拖动进度条
|
||||
class JobHandwritingDragProgressBarBus {
|
||||
int changeVal;
|
||||
int totalVal;
|
||||
JobHandwritingDragProgressBarBus(this.changeVal, this.totalVal);
|
||||
}
|
||||
|
||||
// 播放速度 (原速播放/快速播放)
|
||||
class PlaybackSpeedBus {
|
||||
double speed;
|
||||
PlaybackSpeedBus(this.speed);
|
||||
}
|
||||
|
||||
// 播放倍速
|
||||
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);
|
||||
|
||||
const PlaybackSpeed({required this.name, required this.speed});
|
||||
final double speed;
|
||||
final String name;
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'my_time_util.g.dart';
|
||||
|
||||
// 毫秒转小时、分钟、秒的函数
|
||||
TimeUnitModel? convertMilliseconds(int milliseconds) {
|
||||
try {
|
||||
int hours = milliseconds ~/ (1000 * 60 * 60);
|
||||
int minutes = (milliseconds % (1000 * 60 * 60)) ~/ (1000 * 60);
|
||||
int seconds = (milliseconds % (1000 * 60)) ~/ 1000;
|
||||
|
||||
if ((milliseconds % 1000) > 500) seconds += 1;
|
||||
|
||||
return TimeUnitModel(hours, minutes, seconds);
|
||||
} catch (e) {
|
||||
print('时间转换报错');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 毫秒转小时、分钟、秒的函数
|
||||
TimeUnitModel? convertSeconds(int totalSeconds) {
|
||||
try {
|
||||
int hours = totalSeconds ~/ 3600; // 整除3600得到小时数
|
||||
int remainingSeconds = totalSeconds % 3600; // 取模3600得到剩余的秒数
|
||||
int minutes = remainingSeconds ~/ 60; // 整除60得到分钟数
|
||||
int seconds = remainingSeconds % 60; // 取模60得到最终的秒数
|
||||
|
||||
return TimeUnitModel(hours, minutes, seconds);
|
||||
} catch (e) {
|
||||
print('时间转换报错');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class TimeUnitModel extends Object {
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
TimeUnitModel(this.hours, this.minutes, this.seconds);
|
||||
|
||||
factory TimeUnitModel.fromJson(Map<String, dynamic> srcJson) => _$TimeUnitModelFromJson(srcJson);
|
||||
|
||||
Map<String, dynamic> toJson() => _$TimeUnitModelToJson(this);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var timeStr = '';
|
||||
if (hours > 0) {
|
||||
timeStr += '${hours > 9 ? hours : '0' + hours.toString()} ';
|
||||
}
|
||||
if (minutes > 0) {
|
||||
timeStr += '${minutes > 9 ? minutes : '0' + minutes.toString()}';
|
||||
}
|
||||
|
||||
if (timeStr.length > 0) {
|
||||
timeStr += ':${seconds > 9 ? seconds : '0' + seconds.toString()}';
|
||||
} else {
|
||||
timeStr += '00:${seconds > 9 ? seconds : '0' + seconds.toString()}';
|
||||
}
|
||||
|
||||
return timeStr;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import 'package:marking_app/common/model/job/job_data_report.dart';
|
|||
import 'package:marking_app/common/model/job/job_do_marking_status_info.dart';
|
||||
import 'package:marking_app/common/model/job/job_fav_student.dart';
|
||||
import 'package:marking_app/common/model/job/job_favorite_model.dart';
|
||||
import 'package:marking_app/common/model/job/job_handwriting.dart';
|
||||
import 'package:marking_app/common/model/job/job_knowledge_detail_student.dart';
|
||||
import 'package:marking_app/common/model/job/job_knowledge_points.dart';
|
||||
import 'package:marking_app/common/model/job/job_knowledge_points_detail.dart';
|
||||
|
|
@ -74,8 +75,7 @@ abstract class RestClient {
|
|||
|
||||
// 最新版本
|
||||
@the_retrofit.GET("/api/version/latest?mobileTypeEnum={mobileTypeEnum}")
|
||||
Future<BaseStructureResult<SystemVersion>> getLatestVersion(
|
||||
@the_retrofit.Path("mobileTypeEnum") int mobileTypeEnum); // 1 安卓 2 ios
|
||||
Future<BaseStructureResult<SystemVersion>> getLatestVersion(@the_retrofit.Path("mobileTypeEnum") int mobileTypeEnum); // 1 安卓 2 ios
|
||||
|
||||
// 用户登录 /auth/login/exam-marking/user-mobile
|
||||
@the_retrofit.POST("/auth/login/exam-marking/user")
|
||||
|
|
@ -91,8 +91,7 @@ abstract class RestClient {
|
|||
|
||||
// 阅卷列表 => 分页获取
|
||||
@the_retrofit.GET("/api/marking/list")
|
||||
Future<BaseStructureResult<BasePageData<MarkingItem>>> getMarkingsByPage(
|
||||
@the_retrofit.Queries() MarkingListParams params);
|
||||
Future<BaseStructureResult<BasePageData<MarkingItem>>> getMarkingsByPage(@the_retrofit.Queries() MarkingListParams params);
|
||||
|
||||
// /api/marking/list
|
||||
|
||||
|
|
@ -117,13 +116,11 @@ abstract class RestClient {
|
|||
|
||||
// 阅卷 => 获取考试试题
|
||||
@the_retrofit.GET("/api/marking/question")
|
||||
Future<BaseStructureResult<MarkingTextQuestion>> getTestQuestionsOfExam(
|
||||
@the_retrofit.Queries() MarkingTextQuestionParams params);
|
||||
Future<BaseStructureResult<MarkingTextQuestion>> getTestQuestionsOfExam(@the_retrofit.Queries() MarkingTextQuestionParams params);
|
||||
|
||||
// 阅卷 => 获取考试tab(试题批次)
|
||||
@the_retrofit.GET("/api/marking/{markingUserId}/tab")
|
||||
Future<BaseStructureResult<List<MarkingTextQuestionTab>>> getTestQuestionsOfTab(
|
||||
@the_retrofit.Path("markingUserId") int markingUserId);
|
||||
Future<BaseStructureResult<List<MarkingTextQuestionTab>>> getTestQuestionsOfTab(@the_retrofit.Path("markingUserId") int markingUserId);
|
||||
|
||||
// 阅卷 => 单个试题Tag阅卷详情
|
||||
@the_retrofit.GET("/api/marking/{markingUserId}/progress")
|
||||
|
|
@ -137,16 +134,15 @@ abstract class RestClient {
|
|||
|
||||
// 阅卷 => 获取考试tab下某次试题
|
||||
@the_retrofit.GET("/api/marking/{markingUserId}/detail")
|
||||
Future<BaseStructureResult<MarkingTextQuestion>> getTabOfExam(@the_retrofit.Path("markingUserId") int markingUserId,
|
||||
@the_retrofit.Queries() MarkingTextQuestionTabParams params);
|
||||
Future<BaseStructureResult<MarkingTextQuestion>> getTabOfExam(
|
||||
@the_retrofit.Path("markingUserId") int markingUserId, @the_retrofit.Queries() MarkingTextQuestionTabParams params);
|
||||
|
||||
// 阅卷 => 提交考试试题
|
||||
@the_retrofit.PUT("/api/marking")
|
||||
Future<BaseStructureResult<bool>> submitTestQuestionsOfExam(@the_retrofit.Body() SubmitExamParams params);
|
||||
|
||||
@the_retrofit.PUT("/api/marking/error")
|
||||
Future<BaseStructureResult<bool>> submitTestQuestionsOfExamAbnormal(
|
||||
@the_retrofit.Body() SubmitExamAbnormalParams params);
|
||||
Future<BaseStructureResult<bool>> submitTestQuestionsOfExamAbnormal(@the_retrofit.Body() SubmitExamAbnormalParams params);
|
||||
|
||||
// 阅卷 => 提交考试试题
|
||||
@the_retrofit.PUT("/api/marking/review")
|
||||
|
|
@ -158,8 +154,7 @@ abstract class RestClient {
|
|||
|
||||
// 阅卷 => 结束阅卷
|
||||
@the_retrofit.GET("/api/marking/original-paper")
|
||||
Future<BaseStructureResult<List<String>>> getViewOriginalVolume(
|
||||
@the_retrofit.Query("markingUserDetailId") String markingUserDetailId);
|
||||
Future<BaseStructureResult<List<String>>> getViewOriginalVolume(@the_retrofit.Query("markingUserDetailId") String markingUserDetailId);
|
||||
|
||||
// 阅卷 => 查看答案
|
||||
@the_retrofit.GET("/api/marking/answer")
|
||||
|
|
@ -185,25 +180,21 @@ abstract class RestClient {
|
|||
|
||||
// 阅卷 => 获取异常详细信息
|
||||
@the_retrofit.GET("/api/marking/error-info")
|
||||
Future<BaseStructureResult<ExceptionInfo>> getMarkingQuestionsErrorInfo(
|
||||
@the_retrofit.Query("markingUserDetailId") int id);
|
||||
Future<BaseStructureResult<ExceptionInfo>> getMarkingQuestionsErrorInfo(@the_retrofit.Query("markingUserDetailId") int id);
|
||||
|
||||
// 阅卷 => 获取仲裁详细信息
|
||||
@the_retrofit.GET("/api/marking/history-score")
|
||||
Future<BaseStructureResult<List<HistoricalScoring>>> getArbitrateOfHistoryScore(
|
||||
@the_retrofit.Query("markingUserDetailId") int id);
|
||||
Future<BaseStructureResult<List<HistoricalScoring>>> getArbitrateOfHistoryScore(@the_retrofit.Query("markingUserDetailId") int id);
|
||||
|
||||
// 阅卷 => 获取仲裁详细信息
|
||||
@the_retrofit.GET("/api/marking/rating-info")
|
||||
Future<BaseStructureResult<List<RatingProgressModel>>> getMarkingRatingInfo(
|
||||
@the_retrofit.Query("markingUserId") int id);
|
||||
Future<BaseStructureResult<List<RatingProgressModel>>> getMarkingRatingInfo(@the_retrofit.Query("markingUserId") int id);
|
||||
|
||||
// ------------------------------------------ 作业 ------------------------------------------
|
||||
|
||||
// 作业 => 作业列表
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task")
|
||||
Future<BaseStructureResult<BasePageData<JobTaskItem>>> getJobsByPage(
|
||||
@the_retrofit.Queries() MarkingListParams params);
|
||||
Future<BaseStructureResult<BasePageData<JobTaskItem>>> getJobsByPage(@the_retrofit.Queries() MarkingListParams params);
|
||||
|
||||
// 作业 => 批改获取tabs
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/tabs")
|
||||
|
|
@ -211,13 +202,11 @@ abstract class RestClient {
|
|||
|
||||
// 作业 => 批改获取tabs
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Marking/students")
|
||||
Future<BaseStructureResult<List<JobConcernedWithStudent>>> getJobWithStudents(
|
||||
@the_retrofit.Queries() JobConcernedWithStudentParams params);
|
||||
Future<BaseStructureResult<List<JobConcernedWithStudent>>> getJobWithStudents(@the_retrofit.Queries() JobConcernedWithStudentParams params);
|
||||
|
||||
// 作业 => 获取考试tab下某次试题
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/detail")
|
||||
Future<BaseStructureResult<MarkingTextQuestionJob>> getJobTabOfExam(
|
||||
@the_retrofit.Queries() MarkingTextQuestionJobTabParams params);
|
||||
Future<BaseStructureResult<MarkingTextQuestionJob>> getJobTabOfExam(@the_retrofit.Queries() MarkingTextQuestionJobTabParams params);
|
||||
|
||||
// 作业 => 提交
|
||||
@the_retrofit.POST("${RequestConfig.hwProxyKeywords}/api/Task")
|
||||
|
|
@ -229,8 +218,7 @@ abstract class RestClient {
|
|||
|
||||
// 作业 => 获取考试tab下某次试题
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/questions")
|
||||
Future<BaseStructureResult<BasePageData<ReviewItem>>> toGoreviewAgainPage(
|
||||
@the_retrofit.Queries() ReviewAgainListParams params);
|
||||
Future<BaseStructureResult<BasePageData<ReviewItem>>> toGoreviewAgainPage(@the_retrofit.Queries() ReviewAgainListParams params);
|
||||
|
||||
// 作业 => 获取参考答案
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/answer")
|
||||
|
|
@ -241,8 +229,7 @@ abstract class RestClient {
|
|||
|
||||
// 作业 => 上传图片请求参数
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Upload")
|
||||
Future<BaseStructureResult<UploadFileInterfaceConfig>> getUploadFile(
|
||||
@the_retrofit.Queries() UploadFileInterfaceConfigParams params);
|
||||
Future<BaseStructureResult<UploadFileInterfaceConfig>> getUploadFile(@the_retrofit.Queries() UploadFileInterfaceConfigParams params);
|
||||
|
||||
// 作业 => 获取参考答案
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Dpc/studentAnswerHandwriting")
|
||||
|
|
@ -251,18 +238,16 @@ abstract class RestClient {
|
|||
|
||||
// 作业 => 查询作业是否收藏
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Dpc/collect")
|
||||
Future<BaseStructureResult<bool>> getJobCollect(@the_retrofit.Query("taskId") int taskId,
|
||||
@the_retrofit.Query("studentId") int studentId, @the_retrofit.Query("paperId") int paperId);
|
||||
Future<BaseStructureResult<bool>> getJobCollect(
|
||||
@the_retrofit.Query("taskId") int taskId, @the_retrofit.Query("studentId") int studentId, @the_retrofit.Query("paperId") int paperId);
|
||||
|
||||
// 作业 => 作业优先批阅取消
|
||||
@the_retrofit.POST("/api/read/cancel-job-read-level")
|
||||
Future<BaseStructureResult<bool>> jobPriorityReviewCancel(
|
||||
@the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId);
|
||||
Future<BaseStructureResult<bool>> jobPriorityReviewCancel(@the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId);
|
||||
|
||||
// 作业 => 作业优先批阅加入
|
||||
@the_retrofit.POST("/api/read/join-read-level")
|
||||
Future<BaseStructureResult> jobPriorityReviewJoin(
|
||||
@the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId);
|
||||
Future<BaseStructureResult> jobPriorityReviewJoin(@the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId);
|
||||
|
||||
// 作业 => 查询作业是否收藏
|
||||
@the_retrofit.POST("${RequestConfig.hwProxyKeywords}/api/Dpc/collect")
|
||||
|
|
@ -297,13 +282,11 @@ abstract class RestClient {
|
|||
|
||||
// 作业 => 列表 ==> 参与班级列表
|
||||
@the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/tasks")
|
||||
Future<BaseStructureResult<List<MarkingTasks>>> getJobListParticipateInClass(
|
||||
@the_retrofit.Query("markingId") int jobId);
|
||||
Future<BaseStructureResult<List<MarkingTasks>>> getJobListParticipateInClass(@the_retrofit.Query("markingId") int jobId);
|
||||
|
||||
// 作业 => 作业收藏数量
|
||||
@the_retrofit.GET("/dpc-api/api/read/job-favorite-count-by-class")
|
||||
Future<BaseStructureResult<List<JobFavoriteModel>>> getListOfJobFavoriteNumber(
|
||||
@the_retrofit.Query("jobid") int jobId);
|
||||
Future<BaseStructureResult<List<JobFavoriteModel>>> getListOfJobFavoriteNumber(@the_retrofit.Query("jobid") int jobId);
|
||||
|
||||
// 作业 => 作业收藏列表
|
||||
@the_retrofit.GET("/api/jobs/fav-student-jobs")
|
||||
|
|
@ -316,13 +299,11 @@ abstract class RestClient {
|
|||
|
||||
// 作业 => 作业收藏列表
|
||||
@the_retrofit.POST("${RequestConfig.hwProxyKeywords}/dpc-api/api/read/cancel-favorite")
|
||||
Future<BaseStructureResult<bool>> toJobCancelFavorite(
|
||||
@the_retrofit.Field() int jobId, @the_retrofit.Field() int studentId);
|
||||
Future<BaseStructureResult<bool>> toJobCancelFavorite(@the_retrofit.Field() int jobId, @the_retrofit.Field() int studentId);
|
||||
|
||||
// 作业 => 数据快查
|
||||
@the_retrofit.GET("/api/read/job-data-center-report")
|
||||
Future<BaseStructureResult<JobDataReport>> getJobDataCenterReport(
|
||||
@the_retrofit.Queries() Map<String, dynamic> params);
|
||||
Future<BaseStructureResult<JobDataReport>> getJobDataCenterReport(@the_retrofit.Queries() Map<String, dynamic> params);
|
||||
|
||||
// 作业 => 数据快查--个人
|
||||
@the_retrofit.GET("/api/read/job-data-center-student-report")
|
||||
|
|
@ -330,8 +311,7 @@ abstract class RestClient {
|
|||
|
||||
// 作业 => 优先批阅,学生分组列表
|
||||
@the_retrofit.GET("/api/read/job-read-level-student-groups")
|
||||
Future<BaseStructureResult<List<JobStudentGroups>>> getJobLevelStudentGroups(
|
||||
@the_retrofit.Query("account") String account);
|
||||
Future<BaseStructureResult<List<JobStudentGroups>>> getJobLevelStudentGroups(@the_retrofit.Query("account") String account);
|
||||
|
||||
// 作业 => 优先批阅,优先批阅列表
|
||||
@the_retrofit.GET("/api/read/job-read-level")
|
||||
|
|
@ -344,8 +324,8 @@ abstract class RestClient {
|
|||
|
||||
// 作业 => 取消收藏
|
||||
@the_retrofit.POST("/api/jobs/de-fav-student-job")
|
||||
Future<BaseStructureResult> getJobDeFavorites(@the_retrofit.Field("jobId") int jobId,
|
||||
@the_retrofit.Field("studentId") int studentId, @the_retrofit.Field("questionPage") int questionPage);
|
||||
Future<BaseStructureResult> getJobDeFavorites(
|
||||
@the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId, @the_retrofit.Field("questionPage") int questionPage);
|
||||
|
||||
// 作业 => 学生作业详情历史
|
||||
@the_retrofit.GET("/api/read/student-job-history")
|
||||
|
|
@ -384,4 +364,13 @@ abstract class RestClient {
|
|||
@the_retrofit.Path("sectionid") int questionid,
|
||||
@the_retrofit.Path("questionno") String questionno,
|
||||
);
|
||||
|
||||
// 作业 => 获取学生原稿笔记
|
||||
@the_retrofit.GET("/api/jobs/student-paper-handwriting")
|
||||
Future<BaseStructureResult<JobHandwriting>?> getHandwriting(
|
||||
@the_retrofit.Query("jobId") int jobId,
|
||||
@the_retrofit.Query("studentId") int studentId,
|
||||
@the_retrofit.Query("questionNo") int? questionNo,
|
||||
@the_retrofit.Query("pageNum") int? pageNum,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue