2836 lines
134 KiB
Dart
2836 lines
134 KiB
Dart
/*
|
||
* @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,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
);
|
||
}
|