From 94977b5d96150c71257d675702edb4c8337c7b75 Mon Sep 17 00:00:00 2001 From: machuanyu <840649825@qq.com> Date: Thu, 16 May 2024 14:30:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BF=AB=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/api/retrofit_client.dart | 20 +- lib/common/config/request_config.dart | 3 +- lib/common/job/annotated_class.dart | 146 ++++++ lib/common/job/homework_details.dart | 219 ++++++++ lib/common/job/work_student.dart | 16 +- lib/common/job/work_student_params.dart | 10 +- lib/common/store/user_store.dart | 9 +- lib/common/utils/enum_untils.dart | 4 +- lib/common/utils/utils.dart | 109 ++++ lib/page/global_widget/imgDialog.dart | 26 + .../widget/kgt_zgt_table.dart | 152 ++++++ .../widget/quick_data_check_bottom.dart | 257 ++++++++++ .../widget/quick_student_data_table.dart | 272 ++++++++++ .../quick_data_check/widget/report_table.dart | 467 ++++++++++++++++++ .../children/read_over/read_over_logic.dart | 13 +- .../children/read_over/read_over_view.dart | 3 +- .../read_over/widget/task_list_item.dart | 8 +- lib/page/home_page/widget/progress_bar.dart | 60 +++ lib/routes/app_pages.dart | 10 + lib/routes/app_routes.dart | 3 + pubspec.lock | 24 + pubspec.yaml | 3 + 22 files changed, 1807 insertions(+), 27 deletions(-) create mode 100644 lib/common/job/annotated_class.dart create mode 100644 lib/common/job/homework_details.dart create mode 100644 lib/page/global_widget/imgDialog.dart create mode 100644 lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart create mode 100644 lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart create mode 100644 lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart create mode 100644 lib/page/home_page/children/quick_data_check/widget/report_table.dart create mode 100644 lib/page/home_page/widget/progress_bar.dart diff --git a/lib/common/api/retrofit_client.dart b/lib/common/api/retrofit_client.dart index 7d1bb0b..0bc8129 100644 --- a/lib/common/api/retrofit_client.dart +++ b/lib/common/api/retrofit_client.dart @@ -1,10 +1,12 @@ import 'package:dio/dio.dart' hide Headers; import 'package:retrofit/retrofit.dart'; +import 'package:school_asignment_app/common/job/annotated_class.dart'; import 'package:school_asignment_app/common/job/class_item.dart'; import 'package:school_asignment_app/common/job/common/app_version_model.dart'; import 'package:school_asignment_app/common/job/common/base_app_version.dart'; import 'package:school_asignment_app/common/job/common/base_page_data.dart'; import 'package:school_asignment_app/common/job/enum_subject.dart'; +import 'package:school_asignment_app/common/job/homework_details.dart'; import 'package:school_asignment_app/common/job/student_item.dart'; import 'package:school_asignment_app/common/job/user_info_detail.dart'; import 'package:school_asignment_app/common/job/work_student.dart'; @@ -35,7 +37,7 @@ abstract class RetrofitClient { //获取科目,年级 @GET("/api/app/Common/GetEnumInfos") - Future>> getEnumSubjectList(@Query('enumNames') String enumNames); + Future>> getEnumSubjectList(@Query('enumNames') List enumNames); //学生班级 @GET("/api/rbac/Class/GetTeacherClasses") @@ -44,4 +46,20 @@ abstract class RetrofitClient { //班级学生列表 @GET("/api/rbac/Class/GetClassStudents") Future getStudentList(@Query('ClassId') String classId); + + //待批阅列表 + @GET("/api/hms/Annotate/GetUnAnnotateList") + Future getUnAnnotateList(@Queries() WorkStudentParams params); + + //已批阅列表 + @GET("/api/hms/Annotate/GetAnnotatedList") + Future getAnnotatedList(@Queries() WorkStudentParams params); + + //获取批阅班级 + @GET("/api/hms/Annotate/Get") + Future> getAnnotatedClassList(@Query('homeworkId') String homeworkId); + + //作业明细 + @GET("/api/hms/HmsReport/GetHomeworkDtls") + Future getHomeworkDetails(@Query('homeworkId') String homeworkId,@Query('classId') String classId); } diff --git a/lib/common/config/request_config.dart b/lib/common/config/request_config.dart index a9e3d64..b5a8328 100644 --- a/lib/common/config/request_config.dart +++ b/lib/common/config/request_config.dart @@ -11,6 +11,7 @@ import 'package:school_asignment_app/common/job/common/base_page.dart'; class RequestConfig { static const _devBaseUrl = "http://192.168.2.119:1091"; // 开发 static const _proBaseUrl = "https://dpc-teacher-api.23544.com"; // 生产 + static const imgUrl = 'https://dpcjob.oss-cn-beijing.aliyuncs.com/'; static RequestConfig? _instance; String baseUrl; @@ -21,7 +22,7 @@ class RequestConfig { static const bool printSwitch = true; // 打印返回数据 static const successCode = [204, 200]; // 返回成功code static final BasePage basePage = BasePage(1, 10); // 分页参数 - + // 私有化构造函数,防止外部直接实例化 // 私有化构造函数,防止外部直接实例化 RequestConfig._({required this.baseUrl}); diff --git a/lib/common/job/annotated_class.dart b/lib/common/job/annotated_class.dart new file mode 100644 index 0000000..89fb098 --- /dev/null +++ b/lib/common/job/annotated_class.dart @@ -0,0 +1,146 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'annotated_class.g.dart'; + + +@JsonSerializable() +class AnnotatedClass extends Object { + + @JsonKey(name: 'schoolName') + String schoolName; + + @JsonKey(name: 'classId') + String classId; + + @JsonKey(name: 'className') + String className; + + @JsonKey(name: 'finishTime') + String? finishTime; + + @JsonKey(name: 'questionCount') + int questionCount; + + @JsonKey(name: 'answerCount') + int answerCount; + + @JsonKey(name: 'answerRate') + int answerRate; + + @JsonKey(name: 'unAnnotateCount') + int unAnnotateCount; + + @JsonKey(name: 'annotateRate') + int annotateRate; + + @JsonKey(name: 'students') + List students; + + @JsonKey(name: 'homeworkFavs') + List homeworkFavs; + + @JsonKey(name: 'kgtCorrectRate') + int kgtCorrectRate; + + @JsonKey(name: 'zgtCorrectRate') + int zgtCorrectRate; + + @JsonKey(name: 'correctRate') + int correctRate; + + @JsonKey(name: 'commitStudentCount') + int? commitStudentCount; + + @JsonKey(name: 'noCommitStudentCount') + int? noCommitStudentCount; + + AnnotatedClass(this.schoolName,this.classId,this.className,this.finishTime,this.questionCount,this.answerCount,this.answerRate,this.unAnnotateCount,this.annotateRate,this.students,this.homeworkFavs,this.kgtCorrectRate,this.zgtCorrectRate,this.correctRate,this.commitStudentCount,this.noCommitStudentCount); + + factory AnnotatedClass.fromJson(Map srcJson) => _$AnnotatedClassFromJson(srcJson); + + Map toJson() => _$AnnotatedClassToJson(this); + +} + + +@JsonSerializable() +class Students extends Object { + + @JsonKey(name: 'id') + String? id; + + @JsonKey(name: 'isDeleted') + bool isDeleted; + + @JsonKey(name: 'homeworkId') + String? homeworkId; + + @JsonKey(name: 'classId') + String classId; + + @JsonKey(name: 'studentId') + int studentId; + + @JsonKey(name: 'studentName') + String studentName; + + @JsonKey(name: 'state') + int state; + + Students(this.id,this.isDeleted,this.homeworkId,this.classId,this.studentId,this.studentName,this.state,); + + factory Students.fromJson(Map srcJson) => _$StudentsFromJson(srcJson); + + Map toJson() => _$StudentsToJson(this); + +} + + +@JsonSerializable() +class HomeworkFavs extends Object { + + @JsonKey(name: 'id') + String id; + + @JsonKey(name: 'homeworkId') + String homeworkId; + + @JsonKey(name: 'homeworkName') + String homeworkName; + + @JsonKey(name: 'grade') + int grade; + + @JsonKey(name: 'subject') + int subject; + + @JsonKey(name: 'classId') + String classId; + + @JsonKey(name: 'className') + String className; + + @JsonKey(name: 'studentId') + int studentId; + + @JsonKey(name: 'studentName') + String studentName; + + @JsonKey(name: 'templateId') + String templateId; + + @JsonKey(name: 'questionNo') + int questionNo; + + @JsonKey(name: 'subjectiveAnswer') + String subjectiveAnswer; + + HomeworkFavs(this.id,this.homeworkId,this.homeworkName,this.grade,this.subject,this.classId,this.className,this.studentId,this.studentName,this.templateId,this.questionNo,this.subjectiveAnswer,); + + factory HomeworkFavs.fromJson(Map srcJson) => _$HomeworkFavsFromJson(srcJson); + + Map toJson() => _$HomeworkFavsToJson(this); + +} + + diff --git a/lib/common/job/homework_details.dart b/lib/common/job/homework_details.dart new file mode 100644 index 0000000..2a7c500 --- /dev/null +++ b/lib/common/job/homework_details.dart @@ -0,0 +1,219 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'homework_details.g.dart'; + + +@JsonSerializable() +class HomeworkDetails extends Object { + + @JsonKey(name: 'questions') + List questions; + + @JsonKey(name: 'knows') + List knows; + + @JsonKey(name: 'students') + List students; + + @JsonKey(name: 'dtls') + List dtls; + + HomeworkDetails(this.questions,this.knows,this.students,this.dtls); + + factory HomeworkDetails.fromJson(Map srcJson) => _$HomeworkDetailsFromJson(srcJson); + + Map toJson() => _$HomeworkDetailsToJson(this); + +} + + +@JsonSerializable() +class Questions extends Object { + + @JsonKey(name: 'id') + String id; + + @JsonKey(name: 'templateId') + int templateId; + + @JsonKey(name: 'questionNo') + int questionNo; + + @JsonKey(name: 'questionType') + int questionType; + + @JsonKey(name: 'answer') + String? answer; + + @JsonKey(name: 'score') + int? score; + + @JsonKey(name: 'questionPicture') + String? questionPicture; + + @JsonKey(name: 'subjectivePicture') + String? subjectivePicture; + + @JsonKey(name: 'knows') + List knows; + + @JsonKey(name: 'answerCount') + int? answerCount; + + @JsonKey(name: 'answerRate') + double? answerRate; + + @JsonKey(name: 'okRate') + double? okRate; + + @JsonKey(name: 'priorityInfo') + List? priorityInfo; + + @JsonKey(name: 'noAnswerStudents') + List? noAnswerStudents; + + @JsonKey(name: 'answerOkStudents') + List? answerOkStudents; + + @JsonKey(name: 'answerNgStudents') + List? answerNgStudents; + + Questions(this.id,this.templateId,this.questionNo,this.questionType,this.answer,this.score,this.questionPicture,this.subjectivePicture,this.knows,this.answerCount, + this.answerRate,this.okRate,this.priorityInfo,this.noAnswerStudents,this.answerOkStudents,this.answerNgStudents); + + factory Questions.fromJson(Map srcJson) => _$QuestionsFromJson(srcJson); + + Map toJson() => _$QuestionsToJson(this); + +} + + +@JsonSerializable() +class Knows extends Object { + + @JsonKey(name: 'knowledgeId') + int knowledgeId; + + @JsonKey(name: 'knowledgeName') + String knowledgeName; + + @JsonKey(name: 'okCount') + int? okCount; + + @JsonKey(name: 'ttlCount') + int? ttlCount; + + @JsonKey(name: 'okRate') + double? okRate; + + Knows(this.knowledgeId,this.knowledgeName,this.okCount,this.ttlCount,this.okRate); + + factory Knows.fromJson(Map srcJson) => _$KnowsFromJson(srcJson); + + Map toJson() => _$KnowsToJson(this); + +} + + +@JsonSerializable() +class Students extends Object { + + @JsonKey(name: 'studentId') + int studentId; + + @JsonKey(name: 'studentName') + String studentName; + + @JsonKey(name: 'state') + int state; + + @JsonKey(name: 'priorityAnnotate') + bool priorityAnnotate; + + @JsonKey(name: 'kgtStu') + List? kgtStu; + + @JsonKey(name: 'kgtOkCount') + int? kgtOkCount; + + @JsonKey(name: 'kgtErrorCount') + int? kgtErrorCount; + + @JsonKey(name: 'kgtAnswerCount') + int? kgtAnswerCount; + + @JsonKey(name: 'zgtStu') + List? zgtStu; + + @JsonKey(name: 'zgtOkCount') + int? zgtOkCount; + + @JsonKey(name: 'zgtErrorCount') + int? zgtErrorCount; + + @JsonKey(name: 'zgtAnswerCount') + int? zgtAnswerCount; + + @JsonKey(name: 'zgtUnrated') + int? zgtUnrated; + + @JsonKey(name: 'allOk') + int? allOk; + + @JsonKey(name: 'allNotDone') + bool? allNotDone; + + Students(this.studentId,this.studentName,this.state,this.priorityAnnotate,this.kgtStu,this.kgtOkCount,this.kgtAnswerCount,this.zgtStu,this.zgtAnswerCount,this.zgtOkCount,this.allOk,this.kgtErrorCount,this.zgtErrorCount,this.zgtUnrated,this.allNotDone); + + factory Students.fromJson(Map srcJson) => _$StudentsFromJson(srcJson); + + Map toJson() => _$StudentsToJson(this); + +} + + +@JsonSerializable() +class Dtls extends Object { + + @JsonKey(name: 'id') + String id; + + @JsonKey(name: 'classId') + String? classId; + + @JsonKey(name: 'studentId') + int studentId; + + @JsonKey(name: 'studentName') + String? studentName; + + @JsonKey(name: 'templateId') + int? templateId; + + @JsonKey(name: 'questionNo') + int questionNo; + + @JsonKey(name: 'questionType') + int questionType; + + @JsonKey(name: 'studentAnswer') + String? studentAnswer; + + @JsonKey(name: 'state') + int state; + + @JsonKey(name: 'useTime') + int useTime; + + @JsonKey(name: 'annotatePicture') + String? annotatePicture; + + Dtls(this.id,this.classId,this.studentId,this.templateId,this.questionNo,this.questionType,this.studentAnswer,this.state,this.useTime,this.annotatePicture,this.studentName); + + factory Dtls.fromJson(Map srcJson) => _$DtlsFromJson(srcJson); + + Map toJson() => _$DtlsToJson(this); + +} + + diff --git a/lib/common/job/work_student.dart b/lib/common/job/work_student.dart index 8dd9bd5..1e329bf 100644 --- a/lib/common/job/work_student.dart +++ b/lib/common/job/work_student.dart @@ -43,28 +43,34 @@ class Items extends Object { String publishTime; @JsonKey(name: 'state') - int state; + int? state; @JsonKey(name: 'collectRate') int? collectRate; + @JsonKey(name: 'questionCount') + int? questionCount; + + @JsonKey(name: 'annotateCount') + int annotateCount; + @JsonKey(name: 'annotateRate') double annotateRate; @JsonKey(name: 'classes') - List classes; + List? classes; @JsonKey(name: 'creatorName') - String creatorName; + String? creatorName; @JsonKey(name: 'creationTime') - String creationTime; + String? creationTime; @JsonKey(name: 'classCount') int? classCount; - Items(this.id,this.assessType,this.name,this.grade,this.subject,this.publishTime,this.state,this.collectRate,this.annotateRate,this.classes,this.creatorName,this.creationTime,this.classCount); + Items(this.id,this.assessType,this.name,this.grade,this.subject,this.publishTime,this.state,this.collectRate,this.questionCount,this.annotateCount,this.annotateRate,this.classes,this.creatorName,this.creationTime,this.classCount); factory Items.fromJson(Map srcJson) => _$ItemsFromJson(srcJson); diff --git a/lib/common/job/work_student_params.dart b/lib/common/job/work_student_params.dart index ea6684e..8f39a21 100644 --- a/lib/common/job/work_student_params.dart +++ b/lib/common/job/work_student_params.dart @@ -21,11 +21,11 @@ class WorkStudentParams extends Object { @JsonKey(name: 'State') int? state; - @JsonKey(name: 'PublishTimeStart') - String? publishTimeStart; + @JsonKey(name: 'StartDate') + String? startDate; - @JsonKey(name: 'PublishTimeEnd') - String? publishTimeEnd; + @JsonKey(name: 'EndDate') + String? endDate; @JsonKey(name: 'CreatorId') String? creatorId; @@ -39,7 +39,7 @@ class WorkStudentParams extends Object { @JsonKey(name: 'Sorting') String? sorting; - WorkStudentParams({this.assessType = 0,this.name,this.grade,this.subject,this.state,this.publishTimeStart,this.publishTimeEnd,this.creatorId,this.pageNumber = 1,this.pageSize = 10,this.sorting,}); + WorkStudentParams({this.assessType = 0,this.name,this.grade,this.subject,this.state,this.startDate,this.endDate,this.creatorId,this.pageNumber = 1,this.pageSize = 10,this.sorting,}); factory WorkStudentParams.fromJson(Map srcJson) => _$WorkStudentParamsFromJson(srcJson); diff --git a/lib/common/store/user_store.dart b/lib/common/store/user_store.dart index 9fbba17..451d009 100644 --- a/lib/common/store/user_store.dart +++ b/lib/common/store/user_store.dart @@ -62,7 +62,6 @@ class UserStore extends GetxController with RequestToolMixin { } void getEnum() async{ - await getSubjectList(); await getGradeList(); } @@ -99,14 +98,16 @@ class UserStore extends GetxController with RequestToolMixin { //获取科目 getSubjectList() async { - var res = await getClient().getEnumSubjectList('EnumSubject'); - subjectList.value = res['EnumSubject']!; + // var res = await getClient().getEnumSubjectList(); + } //获取年级 getGradeList() async { - var res = await getClient().getEnumSubjectList('EnumGrade'); + + var res = await getClient().getEnumSubjectList(['EnumGrade','EnumSubject']); gradeList.value = res['EnumGrade']!; + subjectList.value = res['EnumSubject']!; } diff --git a/lib/common/utils/enum_untils.dart b/lib/common/utils/enum_untils.dart index 5e655f4..ff01799 100644 --- a/lib/common/utils/enum_untils.dart +++ b/lib/common/utils/enum_untils.dart @@ -3,7 +3,7 @@ import 'package:school_asignment_app/common/store/user_store.dart'; class EnumUtils{ static String formatSubject(int id) { - if (UserStore.to.subjectList.isEmpty) { + if (UserStore.to.subjectList.isEmpty || id == null) { return ''; } EnumSubject item = UserStore.to.subjectList.firstWhere((element) => element.id == id); @@ -11,7 +11,7 @@ class EnumUtils{ } static String formatGrade(int id) { - if (UserStore.to.gradeList.isEmpty) { + if (UserStore.to.gradeList.isEmpty || id == null) { return ''; } EnumSubject item = UserStore.to.gradeList.firstWhere((element) => element.id == id); diff --git a/lib/common/utils/utils.dart b/lib/common/utils/utils.dart index 71af9c0..c4f2b33 100644 --- a/lib/common/utils/utils.dart +++ b/lib/common/utils/utils.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:school_asignment_app/common/job/homework_details.dart'; +import 'package:school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_state.dart'; class Utils{ Utils._internal(); @@ -36,4 +38,111 @@ class Utils{ return defaultVal ?? ''; } } + + /// 去除小数点 + static String doubleToStringAsFixed(double val, {int fractionDigits = 2}) { + return val.toStringAsFixed(fractionDigits).replaceAll(RegExp(r'\.0*$'), ''); + } + + static calcRate (int divisor, int dividend) { + if(dividend != 0){ + return ((100 * divisor) / dividend); + // return ((100 * divisor) / dividend).toStringAsFixed(0); + }else{ + return 0; + } + + } + + static getHomeworkData(HomeworkDetails data){ + + CountData dataCount = CountData(); + List kgt = data.dtls.where((w) => w.questionType == 1).toList(); + dataCount.kgtAnswerCount = kgt.where((w) => w.state != 0).length; + dataCount.kgtOkCount = kgt.where((w) => w.state == 4).length; + dataCount.kgtDtlCount = kgt.length; + dataCount.kgtAnswerRate = Utils.calcRate(dataCount.kgtAnswerCount!, dataCount.kgtDtlCount!); + dataCount.kgtOkRate = Utils.calcRate(dataCount.kgtOkCount!, dataCount.kgtDtlCount!); + dataCount.kgtCount = data.questions.where((w) => w.questionType == 1).length; + + List zgt = data.dtls.where((w) => w.questionType == 2).toList(); + dataCount.zgtAnswerCount = zgt.where((w) => w.state != 0).length; + dataCount.zgtOkCount = zgt.where((w) => w.state == 4).length; + dataCount.zgtDtlCount = zgt.length; + dataCount.zgtAnswerRate = Utils.calcRate(dataCount.zgtAnswerCount!, dataCount.zgtDtlCount!); + dataCount.zgtOkRate = Utils.calcRate(dataCount.zgtOkCount!, dataCount.zgtDtlCount!); + dataCount.zgtCount = data.questions.where((w) => w.questionType == 2).length; + dataCount.studentCount = data.students.length; + dataCount.priorityStudents = data.students.where((w) => w.priorityAnnotate).toList(); + + + for(var que in data.questions){ + List ques = data.dtls.where((w) => w.templateId == que.templateId && w.questionNo == que.questionNo).toList(); + que.answerCount = ques.where((w) => w.state != 0).length; + que.answerRate = Utils.calcRate(que.answerCount!, dataCount.studentCount!); + int okCount = ques.where((w) => w.state == 4).length; + que.okRate = Utils.calcRate(okCount, dataCount.studentCount!) ; + que.priorityInfo = ques.where((w) { + return dataCount.priorityStudents!.indexWhere((s) { + w.studentName = s.studentName; + return s.studentId == w.studentId; + }) > -1 && w.state != 4; + }).toList(); + + que.answerNgStudents = ques.where((w) { + w.studentName = data.students.firstWhere((s) => s.studentId == w.studentId).studentName; + return w.state == 2; + }).toList(); + + que.noAnswerStudents = ques.where((w) { + return w.state == 0; + }).toList(); + que.answerOkStudents = ques.where((w) { + return w.state == 4; + }).toList(); + + } + + + + + dataCount.studentSubmitCount = data.students.where((s) => s.state != 0).length; + + for(var stu in data.students){ + stu.kgtStu = kgt.where((w) => w.studentId == stu.studentId).toList(); + stu.kgtStu!.sort((a, b) => a.questionNo.compareTo(b.questionNo)); + stu.kgtOkCount = stu.kgtStu!.where((w) => w.state == 4).length; + stu.kgtErrorCount = stu.kgtStu!.where((w) => w.state == 2).length; + stu.kgtAnswerCount = stu.kgtStu!.where((w) => w.state != 0).length; + + stu.zgtStu = zgt.where((w) => w.studentId == stu.studentId).toList(); + stu.zgtStu!.sort((a, b) => a.questionNo.compareTo(b.questionNo)); + stu.zgtOkCount = stu.zgtStu!.where((w) => w.state == 4).length; + stu.zgtErrorCount = stu.zgtStu!.where((w) => w.state == 2).length; + stu.zgtUnrated = stu.zgtStu!.where((w) => w.state == 1).length; + stu.zgtAnswerCount = stu.zgtStu!.where((w) => w.state != 0).length; + stu.allOk = data.dtls.where((w) => w.studentId == stu.studentId && w.state != 4).length??0; + if( (stu.kgtStu!.length - stu.kgtAnswerCount!) + (stu.zgtStu!.length-stu.zgtAnswerCount!) == (stu.kgtStu!.length + stu.zgtStu!.length)){ + stu.allNotDone = true; + }else{ + stu.allNotDone = false; + } + } + + data.students.sort((a, b) { + int num1 = a.state; + int num2 = b.state; + return num2.compareTo(num1); + }); + + for(var know in data.knows){ + List ques = data.questions.where((w) => w.knows.indexWhere((k) => k.knowledgeId == know.knowledgeId) > -1).toList(); + List queDtls = data.dtls.where((w) => ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1).toList(); + know.okCount = queDtls.where((w) => w.state == 4).length; + know.ttlCount = queDtls.length; + know.okRate = Utils.calcRate(know.okCount!, know.ttlCount!); + } + + return dataCount; + } } \ No newline at end of file diff --git a/lib/page/global_widget/imgDialog.dart b/lib/page/global_widget/imgDialog.dart new file mode 100644 index 0000000..0464844 --- /dev/null +++ b/lib/page/global_widget/imgDialog.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:school_asignment_app/common/config/request_config.dart'; + +class ImageDialog{ + static void showImgDialog(BuildContext context,String imgUrl) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + // insetPadding: EdgeInsets.symmetric(vertical: 10.r,horizontal: 45.r), + backgroundColor: Colors.transparent, + contentPadding: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: Container( + width: MediaQuery.of(context).size.width - 48.r, + // height: MediaQuery.of(context).size.height * 0.4, + color: Colors.white, + // child: PhotoView(imageProvider: NetworkImage(imgUrl),backgroundDecoration: BoxDecoration(color: Colors.transparent),)), + child: Image.network(RequestConfig.imgUrl+imgUrl)), + ); + }, + ); + } +} \ No newline at end of file diff --git a/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart b/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart new file mode 100644 index 0000000..22771d7 --- /dev/null +++ b/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart @@ -0,0 +1,152 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:school_asignment_app/common/job/homework_details.dart'; +import 'package:school_asignment_app/common/utils/utils.dart'; +import 'package:school_asignment_app/page/home_page/children/quick_data_check/widget/report_table.dart'; + +class KgtZgtTable extends StatefulWidget { + final int studentCount; + final String homeworkId; + final List kgReport; + final List zgReport; + final String kgtOkRate; + final String zgtOkRate; + + const KgtZgtTable( + {Key? key, + required this.studentCount, + required this.homeworkId, + required this.kgReport, + required this.zgReport, + required this.kgtOkRate, + required this.zgtOkRate}) + : super(key: key); + + @override + State createState() => _KgtZgtTableState(); +} + +class _KgtZgtTableState extends State { + @override + void initState() { + super.initState(); + + + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + //客观题 + Container( + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6.r)), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + '客观题', + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF5C5C5C), + fontWeight: FontWeight.w600), + ), + SizedBox( + width: 10.r, + ), + Text( + '${widget.kgtOkRate}%', + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF6888FD), + fontWeight: FontWeight.w600), + ), + ], + ), + SizedBox( + height: 6.r, + ), + SizedBox( + height: widget.kgReport.length > 10 + ? 300.r + : widget.kgReport.length * 40.r + + (Utils.isPad() == true ? 40.r : 65.r), + child: ReportTable( + headList: const ['题', '作答率', '作答人数', '正确率', '标准答案', '优先批阅概况'], + bodyList: widget.kgReport, + fixedCols: 1, + fixedRows: 1, + jobId: widget.homeworkId, + studentCount: widget.studentCount, + ), + ) + ], + ), + ), + //主观题 + Container( + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), + margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6.r)), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + '主观题', + style: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF5C5C5C), + fontWeight: FontWeight.w600), + ), + SizedBox( + width: 6.r, + ), + Text( + '${widget.zgtOkRate}%', + style: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF6888FD), + fontWeight: FontWeight.w600), + ), + ], + ), + SizedBox( + height: 10.r, + ), + SizedBox( + height: widget.zgReport.length > 10 + ? 300.r + : widget.zgReport.length * 40.r + + (Utils.isPad() == true ? 40.r : 65.r), + child: ReportTable( + headList: const ['题', '作答率', '作答人数', '正确率', '查看原题', '优先批阅概况'], + bodyList: widget.zgReport, + fixedCols: 1, + fixedRows: 1, + isKG: true, + jobId: widget.homeworkId, + studentCount: widget.studentCount, + ), + ) + ], + ), + ), + ], + ); + } +} diff --git a/lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart b/lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart new file mode 100644 index 0000000..d6bc129 --- /dev/null +++ b/lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart @@ -0,0 +1,257 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:school_asignment_app/common/job/homework_details.dart'; +import 'package:school_asignment_app/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart'; + +class QuickDataCheckBottom extends StatefulWidget { + final String jobId; + final int kgCount; + final int zgCount; + final List? jobData; + + const QuickDataCheckBottom( + {Key? key, required this.jobId, required this.jobData, required this.kgCount, required this.zgCount}) + : super(key: key); + + @override + State createState() => _QuickDataCheckBottomState(); +} + +class _QuickDataCheckBottomState extends State { + RxList showList = RxList(); + RxList followList = RxList(); + RxBool sortType = true.obs; + RxBool sortLevel = false.obs; + + void initState() { + super.initState(); + showList.value = widget.jobData!; + for (var e in widget.jobData!) { + if(e.priorityAnnotate){ + followList.add(e); + } + } + } + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6.r))), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + InkWell( + onTap: () { + sortType.value = !sortType.value; + sortLevel.value = false; + if (widget.jobData == null) return; + if (!sortType.value) { + showList.sort((a, b) { + return a.state.compareTo(b.state); + }); + } else { + showList.sort((a, b) { + return b.state.compareTo(a.state); + }); + } + + }, + child: Obx(() { + return Row( + children: [ + if (!sortType.value) + Image.asset( + 'assets/images/no_check_icon.png', + width: 16.r, + height: 16.r, + ), + if (sortType.value) + Image.asset( + 'assets/images/check_icon.png', + width: 16.r, + height: 16.r, + ), + SizedBox( + width: 5.r, + ), + Text( + sortType.value ? '已提交排序' : '未提交排序', + style: + TextStyle(fontSize: 12.sp, color: Color(0xFF707070)), + ), + ], + ); + }), + ), + SizedBox( + width: 20.r, + ), + InkWell( + onTap: () { + if (widget.jobData!.isEmpty) return; + if (!sortLevel.value) { + showList.value = followList.value; + } else { + widget.jobData!.sort((a, b) { + int num1 = a.state; + int num2 = b.state; + return num2.compareTo(num1); + }); + showList.value = widget.jobData!; + } + sortLevel.value = !sortLevel.value; + sortType.value = false; + }, + child: Obx(() { + return Row( + children: [ + if (!sortLevel.value) + Image.asset( + 'assets/images/no_check_icon.png', + width: 16.r, + height: 16.r, + ), + if (sortLevel.value) + Image.asset( + 'assets/images/check_icon.png', + width: 16.r, + height: 16.r, + ), + SizedBox( + width: 5.r, + ), + Text( + '看关注学生', + style: TextStyle( + fontSize: 12.sp, color: const Color(0xFF707070)), + ), + ], + ); + }), + ), + ], + ), + SizedBox( + height: 10.r, + ), + Row( + children: [ + Text( + '注:', + style: + TextStyle(fontSize: 8.sp, color: const Color(0xFF717171)), + ), + Container( + width: 10.r, + height: 10.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.r)), + color: const Color(0xFF4CC793), + ), + ), + SizedBox( + width: 2.r, + ), + Text( + '正确', + style: TextStyle(fontSize: 8.sp, color: Color(0xFF717171)), + ), + SizedBox( + width: 15.r, + ), + Container( + width: 10.r, + height: 10.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.r)), + color: const Color(0xFFFF7474), + ), + ), + SizedBox( + width: 2.r, + ), + Text( + '错误', + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF717171)), + ), + SizedBox( + width: 15.r, + ), + Container( + width: 10.r, + height: 10.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.r)), + color: Colors.white, + // border: Border.all(width: 1.r,color: Colors.grey), + boxShadow: [ + BoxShadow( + color: Colors.grey, + offset: Offset(1.w, 1.h), //阴影y轴偏移量 + blurRadius: 4, //阴影模糊程度 + spreadRadius: 0.1, //阴影扩散程度 + ) + ], + ), + ), + SizedBox( + width: 2.r, + ), + Text( + '已作答未批阅', + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF717171)), + ), + SizedBox( + width: 15.r, + ), + Container( + width: 10.r, + height: 10.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.r)), + color: const Color(0xFFD3D3D3), + ), + ), + SizedBox( + width: 2.r, + ), + Text( + '未做', + style: TextStyle( + fontSize: 8.sp, color: const Color(0xFF717171)), + ), + ], + ), + SizedBox( + height: 10.r, + ), + Obx(() { + return SizedBox( + height: showList.value.length > 5 ? 350.r : showList.value + .length * 50.r + 40.r, + child: QuickStudentDataTable( + headList: ['学生姓名', '客观题', '主观题', '客观题状态', '主观题状态', '未批阅'], + bodyList: showList.value, + jobId: widget.jobId, + fixedRows: 1, + fixedCols: 0, + // hasUnrated: widget.jobData!.hasUnrated, + hasUnrated: false, + kgCount: widget.kgCount, + zgCount: widget.zgCount, + ), + ); + }) + ], + ), + ); + } +} diff --git a/lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart b/lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart new file mode 100644 index 0000000..f364ecd --- /dev/null +++ b/lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart @@ -0,0 +1,272 @@ +import 'package:data_table_2/data_table_2.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:school_asignment_app/common/job/homework_details.dart'; + +class QuickStudentDataTable extends StatefulWidget { + final List headList; + final List bodyList; + final int? fixedRows; + final int? fixedCols; + final String jobId; + final bool hasUnrated; + final int kgCount; + final int zgCount; + + const QuickStudentDataTable({ + Key? key, + required this.headList, + required this.bodyList, + required this.jobId, + required this.hasUnrated, + required this.kgCount, + required this.zgCount, + this.fixedCols = 0, + this.fixedRows = 0, + }) : super(key: key); + + @override + State createState() => _QuickStudentDataTableState(); +} + +class _QuickStudentDataTableState extends State { + final ScrollController _controller = ScrollController(); + int? _sortColumnIndex; + final bool _sortAscending = true; + + + DataRow _getRow(int index, [Color? color]) { + assert(index >= 0); + Students item = widget.bodyList[index]; + return DataRow2.byIndex( + index: index, + color: color != null + ? item.allNotDone! + ? MaterialStateProperty.all(Color(0xFFFFD79C)) + : MaterialStateProperty.all(color) + : null, + cells: [ + DataCell(InkWell( + onTap: () { + /*RouterManager.router.navigateTo( + context, + RouterManager.quickCheckPersonalPath + + '?jobId=${widget.jobId}&studentId=${item.studentId}', + transition: getTransition(), + );*/ + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(item.studentName!, + style: + TextStyle(fontSize: 10.sp, color: const Color(0xFF6888FD),overflow: TextOverflow.ellipsis)), + SizedBox( + width: 5.r, + ), + Image.asset( + 'assets/images/job_data_right_icon.png', + width: 10.r, + height: 10.r, + ) + ], + ), + ), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '${item.kgtOkCount}', + style: TextStyle(fontSize: 10.sp, color: Color(0xFF4CC793))), + Text( + '/', + style: TextStyle(fontSize: 10.sp, color: Color(0xFF525252))), + Text( + '${item.kgtErrorCount}', + style: TextStyle(fontSize: 10.sp, color: Color(0xFFFF7474))), + ], + ), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '${item.zgtOkCount}', + style: TextStyle(fontSize: 10.sp, color: Color(0xFF4CC793))), + Text( + '/', + style: TextStyle(fontSize: 10.sp, color: Color(0xFF525252))), + Text( + '${item.zgtErrorCount}', + style: TextStyle(fontSize: 10.sp, color: Color(0xFFFF7474))), + ], + ), + ), + )), + DataCell( + Padding( + padding: EdgeInsets.symmetric(vertical: 2.r, horizontal: 5.r), + child: SingleChildScrollView( + child: Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + spacing: 2, + runSpacing: 3, + children: List.generate(item.kgtStu!.length, (index) { + Dtls kgInfo = item.kgtStu![index]; + return Container( + width: 14.r, + height: 14.r, + decoration: BoxDecoration( + color: kgInfo.state == 0 + ? const Color(0xFFD3D3D3) + : kgInfo.state == 1?Colors.white:kgInfo.state == 2 + ? const Color(0xFFFF7474) + : const Color(0xFF4CC793), + borderRadius: BorderRadius.all(Radius.circular(7.r))), + child: Center( + child: Text( + kgInfo.questionNo.toString(), + style: TextStyle( + fontSize: 8.sp, + color: kgInfo.state == 1 + ? Color(0xFF525252) + : Colors.white), + )), + ); + })), + ), + ), + ), + DataCell( + Padding( + padding: EdgeInsets.symmetric(vertical: 2.r, horizontal: 5.r), + child: SingleChildScrollView( + child: Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + spacing: 2, + runSpacing: 3, + children: List.generate(item.zgtStu!.length, (index) { + Dtls kgInfo = item.zgtStu![index]; + return Container( + width: 14.r, + height: 14.r, + decoration: BoxDecoration( + color: kgInfo.state == 0 + ? const Color(0xFFD3D3D3) + : kgInfo.state == 1?Colors.white:kgInfo.state == 2 + ? const Color(0xFFFF7474) + : const Color(0xFF4CC793), + borderRadius: BorderRadius.all(Radius.circular(7.r))), + child: Center( + child: Text( + kgInfo.questionNo.toString(), + style: TextStyle( + fontSize: 8.sp, + color: kgInfo.state == 1 + ? Color(0xFF525252) + : Colors.white), + )), + ); + })), + ), + ), + ), + if(widget.hasUnrated) + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text('${item.zgtUnrated}', + style: + TextStyle(fontSize: 10.sp, color: const Color(0xFF6888FD))), + ), + )), + ], + ); + } + + @override + Widget build(BuildContext context) { + if(!widget.hasUnrated){ + widget.headList.removeLast(); + } + return DataTable2( + dividerThickness: 0, + scrollController: _controller, + columnSpacing: 0, + horizontalMargin: 0, + bottomMargin: 0, + dataRowHeight: 50.r, + border: const TableBorder( + horizontalInside: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => + widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), + fixedColumnsColor: Color(0xFFE6E6E6), + fixedCornerColor: Colors.grey[400], + minWidth: MediaQuery.of(context).size.width, + fixedTopRows: widget.fixedRows!, + fixedLeftColumns: widget.fixedCols!, + sortColumnIndex: _sortColumnIndex, + sortAscending: _sortAscending, + // onSelectAll: (val) => setState(() => selectAll(val)), + columns: List.generate(widget.headList.length, (index) { + var item = widget.headList[index]; + return index == 1?DataColumn2( + label: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(item, + style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), + Text('(${widget.kgCount})', + style: TextStyle(fontSize: 8.sp, color: Color(0xFF505767))), + ] + ), + // size: ColumnSize.S, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, + ):index == 2?DataColumn2( + label: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(item, + style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), + Text('(${widget.zgCount})', + style: TextStyle(fontSize: 8.sp, color: Color(0xFF505767))), + ] + ), + // size: ColumnSize.S, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, + ):DataColumn2( + label: Center( + child: Text(item, + style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), + ), + // size: ColumnSize.S, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, + ); + }), + rows: List.generate(widget.bodyList.length, + (index) => _getRow(index, Color(0xFFF5F5F5)))); + } +} diff --git a/lib/page/home_page/children/quick_data_check/widget/report_table.dart b/lib/page/home_page/children/quick_data_check/widget/report_table.dart new file mode 100644 index 0000000..56ab672 --- /dev/null +++ b/lib/page/home_page/children/quick_data_check/widget/report_table.dart @@ -0,0 +1,467 @@ +import 'package:data_table_2/data_table_2.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:school_asignment_app/common/job/annotated_class.dart'; +import 'package:school_asignment_app/common/job/homework_details.dart'; +import 'package:school_asignment_app/common/utils/toast_utils.dart'; +import 'package:school_asignment_app/common/utils/utils.dart'; +import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:school_asignment_app/page/global_widget/imgDialog.dart'; + + +class ReportTable extends StatefulWidget { + final List headList; + final List bodyList; + final int? fixedRows; + final int? fixedCols; + final bool? isKG; + final String jobId; + final int studentCount; + + const ReportTable({ + Key? key, + required this.headList, + required this.bodyList, + required this.jobId, + required this.studentCount, + this.fixedCols = 0, + this.fixedRows = 0, + this.isKG = false, + }) : super(key: key); + + @override + State createState() => _ReportTableState(); +} + +class _ReportTableState extends State { + final ScrollController _controller = ScrollController(); + int? _sortColumnIndex; + final bool _sortAscending = true; + + void showPeopleListDialog( + {required BuildContext context, + required String title, + required String questionNo, + required List arr, + List? dcList}) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + // insetPadding: EdgeInsets.symmetric(vertical: 20.r,horizontal: 20.r), + contentPadding: EdgeInsets.all(20.r), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + height: MediaQuery.of(context).size.height * 0.7, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Text( + title, + style: TextStyle( + fontSize: 15.sp, + color: const Color(0xFF3C3C3C), + fontWeight: FontWeight.w500), + ), + ), + SizedBox( + height: 5.r, + ), + Row( + children: [ + Text( + widget.isKG == true ? '主观题' : '客观题', + style: TextStyle( + fontSize: 14.sp, color: const Color(0xFF436CFF)), + ), + Text( + '―', + style: TextStyle( + fontSize: 14.sp, color: const Color(0xFF436CFF)), + ), + Text( + '第$questionNo题', + style: TextStyle( + fontSize: 14.sp, color: Color(0xFF436CFF)), + ), + ], + ), + SizedBox( + height: 15.r, + ), + dcList != null + ? Row( + children: [ + Expanded( + flex: 1, + child: Center( + child: Text( + '未作答人', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6A6A6A)), + ))), + Expanded( + flex: 1, + child: Center( + child: Text( + '答对人数', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6A6A6A)), + ))), + Expanded( + flex: 1, + child: Center( + child: Text( + '答错人', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6A6A6A)), + ))), + ], + ) + : Padding( + padding: EdgeInsets.only(left: 15.r), + child: Text( + title, + style: TextStyle( + fontSize: 12.sp, color: Color(0xFF6A6A6A)), + ), + ), + SizedBox( + height: 5.r, + ), + if (dcList != null) + Expanded( + child: ListView.builder( + shrinkWrap: true, + itemBuilder: (context, index) { + var item = arr[index]; + return Container( + padding: EdgeInsets.symmetric(vertical: 5.r), + color: + index.isOdd ? Colors.white : Color(0xFFF0F0F0), + child: Row( + children: [ + Expanded( + flex: 1, + child: InkWell( + onTap: () { + goQuickCheckPersonalPath( + item['noAnswerStudents'].id); + }, + child: Center( + child: Text( + item['noAnswerStudents']?.studentName??'--', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF323232)), + )))), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + goQuickCheckPersonalPath( + item['answerOkStudents'].id); + }, + child: Center( + child: Text( + item['answerOkStudents']?.studentName??'--', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF323232)), + )))), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + goQuickCheckPersonalPath( + item['answerNgStudents'].id); + }, + child: Center( + child: Text( + item['answerNgStudents']?.studentName??'--', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF323232)), + )))), + ], + ), + ); + }, + itemCount: arr.length, + ), + ) + else + arr.isNotEmpty + ? Expanded( + child: ListView.builder( + shrinkWrap: true, + itemBuilder: (context, index) { + Dtls item = arr[index]; + return InkWell( + onTap: () { + goQuickCheckPersonalPath(item.id); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 5.r, horizontal: 15.r), + color: index.isOdd + ? Colors.white + : Color(0xFFF0F0F0), + child: Text( + item.studentName!??'--', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF323232)), + ), + ), + ); + }, + itemCount: arr.length, + ), + ) + : const MyEmptyWidget() + ], + ), + ), + ); + }); + } + + void goQuickCheckPersonalPath(id) { + if (id) { + /*RouterManager.router.navigateTo( + context, + RouterManager.quickCheckPersonalPath + + '?jobId=${widget.jobId}&studentId=$id', + transition: getTransition(), + );*/ + } + } + + void zdHandle(BuildContext context, String title, String questionNo, + List noAnswerStudents, List answerNgStudents, List answerOkStudents) { + List list = []; + // Questions student = Questions('','',-1,-1,'',-1,'','',[],-1,-1,[] as double?); + print('noAnswerStudents.length=${noAnswerStudents.length}'); + print('answerNgStudents.length=${answerNgStudents.length}'); + print('answerOkStudents.length=${answerOkStudents.length}'); + if (noAnswerStudents.length > answerNgStudents.length && + noAnswerStudents.length > answerOkStudents.length) { + for (int i = 0; i < noAnswerStudents.length; i++) { + var obj = { + 'noAnswerStudents': noAnswerStudents[i], + 'answerNgStudents': + answerNgStudents.length > i ? answerNgStudents[i] : null, + 'answerOkStudents': + answerOkStudents.length > i ? answerOkStudents[i] : null + }; + list.add(obj); + } + } else if (answerNgStudents.length > noAnswerStudents.length && + answerNgStudents.length > answerOkStudents.length) { + for (int i = 0; i < answerNgStudents.length; i++) { + var obj = { + 'noAnswerStudents': + noAnswerStudents.length > i ? noAnswerStudents[i] : null, + 'answerNgStudents': answerNgStudents[i], + 'answerOkStudents': + answerOkStudents.length > i ? answerOkStudents[i] : null + }; + list.add(obj); + } + } else if (answerOkStudents.length > noAnswerStudents.length && + answerOkStudents.length > answerNgStudents.length) { + for (int i = 0; i < answerOkStudents.length; i++) { + var obj = { + 'noAnswerStudents': + noAnswerStudents.length > i ? noAnswerStudents[i] : null, + 'answerNgStudents': + answerNgStudents.length > i ? answerNgStudents[i] : null, + 'answerOkStudents': answerOkStudents[i] + }; + list.add(obj); + } + } + + showPeopleListDialog( + context: context, + title: title, + questionNo: questionNo, + arr: list, + dcList: []); + } + + void dcHandle( + BuildContext context, String title, String questionNo, List arr) { + showPeopleListDialog( + context: context, title: title, questionNo: questionNo, arr: arr); + } + + DataRow _getRow(int index, [Color? color]) { + assert(index >= 0); + var item = widget.bodyList[index]; + return DataRow2.byIndex( + index: index, + color: color != null ? MaterialStateProperty.all(color) : null, + cells: [ + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text(item.questionNo.toString(), + style: TextStyle(fontSize: 10.sp, color: const Color(0xFF525252))), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text('${item.answerRate.toStringAsFixed(0)}%', + style: TextStyle(fontSize: 10.sp, color: const Color(0xFF525252))), + ), + )), + DataCell(InkWell( + onTap: () { + zdHandle(context, '作答人数', item.questionNo.toString(), item.noAnswerStudents, + item.answerNgStudents, item.answerOkStudents); + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('${item.answerCount}/${widget.studentCount}', + style: + TextStyle(fontSize: 10.sp, color: const Color(0xFF4CC793))), + Image.asset( + 'assets/images/green_right_icon.png', + width: 12.r, + height: 12.r, + ), + ], + ), + ), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text('${item.okRate.toStringAsFixed(0)}%', + style: TextStyle(fontSize: 10.sp, color: Color(0xFF525252))), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: widget.isKG == true + ? InkWell( + onTap: () { + if (item.questionPicture == null) { + ToastUtils.showInfo('当前试题没有原题'); + }else{ + ImageDialog.showImgDialog(context,item.questionPicture); + } + }, + child: Text('原题', + style: TextStyle( + fontSize: 10.sp, + color: widget.isKG == true + ? const Color(0xFFFF8A00) + : const Color(0xFF4CC793))), + ) + : Text(item.answer, + style: TextStyle( + fontSize: 10.sp, + color: widget.isKG == true + ? const Color(0xFFFF8A00) + : const Color(0xFF4CC793))), + ), + )), + DataCell(InkWell( + onTap: () { + // List parts = item.priorityGeneral.split('人'); + dcHandle(context, '优先批阅答错人', item.questionNo.toString(), + item.priorityInfo); + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('${item.priorityInfo.length}人答错', + style: + TextStyle(fontSize: 10.sp, color: const Color(0xFF6888FD))), + Image.asset( + 'assets/images/job_data_right_icon.png', + width: 10.r, + height: 10.r, + ) + ], + ), + ), + ), + )), + ], + ); + } + + @override + Widget build(BuildContext context) { + bool isPadFlag = Utils.isPad(); + return DataTable2( + dividerThickness: 0, + scrollController: _controller, + columnSpacing: 0, + horizontalMargin: 0, + dataRowHeight: 40.r, + bottomMargin: 0, + border: const TableBorder( + horizontalInside: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => + widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), + fixedColumnsColor: Color(0xFFE6E6E6), + fixedCornerColor: Colors.grey[400], + minWidth: widget.headList.length > 6 + ? 80.r * widget.headList.length + : isPadFlag + ? MediaQuery.of(context).size.width + : 85.r * widget.headList.length, + fixedTopRows: widget.fixedRows!, + fixedLeftColumns: widget.fixedCols!, + sortColumnIndex: _sortColumnIndex, + sortAscending: _sortAscending, + // onSelectAll: (val) => setState(() => selectAll(val)), + columns: List.generate(widget.headList.length, (index) { + var item = widget.headList[index]; + return DataColumn2( + label: Center( + child: Text(item, + style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), + ), + // size: ColumnSize.S, + fixedWidth: index == 0 + ? 40.r + : widget.headList.length > 6 + ? 80.r + : isPadFlag + ? (MediaQuery.of(context).size.width - 8.r) / + widget.headList.length + : 85.r, + ); + }), + rows: List.generate(widget.bodyList.length, + (index) => _getRow(index, Color(0xFFF5F5F5)))); + } +} diff --git a/lib/page/home_page/children/read_over/read_over_logic.dart b/lib/page/home_page/children/read_over/read_over_logic.dart index c3650d2..65789c8 100644 --- a/lib/page/home_page/children/read_over/read_over_logic.dart +++ b/lib/page/home_page/children/read_over/read_over_logic.dart @@ -27,19 +27,24 @@ class ReadOverLogic extends GetxController with RequestToolMixin, GetTickerProvi ); getList(); } - +//待批阅列表 void getList() async { WorkStudentParams params = WorkStudentParams( - assessType: state.tabIndex.value, + assessType: 0, ); - WorkStudent data = await getClient().getWorkList(params); + WorkStudent data = WorkStudent([], 0); + if(state.tabIndex.value == 0){ + data = await getClient().getUnAnnotateList(params); + }else{ + data = await getClient().getAnnotatedList(params); + } + state.workList.value = data.items; refreshController1.finishRefresh(); refreshController2.finishRefresh(); print('state.workList.length='); print(state.workList.length); } - /// 刷新方法 Future onMyRefresh(EasyRefreshController controller, int tab) async { /* params.page = RequestConfig.basePage.page; diff --git a/lib/page/home_page/children/read_over/read_over_view.dart b/lib/page/home_page/children/read_over/read_over_view.dart index 87142f4..0fe0ec4 100644 --- a/lib/page/home_page/children/read_over/read_over_view.dart +++ b/lib/page/home_page/children/read_over/read_over_view.dart @@ -347,8 +347,7 @@ Widget $reviewedItem({required Items jobTaskItem, required int type, required St child: Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - quickText( - jobTaskItem.publishTime.substring(0, 10), + quickText(DateTime.parse(jobTaskItem.publishTime).toString().substring(0,10), color: const Color.fromRGBO(97, 97, 97, 1), size: 10.sp, fontWeight: FontWeight.w500, diff --git a/lib/page/home_page/children/read_over/widget/task_list_item.dart b/lib/page/home_page/children/read_over/widget/task_list_item.dart index 1fefafb..84cd9f5 100644 --- a/lib/page/home_page/children/read_over/widget/task_list_item.dart +++ b/lib/page/home_page/children/read_over/widget/task_list_item.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; import 'package:percent_indicator/percent_indicator.dart'; import 'package:school_asignment_app/common/job/work_student.dart'; import 'package:school_asignment_app/common/utils/enum_untils.dart'; import 'package:school_asignment_app/page/global_widget/my_text.dart'; import 'package:school_asignment_app/common/utils/utils.dart'; +import 'package:school_asignment_app/routes/app_pages.dart'; class TaskListItem extends StatefulWidget { final bool completed; @@ -89,8 +91,7 @@ class _TaskListItemState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - quickText( - widget.jobTaskItem.publishTime.substring(0, 10), + quickText(DateTime.parse(widget.jobTaskItem.publishTime).toString().substring(0,10), color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp, fontWeight: FontWeight.w500, @@ -158,6 +159,7 @@ class _TaskListItemState extends State { RouterManager.router.navigateTo(context, url, transition: getTransition()).then((value) { if (value != null && value == true) call(); });*/ + Get.toNamed(Routes.annotateClassPage,arguments: {'id':widget.jobTaskItem.id,'name':widget.jobTaskItem.name,'grade':widget.jobTaskItem.grade}); }, child: Stack( alignment: const FractionalOffset(0.95, 0), @@ -244,7 +246,7 @@ class _TaskListItemState extends State { ), quickText(' / ', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500), - quickText(widget.jobTaskItem.publishTime.substring(0, 16), + quickText(DateTime.parse(widget.jobTaskItem.publishTime).toString().substring(0,10), color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp), ], ), diff --git a/lib/page/home_page/widget/progress_bar.dart b/lib/page/home_page/widget/progress_bar.dart new file mode 100644 index 0000000..be9ddae --- /dev/null +++ b/lib/page/home_page/widget/progress_bar.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:percent_indicator/percent_indicator.dart'; +import 'package:school_asignment_app/common/utils/utils.dart'; +import 'package:school_asignment_app/page/global_widget/my_text.dart'; + +class ProgressBar extends StatefulWidget { + late double? fontSize; + late double? lineHeight; + final String title; + final Color color; + final double percent; + final EdgeInsets padingEdg; + final EdgeInsets marginEdg; + ProgressBar({Key? key,this.fontSize,this.lineHeight,required this.title,required this.color,required this.percent,required this.marginEdg,required this.padingEdg}) : super(key: key); + + @override + State createState() => _ProgressBarState(); +} + +class _ProgressBarState extends State { + @override + Widget build(BuildContext context) { + var percentStr = '${Utils.doubleToStringAsFixed(widget.percent * 100)}%'; + widget.fontSize ??= 10.sp; + widget.lineHeight ??= 8.h; + return Container( + margin: widget.marginEdg, + padding: widget.padingEdg, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (widget.title == '总正确率:') quickText('确率', color: Colors.transparent, size: widget.fontSize), + quickText(widget.title, color: const Color(0xFF8B8B8B), size: widget.fontSize), + Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.r), + ), + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: widget.lineHeight!, + animationDuration: 2500, + percent: widget.percent, + progressColor: widget.color, + backgroundColor: const Color(0xFFE8E8E8), + barRadius: Radius.circular(10.r), + ), + ), + ), + SizedBox(width: 4.w), + // percentStr + quickText(percentStr, size: widget.fontSize, color: const Color(0xFF464646)), + ], + ), + ); + } +} diff --git a/lib/routes/app_pages.dart b/lib/routes/app_pages.dart index cd3ff4f..7cbbd4c 100644 --- a/lib/routes/app_pages.dart +++ b/lib/routes/app_pages.dart @@ -1,9 +1,15 @@ import 'package:get/get.dart'; import 'package:school_asignment_app/page/global_widget/other_page.dart'; import 'package:school_asignment_app/page/global_widget/start_page.dart'; +import 'package:school_asignment_app/page/home_page/children/annotate_class/annotate_class_binding.dart'; +import 'package:school_asignment_app/page/home_page/children/annotate_class/annotate_class_view.dart'; import 'package:school_asignment_app/page/home_page/children/class_student/class_student_binding.dart'; import 'package:school_asignment_app/page/home_page/children/class_student/class_student_view.dart'; +import 'package:school_asignment_app/page/home_page/children/job_report/job_report_binding.dart'; +import 'package:school_asignment_app/page/home_page/children/job_report/job_report_view.dart'; import 'package:school_asignment_app/page/home_page/children/my_info.dart'; +import 'package:school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_binding.dart'; +import 'package:school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_view.dart'; import 'package:school_asignment_app/page/home_page/children/read_over/read_over_binding.dart'; import 'package:school_asignment_app/page/home_page/children/read_over/read_over_view.dart'; import 'package:school_asignment_app/page/home_page/children/student_history_work/student_history_work_binding.dart'; @@ -29,5 +35,9 @@ abstract class AppPages { GetPage(name: Routes.readOverPage, page: () => const ReadOverPage(), binding: ReadOverBinding(), transition: Transition.noTransition), GetPage(name: Routes.studentHistoryWorkPage, page: () => const StudentHistoryWorkPage(), binding: StudentHistoryWorkBinding(), transition: Transition.noTransition), GetPage(name: Routes.classStudentPage, page: () => const ClassStudentPage(), binding: ClassStudentBinding(), transition: Transition.noTransition), + GetPage(name: Routes.annotateClassPage, page: () => const AnnotateClassPage(), binding: AnnotateClassBinding(), transition: Transition.noTransition), + GetPage(name: Routes.quickDataCheckPage, page: () => const QuickDataCheckPage(), binding: QuickDataCheckBinding(), transition: Transition.noTransition), + GetPage(name: Routes.jobReportPage, page: () => const JobReportPage(), binding: JobReportBinding(), transition: Transition.noTransition), + ]; } diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index af7f5ab..5b51d1e 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -11,4 +11,7 @@ abstract class Routes { static const readOverPage = '/readOverPage'; static const studentHistoryWorkPage = '/studentHistoryWorkPage'; static const classStudentPage = '/classStudentPage'; + static const annotateClassPage = '/annotateClassPage'; + static const quickDataCheckPage = '/quickDataCheckPage'; + static const jobReportPage = '/jobReportPage'; } \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 5758047..f25000c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -233,6 +233,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.6" + data_table_2: + dependency: "direct main" + description: + name: data_table_2 + sha256: e403de6d9a58dddf27700114b614ea8ea5aa8442d7fbdfbe8b3d11b0512e7a49 + url: "https://pub.dev" + source: hosted + version: "2.5.12" dbus: dependency: transitive description: @@ -249,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.4.2+1" + equatable: + dependency: transitive + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" fake_async: dependency: transitive description: @@ -281,6 +297,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + fl_chart: + dependency: "direct main" + description: + name: fl_chart + sha256: "48a1b69be9544e2b03d9a8e843affd89e43f3194c9248776222efcb4206bb1ec" + url: "https://pub.dev" + source: hosted + version: "0.62.0" flutter: dependency: "direct main" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 91159ab..0392ebb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,6 +70,9 @@ dependencies: # 进度条 percent_indicator: ^4.2.3 badges: ^3.1.2 + # 图表 + fl_chart: ^0.62.0 + data_table_2: ^2.5.10 dev_dependencies: flutter_test: