Marking.Client.Moblie/marking_app/lib/pages/marking/do_papers.dart

2836 lines
134 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: wangyang 1147192855@qq.com
* @Date: 2022-07-22 09:43:24
* @LastEditors: wangyang 1147192855@qq.com
* @LastEditTime: 2022-09-29 10:18:53
* @FilePath: \marking_app\lib\pages\marking\marking_papers.dart
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import 'dart:async';
import 'dart:convert';
import 'package:awesome_dialog/awesome_dialog.dart';
import 'package:achievement_view/achievement_view.dart';
import 'package:collection/collection.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:fluttertoast/fluttertoast.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/common/base_structure_result.dart';
import 'package:marking_app/common/model/common/upload_img_secret_key.dart';
import 'package:marking_app/common/model/enum/KeyboardType.dart';
import 'package:marking_app/common/model/enum/marking_list_type.dart';
import 'package:marking_app/common/model/marking/current_review_task.dart';
import 'package:marking_app/common/model/marking/do_marking_keyboard_model.dart';
import 'package:marking_app/common/model/marking/keyboard_assist_event.dart';
import 'package:marking_app/common/model/marking/marking_tag_single_params.dart';
import 'package:marking_app/common/model/marking/marking_text_question.dart';
import 'package:marking_app/common/model/marking/marking_text_question_params.dart';
import 'package:marking_app/common/model/marking/marking_text_question_tab.dart';
import 'package:marking_app/common/model/marking/marking_text_question_tab_params.dart';
import 'package:marking_app/common/model/marking/marking_text_question_tab_step_size.dart';
import 'package:marking_app/common/model/marking/marking_zoom.dart';
import 'package:marking_app/common/model/marking/submit_exam_abnormal_params.dart';
import 'package:marking_app/common/model/marking/submit_exam_params.dart';
import 'package:marking_app/common/model/marking/submit_exam_small_params.dart';
import 'package:marking_app/common/model/marking/switch_keyboard_to_reload_images.dart';
import 'package:marking_app/components/PictureOverview.dart';
import 'package:marking_app/components/marking/marking_keyboard_switch.dart';
import 'package:marking_app/components/marking/marking_question_type_drawer.dart';
import 'package:marking_app/components/marking/marking_seting.dart';
import 'package:marking_app/components/marking/marking_seting_main.dart';
import 'package:marking_app/components/marking/review_records_view.dart';
import 'package:marking_app/components/marking/selectable_keyboard_bottom.dart';
import 'package:marking_app/pages/common/event_bus_mixin.dart';
import 'package:marking_app/pages/marking/hooks/use_zoomImage_history_utils.dart';
import 'package:marking_app/pages/marking/provider/rating_progress_provider.dart';
import 'package:marking_app/provider/annotation_graffiti_switch_provider.dart';
import 'package:marking_app/provider/do_marking_provider.dart';
import 'package:marking_app/provider/review_provider.dart';
import 'package:marking_app/routes/RouterManager.dart';
import 'package:marking_app/utils/image/gallery_example_item_model.dart';
import 'package:marking_app/utils/image/image_utils.dart';
import 'package:marking_app/utils/index.dart';
import 'package:marking_app/components/marking/Input_keyboard_guide_page.dart';
import 'package:marking_app/utils/my_text.dart';
import 'package:marking_app/utils/request/rest_client.dart';
import 'package:percent_indicator/percent_indicator.dart';
import 'package:wakelock/wakelock.dart';
import 'hooks/use_abnormal.dart';
part 'do_papers.g.dart';
class DoPapers extends StatefulHookConsumerWidget {
final int markingUserId;
final MarkingListType? markingtype;
int markingUserDetailId; // 回评需要 其他不需要
final int examSubjectId;
final int pageOper; // 0下一题1上一题2当前题
final bool isReview; // false正常 true回评
final bool exceptional; // 是否是异常处理
final String? questionNum;
DoPapers(this.markingUserId,
{required this.examSubjectId,
this.markingtype,
this.questionNum,
this.markingUserDetailId = 0,
this.pageOper = 2,
this.exceptional = false,
required this.isReview,
Key? key})
: super(key: key);
@override
_MarkingPapersState createState() => _MarkingPapersState();
}
class _MarkingPapersState extends ConsumerState<DoPapers>
with CommonMixin, EventBusMixin<KeyboardAssistEvent>, EventBusMixinSub<SwitchKeyboardToReloadImages> {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
double imageScale = 1;
Offset? imagePosition;
late bool firstComeIn = true; // 是否第一次进入
MarkingTextQuestion? currentQuestion; // 当前试题
MarkingTextQuestionTab? _currentTab; // 当前选中tab
// late ValueNotifier<MarkingTextQuestionTab?> _currentTabValueNotifier;
List<MarkingTextQuestionTab> _currentTabs = []; // 当前考试tab集合
late MarkingTextQuestionParams params; // 获取试题参数
late MarkingTextQuestionTabParams tabParams; // tba的方式获取试题参数
bool showSetingFlag = false; // 关闭设置
late Future<MarkingTextQuestion?> _future; // 考试试卷
int activeQuestIndex = 0; // 选中题号
String questScore = ''; // 打分值
bool hasZeroPointFive = false; // 是否可以评分(已经满分了就不可更改了)
bool showSubtopicArea = true;
late Offset keyboardOrigin; // 键盘滑动起始坐标
late Offset keyboarddestination; // 键盘滑动截止坐标
bool showAbnormal = false; // 是否显示异常区域
bool needRefresh = false; // 是否需要外不刷新
bool theRequesting = false; // 正在发起请求
String? standardAnswers; // 标准答案
bool showStandardAnswer = false; // 显示标准答案
bool inputKeyboardGuidePage = false; // 输入型键盘引导页
bool setingOperation = false; // 设置操作页
late RemoveListener _markingKeyboardListener;
bool _theOldAnnotationGraffiti = false;
late RemoveListener _annotationGraffitiListener;
DoMarkingKeyboardModel? keyboardModel; // 键盘阅卷偏好
bool annotationsFlag = false; // 批注开关
// int theExamIndex = 0; // tab模式下计算当前试题所在位置
late FToast fToast;
bool _completionPrompt = false; // 全部试题完成并提示
bool _completionPromptTab = false; // tab下试题完成并提示
bool _reviewCompletedPrompted = false; // 已经批阅完成提示
// bool _switchQueTypePrompt = false; // 切换题型
// void _cruuentTabListenerCall() {
// // 监听当前试题类型切换后就更新 已经提示旗帜
// print('更新是否切换试题提示');
// _switchQueTypePrompt = false;
// }
@override
void initState() {
super.initState();
Wakelock.enable(); // 常亮
fToast = FToast();
// _currentTabValueNotifier = ValueNotifier(_currentTab)..addListener(_cruuentTabListenerCall);
// if you want to use context from globally instead of content we need to pass navigatorKey.currentContext!
fToast.init(context);
Future.delayed(const Duration(seconds: 0)).then((onValue) {
ref.read(annotationGraffitiSwitchProvider.notifier).init();
});
// 批注监听
_annotationGraffitiListener = ref.read(annotationGraffitiSwitchProvider.notifier).addListener((state) {
var oldState = _theOldAnnotationGraffiti;
_theOldAnnotationGraffiti = state.annotationSwitch;
if (oldState != state.annotationSwitch) {
toUpState(setState, () {}, mounted);
}
}, fireImmediately: false);
// 键盘阅卷偏好监听
_markingKeyboardListener = ref.read(markingKeyboardProvider.notifier).addListener((state) {
print('进入阅卷偏好监听.................');
if (keyboardModel == null) {
screenDirectionSwitch(state.screenDirection);
} else {
ScreenDirection nowScreenDirection = state.screenDirection; // 当前屏幕方向
ScreenDirection theOrientation = MediaQuery.of(context).orientation == Orientation.landscape
? ScreenDirection.HORIZONTAL_SCREEN
: ScreenDirection.VERTICAL_SCREEN;
if (theOrientation != nowScreenDirection) {
screenDirectionSwitch(nowScreenDirection);
}
}
keyboardModel = state;
inputKeyboardGuidePage = state.guidePageDisplay && state.keyboard == KeyboardType.INPUT_TYPE; // 引导页标志配置
toUpState(setState, () {}, mounted);
setTimeOut(300, () {
eventFireSub(model: SwitchKeyboardToReloadImages(true));
});
});
params = MarkingTextQuestionParams(
pageType: widget.markingtype?.index,
markingUserId: widget.markingUserId,
markingUserDetailId: widget.markingUserDetailId,
type: widget.pageOper,
isReview: widget.isReview,
);
tabParams = MarkingTextQuestionTabParams(
// pageType: widget.markingtype?.index,
markingUserId: widget.markingUserId,
questionNum: _currentTab?.questionNum,
markingUserDetailId: 0,
// type: widget.pageOper,
// isExcess: _currentTab?.isExcess ?? false,
// examSubjectId: widget.examSubjectId,
);
_future = getData(tabQuestionNum: widget.questionNum);
}
@override
void dispose() {
FastData.getInstance().cleanMarkingKeyboardSlidingPosition();
FastData.getInstance().cleanMarkingMarkingZoomInfo();
exitQuestion();
super.dispose();
// _currentTabValueNotifier
// ..removeListener(_cruuentTabListenerCall)
// ..dispose();
_markingKeyboardListener();
_annotationGraffitiListener();
// ref.read(annotationGraffitiSwitchProvider.notifier).init();
eventCancel();
Wakelock.disable();
if (keyboardModel?.screenDirection == ScreenDirection.HORIZONTAL_SCREEN) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); // 强制竖屏
}
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]);
}
Future<void> exitQuestion() async {
FastData.getInstance().cleanMarkingPapersImageZoom(); // 清空当前图片放大缩小位置方向
RestClient client = await getClient();
client.exitMarking(widget.markingUserId);
}
// 屏幕切换方向
void screenDirectionSwitch(ScreenDirection direction) {
annotationsFlag = false; // 屏幕方向切换,重新计算批注组件尺寸
toUpState(setState, () {}, mounted);
bool isHorizontal = direction == ScreenDirection.HORIZONTAL_SCREEN;
Future.delayed(Duration.zero, () {
SystemChrome.setPreferredOrientations(
[isHorizontal ? DeviceOrientation.landscapeLeft : DeviceOrientation.portraitUp]);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
setTimeOut(1000, () => toUpState(setState, () => annotationsFlag = true, mounted));
});
}
// 获取整卷数据
Future<List<GalleryExampleItemModel>?> getViewOriginal(String markingUserDetailId) async {
RestClient client = await getClient();
BaseStructureResult<List<String>> result = await client.getViewOriginalVolume(markingUserDetailId);
List<String>? paperUrls = result.data;
if (!result.success || paperUrls == null || paperUrls.isEmpty) {
ToastUtils.showError(!result.success ? "获取原试卷失败" : "没有获取到原试卷");
return null;
}
currentQuestion!.papersUrlStr = paperUrls;
currentQuestion!.papersUrl =
paperUrls.asMap().keys.map((e) => GalleryExampleItemModel(id: e.toString(), resource: paperUrls[e])).toList();
return currentQuestion!.papersUrl;
}
// 查看整卷
void viewEntireVolume(BuildContext context) {
toUpState(setState, () => showSetingFlag = false, mounted);
int? markingUserDetailId = currentQuestion?.id;
if (markingUserDetailId == null) return;
if (currentQuestion!.papersUrlStr == null) {
getViewOriginal(markingUserDetailId.toString()).then((List<GalleryExampleItemModel>? value) {
if (value == null) return;
Navigator.push(
this.context,
MaterialPageRoute(
builder: (context) => GalleryPhotoViewWrapper(
galleryItems: value,
backgroundDecoration: const BoxDecoration(color: Colors.black),
initialIndex: 0,
scrollDirection: Axis.vertical,
),
),
);
});
return;
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GalleryPhotoViewWrapper(
galleryItems: currentQuestion!.papersUrl,
backgroundDecoration: const BoxDecoration(color: Colors.black),
initialIndex: 0,
scrollDirection: Axis.vertical,
),
),
);
}
// 查看答案
void viewAnswer() async {
String? questionNum = currentQuestion?.questionNum;
if (questionNum == null) return;
try {
EasyLoading.show(status: 'loading...');
RestClient client = await getClient();
BaseStructureResult<String> result = await client.getStandardAnswer(widget.examSubjectId, questionNum);
if (!result.success) {
throw Exception(result.message ?? '查看答案请求失败');
}
if ((result.data?.length ?? 0) <= 0) {
return ToastUtils.showError('该题暂未设置标准答案');
}
toUpState(setState, () {
standardAnswers = result.data;
showStandardAnswer = true;
}, mounted);
} catch (e) {
ToastUtils.showError('查看答案请求失败');
} finally {
toUpState(setState, () => showSetingFlag = false, mounted);
EasyLoading.dismiss();
}
}
// 发起异常
void initiateException(flag, reasonKey, otherReasons) async {
final timer = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading());
try {
if (!flag) {
toUpState(setState, () => showAbnormal = false, mounted);
return;
}
int? detailId = currentQuestion?.id;
if (detailId == null) {
ToastUtils.getFluttertoast(context: context, msg: '没有必须参数,请退出重试');
toUpState(setState, () => showAbnormal = false, mounted);
return;
}
if (currentQuestion!.completeRating) {
ToastUtils.getFluttertoast(context: context, msg: '已批阅,不可提交异常题');
toUpState(setState, () => showAbnormal = false, mounted);
return;
}
if (currentQuestion!.isException) {
ToastUtils.getFluttertoast(context: context, msg: '此题已异常题,不可重复提交');
toUpState(setState, () => showAbnormal = false, mounted);
return;
}
// 上传批注图片
// FileResult? res = await pictureOverviewKey.currentState?.saveImage();
// if (res != null && res.url != null) {
// currentQuestion!.setImageList(res.url!, res.otherParam as int);
// }
// String? commentImageUrlStr;
// List<String>? commentImageUrl = currentQuestion?.commentImageUrlTodo;
// if (commentImageUrl?.isEmpty ?? true) commentImageUrl = currentQuestion?.commentImageUrl;
// if (commentImageUrl != null) commentImageUrlStr = jsonEncode(commentImageUrl);
RestClient client = await getClient();
BaseStructureResult<bool> result = await client.submitTestQuestionsOfExamAbnormal(SubmitExamAbnormalParams(
errorType: int.parse(reasonKey),
markingUserDetailId: detailId,
markingUserId: widget.markingUserId,
reason: otherReasons ?? '',
));
if (result.success && (result.data ?? false)) {
toUpState(setState, () {
currentQuestion!.isException = true;
showAbnormal = false;
if (!needRefresh) needRefresh = true; // 是否刷新外部任务
}, mounted);
if (_currentTab != null) {
await getTabsData(updateCurrentTag: true); // 更新当前tag
}
MarkingTextQuestionTab tab = await getTabsData(hasNext: true, firstWhereCall: (e) => !e.isFinished);
if (tab.questionNum == '0.0') {
toUpState(setState, () => {_currentTab?.percent = 1}, mounted);
// 非tag试题提示
if (currentQuestion!.lastOne) {
// 最后一题需要提示
return showExitDialog();
}
}
if (currentQuestion?.lastOne ?? false) {
ToastUtils.dismiss();
bool? isGoOn = await _showExitDialogOfTag(context: context);
if (isGoOn == true) setTimeOut(0, () => _future = getData(tabQuestionNum: tab.questionNum));
return;
}
// 自动进入下一题
if (ref.read(markingKeyboardProvider).autoSubmitToNextQuestion) {
ToastUtils.showSuccess('提交成功');
refresh(isNext: true);
} else {
ToastUtils.showSuccess('评阅提交成功,请手动前往下一题', duration: const Duration(milliseconds: 400));
}
return;
}
toUpState(setState, () => showAbnormal = false, mounted);
ToastUtils.showError('提交失败');
} finally {
// 关闭批注操作工具栏
ref.read(annotationGraffitiSwitchProvider.notifier).setSwitch(false);
timer.cancel();
ToastUtils.dismiss();
}
}
// 提交试题
Future<void> submitTestQuestions(BuildContext theContext, MarkingTextQuestion data) async {
Timer timer = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading());
try {
if (widget.markingtype == MarkingListType.NORMAL && currentQuestion!.isException)
return ToastUtils.showError('异常题,不允许再评分');
if (currentQuestion == null) {
return ToastUtils.showError('提交失败,请退出重试。');
}
// 上传批注图片
FileResult? res = await pictureOverviewKey.currentState?.saveImage();
if (res != null && res.url != null) {
currentQuestion!.setImageList(res.url!, res.otherParam as int);
}
int detailId = currentQuestion!.id;
List<SubmitExamSmallParams> subQuestinDetails = [];
List<SubQuestions> subQuestionDetailList = currentQuestion!.subQuestionDetailList;
bool hasSubtopic = subQuestionDetailList.isNotEmpty; //是否有小题
double score = 0;
if (hasSubtopic) {
// 有小题 小题处理
for (SubQuestions item in subQuestionDetailList) {
double? gotScore = item.subQuestionGotScore;
bool completeRating = item.completeRating;
if (gotScore == null || !completeRating) {
return ToastUtils.getFluttertoast(context: theContext, msg: '小题题号:${item.subQuestionNum}未评分,请评阅分数');
}
score += gotScore;
subQuestinDetails.add(SubmitExamSmallParams(item.subQuestionNum, item.subQuestionScore, gotScore, true));
}
} else {
// 没有小题
if (!currentQuestion!.completeRating || currentQuestion!.score == null) {
return ToastUtils.getFluttertoast(context: theContext, msg: '请为此题评阅分数');
}
score += currentQuestion!.score!;
}
RestClient client = await getClient();
String? commentImageUrlStr;
List<String>? commentImageUrl = currentQuestion?.commentImageUrlTodo;
if (commentImageUrl?.isEmpty ?? true) commentImageUrl = currentQuestion?.commentImageUrl;
if (commentImageUrl?.isNotEmpty ?? false) commentImageUrlStr = jsonEncode(commentImageUrl);
// bool excessContinue =
// _currentTab?.agreementExcess == null ? true : _currentTab!.agreementExcess!; // 如果没有询问默认为true 如果询问了 就已询问为主
bool isExit = false;
MarkingTextQuestionTab? nextTag;
BaseStructureResult<bool> result = await client.submitTestQuestionsOfExam(SubmitExamParams(
widget.markingUserId,
detailId,
score: score,
isReview: widget.isReview,
subQuestionDetailList: subQuestinDetails,
commentImageUrl: commentImageUrlStr ?? '',
questionNum: _currentTab?.questionNum,
isExcess: _currentTab?.isExcess ?? false,
// excessContinue: excessContinue,
pageType: widget.markingtype?.index,
));
if (!result.success || !(result.data ?? false)) {
return setTimeOut(300, () => ToastUtils.showError(result.message ?? '提交失败,请退出重试。'));
}
// toUpState(setState, () {
// if (!needRefresh) needRefresh = true;
// // 处理已提交字段
// currentQuestion!.isFinish = true; // 已提交
// if (hasSubtopic) {
// for (var e in subQuestionDetailList) {
// e.isFinish = true;
// }
// }
// // toScoreFlag = false; // 每次提交后是否需要关闭打分键盘
// }, mounted);
if (!needRefresh) needRefresh = true;
// 处理已提交字段
currentQuestion!.isFinish = true; // 已提交
if (hasSubtopic) {
for (var e in subQuestionDetailList) {
e.isFinish = true;
}
}
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text('得分$score'),
// duration: const Duration(seconds: 2),
// ),
// );
// // 自动进入下一题
// Fluttertoast.showToast(
// timeInSecForIosWeb: 2,
// msg: getDoubleRemoveZero(score),
// toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.BOTTOM,
// fontSize: 140.sp,
// textColor: Colors.red,
// backgroundColor: Colors.transparent,
// );
fToast.showToast(
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
),
child: quickText(getDoubleRemoveZero(score), color: Colors.red, size: 140.sp)),
gravity: ToastGravity.BOTTOM,
toastDuration: Duration(seconds: 1),
);
if (_currentTab != null) {
await getTabsData(updateCurrentTag: true); // 更新当前tag
}
MarkingTextQuestionTab tab = await getTabsData(hasNext: true, firstWhereCall: (e) => !e.isFinished);
if (tab.questionNum == '0.0') {
toUpState(setState, () => {_currentTab?.percent = 1}, mounted);
// 非tag试题提示
if (currentQuestion!.lastOne) {
// 最后一题需要提示
return showExitDialog();
}
}
if (_currentTab != null) {
if (data.lastOne) {
timer.cancel();
ToastUtils.dismiss();
bool? isGoOn = await _showExitDialogOfTag(context: context);
if (isGoOn == true) setTimeOut(0, () => _future = getData(tabQuestionNum: tab.questionNum));
return;
}
}
if (ref.read(markingKeyboardProvider).autoSubmitToNextQuestion) {
refresh(isNext: true);
} else {
ToastUtils.showSuccess('评阅提交成功,请手动前往下一题', duration: const Duration(milliseconds: 400));
}
} catch (e) {
ToastUtils.showError('提交错误,请重试');
toPrint(val: '提交报错了,$e');
} finally {
// 关闭批注操作工具栏
ref.read(annotationGraffitiSwitchProvider.notifier).setSwitch(false);
timer.cancel();
ToastUtils.dismiss();
}
}
Future<bool?> _showExitDialogOfTag({required BuildContext context}) async {
// if (_switchQueTypePrompt) return false; // 放开后就可以做到没有切换试题钱只提示一次
// _switchQueTypePrompt = true;
return showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (context1) {
return AlertDialog(
title: quickText("提示"),
content: Row(
children: [
Expanded(
child: quickText(
"当前题型:${_currentTab!.questionNum}题已批阅完成,是否进入下一个题型?",
color: Theme.of(context).primaryColor,
maxLines: 2,
),
)
],
),
actions: <Widget>[
MaterialButton(
color: const Color.fromRGBO(245, 246, 251, 1),
disabledColor: const Color.fromRGBO(245, 246, 251, 1),
minWidth: 30.w,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(3.w)),
),
onPressed: () {
Navigator.of(context1).pop(false);
}, // 关闭对话框返回false
child: Text(
'',
style: TextStyle(
fontSize: 16.sp,
color: const Color.fromRGBO(80, 87, 103, 1),
fontWeight: FontWeight.w400,
),
),
),
SizedBox(width: 2.w),
MaterialButton(
color: const Color.fromRGBO(54, 86, 255, 0.99),
disabledColor: const Color.fromRGBO(54, 86, 255, 0.99),
minWidth: 30.w,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(3.w)),
),
onPressed: () {
Navigator.of(context1).pop(true);
},
child: Text(
"切换",
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
fontWeight: FontWeight.w400,
),
),
),
],
);
},
);
}
// 完成任务提示
//AlertDialog
Future showExitDialog() async {
EasyLoading.dismiss();
if (_reviewCompletedPrompted) {
return AchievementView(
elevation: 1,
duration: Duration(milliseconds: 800),
title: "完成提示",
subTitle: "没有更多试题了",
color: Theme.of(context).primaryColor,
).show(context);
}
_reviewCompletedPrompted = true;
// bool? res = await showDialog<bool>(
// context: context,
// barrierDismissible: false,
// builder: (context1) {
// return AlertDialog(
// title: quickText("完成提示"),
// content: Row(
// children: [
// Expanded(
// child: quickText(
// "您已完成批阅任务!",
// color: Theme.of(context).primaryColor,
// maxLines: 2,
// ),
// )
// ],
// ),
// actions: <Widget>[
// MaterialButton(
// color: const Color.fromRGBO(245, 246, 251, 1),
// disabledColor: const Color.fromRGBO(245, 246, 251, 1),
// minWidth: 30.w,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.all(Radius.circular(3.w)),
// ),
// onPressed: () {
// Navigator.of(context1).pop(false);
// }, // 关闭对话框返回false
// child: Text(
// '继续回评',
// style: TextStyle(
// fontSize: 16.sp,
// color: const Color.fromRGBO(80, 87, 103, 1),
// fontWeight: FontWeight.w400,
// ),
// ),
// ),
// SizedBox(width: 2.w),
// MaterialButton(
// color: const Color.fromRGBO(54, 86, 255, 0.99),
// disabledColor: const Color.fromRGBO(54, 86, 255, 0.99),
// minWidth: 30.w,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.all(Radius.circular(3.w)),
// ),
// onPressed: () {
// Navigator.of(context1).pop(true);
// },
// child: Text(
// "退出任务",
// style: TextStyle(
// fontSize: 16.sp,
// color: Colors.white,
// fontWeight: FontWeight.w400,
// ),
// ),
// ),
// ],
// );
// },
// );
// if (res != null && res) {
// Navigator.of(context).pop(true);
// }
setTimeOut(200, () {
var isPortrait = MediaQuery.of(context).orientation == Orientation.portrait;
AwesomeDialog(
context: context,
dialogType: DialogType.info,
// borderSide: BorderSide(color: Theme.of(context).primaryColor, width: 2.sp),
width: !isPortrait ? 190.w : 500.w,
buttonsBorderRadius: const BorderRadius.all(Radius.circular(2)),
dismissOnTouchOutside: true,
dismissOnBackKeyPress: false,
headerAnimationLoop: false,
animType: AnimType.bottomSlide,
title: '完成提示',
desc: '您已完成批阅任务!',
btnCancelText: '继续阅卷',
btnCancelColor: Colors.green[300],
btnOkText: '退出任务',
btnOkColor: Theme.of(context).primaryColor.withOpacity(0.8),
btnCancelOnPress: () {},
btnOkOnPress: () {
Navigator.of(context).pop(needRefresh);
},
).show();
});
}
//刷新数据,重新设置future就行了
Future refresh({bool isNext = false, int? theId, String? theQuestionNum}) async {
if (isNext && !(currentQuestion?.isException ?? false) && !(currentQuestion?.isFinish ?? false)) {
return ToastUtils.getFluttertoast(context: context, msg: '请先评分后提交再进入下一题');
}
int detailId = theId ?? (isNext ? currentQuestion!.nextId : currentQuestion!.prevId);
bool isReview = widget.isReview;
if (theId != null && _currentTab != null && theQuestionNum != _currentTab!.questionNum) {
MarkingTextQuestionTab? _foundCrrentTab =
_currentTabs.firstWhereOrNull((element) => element.questionNum == theQuestionNum);
if (_foundCrrentTab != null) {
_currentTab = _foundCrrentTab;
}
}
params = MarkingTextQuestionParams(
pageType: widget.markingtype?.index,
markingUserId: widget.markingUserId,
markingUserDetailId: detailId,
type: theId == null ? (isNext ? 0 : 1) : params.type,
isReview: isReview,
);
tabParams = MarkingTextQuestionTabParams(
// pageType: widget.markingtype?.index,
markingUserId: widget.markingUserId,
markingUserDetailId: detailId,
questionNum: _currentTab?.questionNum,
// type: isNext ? 0 : 1,
// isExcess: _currentTab?.isExcess ?? false,
// examSubjectId: widget.examSubjectId,
);
setTimeOut(500, () => Fluttertoast.cancel());
return _future = getData();
}
// 同步小题得分 score:分值 continueScoring是否可以持续打分 hasSubtopic是否有小题; cleanScore:是否是清空
Future<void> synchroScore(
{required double score,
required bool continueScoring,
required bool hasSubtopic,
bool allWrong = false,
bool cleanScore = false}) async {
if (currentQuestion == null) return;
if (cleanScore) {
// 清空
toUpState(setState, () {
hasZeroPointFive = false;
questScore = '';
if (hasSubtopic) {
SubQuestions subItem = currentQuestion!.subQuestionDetailList[activeQuestIndex];
subItem.subQuestionGotScore = null;
subItem.completeRating = false;
currentQuestion!.score = 0;
} else {
currentQuestion!.score = 0;
currentQuestion!.completeRating = false;
}
}, mounted);
return;
}
toUpState(setState, () {
questScore = score.toString();
hasZeroPointFive = continueScoring; //
if (!showSubtopicArea) showSubtopicArea = true;
if (hasSubtopic) {
// 有小题
if (score == currentQuestion!.totalScore || allWrong) {
currentQuestion!.subQuestionDetailList.forEach((subQuestion) {
subQuestion.subQuestionGotScore = allWrong ? 0 : subQuestion.subQuestionScore;
subQuestion.completeRating = true;
});
} else {
SubQuestions subQuestion = currentQuestion!.subQuestionDetailList[activeQuestIndex];
subQuestion.subQuestionGotScore = score;
subQuestion.completeRating = true;
try {
SubQuestions? nextSubQuestion = activeQuestIndex + 1 < currentQuestion!.subQuestionDetailList.length
? currentQuestion!.subQuestionDetailList[activeQuestIndex + 1]
: null;
currentQuestion!.score = currentQuestion!.subQuestionDetailList
.where((element) => element.subQuestionGotScore != null)
.map((e) => e.subQuestionGotScore)
.reduce((value, element) => (value ?? 0) + (element ?? 0));
// ignore: unnecessary_null_comparison
if (nextSubQuestion != null && !nextSubQuestion.completeRating) {
activeQuestIndex += 1;
ref.read(markingSubtopicSwitchingProvider.notifier).setVal(activeQuestIndex);
}
} catch (e) {}
return;
}
}
currentQuestion!.score = score;
currentQuestion!.completeRating = true;
}, mounted);
}
// 关闭因输入键盘引导页
void clostInputKeyboardGuidePage() {
toUpState(setState, () => inputKeyboardGuidePage = false, mounted);
keyboardModel!.guidePageDisplay = false;
ref.read(markingKeyboardProvider.notifier).toggleKeyboard(keyboardModel!);
// FastData.getInstance().setInputKeyboardGuidePage(false);
}
// 查看阅卷设置操作页
void viewMarkingSettings(bool? val) {
toUpState(setState, () => setingOperation = val ?? false, mounted);
}
// 当打开题型列表刷新tags题型集合
Future<void> getUpdateTags() async {
RestClient client = await getClient();
BaseStructureResult<List<MarkingTextQuestionTab>> res = await client.getTestQuestionsOfTab(widget.markingUserId);
if (!res.success || res.data == null) {
var msg = res.message ?? '更新试题集合失败,请重新重试';
ToastUtils.showError(msg);
return Future.error(msg);
}
res.data = res.data!.where((element) => !(element.isFinished && element.finishCount == 0)).toList();
// 方便更新tags key是题号
Map<String, MarkingTextQuestionTab> _currentTabsMap = Map<String, MarkingTextQuestionTab>.fromIterable(_currentTabs,
key: (item) => item.questionNum, value: (item) => item);
MarkingTextQuestionTab? theCurrentTab;
String currentTagQueNum = _currentTab!.questionNum;
res.data!.forEach((e) {
String questionNum = e.questionNum;
MarkingTextQuestionTab? tag = _currentTabsMap[questionNum];
if (tag != null) {
e.scoreInterval = tag.scoreInterval;
// e.agreementExcess = tag.agreementExcess;
if (questionNum == currentTagQueNum) theCurrentTab = e;
}
});
if (theCurrentTab == null) {
theCurrentTab = res.data![0];
}
_currentTab = theCurrentTab;
_currentTabs = res.data!;
}
/// 获取tab数据试题的批次集合.
/// @param tabQuestionNum {String} 需要跳转的题号
/// @param hasNext {bool} 只是检查是否还有下一个tag
/// @param firstWhereCall {Function} 筛选条件
Future<MarkingTextQuestionTab> getTabsData(
{String? tabQuestionNum,
bool hasNext = false,
bool updateCurrentTag = false,
bool resetting = false,
bool Function(MarkingTextQuestionTab)? firstWhereCall}) async {
String? oldQuestionNum = _currentTab?.questionNum;
firstWhereCall ??= getTagCondition;
// if (!updateCurrentTag && tabQuestionNum != null) updateCurrentTag = true; // 切换试题更新tag
late MarkingTextQuestionTab currentTab;
if (!widget.exceptional && _currentTabs.length <= 0 && _currentTab == null) {
// tag为空请求tag数据并且为对应的tag赋值上分值步长
RestClient client = await getClient();
List<BaseStructureResult> res = await Future.wait([
client.getTestQuestionsOfTab(widget.markingUserId),
client.getTestQuestionsOfTabStepSize(widget.examSubjectId)
]);
BaseStructureResult<List<MarkingTextQuestionTab>> resultTab =
res[0] as BaseStructureResult<List<MarkingTextQuestionTab>>;
BaseStructureResult<List<MarkingTextQuestionTabStepSize>> resultTabStep =
res[1] as BaseStructureResult<List<MarkingTextQuestionTabStepSize>>;
if ((!resultTab.success || (resultTab.data?.isEmpty ?? true)) ||
(!resultTabStep.success || (resultTabStep.data?.isEmpty ?? true)) ||
(resultTabStep.data!.length < resultTab.data!.length)) {
throw Error();
}
Map<String, double> tabStepMap = Map<String, double>.fromIterable(resultTabStep.data!,
key: (item) => item.questionNum, value: (item) => item.scoreInterval);
resultTab.data = resultTab.data!.where((element) => !(element.isFinished && element.finishCount == 0)).toList();
resultTab.data!.forEach((element) => element.setStepSize(tabStepMap[element.questionNum] ?? 1.0));
_currentTabs = resultTab.data!;
// 获取当前tabs批次下第一个没有完成数据
currentTab = resultTab.data!.firstWhere(
tabQuestionNum == null ? firstWhereCall : (e) => e.questionNum == tabQuestionNum,
orElse: () =>
MarkingTextQuestionTab(isFinished: false, questionNum: '0.0', total: 0, finishCount: 0, isExcess: false));
if (currentTab.questionNum == '0.0') {
// 全部都批改完成了默认tab设置为第一个
showExitDialog();
if (resultTab.data!.isEmpty) {
bool? flag1 = await showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: Text("提示"),
content: Text("该批阅任务已完成,没有试题"),
actions: <Widget>[
MaterialButton(
color: const Color.fromRGBO(54, 86, 255, 0.99),
disabledColor: const Color.fromRGBO(54, 86, 255, 0.99),
minWidth: 30.w,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4.w)),
),
onPressed: () => Navigator.of(context).pop(true),
child: Text(
'',
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
fontWeight: FontWeight.w400,
),
),
),
],
);
},
);
Navigator.of(context).pop(needRefresh);
} else {
currentTab = resultTab.data![0];
}
}
} else {
// Tags有数据校验当前Tag最后一题、切换Tag
MarkingTextQuestionTab? newCurrentTag;
MarkingTextQuestionTab? currentTab1;
if (updateCurrentTag) {
// 更新当前_currentTab
bool isExcess = _currentTab!.isExcess;
String questionNum = _currentTab!.questionNum;
if (tabQuestionNum != null) {
currentTab1 = _currentTabs.firstWhere((e) => e.questionNum == tabQuestionNum);
isExcess = currentTab1.isExcess;
questionNum = currentTab1.questionNum;
}
newCurrentTag = await getSingleTaginfo(
widget.markingUserId,
MarkingTagSingleParams(isExcess: isExcess, markingUserId: widget.markingUserId, questionNum: questionNum),
);
}
if (newCurrentTag != null) {
if (currentTab1 != null) {
currentTab1.questionNum = newCurrentTag.questionNum;
currentTab1.total = newCurrentTag.total;
currentTab1.finishCount = newCurrentTag.finishCount;
currentTab1.isExcess = newCurrentTag.isExcess;
currentTab1.isFinished = newCurrentTag.isFinished;
currentTab1.initGradingProgress();
} else {
_currentTab!.questionNum = newCurrentTag.questionNum;
_currentTab!.total = newCurrentTag.total;
_currentTab!.finishCount = newCurrentTag.finishCount;
_currentTab!.isExcess = newCurrentTag.isExcess;
_currentTab!.isFinished = newCurrentTag.isFinished;
_currentTab!.initGradingProgress();
}
// 超量题 总数已已经批阅完成的总数大于total为总数
// currentQuestion?.totalCount = newCurrentTag.isExcess && newCurrentTag.finishCount >= newCurrentTag.total
// ? newCurrentTag.finishCount
// : newCurrentTag.total;
}
if (hasNext) {
// 查找下一个tab
return _currentTabs.firstWhere(firstWhereCall,
orElse: () => MarkingTextQuestionTab(
questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false));
}
if (tabQuestionNum != null) {
currentTab = _currentTabs.firstWhere((e) => e.questionNum == tabQuestionNum, orElse: () => _currentTabs[0]);
} else {
currentTab = _currentTab!;
if (resetting) {
// 是否进行重置,继续阅卷
MarkingTextQuestionTab theMarking = _currentTabs.firstWhere(firstWhereCall,
orElse: () => MarkingTextQuestionTab(
questionNum: '0.0', total: 0, finishCount: 0, isExcess: false, isFinished: false));
if (theMarking.questionNum != '0.0') {
currentTab = theMarking;
}
}
}
}
if (oldQuestionNum != currentTab.questionNum) {
_completionPromptTab = false;
}
return _currentTab = currentTab;
}
/// 找到tag下未完成第一个试题
/// questionNum 当前题号用于指定题号finishCount+1使用 因为在提交前判定是否有下一题 只用于试题提交之前使用
bool getTagCondition(MarkingTextQuestionTab e, {String? questionNum}) {
/** 已经废弃常量题是否完成判断 统一使用`isFinished`判断
if (e.isExcess) {
// 超量题的完成是已当前完成量大于等于平均量
if (e.isFinished) return false;
return e.finishCount < e.total;
}
*/
return !e.isFinished;
// if (e.isExcess) {
// // 非平均试题
// bool? agreement = e.agreementExcess; // 是否已经同意继续批阅
// bool hasExcess = e.excessCount > 0; // 题池中是否还有试题
// int finishCount = questionNum != null && questionNum == e.questionNum ? e.finishCount + 1 : e.finishCount;
// bool completedTask = finishCount >= e.total; // 是否完成已经领取的任务数量没有阅卷时都是0
// if (hasExcess &&
// completedTask &&
// finishCount >= e.excessAvgCount &&
// agreement == null &&
// questionNum != null &&
// e.questionNum == questionNum) {
// // 剔除当前这个没有询问过的数据 跳过当前正在批阅的试题
// return false;
// }
// if (completedTask) {
// // 完成本身任务 判断是否完成指标数量
// if (hasExcess) {
// // 题池中还有待阅试题
// if (finishCount >= e.excessAvgCount) {
// // 完成指标
// if (completedTask = agreement != null) {
// // 没有询问过就视为未完成
// completedTask = !agreement!;
// }
// } else {
// // 未完成指标
// completedTask = false;
// }
// }
// }
// return !completedTask;
// }
// return (questionNum != null && questionNum == e.questionNum ? e.finishCount + 1 : e.finishCount) < e.total;
}
/* 请求获取回评tab */
Future<MarkingTextQuestion?> getData({String? tabQuestionNum, bool resetting = false}) async {
// bool flagInputKeyboardGuidePage = await FastData.getInstance().getInputKeyboardGuidePage(); // 引导页标志
try {
theRequesting = true;
RestClient client = await getClient();
MarkingTextQuestionTab? temTab;
bool isNormal = !widget.exceptional;
// 正常阅卷参与tab的方式获取试题
MarkingTextQuestionTab? oldCurrentTab = _currentTab;
temTab = await getTabsData(tabQuestionNum: tabQuestionNum, resetting: resetting); // 切换tag 返回对应的tag
print('当前选中类型:${temTab.questionNum}');
MarkingTextQuestionTabParams theParam = tabParams.setQuestionNum(
tab: temTab,
locaQuestionNum: oldCurrentTab?.questionNum,
);
// 回评第一次进入处理
if (widget.isReview && firstComeIn) {
theParam..markingUserDetailId = widget.markingUserDetailId;
// ..type = 2;
}
BaseStructureResult<MarkingTextQuestion> result = await client.getTabOfExam(widget.markingUserId, theParam);
if (result.success && result.data == null) {
ToastUtils.showInfo('当前试题已经批阅完成');
// _currentTab!.excessCountTotal = _currentTab!.finishCount;
return currentQuestion;
}
if (!result.success) {
setTimeOut(300, () => ToastUtils.showError('请求错诶,请重试'));
throw Error();
}
currentQuestion = result.data;
if (temTab != null) {
result.data!.scoreInterval = temTab.scoreInterval ?? 1;
MarkingZoom? markingZoom = await UseZoomImageHistoryUtils.getZoomImageInfo(
widget.markingUserId.toString() + '-' + (currentQuestion?.questionNum.toString() ?? ''));
if (markingZoom != null) {
imageScale = double.parse(markingZoom.scale.toStringAsFixed(2));
imagePosition = Offset(
double.parse(markingZoom.dx.toStringAsFixed(2)),
double.parse(markingZoom.dy.toStringAsFixed(2)),
);
print('缩放比例:${imageScale};图片的历史位置:${imagePosition}');
} else {
imageScale = 1;
imagePosition = Offset(0, 0);
}
/** */
// int? thetypeNum = tabParams.type;
// // || _currentTab?.total == 0 是因为第一次进入页面 total没有更新造成了total是0
// if (tabQuestionNum != null || _currentTab?.total == 0)
// await getTabsData(updateCurrentTag: true); // 切换tag更新当前Tag数据
// currentQuestion?.scoreInterval = temTab.scoreInterval!;
// if (oldCurrentQuestion == null ||
// (oldCurrentQuestion.markingUserDetailId != currentQuestion!.markingUserDetailId)) {
// if (theExamIndex == 0 || tabQuestionNum != null) {
// // 当前试题位置 条件意思代表:当批阅的试题大于等于当前任务并且题池中没有试题 或者 获取当前试题是否继续取题池中的试题(!tabParams.excessContinue
// theExamIndex = (temTab.finishCount >= temTab.total && temTab.excessCount <= 0) ||
// (!tabParams.excessContinue && currentQuestion!.isFinish)
// ? temTab.finishCount
// : temTab.finishCount + 1; // 当前试题的位置
// } else if (thetypeNum != null) {
// thetypeNum == 0 ? ++theExamIndex : --theExamIndex;
// }
// }
// theExamIndex = currentQuestion?.currentIndex ?? 0;
/**后端返回当前试题位置不需要前端再去计算位置了 不需要判断超量题和平均量了 */
// currentQuestion!.setTotalCountAndCurrentIndex(
// temTab.isExcess
// ? (temTab.total > temTab.excessAvgCount ? temTab.total : temTab.excessAvgCount)
// : temTab.total,
// temTab.finishCount); // 设置下标
// currentQuestion?.totalCount = temTab.total;
}
/**
toUpState(setState, () {
bool hasSub = currentQuestion!.subQuestionDetailList.isNotEmpty;
activeQuestIndex = 0; // 选中题号
double fullScore;
double getScore;
if (hasSub) {
SubQuestions questions = currentQuestion!.subQuestionDetailList[activeQuestIndex];
bool isFinish = questions.isFinish;
fullScore = questions.subQuestionScore;
getScore = isFinish ? questions.subQuestionGotScore! : 0;
} else {
fullScore = currentQuestion!.totalScore;
bool isFinish = currentQuestion!.isFinish; // 是否提交
getScore = isFinish ? currentQuestion!.score! : 0;
}
questScore = getScore == 0 ? '' : getScore.toString(); // 打分值
hasZeroPointFive = getScore >= fullScore || questScore.length > 1; // 是否是满分/是否已经包含小数
// inputKeyboardGuidePage = flagInputKeyboardGuidePage; // 引导页标志配置
}, mounted);*/
bool hasSub = currentQuestion!.subQuestionDetailList.isNotEmpty;
activeQuestIndex = 0; // 选中题号
double fullScore;
double getScore;
if (hasSub) {
SubQuestions questions = currentQuestion!.subQuestionDetailList[activeQuestIndex];
bool isFinish = questions.isFinish;
fullScore = questions.subQuestionScore;
getScore = isFinish ? questions.subQuestionGotScore! : 0;
} else {
fullScore = currentQuestion!.totalScore;
bool isFinish = currentQuestion!.isFinish; // 是否提交
getScore = isFinish ? currentQuestion!.score! : 0;
}
questScore = getScore == 0 ? '' : getScore.toString(); // 打分值
hasZeroPointFive = getScore >= fullScore || questScore.length > 1; // 是否是满分/是否已经包含小数
// inputKeyboardGuidePage = flagInputKeyboardGuidePage; // 引导页标志配置
if (firstComeIn) setTimeOut(2000, () => firstComeIn = false);
if (ref.read(markingSubtopicSwitchingProvider.notifier).state != activeQuestIndex) {
// 重置小题题号位置下标
Future.delayed(
Duration.zero, () => ref.read(markingSubtopicSwitchingProvider.notifier).setVal(activeQuestIndex));
}
if (currentQuestion != null && widget.markingtype == MarkingListType.EXCEPTIONAL) {
BaseStructureResult<ExceptionInfo> res = await client.getMarkingQuestionsErrorInfo(currentQuestion!.id);
printJson(res);
if (res.success && res.data != null) {
currentQuestion!.exceptionInfo = res.data;
}
}
if (currentQuestion != null && widget.markingtype == MarkingListType.ARBITRATE) {
BaseStructureResult<List<HistoricalScoring>> res = await client.getArbitrateOfHistoryScore(currentQuestion!.id);
if (res.success && res.data != null) {
currentQuestion!.historicalScorings = res.data!;
}
}
// getMarkingQuestionsErrorInfo
return currentQuestion;
} catch (e) {
toPrint(val: '进入获取试题报错..................${e}');
setTimeOut(1100, () => RouterManager.router.pop(context));
return null;
} finally {
widget.markingUserDetailId = 0;
setState(() => theRequesting = false);
}
}
Future<MarkingTextQuestionTab?> getSingleTaginfo(int markingUserId, MarkingTagSingleParams params) async {
RestClient client = await getClient();
BaseStructureResult<MarkingTextQuestionTab> res = await client.getMarkingTagSingleDetails(markingUserId, params);
if (res.success && res.data != null) {
return res.data;
}
}
// 超量题提示
void toNextPromptOfExcess(markingUserDetailId) async {
/**
MarkingTextQuestionTab tempCurrentTab = await getTabsData(
hasNext: true,
updateCurrentTag: true,
firstWhereCall: (MarkingTextQuestionTab e) => getTagCondition(e, questionNum: _currentTab!.questionNum));
bool noNxetTag = tempCurrentTab.questionNum == '0.0'; // true 整个任务都已经批阅完成没有更多了
bool isExit = false;
MarkingTextQuestionTab? nextTag;
bool? flag1 = await showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: Text("提示"),
content: Text("该题批阅量已完成平均值,是否继续批阅该题剩余题目?"),
actions: <Widget>[
if (noNxetTag)
MaterialButton(
color: const Color.fromRGBO(245, 246, 251, 1),
disabledColor: const Color.fromRGBO(245, 246, 251, 1),
minWidth: 40.w,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4.w)),
),
onPressed: () {
isExit = noNxetTag;
Navigator.of(context).pop(needRefresh);
},
child: Text(
'退出阅卷',
style: TextStyle(
fontSize: 16.sp,
color: const Color.fromRGBO(80, 87, 103, 1),
fontWeight: FontWeight.w400,
),
),
),
SizedBox(width: 2.w),
MaterialButton(
color: const Color.fromRGBO(245, 246, 251, 1),
disabledColor: const Color.fromRGBO(245, 246, 251, 1),
minWidth: 30.w,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4.w)),
),
onPressed: () {
// isExit = noNxetTag;
// if (!isExit) nextTag = tempCurrentTab; // 下一个试题
Navigator.of(context).pop(needRefresh);
},
child: Text(
'否',
style: TextStyle(
fontSize: 16.sp,
color: const Color.fromRGBO(80, 87, 103, 1),
fontWeight: FontWeight.w400,
),
),
),
SizedBox(width: 2.w),
MaterialButton(
color: const Color.fromRGBO(54, 86, 255, 0.99),
disabledColor: const Color.fromRGBO(54, 86, 255, 0.99),
minWidth: 30.w,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4.w)),
),
onPressed: () => Navigator.of(context).pop(needRefresh),
child: Text(
'是',
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
fontWeight: FontWeight.w400,
),
),
),
],
);
},
);
flag1 ??= false;
_currentTab!.agreementExcess = flag1;
if (flag1) {
// 注意这里“markingUserDetailId”=0 是因为 这里没有任务却要领取下一道任务中的题,then 中获取了一次题后需要刷新一下任务
refresh(isNext: true, detailId: 0)
.then((value) => getTabsData(updateCurrentTag: true).then((value) => toUpState(setState, () => {}, mounted)));
} else {
if (isExit) {
// 退出
// 需要直接退出当前阅卷页面
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]);
if (needRefresh) {
/* 是否需要刷新首页阅卷列表和阅卷主页列表主页刷新 */
var theProvider = ref.read(currentTaskIdProvider.notifier);
theProvider.setDoTaskEntity(CurrentReviewTask(taskId: theProvider.state.taskId, refresh: true));
}
return RouterManager.router.pop(context);
} else {
// 下一题
nextTag = await getTabsData(hasNext: true);
_future = getData(tabQuestionNum: nextTag!.questionNum);
}
}
ref.read(annotationGraffitiSwitchProvider.notifier).setSwitch(false);
*/
}
void toOpenEndDrawer() {
getUpdateTags().then((value) => scaffoldKey.currentState?.openDrawer());
}
@override
Widget build(BuildContext context) {
BuildContext _thecontext = context;
bool annotationSwitch = ref.watch(annotationGraffitiSwitchProvider).annotationSwitch;
DoMarkingKeyboardModel model = ref.watch(markingKeyboardProvider);
bool hasAuxiliaryKeyboard = model.auxiliaryKeyboard; // 是否需要辅助键盘打开按钮
bool openAuxiliary = model.openAuxiliary; // 是否需要辅助键盘打开按钮
bool isBroadwise = model.screenDirection == ScreenDirection.HORIZONTAL_SCREEN; // 是否横向
int questNumTotal = _currentTab == null ? 0 : _currentTab!.total;
double percent = _currentTab?.percent ?? 0.0;
final Color color = Color.lerp(Color.fromRGBO(209, 219, 254, 1), Theme.of(context).primaryColor, percent)!;
// 创建渐变对象
final gradient = LinearGradient(colors: [Color.fromRGBO(209, 219, 254, 1), color], stops: [0.0, percent]);
print(keyboardModel!.open && keyboardModel!.keyboard == KeyboardType.BOTTOM_SELECTION);
return GestureDetector(
onTap: () {
// 点击空白处时,移除当前焦点并收起键盘
FocusScope.of(context).unfocus();
},
child: WillPopScope(
child: Scaffold(
key: scaffoldKey,
backgroundColor: const Color.fromRGBO(249, 250, 254, 1),
body: SafeArea(
bottom: !isBroadwise ? true : false,
top: !isBroadwise ? true : false,
left: false,
right: true,
// top: false,
child: Stack(
children: [
MyFutureBuilder.buildFutureBuilderOfSingleInstance<MarkingTextQuestion>(
context,
_future,
(MarkingTextQuestion? data) {
if (data == null) {
return Container(
child: TextButton(
onPressed: () => RouterManager.router.pop(context),
child: quickText('没有获取到数据,点击返回'),
),
);
}
bool hasSubtopic = data.subQuestionDetailList.isNotEmpty; // 是否有小题
bool isNormal = !widget.exceptional; // 正常批题
bool notNextTest = data.nextId == 0; // 没有下一个试题了
// 下一题点击触发的方法
var pressedNextTest =
notNextTest ? null : () => easyThrottle('TestQuestionSwitch', () => refresh(isNext: true));
bool notHasPreviousTest = data.prevId == 0;
/** 无需根据当前位置判断
(isNormal ? theExamIndex : data.currentIndex) <= 1; // 是否有上一道试题
*/
return Column(
children: [
Stack(
children: [
Container(
height: 40.h,
padding: EdgeInsets.only(left: 5.w, right: 10.w),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.2),
offset: Offset(0, 1.h), //阴影y轴偏移量
blurRadius: 1, //阴影模糊程度
spreadRadius: 0.1, //阴影扩散程度
)
],
color: Colors.white,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
if (_currentTab != null)
InkWell(
onTap: () => toOpenEndDrawer(),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${_currentTab!.questionNum}',
style: TextStyle(
fontSize: isBroadwise ? 18.sp : 14.sp,
fontWeight: FontWeight.w500,
color: const Color.fromRGBO(80, 87, 103, 1),
),
),
Container(
width: isBroadwise ? 6.w : 8.w,
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 2.w),
child: Icon(
IconData(0xe631, fontFamily: "AlibabaIcon"),
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 10.sp : 6.sp,
),
),
Text(
'(已阅${_currentTab!.finishCount}/${_currentTab!.total})',
style: TextStyle(
fontSize: isBroadwise ? 14.sp : 12.sp,
color: const Color.fromRGBO(148, 163, 182, 1),
),
),
if (_currentTab!.isExcess &&
_currentTab!.finishCount > _currentTab!.total)
Container(
margin: EdgeInsets.only(left: 4.w),
child: Row(
children: [
quickText(
'超额完成',
size: isBroadwise ? 18.sp : 14.sp,
color: const Color.fromRGBO(148, 163, 182, 1),
),
quickText(
(_currentTab!.finishCount - _currentTab!.total)
.toString(),
size: isBroadwise ? 18.sp : 14.sp,
color: Color.fromRGBO(251, 144, 84, 1),
),
quickText(
'',
size: isBroadwise ? 18.sp : 14.sp,
color: const Color.fromRGBO(148, 163, 182, 1),
),
],
),
)
// SizedBox(width: isBroadwise ? 0.6.w : 0.6.w),
],
),
),
if (!isNormal)
Text(
// '${isNormal ? theExamIndex : data.currentIndex}/${data.totalCount}',
'${_currentTab!.finishCount}/${_currentTab!.total}',
style: TextStyle(
fontSize: isBroadwise ? 18.sp : 14.sp,
color: const Color.fromRGBO(148, 163, 182, 1),
),
),
SizedBox(width: 8.w),
if (model.hideQuestionId &&
model.screenDirection == ScreenDirection.HORIZONTAL_SCREEN)
InkWell(
onTap: () {
Clipboard.setData(ClipboardData(text: data.paperNum ?? ''))
.then((value) {
ToastUtils.showSuccess('试卷编号已复制');
});
},
child: Row(
children: [
quickText('试卷编号: ',
size: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
quickText(
data.paperNum ?? '',
size: 16.sp,
color: const Color.fromRGBO(148, 163, 182, 1),
)
],
),
),
// SizedBox(width: 8.w),
// Row(
// children: [
// quickText('总分: ',
// size: isBroadwise ? 16.sp : 14.sp,
// color: const Color.fromRGBO(148, 163, 182, 1)),
// quickText(
// '${doubleToStringAsFixed(data.totalScore)}',
// size: isBroadwise ? 16.sp : 14.sp,
// color: const Color.fromRGBO(148, 163, 182, 1),
// )
// ],
// ),
SizedBox(width: 8.w),
if (isBroadwise && widget.markingtype == MarkingListType.ARBITRATE)
Container(
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 2.h),
color: const Color.fromRGBO(4, 201, 208, 0.10),
child: quickText(
'仲裁题',
size: 14.sp,
color: const Color.fromRGBO(4, 201, 208, 1),
),
),
if (isBroadwise && widget.markingtype == MarkingListType.EXCEPTIONAL ||
data.isException)
Container(
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 2.h),
color: const Color.fromRGBO(245, 108, 108, 0.236),
child: quickText(
'异常题',
size: 14.sp,
color: const Color.fromRGBO(215, 74, 74, 1),
),
),
],
),
],
),
),
Row(
children: [
if ((currentQuestion?.isFinish ?? false) && !(currentQuestion?.lastOne ?? true))
InkWell(
onTap: () {
params = MarkingTextQuestionParams(
pageType: widget.markingtype?.index,
markingUserId: widget.markingUserId,
markingUserDetailId: widget.markingUserDetailId,
type: widget.pageOper,
isReview: widget.isReview,
);
tabParams = MarkingTextQuestionTabParams(
markingUserId: widget.markingUserId,
questionNum: null,
markingUserDetailId: 0,
);
_future = getData(resetting: true);
// setTimeOut(0, ()=>setT)
},
child: Row(
children: [
SizedBox(width: 2.w),
Icon(
IconData(0xe632, fontFamily: "AlibabaIcon"),
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp,
),
SizedBox(width: 1.w),
quickText('继续阅卷',
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp),
],
),
),
SizedBox(width: 10.w),
InkWell(
onTap: () {
ref
.read(ratingProgressProvider.notifier)
.setState(EndDrawerViewEnum.REVIEW_RECORD);
scaffoldKey.currentState?.openEndDrawer();
},
child: Row(
children: [
Icon(
IconData(0xe630, fontFamily: "AlibabaIcon"),
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp,
),
SizedBox(width: 1.w),
quickText('阅卷记录',
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp),
],
),
),
Container(
width: 0.3.w,
height: 15.h,
color: Colors.grey,
margin: EdgeInsets.symmetric(horizontal: 1.5.w),
),
InkWell(
onTap: () {
ref
.read(ratingProgressProvider.notifier)
.setState(EndDrawerViewEnum.RATING_PROGRESS);
scaffoldKey.currentState?.openEndDrawer();
},
child: Row(
children: [
Icon(
IconData(0xe630, fontFamily: "AlibabaIcon"),
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp,
),
SizedBox(width: 1.w),
quickText('评分进度',
color: const Color.fromRGBO(80, 87, 103, 1),
size: isBroadwise ? 15.sp : 12.sp),
],
),
),
SizedBox(width: 10.w),
if (widget.markingtype == MarkingListType.NORMAL && !data.isException)
InkWell(
onTap: () {
if (data.isException) {
return ToastUtils.getFluttertoast(
context: context, msg: '当前试题已为异常题,无需重复提交');
}
toUpState(setState, () => showAbnormal = true, mounted);
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
// margin: EdgeInsets.only(right: 1.w),
padding: EdgeInsets.only(bottom: 2.h),
child: Icon(
Icons.warning_amber_rounded,
color: const Color.fromRGBO(215, 74, 74, 1),
size: isBroadwise ? 16.sp : 12.sp,
),
),
Text(
'异常',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: isBroadwise ? 16.sp : 12.sp,
color: const Color.fromRGBO(215, 74, 74, 1),
),
)
],
),
),
SizedBox(width: 10.w),
InkWell(
onTap: () {
ref.read(annotationGraffitiSwitchProvider.notifier).setSwitch(false);
// setingDialog(context);
toUpState(setState, () => showSetingFlag = true, mounted);
},
child: Icon(
Icons.settings,
color: const Color.fromRGBO(148, 163, 182, 1),
size: isBroadwise ? 30.sp : 20.sp,
),
),
SizedBox(width: 10.w),
InkWell(
onTap: () {
Navigator.of(context).pop(needRefresh);
},
child: Icon(
Icons.exit_to_app_rounded,
color: Theme.of(context).primaryColor.withOpacity(0.5),
size: isBroadwise ? 30.sp : 20.sp,
),
),
],
)
],
),
),
SizedBox(
height: 6.h,
child: LinearPercentIndicator(
padding: const EdgeInsets.all(0),
animation: true,
lineHeight: 12.h,
animationDuration: firstComeIn ? 800 : 0,
percent: percent,
progressColor: percent == 1 ? Colors.green : null,
linearGradient: percent != 1 ? gradient : null,
backgroundColor: Colors.transparent,
),
),
],
),
Expanded(
child: Row(
children: [
// 小题打分框
if (hasSubtopic)
AnimatedContainer(
width: showSubtopicArea ? (isBroadwise ? 50.w : 70.w) : (isBroadwise ? 10.w : 20.w),
duration: const Duration(seconds: 1),
curve: Curves.easeInOutQuint,
child: showSubtopicArea
? Container(
width: 50.w,
margin: EdgeInsets.only(right: 1.5.w),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset(0.1.w, 0), //阴影y轴偏移量
blurRadius: 6, //阴影模糊程度
spreadRadius: 0.06, //阴影扩散程度
)
],
),
child: Column(
children: [
InkWell(
onTap: () {
toUpState(setState, () {
showSubtopicArea = !showSubtopicArea;
}, mounted);
},
child: Container(
height: 30.h,
width: double.infinity,
alignment: Alignment.center,
margin: EdgeInsets.only(bottom: 6.h),
color: const Color.fromRGBO(249, 250, 254, 1),
child: Icon(
Icons.chevron_left_sharp,
size: 34.sp,
color: const Color.fromRGBO(80, 87, 103, 1),
),
),
),
Expanded(
child: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 4.h),
itemBuilder: (context, index) {
SubQuestions quest = data.subQuestionDetailList[index];
bool activeIndex = activeQuestIndex == index;
return InkWell(
onTap: () {
double? getScore = quest.subQuestionGotScore;
ref
.read(markingSubtopicSwitchingProvider.notifier)
.setVal(index);
toUpState(setState, () {
activeQuestIndex = index;
// TODO 这是什么
// pictureOverviewKey.currentState?.jumpToPage(activeQuestIndex);
questScore = getScore?.toString() ?? '';
hasZeroPointFive =
questScore != '' && getScore! >= quest.subQuestionScore;
}, mounted);
},
child: Container(
margin: EdgeInsets.only(top: 5.h),
decoration: BoxDecoration(
border: Border.all(
width: 0.6.w,
color: activeIndex
? const Color.fromRGBO(46, 91, 255, 1)
: const Color.fromRGBO(224, 230, 255, 1),
),
borderRadius: BorderRadius.all(Radius.circular(1.8.w)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Stack(
alignment: const FractionalOffset(0.5, 1.78),
children: [
Container(
padding: EdgeInsets.symmetric(
horizontal: 4.w, vertical: 8.h),
alignment: Alignment.center,
decoration: BoxDecoration(
color: !activeIndex
? const Color.fromRGBO(249, 250, 254, 1)
: const Color.fromRGBO(46, 91, 255, 1),
border: Border(
bottom: BorderSide(
color: activeIndex
? const Color.fromRGBO(46, 91, 255, 1)
: const Color.fromRGBO(224, 230, 255, 1),
width: 0.2.w,
))),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${quest.subQuestionNum}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: activeIndex
? Colors.white
: const Color.fromRGBO(80, 87, 103, 1),
fontSize: 13.sp,
fontWeight: FontWeight.w500,
),
),
SizedBox(width: 1.w),
Padding(
padding: EdgeInsets.only(bottom: 1.h),
child: quickText(
'(${getDoubleRemoveZero(data.subQuestionDetailList[index].subQuestionScore)})',
size: 11.sp,
color: activeIndex
? Colors.white
: const Color.fromRGBO(
80, 87, 103, 1)),
)
],
)),
if (activeIndex)
Icon(Icons.arrow_drop_down_outlined,
color: const Color.fromRGBO(46, 91, 255, 1),
size: 20.sp)
],
),
Container(
padding:
EdgeInsets.symmetric(horizontal: 4.w, vertical: 8.h),
alignment: Alignment.center,
child: Text(
getDoubleRemoveZero(quest.subQuestionGotScore, '请评分'),
style: TextStyle(
color: const Color.fromRGBO(80, 87, 103, 1),
fontSize: 14.sp,
fontWeight: FontWeight.w400,
),
),
)
],
),
),
);
},
itemCount: data.subQuestionDetailList.length,
),
)
],
))
: GestureDetector(
child: InkWell(
onTap: () {
toUpState(setState, () {
showSubtopicArea = !showSubtopicArea;
}, mounted);
},
child: Container(
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
margin: EdgeInsets.only(right: 1.5.w),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset(0.1.w, 0), //阴影y轴偏移量
blurRadius: 6, //阴影模糊程度
spreadRadius: 0.06, //阴影扩散程度
)
],
),
child: Text(
'>>',
style:
TextStyle(color: Theme.of(context).primaryColor, fontSize: 12.sp),
),
)),
onHorizontalDragEnd: (detail) {
toUpState(setState, () {
showSubtopicArea = !showSubtopicArea;
}, mounted);
},
),
),
// 内容区域
Expanded(
child: Stack(
children: [
// 试卷
Container(
margin: EdgeInsets.only(top: 6.h),
padding: EdgeInsets.symmetric(horizontal: 1.w),
child: PictureOverview(
questionNum: data.questionNum,
markingUserId: widget.markingUserId,
key: pictureOverviewKey,
imageScale: imageScale,
imagePosition: imagePosition,
annotationsFlag: annotationSwitch,
commentImageMap: data.commentImageUrlMap,
testQuestionNumber: widget.markingUserId.toString() + '-' + data.questionNum,
imageItems: data.getImageData(),
),
),
// 批注开关 暂时注释
// if (!showSetingFlag &&
// !widget.exceptional &&
// currentQuestion != null &&
// annotationsFlag &&
// !showAbnormal &&
// !showStandardAnswer)
// Positioned(
// left: 0,
// bottom: 0,
// child: BottomAnnotationSwitch(maxWidth: maxWidth - 1.5.w),
// ),
// 大题评分展示框
if (!hasSubtopic)
Positioned(
top: 16.h,
left: 5.w,
child: DottedBorder(
dashPattern: const [8, 4],
strokeWidth: 2,
padding: EdgeInsets.zero,
color: data.isException ? Colors.red : const Color.fromRGBO(46, 91, 255, 1),
child: Container(
padding: EdgeInsets.symmetric(
horizontal: (data.score == null ||
(getDoubleRemoveZero(data.score ?? 0)).length >= 2)
? 4.w
: 12.w,
vertical: 6.h),
alignment: Alignment.center,
child: Text(
data.completeRating
? getDoubleRemoveZero(data.score)
: '请评分,满分${getDoubleRemoveZero(currentQuestion?.totalScore)}',
style: TextStyle(
fontSize: 18.sp,
color: const Color.fromRGBO(46, 91, 255, 1),
),
),
),
),
)
else
Positioned(
top: 16.h,
left: 5.w,
child: DottedBorder(
dashPattern: const [8, 4],
strokeWidth: 2,
padding: EdgeInsets.zero,
color: data.isException ? Colors.red : const Color.fromRGBO(46, 91, 255, 1),
child: Container(
padding: EdgeInsets.symmetric(
horizontal: (data.score == null ||
(getDoubleRemoveZero(data.score ?? 0)).length >= 2)
? 4.w
: 12.w,
vertical: 6.h),
alignment: Alignment.center,
child: Text(
getDoubleRemoveZero(data.score,
'请评分,满分${getDoubleRemoveZero(currentQuestion?.totalScore)}'),
style: TextStyle(
fontSize: 18.sp,
color: const Color.fromRGBO(46, 91, 255, 1),
),
),
),
),
),
// 上一题 按钮
if (widget.markingtype != MarkingListType.EXCEPTIONAL &&
!_theOldAnnotationGraffiti &&
!notHasPreviousTest)
Positioned(
left: 3.w,
top: ScreenUtil().setHeight(MediaQuery.of(context).size.height) / 2 * 0.87,
child: FloatingActionButton(
tooltip: '前往上一题',
backgroundColor: notHasPreviousTest
? const Color.fromRGBO(24, 32, 32, 0.04)
: const Color.fromRGBO(24, 32, 32, 0.1),
focusColor: Theme.of(context).primaryColor,
elevation: 0,
onPressed: notHasPreviousTest
? null
: () => easyThrottle('TestQuestionSwitch', () => refresh()),
child: const Icon(Icons.arrow_back_ios, color: Colors.white),
heroTag: 'other',
),
),
// 下一题 按钮
if (!_theOldAnnotationGraffiti && pressedNextTest != null && isNormal)
Positioned(
right: 2.w,
top: ScreenUtil().setHeight(MediaQuery.of(context).size.height) / 2 * 0.86,
child: FloatingActionButton(
elevation: 0,
tooltip: '点击前往下一题',
backgroundColor: notNextTest
? const Color.fromRGBO(24, 32, 32, 0.04)
: const Color.fromRGBO(24, 32, 32, 0.1),
foregroundColor: Colors.white,
onPressed: pressedNextTest,
child: const Icon(Icons.arrow_forward_ios, color: Colors.white),
),
),
$AbnormalQuestionInfo(
score: data.score,
info: data.exceptionInfo,
isBroadwise: isBroadwise,
hasSubtopic: hasSubtopic,
show: widget.markingtype == MarkingListType.EXCEPTIONAL || data.isException,
),
$ArbitrationQuestionInfo(
data: data.historicalScorings ?? [],
show: widget.markingtype == MarkingListType.ARBITRATE,
hasSubtopic: hasSubtopic,
isBroadwise: isBroadwise,
),
],
),
),
// 键盘
if (isNormal && keyboardModel!.open)
MarkingKeyboardSwitch(
data: data,
markingUserId: widget.markingUserId,
subtopicIndex: activeQuestIndex,
questScore: questScore,
totalScore: data.totalScore.toString(),
closeKeyboard: () => toUpState(setState, () => keyboardModel!.open = false, mounted),
submitCall: () => submitTestQuestions(_thecontext, data),
synchroScore: synchroScore,
)
],
),
),
// 底部键盘
if (isNormal && keyboardModel!.open && keyboardModel!.keyboard == KeyboardType.BOTTOM_SELECTION)
SelectableKeyboardBottom(
markingUserId: widget.markingUserId,
data: data,
subtopicIndex: activeQuestIndex,
questScore: questScore,
totalScore: data.totalScore,
submitCall: () => submitTestQuestions(_thecontext, data),
synchroScore: synchroScore,
)
],
);
},
),
// 输入型键盘引导页
if (inputKeyboardGuidePage) InputKeyboardGuidePage(closeCall: clostInputKeyboardGuidePage),
// 设置
if (showSetingFlag)
SetingBox(
closeHandle: () => toUpState(setState, () => showSetingFlag = false, mounted),
exitPaper: () {
if (!needRefresh) return;
/* 是否需要刷新首页阅卷列表和阅卷主页列表主页刷新 */
var theProvider = ref.read(currentTaskIdProvider.notifier);
CurrentReviewTask newTask = CurrentReviewTask(taskId: theProvider.state.taskId, refresh: true);
theProvider.setDoTaskEntity(newTask);
ref.read(markingKeyboardProvider.notifier).toggleKeyboard(ref.read(markingKeyboardProvider));
},
viewWholeTestPaper: viewEntireVolume,
viewAnswer: viewAnswer,
setingOperation: viewMarkingSettings,
),
// 评阅设置主页
if (setingOperation)
MarkingSeting(
questTotalScore: currentQuestion?.totalScore,
defaultScoreInterval: currentQuestion?.scoreInterval ?? 1,
markingUserId: widget.markingUserId,
questionNum: currentQuestion?.questionNum ?? '',
tagName: _currentTab?.questionNum,
close: (bool closeFlag) async {
setingOperation = false;
if (closeFlag) showSetingFlag = false;
setState(() {});
},
),
// 异常显示区域
$AbnormalBox(
businessHandle: (bool flag, String? reasonKey, String? otherReasons) =>
initiateException(flag, reasonKey, otherReasons),
isBroadwise: isBroadwise,
showAbnormal: !showAbnormal,
),
// 标准答案
if (showStandardAnswer && standardAnswers != null)
StandardAnswerRegion(
closeCall: () => {toUpState(setState, () => showStandardAnswer = false, mounted)},
htmlWStr: standardAnswers!,
),
// 右侧键盘辅助键盘操作按钮
if (currentQuestion != null &&
!widget.exceptional &&
!theRequesting &&
hasAuxiliaryKeyboard &&
model.keyboard == KeyboardType.RIGHT_SELECTION &&
!(showStandardAnswer || showSetingFlag || showAbnormal))
Positioned(
right: isBroadwise ? 72.h : 57.h,
top: 48.h,
child: GestureDetector(
onTap: () {
easyThrottle('Auxiliary_keyboard_control_buttons', () {
bool newOpenAuxiliary = !openAuxiliary;
eventFire(model: KeyboardAssistEvent(openAuxiliary: newOpenAuxiliary));
setTimeOut(300, () {
// 双栏打分开关需要重新加载图片
eventFireSub(model: SwitchKeyboardToReloadImages(true));
});
ref.read(annotationGraffitiSwitchProvider.notifier).setSwitch(false);
ToastUtils.showSuccess(newOpenAuxiliary ? '开启双栏打分' : '关闭双栏打分',
duration: const Duration(milliseconds: 300));
});
},
// 触发总线事件
child: Container(
height: isBroadwise ? 24.h : 18.h,
width: isBroadwise ? 18.w : 42.w,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(topLeft: Radius.circular(8.w), bottomLeft: Radius.circular(8.w)),
color: Theme.of(context).primaryColor,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
!openAuxiliary ? Icons.arrow_back_ios : Icons.arrow_forward_ios,
color: Colors.white,
size: isBroadwise ? 16.sp : 12.sp,
),
quickText('双栏', color: Colors.white, size: isBroadwise ? 12.sp : 10.sp),
],
)),
),
),
],
),
),
drawer: MarkingQuestionTypeDrawer(
scaffoldKey: scaffoldKey,
currentTab: _currentTab,
currentTabs: _currentTabs,
call: (String tabQuestionNum) {
_future = getData(tabQuestionNum: tabQuestionNum);
scaffoldKey.currentState?.closeDrawer();
},
widthPercent: keyboardModel?.screenDirection == ScreenDirection.VERTICAL_SCREEN ? 0.6 : 0.38,
),
endDrawer: ReviewRecords(
tabName: _currentTab?.questionNum ?? '',
tabs: _currentTabs,
direction: keyboardModel?.screenDirection ?? ScreenDirection.HORIZONTAL_SCREEN,
call: (int detailId, String selectedQuesiontNum) =>
refresh(theId: detailId, theQuestionNum: selectedQuesiontNum),
markingUserId: widget.markingUserId,
questionNum: _currentTab?.questionNum,
),
floatingActionButton: keyboardModel!.open || showStandardAnswer || showSetingFlag || showAbnormal
? null
: FloatingActionButton(
onPressed: () {
toUpState(setState, () => keyboardModel!.open = true, mounted);
},
///长按提示
tooltip: "这是打开软键盘按钮",
///设置悬浮按钮的背景
backgroundColor: Theme.of(context).primaryColor,
///获取焦点时显示的颜色
focusColor: Colors.green,
///鼠标悬浮在按钮上时显示的颜色
hoverColor: Colors.yellow,
///水波纹颜色
splashColor: Colors.deepPurple,
///定义前景色 主要影响文字的颜色
foregroundColor: Colors.black,
///配制阴影高度 未点击时
elevation: 0.0,
///配制阴影高度 点击时
highlightElevation: 20.0,
child: Text(
'打开键盘',
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
),
),
),
///用来控制 FloatingActionButton 的位置
///FloatingActionButtonLocation.endFloat 默认使用 浮动右下角
///FloatingActionButtonLocation.endDocked 右下角
///FloatingActionButtonLocation.endTop 右上角
///FloatingActionButtonLocation.startTop 左上角
///FloatingActionButtonLocation.centerFloat 底部中间浮动
///FloatingActionButtonLocation.centerDocked 底部中间不浮动
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
),
onWillPop: () async {
if (!setingOperation && !showSetingFlag && !showStandardAnswer) {
ToastUtils.showInfo('阅卷模式下无法物理退出,请前往设置');
}
return Future.value(false);
},
),
);
}
}
// 异常区域
@hwidget
Widget $abnormalBox(
BuildContext context, {
required Function(bool, String?, String?) businessHandle,
required bool showAbnormal,
required bool isBroadwise,
}) {
UseAbnormal _useAbnormal = UseAbnormal.use();
Map<String, String> map = _useAbnormal.abnormals.value;
String? _abnormalsReason = _useAbnormal.abnormalsReason.value;
TextEditingController controller = useTextEditingController();
useValueChanged<bool, String>(showAbnormal, (oldValue, oldResult) {
controller.clear();
_useAbnormal.abnormalsReason.value = null;
});
useEffect(() {
_useAbnormal.getData();
return () {
try {
controller.dispose();
} catch (e) {}
};
}, []);
return Offstage(
offstage: showAbnormal,
child: Container(
height: double.infinity,
width: double.infinity,
color: const Color.fromRGBO(0, 0, 0, 0.65),
alignment: Alignment.center,
child: Container(
height: isBroadwise ? 400.h : 220.h,
width: double.infinity,
// padding: EdgeInsets.only(bottom: 10.h),
margin: EdgeInsets.symmetric(vertical: 80.h, horizontal: isBroadwise ? 100.w : 40.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(6.w)),
),
child: Column(
children: [
Container(
height: 42.h,
padding: EdgeInsets.only(left: 8.w),
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(6.w), topRight: Radius.circular(6.w)),
color: Theme.of(context).primaryColor,
),
child: quickText('异常', color: Colors.white, size: 18.sp),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
// Image.asset(
// 'assets/images/abnormal_img.png',
// fit: BoxFit.cover,
// width: isBroadwise ? 42.w : 50.w,
// height: isBroadwise ? 42.w : 50.w,
// ),
// Text(
// '你确定该题异常?',
// style: TextStyle(
// fontSize: isBroadwise ? 20.sp : 16.sp,
// color: const Color.fromRGBO(0, 0, 0, 1),
// ),
// ),
Container(
margin: EdgeInsets.symmetric(horizontal: 16.w),
child: quickText(
'设置问题卷后,该试题交由管理员或科组长处理是否继续设置为问题卷?',
size: 20.sp,
color: const Color.fromRGBO(87, 89, 94, 1),
maxLines: 2,
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 18.w),
child: Row(
children: [
quickText('异常类型', size: 16.sp, color: Color.fromRGBO(80, 87, 103, 1)),
SizedBox(width: 4.w),
Expanded(
child: SizedBox(
height: 44.h,
child: DropdownSearch(
items: map.keys.toList(),
onChanged: (String? item) {
_useAbnormal.abnormalsReason.value = item;
},
selectedItem: _abnormalsReason,
),
),
)
],
),
),
if (_abnormalsReason != null && map[_abnormalsReason] == '-1')
Container(
height: 60.h,
padding: EdgeInsets.symmetric(horizontal: 18.w),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
quickText('异常原因', size: 16.sp, color: Color.fromRGBO(80, 87, 103, 1)),
SizedBox(width: 4.w),
Expanded(
child: Container(
height: 200.h,
padding: EdgeInsets.only(left: 2.w),
color: Color.fromRGBO(245, 246, 230, 1),
child: TextField(
controller: controller,
textInputAction: TextInputAction.next,
onEditingComplete: () => easyThrottle(
'Abnormal_submission_confirmation_button',
() => _useAbnormal.submit(context, controller,
(reasonType, reason) => businessHandle(true, reasonType, reason))),
maxLines: 15,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
hintText: '请输入异常原因', // 设置提示文本
hintStyle: TextStyle(fontSize: 12.sp),
border: InputBorder.none,
),
),
),
)
],
),
),
Container(
padding: EdgeInsets.only(top: 10.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () => easyThrottle(
'Abnormal_submission_confirmation_button', () => businessHandle(false, null, null)),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
margin: EdgeInsets.only(right: 16.w),
decoration: BoxDecoration(
color: const Color.fromRGBO(245, 246, 251, 1),
borderRadius: BorderRadius.all(Radius.circular(2.w)),
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.2),
offset: Offset(0, 2.h), //阴影y轴偏移量
blurRadius: 6, //阴影模糊程度
spreadRadius: 0.5, //阴影扩散程度
)
],
),
child: Text(
'取 消',
style: TextStyle(
color: const Color.fromRGBO(80, 87, 103, 1),
fontSize: isBroadwise ? 16.sp : 13.sp,
fontWeight: FontWeight.w400,
),
),
),
),
if (!isBroadwise) SizedBox(width: 60.w) else SizedBox(width: 14.w),
InkWell(
onTap: () => easyThrottle(
'Abnormal_submission_confirmation_button',
() => _useAbnormal.submit(
context, controller, (reasonType, reason) => businessHandle(true, reasonType, reason)),
),
// () {
// String? reasonType = map[_abnormalsReason];
// String? reason = controller?.text;
// if (reasonType == null) {
// return ToastUtils.getFluttertoast(context: context, msg: '请选择异常类型');
// }
// print(reason);
// if (reasonType == '-1' && (reason == null || reason.length <= 0)) {
// return ToastUtils.getFluttertoast(context: context, msg: '请填写异常原因');
// }
// easyThrottle('Abnormal_submission_confirmation_button',
// () => businessHandle(true, reasonType, reason));
// },
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
decoration: BoxDecoration(
gradient: const LinearGradient(colors: [
Color.fromRGBO(54, 97, 255, 1),
Color.fromRGBO(93, 128, 255, 1),
]),
borderRadius: BorderRadius.all(Radius.circular(2.w)),
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.2),
offset: Offset(0, 2.h), //阴影y轴偏移量
blurRadius: 6, //阴影模糊程度
spreadRadius: 0.5, //阴影扩散程度
)
],
),
child: Text(
'确 定',
style: TextStyle(
color: Colors.white,
fontSize: isBroadwise ? 16.sp : 13.sp,
fontWeight: FontWeight.w400,
),
),
),
),
],
),
),
],
),
),
],
),
),
),
);
}
// 显示标准答案
class StandardAnswerRegion extends StatelessWidget {
final GestureTapCallback closeCall;
final String htmlWStr;
const StandardAnswerRegion({required this.htmlWStr, required this.closeCall, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
alignment: const FractionalOffset(0.91, 0.12),
children: [
Container(
height: double.infinity,
width: double.infinity,
color: const Color.fromRGBO(0, 0, 0, 0.65),
padding: EdgeInsets.symmetric(horizontal: 50.w, vertical: 90.h),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.w)),
color: Colors.white,
),
child: ListView(
padding: EdgeInsets.all(6.w),
children: [HtmlWidget(htmlWStr)],
),
),
),
InkWell(
onTap: closeCall,
child: Icon(
Icons.clear_sharp,
color: Colors.white,
size: 40.sp,
),
)
],
);
}
}
/// 异常题提交异常信息
@hwidget
Widget $abnormalQuestionInfo(
{required bool hasSubtopic, required bool isBroadwise, required bool show, double? score, ExceptionInfo? info}) {
final _useFlagAnimation = useState(true);
AnimationController _useAnimationHorizontal = useAnimationController(
initialValue: 300,
lowerBound: 30,
upperBound: 300,
duration: const Duration(milliseconds: 300),
);
AnimationController _useAnimationVertical = useAnimationController(
initialValue: 280,
lowerBound: 30,
upperBound: 280,
duration: const Duration(milliseconds: 300),
);
AnimationController _useAnimation = isBroadwise ? _useAnimationHorizontal : _useAnimationVertical;
double left = 0;
double top = 14.h;
if (isBroadwise) {
// 横向
left = hasSubtopic ? (score != null ? 40.w : 50.w) : 62.w;
} else {
// 纵向
left = hasSubtopic ? 4.w : 4.w;
top = 60.h;
}
String? reason = info?.reason ?? info?.errorType;
if (!show || (reason == null)) return SizedBox();
return Positioned(
top: top,
left: left,
child: AnimatedBuilder(
animation: _useAnimation,
builder: (BuildContext context, Widget? child) {
double widVal = _useAnimation.value;
return Container(
clipBehavior: Clip.hardEdge,
width: _useAnimation.value,
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 1.6.h),
decoration: BoxDecoration(
color: const Color.fromRGBO(215, 74, 74, 0.06),
// color: Color.fromRGBO(255, 255, 255, 0),
borderRadius: BorderRadius.all(Radius.circular(4.r)),
// boxShadow: [
// BoxShadow(
// color: Color.fromRGBO(46, 91, 255, 0.07),
// offset: Offset(0, 0),
// blurRadius: 2.r,
// spreadRadius: 0,
// ),
// ],
),
child: widVal <= (isBroadwise ? 12.w : 36.w)
? InkWell(
onTap: () {
_useAnimation.forward();
_useFlagAnimation.value = true;
},
child: Icon(
Icons.warning_amber_rounded,
color: const Color.fromRGBO(215, 74, 74, 1),
size: 20.sp,
),
)
: GestureDetector(
onTap: () {
if (_useFlagAnimation.value) {
_useAnimation.reverse();
_useFlagAnimation.value = false;
} else {
_useAnimation.forward();
_useFlagAnimation.value = true;
}
},
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.warning_amber_rounded,
color: const Color.fromRGBO(215, 74, 74, 1),
size: 20.sp,
),
SizedBox(width: 4.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
if ((info?.studentName.length ?? 0) > 0)
quickText('考生:${info!.studentName}',
color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp
// overflow: TextOverflow.clip,
),
SizedBox(width: 3.w),
if ((info?.studentExamNum.length ?? 0) > 0)
quickText('考号:${info!.studentExamNum}',
color: const Color.fromRGBO(104, 104, 113, 1), size: 14.sp
// overflow: TextOverflow.clip,
),
],
),
SizedBox(height: 1.h),
quickText(
'异常原因:$reason',
color: Color.fromRGBO(215, 74, 74, 1),
size: 16.sp,
maxLines: 2,
// overflow: TextOverflow.clip,
),
],
),
),
// quickText('异常原因:${info!.reason ?? info.errorType}', color: Color.fromRGBO(215, 74, 74, 1), size: 14.sp),
SizedBox(width: 4.w),
Icon(
Icons.arrow_back_ios_new,
color: const Color.fromRGBO(148, 163, 182, 1),
size: 20.sp,
),
],
),
),
);
},
),
);
}
/// 冲裁题仲裁历史得分信息
@hwidget
Widget $arbitrationQuestionInfo(
{required bool show, required bool isBroadwise, required bool hasSubtopic, required List<HistoricalScoring> data}) {
final _useFlagAnimation = useState(true);
AnimationController _useAnimationHorizontal = useAnimationController(
initialValue: 300,
lowerBound: 36,
upperBound: 300,
duration: const Duration(milliseconds: 300),
);
AnimationController _useAnimationVertical = useAnimationController(
initialValue: 240,
lowerBound: 30,
upperBound: 240,
duration: const Duration(milliseconds: 300),
);
AnimationController _useAnimation = isBroadwise ? _useAnimationHorizontal : _useAnimationVertical;
double left = 0;
double top = 16.h;
if (isBroadwise) {
// 横向
left = hasSubtopic ? 4.w : 62.w;
} else {
// 纵向
left = hasSubtopic ? 4.w : 4.w;
top = 60.h;
}
if (!show) return Container();
return Positioned(
top: top,
left: left,
child: AnimatedBuilder(
animation: _useAnimation,
builder: (BuildContext context, Widget? child) {
double widVal = _useAnimation.value;
return Container(
clipBehavior: Clip.hardEdge,
width: _useAnimation.value,
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 3.h),
decoration: BoxDecoration(
color: const Color.fromRGBO(4, 201, 208, 0.08),
borderRadius: BorderRadius.all(Radius.circular(4.r)),
// boxShadow: [
// BoxShadow(
// color: Color.fromRGBO(46, 91, 255, 0.1),
// offset: Offset(0, 0),
// blurRadius: 2.r,
// spreadRadius: 0,
// ),
// ],
),
child: widVal <= (isBroadwise ? 12.w : 36.w)
? InkWell(
onTap: () {
_useAnimation.forward();
_useFlagAnimation.value = true;
},
child: Icon(
Icons.edit_square,
// color: const Color.fromRGBO(80, 84, 103, 1),
color: const Color.fromRGBO(4, 201, 208, 1),
size: 20.sp,
),
)
: GestureDetector(
onTap: () {
if (_useFlagAnimation.value) {
_useAnimation.reverse();
_useFlagAnimation.value = false;
} else {
_useAnimation.forward();
_useFlagAnimation.value = true;
}
},
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.edit_square,
color: const Color.fromRGBO(4, 201, 208, 1),
size: 20.sp,
),
SizedBox(width: 4.w),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
...data.map((e) {
return quickText(
'${e.name}${doubleToStringAsFixed(e.scorel)}',
color: const Color.fromRGBO(4, 201, 208, 1),
size: 16.sp,
maxLines: 2,
// overflow: TextOverflow.clip,
);
})
],
),
),
// quickText('异常原因:${info!.reason ?? info.errorType}', color: Color.fromRGBO(215, 74, 74, 1), size: 14.sp),
SizedBox(width: 8.w),
Icon(
Icons.arrow_back_ios_new,
color: const Color.fromRGBO(148, 163, 182, 1),
size: 20.sp,
),
],
),
),
);
},
),
);
}